2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 00/76] wifi: more MLO work

Hi,

So our MLO work is progressing. Internally, I have limited support
for MLO connections now (over hwsim), but that's at least another
25 patches on top of this series.

But would be good to get things out first anyway. I'm tempted to
just apply this (after net-next merges wireless-next and we will
merge back) though - even if we have more fixes to it later.

johannes



2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 05/76] wifi: cfg80211: Allow MLO TX with link source address

From: Andrei Otcheretianski <[email protected]>

Management frames are transmitted from link address and not device
address. Allow that.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/mlme.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 14584488de67..935537c64ed8 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -637,6 +637,18 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
cfg80211_mgmt_registrations_update(wdev);
}

+static bool cfg80211_allowed_address(struct wireless_dev *wdev, const u8 *addr)
+{
+ int i;
+
+ for_each_valid_link(wdev, i) {
+ if (ether_addr_equal(addr, wdev->links[i].addr))
+ return true;
+ }
+
+ return ether_addr_equal(addr, wdev_address(wdev));
+}
+
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
@@ -735,7 +747,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return err;
}

- if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) {
+ if (!cfg80211_allowed_address(wdev, mgmt->sa)) {
/* Allow random TA to be used with Public Action frames if the
* driver has indicated support for this. Otherwise, only allow
* the local address to be used.
--
2.36.1

2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 01/76] wifi: mac80211_hwsim: Support link channel matching on rx

From: Andrei Otcheretianski <[email protected]>

Accept frames from all the links' channels.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 91440b0dc0cc..7be846d4d63e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1474,15 +1474,25 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
struct ieee80211_vif *vif)
{
struct tx_iter_data *data = _data;
+ int i;

- if (!vif->bss_conf.chanctx_conf)
- return;
+ for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
+ struct ieee80211_bss_conf *conf = vif->link_conf[i];
+ struct ieee80211_chanctx_conf *chanctx;

- if (!hwsim_chans_compat(data->channel,
- rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan))
- return;
+ if (!conf)
+ continue;
+
+ chanctx = rcu_dereference(conf->chanctx_conf);
+ if (!chanctx)
+ continue;
+
+ if (!hwsim_chans_compat(data->channel, chanctx->def.chan))
+ continue;

- data->receive = true;
+ data->receive = true;
+ return;
+ }
}

static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb)
--
2.36.1

2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 02/76] wifi: mac80211: consistently use sdata_dereference()

From: Johannes Berg <[email protected]>

Instead of open-coding it, use sdata_dereference().

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ibss.c | 12 ++++--------
net/mac80211/mesh.c | 9 +++------
2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 65b6255c6747..d30a82f1620b 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -255,8 +255,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
drv_leave_ibss(local, sdata);
}

- presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
+ presp = sdata_dereference(ifibss->presp, sdata);
RCU_INIT_POINTER(ifibss->presp, NULL);
if (presp)
kfree_rcu(presp, rcu_head);
@@ -509,8 +508,7 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
cfg80211_put_bss(sdata->local->hw.wiphy, cbss);

- old_presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
+ old_presp = sdata_dereference(ifibss->presp, sdata);

presp = ieee80211_ibss_build_presp(sdata,
sdata->vif.bss_conf.beacon_int,
@@ -714,8 +712,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
sdata->vif.cfg.ssid_len = 0;

/* remove beacon */
- presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
+ presp = sdata_dereference(ifibss->presp, sdata);
RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
if (presp)
kfree_rcu(presp, rcu_head);
@@ -1530,8 +1527,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,

sdata_assert_lock(sdata);

- presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
+ presp = sdata_dereference(ifibss->presp, sdata);

if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
len < 24 + 2 || !presp)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 13722a7f2254..6160211a7eee 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -993,8 +993,7 @@ ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
struct beacon_data *old_bcn;
int ret;

- old_bcn = rcu_dereference_protected(sdata->u.mesh.beacon,
- lockdep_is_held(&sdata->wdev.mtx));
+ old_bcn = sdata_dereference(sdata->u.mesh.beacon, sdata);
ret = ieee80211_mesh_build_beacon(&sdata->u.mesh);
if (ret)
/* just reuse old beacon */
@@ -1084,8 +1083,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED);

/* remove beacon */
- bcn = rcu_dereference_protected(ifmsh->beacon,
- lockdep_is_held(&sdata->wdev.mtx));
+ bcn = sdata_dereference(ifmsh->beacon, sdata);
RCU_INIT_POINTER(ifmsh->beacon, NULL);
kfree_rcu(bcn, rcu_head);

@@ -1380,8 +1378,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
ifmsh->chsw_ttl = 0;

/* Remove the CSA and MCSP elements from the beacon */
- tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
- lockdep_is_held(&sdata->wdev.mtx));
+ tmp_csa_settings = sdata_dereference(ifmsh->csa, sdata);
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
--
2.36.1

2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 04/76] wifi: mac80211: Consider MLO links in offchannel logic

From: Andrei Otcheretianski <[email protected]>

Check all the MLO links to decide whether offchannel TX is needed.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/offchannel.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 2ed4e2325914..aff5d3c39902 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -842,10 +842,24 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,

/* Check if the operating channel is the requested channel */
if (!need_offchan) {
- struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_chanctx_conf *chanctx_conf = NULL;
+ int i;

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ /* Check all the links first */
+ for (i = 0; i < ARRAY_SIZE(sdata->vif.link_conf); i++) {
+ if (!sdata->vif.link_conf[i])
+ continue;
+
+ chanctx_conf = rcu_dereference(sdata->vif.link_conf[i]->chanctx_conf);
+ if (!chanctx_conf)
+ continue;
+
+ if (ether_addr_equal(sdata->vif.link_conf[i]->addr, mgmt->sa))
+ break;
+
+ chanctx_conf = NULL;
+ }

if (chanctx_conf) {
need_offchan = params->chan &&
--
2.36.1

2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 06/76] wifi: mac80211: Remove AP SMPS leftovers

From: Andrei Otcheretianski <[email protected]>

AP SMPS was removed and not needed anymore. Remove the leftovers.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 1 -
net/mac80211/sta_info.c | 30 ------------------------------
net/mac80211/sta_info.h | 4 ----
net/mac80211/status.c | 3 ---
4 files changed, 38 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 46413b6a8de3..18bab27eda4f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1921,7 +1921,6 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid);
-void ieee80211_request_smps_ap_work(struct work_struct *work);
void ieee80211_request_smps_mgd_work(struct work_struct *work);
bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
enum ieee80211_smps_mode smps_mode_new);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c9852f71e8e1..d738534a709e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -616,36 +616,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
}

sta->sta.smps_mode = IEEE80211_SMPS_OFF;
- if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
- struct ieee80211_supported_band *sband;
- u8 smps;
-
- sband = ieee80211_get_sband(sdata);
- if (!sband)
- goto free_txq;
-
- smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >>
- IEEE80211_HT_CAP_SM_PS_SHIFT;
- /*
- * Assume that hostapd advertises our caps in the beacon and
- * this is the known_smps_mode for a station that just assciated
- */
- switch (smps) {
- case WLAN_HT_SMPS_CONTROL_DISABLED:
- sta->known_smps_mode = IEEE80211_SMPS_OFF;
- break;
- case WLAN_HT_SMPS_CONTROL_STATIC:
- sta->known_smps_mode = IEEE80211_SMPS_STATIC;
- break;
- case WLAN_HT_SMPS_CONTROL_DYNAMIC:
- sta->known_smps_mode = IEEE80211_SMPS_DYNAMIC;
- break;
- default:
- WARN_ON(1);
- }
- }
-
sta->sta.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA;

sta->cparams.ce_threshold = CODEL_DISABLED_THRESHOLD;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 70ee55ec5518..a1724e366a35 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -615,8 +615,6 @@ struct link_sta_info {
* @rcu_head: RCU head used for freeing this station struct
* @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
* taken from HT/VHT capabilities or VHT operating mode notification
- * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
- * AP only.
* @cparams: CoDel parameters for this station.
* @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
* @fast_tx: TX fastpath information
@@ -699,8 +697,6 @@ struct sta_info {
struct dentry *debugfs_dir;
#endif

- enum ieee80211_smps_mode known_smps_mode;
-
struct codel_params cparams;

u8 reserved_tid;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 9bd4d336d444..fad457f99711 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -225,9 +225,6 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
*/
sdata->deflink.smps_mode = smps_mode;
ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
- } else if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
- sta->known_smps_mode = smps_mode;
}
}
}
--
2.36.1

2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 11/76] wifi: nl80211: hold wdev mutex in add/mod/del link station

From: Johannes Berg <[email protected]>

Since we deal with links, and that requires looking at wdev links,
we should hold the wdev mutex for driver convenience.

Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5f6cbc2d73b4..26d277c14fd4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -15781,9 +15781,14 @@ nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,
if (err)
return err;

+ wdev_lock(dev->ieee80211_ptr);
if (add)
- return rdev_add_link_station(rdev, dev, &params);
- return rdev_mod_link_station(rdev, dev, &params);
+ err = rdev_add_link_station(rdev, dev, &params);
+ else
+ err = rdev_mod_link_station(rdev, dev, &params);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return err;
}

static int
@@ -15804,6 +15809,7 @@ nl80211_remove_link_station(struct sk_buff *skb, struct genl_info *info)
struct link_station_del_parameters params = {};
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
+ int ret;

if (!rdev->ops->del_link_station)
return -EOPNOTSUPP;
@@ -15815,7 +15821,11 @@ nl80211_remove_link_station(struct sk_buff *skb, struct genl_info *info)
params.mld_mac = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
params.link_id = nla_get_u8(info->attrs[NL80211_ATTR_MLO_LINK_ID]);

- return rdev_del_link_station(rdev, dev, &params);
+ wdev_lock(dev->ieee80211_ptr);
+ ret = rdev_del_link_station(rdev, dev, &params);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return ret;
}

#define NL80211_FLAG_NEED_WIPHY 0x01
--
2.36.1

2022-07-13 09:47:14

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 08/76] wifi: cfg80211: add API to add/modify/remove a link station

From: Shaul Triebitz <[email protected]>

Add an API for adding/modifying/removing a link of a station.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 64 +++++++++++++
include/uapi/linux/nl80211.h | 8 ++
net/wireless/nl80211.c | 168 +++++++++++++++++++++++++++++++++--
net/wireless/rdev-ops.h | 48 ++++++++++
net/wireless/trace.h | 97 ++++++++++++++++++++
5 files changed, 377 insertions(+), 8 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 140354f5f15b..a26d738a2f52 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1456,6 +1456,61 @@ struct sta_txpwr {
enum nl80211_tx_power_setting type;
};

+/**
+ * struct link_station_parameters - link station parameters
+ *
+ * Used to change and create a new link station.
+ *
+ * @mld_mac: MAC address of the station
+ * @link_id: the link id (-1 for non-MLD station)
+ * @link_mac: MAC address of the link
+ * @supported_rates: supported rates in IEEE 802.11 format
+ * (or NULL for no change)
+ * @supported_rates_len: number of supported rates
+ * @ht_capa: HT capabilities of station
+ * @vht_capa: VHT capabilities of station
+ * @opmode_notif: operating mode field from Operating Mode Notification
+ * @opmode_notif_used: information if operating mode field is used
+ * @he_capa: HE capabilities of station
+ * @he_capa_len: the length of the HE capabilities
+ * @txpwr: transmit power for an associated station
+ * @txpwr_set: txpwr field is set
+ * @he_6ghz_capa: HE 6 GHz Band capabilities of station
+ * @eht_capa: EHT capabilities of station
+ * @eht_capa_len: the length of the EHT capabilities
+ */
+struct link_station_parameters {
+ const u8 *mld_mac;
+ int link_id;
+ const u8 *link_mac;
+ const u8 *supported_rates;
+ u8 supported_rates_len;
+ const struct ieee80211_ht_cap *ht_capa;
+ const struct ieee80211_vht_cap *vht_capa;
+ u8 opmode_notif;
+ bool opmode_notif_used;
+ const struct ieee80211_he_cap_elem *he_capa;
+ u8 he_capa_len;
+ struct sta_txpwr txpwr;
+ bool txpwr_set;
+ const struct ieee80211_he_6ghz_capa *he_6ghz_capa;
+ const struct ieee80211_eht_cap_elem *eht_capa;
+ u8 eht_capa_len;
+};
+
+/**
+ * struct link_station_del_parameters - link station deletion parameters
+ *
+ * Used to delete a link station entry (or all stations).
+ *
+ * @mld_mac: MAC address of the station
+ * @link_id: the link id
+ */
+struct link_station_del_parameters {
+ const u8 *mld_mac;
+ u32 link_id;
+};
+
/**
* struct station_parameters - station parameters
*
@@ -4215,6 +4270,9 @@ struct mgmt_frame_regs {
* radar channel.
* The caller is expected to set chandef pointer to NULL in order to
* disable background CAC/radar detection.
+ * @add_link_station: Add a link to a station.
+ * @mod_link_station: Modify a link of a station.
+ * @del_link_station: Remove a link of a station.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4560,6 +4618,12 @@ struct cfg80211_ops {
struct cfg80211_fils_aad *fils_aad);
int (*set_radar_background)(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef);
+ int (*add_link_station)(struct wiphy *wiphy, struct net_device *dev,
+ struct link_station_parameters *params);
+ int (*mod_link_station)(struct wiphy *wiphy, struct net_device *dev,
+ struct link_station_parameters *params);
+ int (*del_link_station)(struct wiphy *wiphy, struct net_device *dev,
+ struct link_station_del_parameters *params);
};

/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 7bb1ae59f3a5..37bfc934325a 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1254,6 +1254,10 @@
* without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links
* in preparation for e.g. roaming to a regular (non-MLO) AP.
*
+ * @NL80211_CMD_ADD_LINK_STA: Add a link to an MLD station
+ * @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station
+ * @NL80211_CMD_REMOVE_LINK_STA: Remove a link of an MLD station
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1501,6 +1505,10 @@ enum nl80211_commands {
NL80211_CMD_ADD_LINK,
NL80211_CMD_REMOVE_LINK,

+ NL80211_CMD_ADD_LINK_STA,
+ NL80211_CMD_MODIFY_LINK_STA,
+ NL80211_CMD_REMOVE_LINK_STA,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 22c4cf6fbb57..3cf8e01e3f7e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6801,7 +6801,8 @@ static int nl80211_set_station_tdls(struct genl_info *info,
}

static int nl80211_parse_sta_txpower_setting(struct genl_info *info,
- struct station_parameters *params)
+ struct sta_txpwr *txpwr,
+ bool *txpwr_set)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
int idx;
@@ -6813,18 +6814,20 @@ static int nl80211_parse_sta_txpower_setting(struct genl_info *info,
return -EOPNOTSUPP;

idx = NL80211_ATTR_STA_TX_POWER_SETTING;
- params->txpwr.type = nla_get_u8(info->attrs[idx]);
+ txpwr->type = nla_get_u8(info->attrs[idx]);

- if (params->txpwr.type == NL80211_TX_POWER_LIMITED) {
+ if (txpwr->type == NL80211_TX_POWER_LIMITED) {
idx = NL80211_ATTR_STA_TX_POWER;

if (info->attrs[idx])
- params->txpwr.power =
- nla_get_s16(info->attrs[idx]);
+ txpwr->power = nla_get_s16(info->attrs[idx]);
else
return -EINVAL;
}
- params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;
+
+ *txpwr_set = true;
+ } else {
+ *txpwr_set = false;
}

return 0;
@@ -6837,6 +6840,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
struct station_parameters params;
u8 *mac_addr;
int err;
+ bool txpwr_set;

memset(&params, 0, sizeof(params));

@@ -6930,9 +6934,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
return -EOPNOTSUPP;

- err = nl80211_parse_sta_txpower_setting(info, &params);
+ err = nl80211_parse_sta_txpower_setting(info, &params.txpwr, &txpwr_set);
if (err)
return err;
+ if (txpwr_set)
+ params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;

/* Include parameters for TDLS peer (will check later) */
err = nl80211_set_station_tdls(info, &params);
@@ -6975,6 +6981,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
u8 *mac_addr = NULL;
u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
BIT(NL80211_STA_FLAG_ASSOCIATED);
+ bool txpwr_set;

memset(&params, 0, sizeof(params));

@@ -7085,9 +7092,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
return -EOPNOTSUPP;

- err = nl80211_parse_sta_txpower_setting(info, &params);
+ err = nl80211_parse_sta_txpower_setting(info, &params.txpwr, &txpwr_set);
if (err)
return err;
+ if (txpwr_set)
+ params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;

err = nl80211_parse_sta_channel_info(info, &params);
if (err)
@@ -15682,6 +15691,128 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
return 0;
}

+static int
+nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,
+ bool add)
+{
+ struct link_station_parameters params = {};
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ int err;
+
+ if ((add && !rdev->ops->add_link_station) ||
+ (!add && !rdev->ops->mod_link_station))
+ return -EOPNOTSUPP;
+
+ if (add && !info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (add && !info->attrs[NL80211_ATTR_MLD_ADDR])
+ return -EINVAL;
+
+ if (add && !info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_MLD_ADDR])
+ params.mld_mac = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+
+ if (info->attrs[NL80211_ATTR_MAC]) {
+ params.link_mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ if (!is_valid_ether_addr(params.link_mac))
+ return -EINVAL;
+ }
+
+ if (!info->attrs[NL80211_ATTR_MLO_LINK_ID])
+ return -EINVAL;
+
+ params.link_id = nla_get_u8(info->attrs[NL80211_ATTR_MLO_LINK_ID]);
+
+ if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
+ params.supported_rates =
+ nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ params.supported_rates_len =
+ nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+ }
+
+ if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
+ params.ht_capa =
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+
+ if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
+ params.vht_capa =
+ nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
+
+ if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
+ params.he_capa =
+ nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+ params.he_capa_len =
+ nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+
+ if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) {
+ params.eht_capa =
+ nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
+ params.eht_capa_len =
+ nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
+
+ if (!ieee80211_eht_capa_size_ok((const u8 *)params.he_capa,
+ (const u8 *)params.eht_capa,
+ params.eht_capa_len))
+ return -EINVAL;
+ }
+ }
+
+ if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
+ params.he_6ghz_capa =
+ nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
+
+ if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
+ params.opmode_notif_used = true;
+ params.opmode_notif =
+ nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
+ }
+
+ err = nl80211_parse_sta_txpower_setting(info, &params.txpwr,
+ &params.txpwr_set);
+ if (err)
+ return err;
+
+ if (add)
+ return rdev_add_link_station(rdev, dev, &params);
+ return rdev_mod_link_station(rdev, dev, &params);
+}
+
+static int
+nl80211_add_link_station(struct sk_buff *skb, struct genl_info *info)
+{
+ return nl80211_add_mod_link_station(skb, info, true);
+}
+
+static int
+nl80211_modify_link_station(struct sk_buff *skb, struct genl_info *info)
+{
+ return nl80211_add_mod_link_station(skb, info, false);
+}
+
+static int
+nl80211_remove_link_station(struct sk_buff *skb, struct genl_info *info)
+{
+ struct link_station_del_parameters params = {};
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+
+ if (!rdev->ops->del_link_station)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_MLD_ADDR] ||
+ !info->attrs[NL80211_ATTR_MLO_LINK_ID])
+ return -EINVAL;
+
+ params.mld_mac = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+ params.link_id = nla_get_u8(info->attrs[NL80211_ATTR_MLO_LINK_ID]);
+
+ return rdev_del_link_station(rdev, dev, &params);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -16832,6 +16963,27 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_MLO_VALID_LINK_ID),
},
+ {
+ .cmd = NL80211_CMD_ADD_LINK_STA,
+ .doit = nl80211_add_link_station,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_MLO_VALID_LINK_ID),
+ },
+ {
+ .cmd = NL80211_CMD_MODIFY_LINK_STA,
+ .doit = nl80211_modify_link_station,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_MLO_VALID_LINK_ID),
+ },
+ {
+ .cmd = NL80211_CMD_REMOVE_LINK_STA,
+ .doit = nl80211_remove_link_station,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_MLO_VALID_LINK_ID),
+ },
};

static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index a329ba036989..6221a996c19f 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1448,4 +1448,52 @@ rdev_del_intf_link(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}

+static inline int
+rdev_add_link_station(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct link_station_parameters *params)
+{
+ int ret;
+
+ if (!rdev->ops->add_link_station)
+ return -EOPNOTSUPP;
+
+ trace_rdev_add_link_station(&rdev->wiphy, dev, params);
+ ret = rdev->ops->add_link_station(&rdev->wiphy, dev, params);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int
+rdev_mod_link_station(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct link_station_parameters *params)
+{
+ int ret;
+
+ if (!rdev->ops->mod_link_station)
+ return -EOPNOTSUPP;
+
+ trace_rdev_mod_link_station(&rdev->wiphy, dev, params);
+ ret = rdev->ops->mod_link_station(&rdev->wiphy, dev, params);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int
+rdev_del_link_station(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct link_station_del_parameters *params)
+{
+ int ret;
+
+ if (!rdev->ops->del_link_station)
+ return -EOPNOTSUPP;
+
+ trace_rdev_del_link_station(&rdev->wiphy, dev, params);
+ ret = rdev->ops->del_link_station(&rdev->wiphy, dev, params);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 65f8b814ecd0..16d0fe53fcf2 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3775,6 +3775,103 @@ TRACE_EVENT(cfg80211_assoc_comeback,
WDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->timeout)
);

+DECLARE_EVENT_CLASS(link_station_add_mod,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct link_station_parameters *params),
+ TP_ARGS(wiphy, netdev, params),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __array(u8, mld_mac, 6)
+ __array(u8, link_mac, 6)
+ __field(u32, link_id)
+ __dynamic_array(u8, supported_rates,
+ params->supported_rates_len)
+ __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap))
+ __array(u8, vht_capa, (int)sizeof(struct ieee80211_vht_cap))
+ __field(u8, opmode_notif)
+ __field(bool, opmode_notif_used)
+ __dynamic_array(u8, he_capa, params->he_capa_len)
+ __array(u8, he_6ghz_capa, (int)sizeof(struct ieee80211_he_6ghz_capa))
+ __dynamic_array(u8, eht_capa, params->eht_capa_len)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ memset(__entry->mld_mac, 0, 6);
+ memset(__entry->link_mac, 0, 6);
+ if (params->mld_mac)
+ memcpy(__entry->mld_mac, params->mld_mac, 6);
+ if (params->link_mac)
+ memcpy(__entry->link_mac, params->link_mac, 6);
+ __entry->link_id = params->link_id;
+ if (params->supported_rates && params->supported_rates_len)
+ memcpy(__get_dynamic_array(supported_rates),
+ params->supported_rates,
+ params->supported_rates_len);
+ memset(__entry->ht_capa, 0, sizeof(struct ieee80211_ht_cap));
+ if (params->ht_capa)
+ memcpy(__entry->ht_capa, params->ht_capa,
+ sizeof(struct ieee80211_ht_cap));
+ memset(__entry->vht_capa, 0, sizeof(struct ieee80211_vht_cap));
+ if (params->vht_capa)
+ memcpy(__entry->vht_capa, params->vht_capa,
+ sizeof(struct ieee80211_vht_cap));
+ __entry->opmode_notif = params->opmode_notif;
+ __entry->opmode_notif_used = params->opmode_notif_used;
+ if (params->he_capa && params->he_capa_len)
+ memcpy(__get_dynamic_array(he_capa), params->he_capa,
+ params->he_capa_len);
+ memset(__entry->he_6ghz_capa, 0, sizeof(struct ieee80211_he_6ghz_capa));
+ if (params->he_6ghz_capa)
+ memcpy(__entry->he_6ghz_capa, params->he_6ghz_capa,
+ sizeof(struct ieee80211_he_6ghz_capa));
+ if (params->eht_capa && params->eht_capa_len)
+ memcpy(__get_dynamic_array(eht_capa), params->eht_capa,
+ params->eht_capa_len);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+ ", link mac: " MAC_PR_FMT ", link id: %u",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(mld_mac),
+ MAC_PR_ARG(link_mac), __entry->link_id)
+);
+
+DEFINE_EVENT(link_station_add_mod, rdev_add_link_station,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct link_station_parameters *params),
+ TP_ARGS(wiphy, netdev, params)
+);
+
+DEFINE_EVENT(link_station_add_mod, rdev_mod_link_station,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct link_station_parameters *params),
+ TP_ARGS(wiphy, netdev, params)
+);
+
+TRACE_EVENT(rdev_del_link_station,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct link_station_del_parameters *params),
+ TP_ARGS(wiphy, netdev, params),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __array(u8, mld_mac, 6)
+ __field(u32, link_id)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ memset(__entry->mld_mac, 0, 6);
+ if (params->mld_mac)
+ memcpy(__entry->mld_mac, params->mld_mac, 6);
+ __entry->link_id = params->link_id;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+ ", link id: %u",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(mld_mac),
+ __entry->link_id)
+);
+
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */

#undef TRACE_INCLUDE_PATH
--
2.36.1

2022-07-13 09:47:19

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 09/76] wifi: cfg80211/mac80211: separate link params from station params

From: Shaul Triebitz <[email protected]>

Put the link_station_parameters structure in the station_parameters
structure (and remove the station_parameters fields already existing
in link_station_parameters).
Now, for an MLD station, the default link is added together with
the station.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
.../net/wireless/marvell/mwifiex/sta_cmd.c | 20 +--
drivers/net/wireless/microchip/wilc1000/hif.c | 20 +--
include/net/cfg80211.h | 28 +---
net/mac80211/cfg.c | 143 +++++++++++-------
net/wireless/nl80211.c | 97 ++++++------
net/wireless/trace.h | 24 +--
6 files changed, 180 insertions(+), 152 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
index 1e2798dce18f..851ea58fb38e 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
@@ -1790,29 +1790,31 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
wmm_qos_info->qos_info = 0;
config_len += sizeof(struct mwifiex_ie_types_qos_info);

- if (params->ht_capa) {
+ if (params->link_sta_params.ht_capa) {
ht_capab = (struct mwifiex_ie_types_htcap *)(pos +
config_len);
ht_capab->header.type =
cpu_to_le16(WLAN_EID_HT_CAPABILITY);
ht_capab->header.len =
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
- memcpy(&ht_capab->ht_cap, params->ht_capa,
+ memcpy(&ht_capab->ht_cap, params->link_sta_params.ht_capa,
sizeof(struct ieee80211_ht_cap));
config_len += sizeof(struct mwifiex_ie_types_htcap);
}

- if (params->supported_rates && params->supported_rates_len) {
+ if (params->link_sta_params.supported_rates &&
+ params->link_sta_params.supported_rates_len) {
tlv_rates = (struct host_cmd_tlv_rates *)(pos +
config_len);
tlv_rates->header.type =
cpu_to_le16(WLAN_EID_SUPP_RATES);
tlv_rates->header.len =
- cpu_to_le16(params->supported_rates_len);
- memcpy(tlv_rates->rates, params->supported_rates,
- params->supported_rates_len);
+ cpu_to_le16(params->link_sta_params.supported_rates_len);
+ memcpy(tlv_rates->rates,
+ params->link_sta_params.supported_rates,
+ params->link_sta_params.supported_rates_len);
config_len += sizeof(struct host_cmd_tlv_rates) +
- params->supported_rates_len;
+ params->link_sta_params.supported_rates_len;
}

if (params->ext_capab && params->ext_capab_len) {
@@ -1826,14 +1828,14 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
config_len += sizeof(struct mwifiex_ie_types_extcap) +
params->ext_capab_len;
}
- if (params->vht_capa) {
+ if (params->link_sta_params.vht_capa) {
vht_capab = (struct mwifiex_ie_types_vhtcap *)(pos +
config_len);
vht_capab->header.type =
cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
vht_capab->header.len =
cpu_to_le16(sizeof(struct ieee80211_vht_cap));
- memcpy(&vht_capab->vht_cap, params->vht_capa,
+ memcpy(&vht_capab->vht_cap, params->link_sta_params.vht_capa,
sizeof(struct ieee80211_vht_cap));
config_len += sizeof(struct mwifiex_ie_types_vhtcap);
}
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index 4038a254465f..021e0db80bd2 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -816,15 +816,15 @@ static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
put_unaligned_le16(params->aid, cur_byte);
cur_byte += 2;

- *cur_byte++ = params->supported_rates_len;
- if (params->supported_rates_len > 0)
- memcpy(cur_byte, params->supported_rates,
- params->supported_rates_len);
- cur_byte += params->supported_rates_len;
+ *cur_byte++ = params->link_sta_params.supported_rates_len;
+ if (params->link_sta_params.supported_rates_len > 0)
+ memcpy(cur_byte, params->link_sta_params.supported_rates,
+ params->link_sta_params.supported_rates_len);
+ cur_byte += params->link_sta_params.supported_rates_len;

- if (params->ht_capa) {
+ if (params->link_sta_params.ht_capa) {
*cur_byte++ = true;
- memcpy(cur_byte, params->ht_capa,
+ memcpy(cur_byte, params->link_sta_params.ht_capa,
sizeof(struct ieee80211_ht_cap));
} else {
*cur_byte++ = false;
@@ -1799,7 +1799,8 @@ int wilc_add_station(struct wilc_vif *vif, const u8 *mac,

wid.id = WID_ADD_STA;
wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+ wid.size = WILC_ADD_STA_LENGTH +
+ params->link_sta_params.supported_rates_len;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
return -ENOMEM;
@@ -1884,7 +1885,8 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,

wid.id = WID_EDIT_STA;
wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+ wid.size = WILC_ADD_STA_LENGTH +
+ params->link_sta_params.supported_rates_len;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
return -ENOMEM;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a26d738a2f52..d4632b391a15 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1433,7 +1433,6 @@ enum station_parameters_apply_mask {
STATION_PARAM_APPLY_UAPSD = BIT(0),
STATION_PARAM_APPLY_CAPABILITY = BIT(1),
STATION_PARAM_APPLY_PLINK_STATE = BIT(2),
- STATION_PARAM_APPLY_STA_TXPOWER = BIT(3),
};

/**
@@ -1517,9 +1516,6 @@ struct link_station_del_parameters {
* Used to change and create a new station.
*
* @vlan: vlan interface station should belong to
- * @supported_rates: supported rates in IEEE 802.11 format
- * (or NULL for no change)
- * @supported_rates_len: number of supported rates
* @sta_flags_mask: station flags that changed
* (bitmask of BIT(%NL80211_STA_FLAG_...))
* @sta_flags_set: station flags values
@@ -1530,8 +1526,6 @@ struct link_station_del_parameters {
* @peer_aid: mesh peer AID or zero for no change
* @plink_action: plink action to take
* @plink_state: set the peer link state for a station
- * @ht_capa: HT capabilities of station
- * @vht_capa: VHT capabilities of station
* @uapsd_queues: bitmap of queues configured for uapsd. same format
* as the AC bitmap in the QoS info field
* @max_sp: max Service Period. same format as the MAX_SP in the
@@ -1548,19 +1542,11 @@ struct link_station_del_parameters {
* @supported_channels_len: number of supported channels
* @supported_oper_classes: supported oper classes in IEEE 802.11 format
* @supported_oper_classes_len: number of supported operating classes
- * @opmode_notif: operating mode field from Operating Mode Notification
- * @opmode_notif_used: information if operating mode field is used
* @support_p2p_ps: information if station supports P2P PS mechanism
- * @he_capa: HE capabilities of station
- * @he_capa_len: the length of the HE capabilities
* @airtime_weight: airtime scheduler weight for this station
- * @txpwr: transmit power for an associated station
- * @he_6ghz_capa: HE 6 GHz Band capabilities of station
- * @eht_capa: EHT capabilities of station
- * @eht_capa_len: the length of the EHT capabilities
+ * @link_sta_params: link related params.
*/
struct station_parameters {
- const u8 *supported_rates;
struct net_device *vlan;
u32 sta_flags_mask, sta_flags_set;
u32 sta_modify_mask;
@@ -1568,11 +1554,8 @@ struct station_parameters {
u16 aid;
u16 vlan_id;
u16 peer_aid;
- u8 supported_rates_len;
u8 plink_action;
u8 plink_state;
- const struct ieee80211_ht_cap *ht_capa;
- const struct ieee80211_vht_cap *vht_capa;
u8 uapsd_queues;
u8 max_sp;
enum nl80211_mesh_power_mode local_pm;
@@ -1583,16 +1566,9 @@ struct station_parameters {
u8 supported_channels_len;
const u8 *supported_oper_classes;
u8 supported_oper_classes_len;
- u8 opmode_notif;
- bool opmode_notif_used;
int support_p2p_ps;
- const struct ieee80211_he_cap_elem *he_capa;
- u8 he_capa_len;
u16 airtime_weight;
- struct sta_txpwr txpwr;
- const struct ieee80211_he_6ghz_capa *he_6ghz_capa;
- const struct ieee80211_eht_cap_elem *eht_capa;
- u8 eht_capa_len;
+ struct link_station_parameters link_sta_params;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fd6c4291c971..a63f9235bcc3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1581,6 +1581,83 @@ static void sta_apply_mesh_params(struct ieee80211_local *local,
#endif
}

+static int sta_link_apply_parameters(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct link_station_parameters *params)
+{
+ int ret = 0;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u32 link_id = params->link_id < 0 ? 0 : params->link_id;
+ struct link_sta_info *link_sta =
+ rcu_dereference_protected(sta->link[link_id],
+ lockdep_is_held(&local->sta_mtx));
+
+ if (WARN_ON(!link_sta))
+ return -EINVAL;
+
+ sband = ieee80211_get_link_sband(sdata, link_id);
+ if (!sband)
+ return -EINVAL;
+
+ if (params->link_mac) {
+ memcpy(link_sta->addr, params->link_mac, ETH_ALEN);
+ memcpy(link_sta->pub->addr, params->link_mac, ETH_ALEN);
+ }
+
+ if (params->txpwr_set) {
+ link_sta->pub->txpwr.type = params->txpwr.type;
+ if (params->txpwr.type == NL80211_TX_POWER_LIMITED)
+ link_sta->pub->txpwr.power = params->txpwr.power;
+ ret = drv_sta_set_txpwr(local, sdata, sta);
+ if (ret)
+ return ret;
+ }
+
+ if (params->supported_rates &&
+ params->supported_rates_len) {
+ ieee80211_parse_bitrates(&sdata->vif.link_conf[link_id]->chandef,
+ sband, params->supported_rates,
+ params->supported_rates_len,
+ &link_sta->pub->supp_rates[sband->band]);
+ }
+
+ if (params->ht_capa)
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
+ params->ht_capa, link_sta);
+
+ /* VHT can override some HT caps such as the A-MSDU max length */
+ if (params->vht_capa)
+ ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+ params->vht_capa, link_sta);
+
+ if (params->he_capa)
+ ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
+ (void *)params->he_capa,
+ params->he_capa_len,
+ (void *)params->he_6ghz_capa,
+ link_sta);
+
+ if (params->eht_capa)
+ ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
+ (u8 *)params->he_capa,
+ params->he_capa_len,
+ params->eht_capa,
+ params->eht_capa_len,
+ link_sta);
+
+ if (params->opmode_notif_used) {
+ /* returned value is only needed for rc update, but the
+ * rc isn't initialized here yet, so ignore it
+ */
+ __ieee80211_vht_handle_opmode(sdata, link_sta,
+ params->opmode_notif,
+ sband->band);
+ }
+
+ return ret;
+}
+
static int sta_apply_parameters(struct ieee80211_local *local,
struct sta_info *sta,
struct station_parameters *params)
@@ -1588,9 +1665,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
int ret = 0;
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u32 link_id = params->link_sta_params.link_id < 0 ?
+ 0 : params->link_sta_params.link_id;
u32 mask, set;

- sband = ieee80211_get_sband(sdata);
+ sband = ieee80211_get_link_sband(sdata, link_id);
if (!sband)
return -EINVAL;

@@ -1721,56 +1800,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (params->listen_interval >= 0)
sta->listen_interval = params->listen_interval;

- if (params->sta_modify_mask & STATION_PARAM_APPLY_STA_TXPOWER) {
- sta->sta.deflink.txpwr.type = params->txpwr.type;
- if (params->txpwr.type == NL80211_TX_POWER_LIMITED)
- sta->sta.deflink.txpwr.power = params->txpwr.power;
- ret = drv_sta_set_txpwr(local, sdata, sta);
- if (ret)
- return ret;
- }
-
- if (params->supported_rates && params->supported_rates_len) {
- ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
- sband, params->supported_rates,
- params->supported_rates_len,
- &sta->sta.deflink.supp_rates[sband->band]);
- }
-
- if (params->ht_capa)
- ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
- params->ht_capa,
- &sta->deflink);
-
- /* VHT can override some HT caps such as the A-MSDU max length */
- if (params->vht_capa)
- ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
- params->vht_capa,
- &sta->deflink);
-
- if (params->he_capa)
- ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
- (void *)params->he_capa,
- params->he_capa_len,
- (void *)params->he_6ghz_capa,
- &sta->deflink);
-
- if (params->eht_capa)
- ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
- (u8 *)params->he_capa,
- params->he_capa_len,
- params->eht_capa,
- params->eht_capa_len,
- &sta->deflink);
-
- if (params->opmode_notif_used) {
- /* returned value is only needed for rc update, but the
- * rc isn't initialized here yet, so ignore it
- */
- __ieee80211_vht_handle_opmode(sdata, &sta->deflink,
- params->opmode_notif,
- sband->band);
- }
+ ret = sta_link_apply_parameters(local, sta, &params->link_sta_params);
+ if (ret)
+ return ret;

if (params->support_p2p_ps >= 0)
sta->sta.support_p2p_ps = params->support_p2p_ps;
@@ -1821,14 +1853,21 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
!sdata->u.mgd.associated)
return -EINVAL;

- sta = sta_info_alloc(sdata, mac, -1, GFP_KERNEL);
+ sta = sta_info_alloc(sdata, mac, params->link_sta_params.link_id,
+ GFP_KERNEL);
if (!sta)
return -ENOMEM;

if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
sta->sta.tdls = true;

+ /* Though the mutex is not needed here (since the station is not
+ * visible yet), sta_apply_parameters (and inner functions) require
+ * the mutex due to other paths.
+ */
+ mutex_lock(&local->sta_mtx);
err = sta_apply_parameters(local, sta, params);
+ mutex_unlock(&local->sta_mtx);
if (err) {
sta_info_free(local, sta);
return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3cf8e01e3f7e..5f6cbc2d73b4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6573,10 +6573,12 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
return -EINVAL;
if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
return -EINVAL;
- if (params->supported_rates)
+ if (params->link_sta_params.supported_rates)
return -EINVAL;
- if (params->ext_capab || params->ht_capa || params->vht_capa ||
- params->he_capa || params->eht_capa)
+ if (params->ext_capab || params->link_sta_params.ht_capa ||
+ params->link_sta_params.vht_capa ||
+ params->link_sta_params.he_capa ||
+ params->link_sta_params.eht_capa)
return -EINVAL;
}

@@ -6624,7 +6626,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
return -EINVAL;
/* force (at least) rates when authorizing */
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
- !params->supported_rates)
+ !params->link_sta_params.supported_rates)
return -EINVAL;
break;
case CFG80211_STA_TDLS_PEER_ACTIVE:
@@ -6648,7 +6650,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
*/
if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
statype != CFG80211_STA_TDLS_PEER_SETUP)
- params->opmode_notif_used = false;
+ params->link_sta_params.opmode_notif_used = false;

return 0;
}
@@ -6769,26 +6771,26 @@ static int nl80211_set_station_tdls(struct genl_info *info,
if (info->attrs[NL80211_ATTR_PEER_AID])
params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
- params->ht_capa =
+ params->link_sta_params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
- params->vht_capa =
+ params->link_sta_params.vht_capa =
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
- params->he_capa =
+ params->link_sta_params.he_capa =
nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
- params->he_capa_len =
+ params->link_sta_params.he_capa_len =
nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);

if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) {
- params->eht_capa =
+ params->link_sta_params.eht_capa =
nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
- params->eht_capa_len =
+ params->link_sta_params.eht_capa_len =
nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);

- if (!ieee80211_eht_capa_size_ok((const u8 *)params->he_capa,
- (const u8 *)params->eht_capa,
- params->eht_capa_len))
+ if (!ieee80211_eht_capa_size_ok((const u8 *)params->link_sta_params.he_capa,
+ (const u8 *)params->link_sta_params.eht_capa,
+ params->link_sta_params.eht_capa_len))
return -EINVAL;
}
}
@@ -6840,7 +6842,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
struct station_parameters params;
u8 *mac_addr;
int err;
- bool txpwr_set;

memset(&params, 0, sizeof(params));

@@ -6876,9 +6877,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);

if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
- params.supported_rates =
+ params.link_sta_params.supported_rates =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
- params.supported_rates_len =
+ params.link_sta_params.supported_rates_len =
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
}

@@ -6916,13 +6917,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);

if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
- params.opmode_notif_used = true;
- params.opmode_notif =
+ params.link_sta_params.opmode_notif_used = true;
+ params.link_sta_params.opmode_notif =
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
}

if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
- params.he_6ghz_capa =
+ params.link_sta_params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);

if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
@@ -6934,11 +6935,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
return -EOPNOTSUPP;

- err = nl80211_parse_sta_txpower_setting(info, &params.txpwr, &txpwr_set);
+ err = nl80211_parse_sta_txpower_setting(info,
+ &params.link_sta_params.txpwr,
+ &params.link_sta_params.txpwr_set);
if (err)
return err;
- if (txpwr_set)
- params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;

/* Include parameters for TDLS peer (will check later) */
err = nl80211_set_station_tdls(info, &params);
@@ -6981,7 +6982,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
u8 *mac_addr = NULL;
u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
BIT(NL80211_STA_FLAG_ASSOCIATED);
- bool txpwr_set;

memset(&params, 0, sizeof(params));

@@ -7001,10 +7001,13 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_PEER_AID])
return -EINVAL;

+ params.link_sta_params.link_id =
+ nl80211_link_id_or_invalid(info->attrs);
+
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- params.supported_rates =
+ params.link_sta_params.supported_rates =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
- params.supported_rates_len =
+ params.link_sta_params.supported_rates_len =
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
params.listen_interval =
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
@@ -7043,39 +7046,39 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
}

if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
- params.ht_capa =
+ params.link_sta_params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);

if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
- params.vht_capa =
+ params.link_sta_params.vht_capa =
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);

if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
- params.he_capa =
+ params.link_sta_params.he_capa =
nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
- params.he_capa_len =
+ params.link_sta_params.he_capa_len =
nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);

if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) {
- params.eht_capa =
+ params.link_sta_params.eht_capa =
nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
- params.eht_capa_len =
+ params.link_sta_params.eht_capa_len =
nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);

- if (!ieee80211_eht_capa_size_ok((const u8 *)params.he_capa,
- (const u8 *)params.eht_capa,
- params.eht_capa_len))
+ if (!ieee80211_eht_capa_size_ok((const u8 *)params.link_sta_params.he_capa,
+ (const u8 *)params.link_sta_params.eht_capa,
+ params.link_sta_params.eht_capa_len))
return -EINVAL;
}
}

if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
- params.he_6ghz_capa =
+ params.link_sta_params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);

if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
- params.opmode_notif_used = true;
- params.opmode_notif =
+ params.link_sta_params.opmode_notif_used = true;
+ params.link_sta_params.opmode_notif =
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
}

@@ -7092,11 +7095,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
return -EOPNOTSUPP;

- err = nl80211_parse_sta_txpower_setting(info, &params.txpwr, &txpwr_set);
+ err = nl80211_parse_sta_txpower_setting(info,
+ &params.link_sta_params.txpwr,
+ &params.link_sta_params.txpwr_set);
if (err)
return err;
- if (txpwr_set)
- params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;

err = nl80211_parse_sta_channel_info(info, &params);
if (err)
@@ -7115,17 +7118,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
* error in this case.
*/
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
- params.ht_capa = NULL;
- params.vht_capa = NULL;
+ params.link_sta_params.ht_capa = NULL;
+ params.link_sta_params.vht_capa = NULL;

/* HE and EHT require WME */
- if (params.he_capa_len || params.he_6ghz_capa ||
- params.eht_capa_len)
+ if (params.link_sta_params.he_capa_len ||
+ params.link_sta_params.he_6ghz_capa ||
+ params.link_sta_params.eht_capa_len)
return -EINVAL;
}

/* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */
- if (params.he_6ghz_capa && (params.ht_capa || params.vht_capa))
+ if (params.link_sta_params.he_6ghz_capa &&
+ (params.link_sta_params.ht_capa || params.link_sta_params.vht_capa))
return -EINVAL;

/* When you run into this, adjust the code below for the new flag */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 16d0fe53fcf2..e78bffbc6f95 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -738,7 +738,7 @@ DECLARE_EVENT_CLASS(station_add_change,
__array(u8, vht_capa, (int)sizeof(struct ieee80211_vht_cap))
__array(char, vlan, IFNAMSIZ)
__dynamic_array(u8, supported_rates,
- params->supported_rates_len)
+ params->link_sta_params.supported_rates_len)
__dynamic_array(u8, ext_capab, params->ext_capab_len)
__dynamic_array(u8, supported_channels,
params->supported_channels_len)
@@ -758,20 +758,23 @@ DECLARE_EVENT_CLASS(station_add_change,
__entry->plink_state = params->plink_state;
__entry->uapsd_queues = params->uapsd_queues;
memset(__entry->ht_capa, 0, sizeof(struct ieee80211_ht_cap));
- if (params->ht_capa)
- memcpy(__entry->ht_capa, params->ht_capa,
+ if (params->link_sta_params.ht_capa)
+ memcpy(__entry->ht_capa,
+ params->link_sta_params.ht_capa,
sizeof(struct ieee80211_ht_cap));
memset(__entry->vht_capa, 0, sizeof(struct ieee80211_vht_cap));
- if (params->vht_capa)
- memcpy(__entry->vht_capa, params->vht_capa,
+ if (params->link_sta_params.vht_capa)
+ memcpy(__entry->vht_capa,
+ params->link_sta_params.vht_capa,
sizeof(struct ieee80211_vht_cap));
memset(__entry->vlan, 0, sizeof(__entry->vlan));
if (params->vlan)
memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ);
- if (params->supported_rates && params->supported_rates_len)
+ if (params->link_sta_params.supported_rates &&
+ params->link_sta_params.supported_rates_len)
memcpy(__get_dynamic_array(supported_rates),
- params->supported_rates,
- params->supported_rates_len);
+ params->link_sta_params.supported_rates,
+ params->link_sta_params.supported_rates_len);
if (params->ext_capab && params->ext_capab_len)
memcpy(__get_dynamic_array(ext_capab),
params->ext_capab,
@@ -788,8 +791,9 @@ DECLARE_EVENT_CLASS(station_add_change,
params->supported_oper_classes_len);
__entry->max_sp = params->max_sp;
__entry->capability = params->capability;
- __entry->opmode_notif = params->opmode_notif;
- __entry->opmode_notif_used = params->opmode_notif_used;
+ __entry->opmode_notif = params->link_sta_params.opmode_notif;
+ __entry->opmode_notif_used =
+ params->link_sta_params.opmode_notif_used;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
", station flags mask: %u, station flags set: %u, "
--
2.36.1

2022-07-13 09:47:21

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 19/76] wifi: mac80211: debug: omit link if non-MLO connection

From: Johannes Berg <[email protected]>

If we don't really have multiple links, omit the link ID from
link debug prints, otherwise we change the format for all of
the existing drivers (most of which might never support MLO),
and also have extra noise in the logs.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/debug.h | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 3302e8da0314..b4c20f5e778e 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -135,14 +135,33 @@ do { \
_sdata_dbg(1, sdata, fmt, ##__VA_ARGS__)

#define link_info(link, fmt, ...) \
- _sdata_info((link)->sdata, "[link %d] " fmt, (link)->link_id, \
- ##__VA_ARGS__)
+ do { \
+ if ((link)->sdata->vif.valid_links) \
+ _sdata_info((link)->sdata, "[link %d] " fmt, \
+ (link)->link_id, \
+ ##__VA_ARGS__); \
+ else \
+ _sdata_info((link)->sdata, fmt, ##__VA_ARGS__); \
+ } while (0)
#define link_err(link, fmt, ...) \
- _sdata_err((link)->sdata, "[link %d] " fmt, (link)->link_id, \
- ##__VA_ARGS__)
+ do { \
+ if ((link)->sdata->vif.valid_links) \
+ _sdata_err((link)->sdata, "[link %d] " fmt, \
+ (link)->link_id, \
+ ##__VA_ARGS__); \
+ else \
+ _sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
+ } while (0)
#define link_dbg(link, fmt, ...) \
- _sdata_dbg(1, (link)->sdata, "[link %d] " fmt, (link)->link_id, \
- ##__VA_ARGS__)
+ do { \
+ if ((link)->sdata->vif.valid_links) \
+ _sdata_dbg(1, (link)->sdata, "[link %d] " fmt, \
+ (link)->link_id, \
+ ##__VA_ARGS__); \
+ else \
+ _sdata_dbg(1, (link)->sdata, fmt, \
+ ##__VA_ARGS__); \
+ } while (0)

#define ht_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_HT_DEBUG, \
--
2.36.1

2022-07-13 09:47:22

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 26/76] wifi: mac80211: provide link ID in link_conf

From: Johannes Berg <[email protected]>

It might be useful to drivers to be able to pass only the
link_conf pointer, rather than both the pointer and the
link_id; add the link_id to the link_conf to facility that.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 2 ++
net/mac80211/iface.c | 1 +
2 files changed, 3 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e6c77e12f94a..f917f7d7614e 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -516,6 +516,7 @@ struct ieee80211_fils_discovery {
* to that BSS) that can change during the lifetime of the BSS.
*
* @addr: (link) address used locally
+ * @link_id: link ID, or 0 for non-MLO
* @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE
* @uora_exists: is the UORA element advertised by AP
* @ack_enabled: indicates support to receive a multi-TID that solicits either
@@ -639,6 +640,7 @@ struct ieee80211_fils_discovery {
*/
struct ieee80211_bss_conf {
const u8 *bssid;
+ unsigned int link_id;
u8 addr[ETH_ALEN] __aligned(2);
u8 htc_trig_based_pkt_ext;
bool uora_exists;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3e1d46119f7a..28fe0735b9a8 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -390,6 +390,7 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
link->sdata = sdata;
link->link_id = link_id;
link->conf = link_conf;
+ link_conf->link_id = link_id;

INIT_WORK(&link->csa_finalize_work,
ieee80211_csa_finalize_work);
--
2.36.1

2022-07-13 09:47:22

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 14/76] wifi: mac80211: RCU-ify link/link_conf pointers

From: Johannes Berg <[email protected]>

Since links can be added and removed dynamically, we need to
somehow protect the sdata->link[] and vif->link_conf[] array
pointers from disappearing when accessing them without locks.
RCU-ify the pointers to achieve this, which requires quite a
bit of rework.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 14 ++-
include/net/mac80211.h | 6 +-
net/mac80211/cfg.c | 169 +++++++++++++++++---------
net/mac80211/chan.c | 123 ++++++++++---------
net/mac80211/debugfs_netdev.c | 2 +-
net/mac80211/driver-ops.h | 10 +-
net/mac80211/ht.c | 24 +++-
net/mac80211/ibss.c | 8 +-
net/mac80211/ieee80211_i.h | 21 ++--
net/mac80211/iface.c | 36 +++---
net/mac80211/main.c | 9 +-
net/mac80211/mesh.c | 7 +-
net/mac80211/mlme.c | 30 +++--
net/mac80211/ocb.c | 4 +-
net/mac80211/offchannel.c | 15 ++-
net/mac80211/rx.c | 8 +-
net/mac80211/sta_info.c | 3 +-
net/mac80211/tdls.c | 3 +-
net/mac80211/trace.h | 19 +--
net/mac80211/tx.c | 88 +++++++-------
net/mac80211/util.c | 34 +++---
net/mac80211/vht.c | 62 +++++++---
22 files changed, 420 insertions(+), 275 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7be846d4d63e..8cc813f66010 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1477,9 +1477,10 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
int i;

for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
- struct ieee80211_bss_conf *conf = vif->link_conf[i];
+ struct ieee80211_bss_conf *conf;
struct ieee80211_chanctx_conf *chanctx;

+ conf = rcu_dereference(vif->link_conf[i]);
if (!conf)
continue;

@@ -1917,7 +1918,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
{
struct mac80211_hwsim_link_data *link_data = arg;
u32 link_id = link_data->link_id;
- struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf;
struct mac80211_hwsim_data *data =
container_of(link_data, struct mac80211_hwsim_data,
link_data[link_id]);
@@ -1931,6 +1932,10 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,

hwsim_check_magic(vif);

+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ if (!link_conf)
+ return;
+
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_MESH_POINT &&
vif->type != NL80211_IFTYPE_ADHOC &&
@@ -2155,12 +2160,11 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw,

static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u32 link_id,
- u64 changed)
+ struct ieee80211_bss_conf *info,
+ u32 link_id, u64 changed)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
struct mac80211_hwsim_data *data = hw->priv;
- struct ieee80211_bss_conf *info = vif->link_conf[link_id];
struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id];

hwsim_check_magic(vif);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 256b9215e17b..e6c77e12f94a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1789,7 +1789,7 @@ struct ieee80211_vif {
enum nl80211_iftype type;
struct ieee80211_vif_cfg cfg;
struct ieee80211_bss_conf bss_conf;
- struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
u16 valid_links;
u8 addr[ETH_ALEN] __aligned(2);
bool p2p;
@@ -4082,7 +4082,9 @@ struct ieee80211_ops {
u64 changed);
void (*link_info_changed)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id, u64 changed);
+ struct ieee80211_bss_conf *info,
+ unsigned int link_id,
+ u64 changed);

int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
unsigned int link_id);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 777c133c3f0b..058163b97c9a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -39,7 +39,7 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
memcpy(sdata->vif.bss_conf.mu_group.position,
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
WLAN_USER_POSITION_LEN);
- ieee80211_link_info_change_notify(sdata, 0,
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_MU_GROUPS);
/* don't care about endianness - just check for 0 */
memcpy(&membership, params->vht_mumimo_groups,
@@ -841,8 +841,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
sdata = wiphy_dereference(local->hw.wiphy,
local->monitor_sdata);
if (sdata) {
- ieee80211_link_release_channel(sdata->link[0]);
- ret = ieee80211_link_use_channel(sdata->link[0],
+ ieee80211_link_release_channel(&sdata->deflink);
+ ret = ieee80211_link_use_channel(&sdata->deflink,
chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
}
@@ -1008,6 +1008,7 @@ ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst,
}

static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link,
struct cfg80211_beacon_data *params,
const struct ieee80211_csa_settings *csa,
const struct ieee80211_color_change_settings *cca)
@@ -1017,9 +1018,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
int new_head_len, new_tail_len;
int size, err;
u32 changed = BSS_CHANGED_BEACON;
- struct ieee80211_link_data *link = sdata->link[params->link_id];
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[params->link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;

old = sdata_dereference(link->u.ap.beacon, sdata);

@@ -1153,8 +1152,14 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
int i, err;
int prev_beacon_int;
unsigned int link_id = params->beacon.link_id;
- struct ieee80211_link_data *link = sdata->link[link_id];
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link;
+ struct ieee80211_bss_conf *link_conf;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ link_conf = link->conf;

old = sdata_dereference(link->u.ap.beacon, sdata);
if (old)
@@ -1264,7 +1269,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL))
link_conf->beacon_tx_rate = params->beacon_rate;

- err = ieee80211_assign_beacon(sdata, &params->beacon, NULL, NULL);
+ err = ieee80211_assign_beacon(sdata, link, &params->beacon, NULL, NULL);
if (err < 0)
goto error;
changed |= err;
@@ -1300,7 +1305,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,

ieee80211_recalc_dtim(local, sdata);
ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID);
- ieee80211_link_info_change_notify(sdata, link_id, changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);

netif_carrier_on(dev);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
@@ -1320,25 +1325,30 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_beacon_data *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_link_data *link;
struct beacon_data *old;
int err;
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[params->link_id];
+ struct ieee80211_bss_conf *link_conf;

sdata_assert_lock(sdata);

+ link = sdata_dereference(sdata->link[params->link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ link_conf = link->conf;
+
/* don't allow changing the beacon while a countdown is in place - offset
* of channel switch counter may change
*/
if (link_conf->csa_active || link_conf->color_change_active)
return -EBUSY;

- old = sdata_dereference(sdata->link[params->link_id]->u.ap.beacon,
- sdata);
+ old = sdata_dereference(link->u.ap.beacon, sdata);
if (!old)
return -ENOENT;

- err = ieee80211_assign_beacon(sdata, params, NULL, NULL);
+ err = ieee80211_assign_beacon(sdata, link, params, NULL, NULL);
if (err < 0)
return err;

@@ -1348,7 +1358,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
err |= BSS_CHANGED_HE_BSS_COLOR;
}

- ieee80211_link_info_change_notify(sdata, params->link_id, err);
+ ieee80211_link_info_change_notify(sdata, link, err);
return 0;
}

@@ -1373,8 +1383,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
struct fils_discovery_data *old_fils_discovery;
struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp;
struct cfg80211_chan_def chandef;
- struct ieee80211_link_data *link = sdata->link[link_id];
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link =
+ sdata_dereference(sdata->link[link_id], sdata);
+ struct ieee80211_bss_conf *link_conf = link->conf;

sdata_assert_lock(sdata);

@@ -1431,7 +1442,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->beacon_rate_set = false;
sdata->vif.cfg.ssid_len = 0;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
- ieee80211_link_info_change_notify(sdata, link_id,
+ ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_BEACON_ENABLED);

if (sdata->wdev.cac_started) {
@@ -1589,14 +1600,16 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 link_id = params->link_id < 0 ? 0 : params->link_id;
+ struct ieee80211_link_data *link =
+ sdata_dereference(sdata->link[link_id], sdata);
struct link_sta_info *link_sta =
rcu_dereference_protected(sta->link[link_id],
lockdep_is_held(&local->sta_mtx));

- if (WARN_ON(!link_sta))
+ if (WARN_ON(!link || !link_sta))
return -EINVAL;

- sband = ieee80211_get_link_sband(sdata, link_id);
+ sband = ieee80211_get_link_sband(link);
if (!sband)
return -EINVAL;

@@ -1616,7 +1629,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,

if (params->supported_rates &&
params->supported_rates_len) {
- ieee80211_parse_bitrates(&sdata->vif.link_conf[link_id]->chandef,
+ ieee80211_parse_bitrates(&link->conf->chandef,
sband, params->supported_rates,
params->supported_rates_len,
&link_sta->pub->supp_rates[sband->band]);
@@ -1667,9 +1680,14 @@ static int sta_apply_parameters(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 link_id = params->link_sta_params.link_id < 0 ?
0 : params->link_sta_params.link_id;
+ struct ieee80211_link_data *link;
u32 mask, set;

- sband = ieee80211_get_link_sband(sdata, link_id);
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ sband = ieee80211_get_link_sband(link);
if (!sband)
return -EINVAL;

@@ -1987,7 +2005,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
}

- err = sta_apply_parameters(local, sta, params);
+ /* we use sta_info_get_bss() so this might be different */
+ if (sdata != sta->sdata) {
+ mutex_lock_nested(&sta->sdata->wdev.mtx, 1);
+ err = sta_apply_parameters(local, sta, params);
+ mutex_unlock(&sta->sdata->wdev.mtx);
+ } else {
+ err = sta_apply_parameters(local, sta, params);
+ }
if (err)
goto out_err;

@@ -2374,7 +2399,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) {
conf->ht_opmode = nconf->ht_opmode;
sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_HT);
}
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask))
conf->dot11MeshHWMPactivePathToRootTimeout =
@@ -2426,7 +2452,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
sdata->deflink.needed_rx_chains = sdata->local->rx_chains;

mutex_lock(&sdata->local->mtx);
- err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef,
+ err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef,
IEEE80211_CHANCTX_SHARED);
mutex_unlock(&sdata->local->mtx);
if (err)
@@ -2441,7 +2467,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)

ieee80211_stop_mesh(sdata);
mutex_lock(&sdata->local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
kfree(sdata->u.mesh.ie);
mutex_unlock(&sdata->local->mtx);

@@ -2529,7 +2555,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
changed |= BSS_CHANGED_P2P_PS;
}

- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);

return 0;
}
@@ -2570,7 +2596,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
return -EINVAL;
}

- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_QOS);

return 0;
}
@@ -2719,7 +2746,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
memcpy(sdata->vif.bss_conf.mcast_rate, rate,
sizeof(int) * NUM_NL80211_BANDS);

- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MCAST_RATE);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_MCAST_RATE);

return 0;
}
@@ -2934,7 +2962,7 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
#endif

int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_link_data *link,
enum ieee80211_smps_mode smps_mode)
{
const u8 *ap;
@@ -2948,8 +2976,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
return -EINVAL;

- old_req = sdata->link[link_id]->u.mgd.req_smps;
- sdata->link[link_id]->u.mgd.req_smps = smps_mode;
+ old_req = link->u.mgd.req_smps;
+ link->u.mgd.req_smps = smps_mode;

if (old_req == smps_mode &&
smps_mode != IEEE80211_SMPS_AUTOMATIC)
@@ -2961,10 +2989,10 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
* the new value until we associate.
*/
if (!sdata->u.mgd.associated ||
- sdata->vif.link_conf[link_id]->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
+ link->conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return 0;

- ap = sdata->link[link_id]->u.mgd.bssid;
+ ap = link->u.mgd.bssid;

rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
@@ -2988,7 +3016,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
err = ieee80211_send_smps_action(sdata, smps_mode,
ap, ap);
if (err)
- sdata->link[link_id]->u.mgd.req_smps = old_req;
+ link->u.mgd.req_smps = old_req;
else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found)
ieee80211_teardown_tdls_peers(sdata);

@@ -3018,10 +3046,14 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
/* no change, but if automatic follow powersave */
sdata_lock(sdata);
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- if (!sdata->link[link_id])
+ struct ieee80211_link_data *link;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+
+ if (!link)
continue;
- __ieee80211_request_smps_mgd(sdata, link_id,
- sdata->link[link_id]->u.mgd.req_smps);
+ __ieee80211_request_smps_mgd(sdata, link,
+ link->u.mgd.req_smps);
}
sdata_unlock(sdata);

@@ -3060,7 +3092,8 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
/* tell the driver upon association, unless already associated */
if (sdata->u.mgd.associated &&
sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_CQM);

return 0;
}
@@ -3085,7 +3118,8 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
/* tell the driver upon association, unless already associated */
if (sdata->u.mgd.associated &&
sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_CQM);

return 0;
}
@@ -3177,7 +3211,7 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
sdata->deflink.needed_rx_chains = local->rx_chains;

- err = ieee80211_link_use_channel(sdata->link[0], chandef,
+ err = ieee80211_link_use_channel(&sdata->deflink, chandef,
IEEE80211_CHANCTX_SHARED);
if (err)
goto out_unlock;
@@ -3206,7 +3240,7 @@ static void ieee80211_end_cac(struct wiphy *wiphy,
cancel_delayed_work(&sdata->deflink.dfs_cac_timer_work);

if (sdata->wdev.cac_started) {
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
sdata->wdev.cac_started = false;
}
}
@@ -3353,7 +3387,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
if (!sdata->deflink.u.ap.next_beacon)
return -EINVAL;

- err = ieee80211_assign_beacon(sdata,
+ err = ieee80211_assign_beacon(sdata, &sdata->deflink,
sdata->deflink.u.ap.next_beacon,
NULL, NULL);
ieee80211_free_next_beacon(&sdata->deflink);
@@ -3410,7 +3444,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
if (sdata->deflink.reserved_ready)
return 0;

- return ieee80211_link_use_reserved_context(sdata->link[0]);
+ return ieee80211_link_use_reserved_context(&sdata->deflink);
}

if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
@@ -3423,7 +3457,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
if (err)
return err;

- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);

if (sdata->deflink.csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
@@ -3522,7 +3556,9 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
csa.count = params->count;

- err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa, NULL);
+ err = ieee80211_assign_beacon(sdata, &sdata->deflink,
+ &params->beacon_csa, &csa,
+ NULL);
if (err < 0) {
ieee80211_free_next_beacon(&sdata->deflink);
return err;
@@ -3675,7 +3711,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if (err)
goto out;

- err = ieee80211_link_reserve_chanctx(sdata->link[0], &params->chandef,
+ err = ieee80211_link_reserve_chanctx(&sdata->deflink, &params->chandef,
chanctx->mode,
params->radar_required);
if (err)
@@ -3684,7 +3720,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
/* if reservation is invalid then this will fail */
err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
if (err) {
- ieee80211_link_unreserve_chanctx(sdata->link[0]);
+ ieee80211_link_unreserve_chanctx(&sdata->deflink);
goto out;
}

@@ -3694,7 +3730,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,

err = ieee80211_set_csa_beacon(sdata, params, &changed);
if (err) {
- ieee80211_link_unreserve_chanctx(sdata->link[0]);
+ ieee80211_link_unreserve_chanctx(&sdata->deflink);
goto out;
}

@@ -3711,7 +3747,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
params->count, params->block_tx);

if (changed) {
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ changed);
drv_channel_switch_beacon(sdata, &params->chandef);
} else {
/* if the beacon didn't change, we can finalize immediately */
@@ -3950,12 +3987,19 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_link_data *link;
int ret = -ENODATA;

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf);
+ link = rcu_dereference(sdata->link[link_id]);
+ if (!link) {
+ ret = -ENOLINK;
+ goto out;
+ }
+
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (chanctx_conf) {
- *chandef = sdata->vif.link_conf[link_id]->chandef;
+ *chandef = link->conf->chandef;
ret = 0;
} else if (local->open_count > 0 &&
local->open_count == local->monitors &&
@@ -3966,6 +4010,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
*chandef = local->_oper_chandef;
ret = 0;
}
+out:
rcu_read_unlock();

return ret;
@@ -4009,13 +4054,15 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_link_data *link;
int ret;
u32 changed = 0;

- ret = ieee80211_link_change_bandwidth(sdata->link[link_id], chandef,
- &changed);
+ link = sdata_dereference(sdata->link[link_id], sdata);
+
+ ret = ieee80211_link_change_bandwidth(link, chandef, &changed);
if (ret == 0)
- ieee80211_link_info_change_notify(sdata, link_id, changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);

return ret;
}
@@ -4358,7 +4405,7 @@ ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata,
if (!sdata->deflink.u.ap.next_beacon)
return -EINVAL;

- ret = ieee80211_assign_beacon(sdata,
+ ret = ieee80211_assign_beacon(sdata, &sdata->deflink,
sdata->deflink.u.ap.next_beacon,
NULL, NULL);
ieee80211_free_next_beacon(&sdata->deflink);
@@ -4401,7 +4448,8 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata,
params->counter_offset_presp;
color_change.count = params->count;

- err = ieee80211_assign_beacon(sdata, &params->beacon_color_change,
+ err = ieee80211_assign_beacon(sdata, &sdata->deflink,
+ &params->beacon_color_change,
NULL, &color_change);
if (err < 0) {
ieee80211_free_next_beacon(&sdata->deflink);
@@ -4424,7 +4472,7 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.he_bss_color.enabled = enable;
changed |= BSS_CHANGED_HE_BSS_COLOR;

- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);

if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) {
struct ieee80211_sub_if_data *child;
@@ -4434,7 +4482,8 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) {
child->vif.bss_conf.he_bss_color.color = color;
child->vif.bss_conf.he_bss_color.enabled = enable;
- ieee80211_link_info_change_notify(child, 0,
+ ieee80211_link_info_change_notify(child,
+ &child->deflink,
BSS_CHANGED_HE_BSS_COLOR);
}
}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 6853b563fb6c..8d384956fde5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -67,14 +67,12 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
}

static struct ieee80211_chanctx *
-ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
{
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
- struct ieee80211_local *local __maybe_unused = sdata->local;
+ struct ieee80211_local *local __maybe_unused = link->sdata->local;
struct ieee80211_chanctx_conf *conf;

- conf = rcu_dereference_protected(link_conf->chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf)
return NULL;
@@ -82,12 +80,6 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata,
return container_of(conf, struct ieee80211_chanctx, conf);
}

-static struct ieee80211_chanctx *
-ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
-{
- return ieee80211_vif_get_chanctx(link->sdata, link->link_id);
-}
-
static const struct cfg80211_chan_def *
ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
@@ -122,8 +114,7 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,

list_for_each_entry(link, &ctx->assigned_links,
assigned_chanctx_list) {
- struct ieee80211_bss_conf *link_conf =
- link->sdata->vif.link_conf[link->link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;

if (link->reserved_chanctx)
continue;
@@ -254,7 +245,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
struct sta_info *sta;

- rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
if (sdata != sta->sdata &&
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
@@ -262,7 +252,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,

max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id));
}
- rcu_read_unlock();

return max_bw;
}
@@ -275,10 +264,11 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
struct ieee80211_vif *vif = &sdata->vif;
int link_id;

+ rcu_read_lock();
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ rcu_dereference(sdata->vif.link_conf[link_id]);

if (!link_conf)
continue;
@@ -319,6 +309,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,

max_bw = max(max_bw, width);
}
+ rcu_read_unlock();

return max_bw;
}
@@ -345,7 +336,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
/* use the configured bandwidth in case of monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
if (sdata &&
- rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == conf)
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf)
max_bw = max(max_bw, conf->def.width);

rcu_read_unlock();
@@ -419,7 +410,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,

for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ rcu_dereference(sdata->vif.link_conf[link_id]);
struct link_sta_info *link_sta;

if (!link_conf)
@@ -572,8 +563,11 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
unsigned int link_id;

for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- if (sdata->link[link_id] &&
- sdata->link[link_id]->radar_required) {
+ struct ieee80211_link_data *link;
+
+ link = rcu_dereference(sdata->link[link_id]);
+
+ if (link && link->radar_required) {
rcu_read_unlock();
return true;
}
@@ -602,15 +596,15 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local,
if (!ieee80211_sdata_running(sdata))
continue;
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link;

- if (!link_conf)
+ link = rcu_dereference(sdata->link[link_id]);
+ if (!link)
continue;

- if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
+ if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
continue;
- if (!sdata->link[link_id]->radar_required)
+ if (!link->radar_required)
continue;
required = true;
break;
@@ -774,7 +768,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,

for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ rcu_dereference(sdata->vif.link_conf[link_id]);

if (!link_conf)
continue;
@@ -850,7 +844,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
return -ENOTSUPP;

- conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));

if (conf) {
@@ -872,7 +866,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
}

out:
- rcu_assign_pointer(sdata->vif.link_conf[link_id]->chanctx_conf, conf);
+ rcu_assign_pointer(link->conf->chanctx_conf, conf);

sdata->vif.cfg.idle = !conf;

@@ -931,14 +925,14 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
}

for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- struct ieee80211_link_data *link = sdata->link[link_id];
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link;

- if (!link_conf)
+ link = rcu_dereference(sdata->link[link_id]);
+
+ if (!link)
continue;

- if (rcu_access_pointer(link_conf->chanctx_conf) != &chanctx->conf)
+ if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
continue;

switch (link->smps_mode) {
@@ -968,7 +962,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
/* Disable SMPS for the monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
if (sdata &&
- rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == &chanctx->conf)
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
rx_chains_dynamic = rx_chains_static = local->rx_chains;

rcu_read_unlock();
@@ -998,7 +992,7 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
{
struct ieee80211_sub_if_data *sdata = link->sdata;
unsigned int link_id = link->link_id;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local __maybe_unused = sdata->local;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_chanctx_conf *conf;
@@ -1021,9 +1015,17 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
if (clear)
conf = NULL;

- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
- rcu_assign_pointer(vlan->vif.link_conf[link_id]->chanctx_conf,
- conf);
+ rcu_read_lock();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ struct ieee80211_bss_conf *vlan_conf;
+
+ vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]);
+ if (WARN_ON(!vlan_conf))
+ continue;
+
+ rcu_assign_pointer(vlan_conf->chanctx_conf, conf);
+ }
+ rcu_read_unlock();
}

void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
@@ -1210,21 +1212,29 @@ ieee80211_link_update_chandef(struct ieee80211_link_data *link,
unsigned int link_id = link->link_id;
struct ieee80211_sub_if_data *vlan;

- sdata->vif.link_conf[link_id]->chandef = *chandef;
+ link->conf->chandef = *chandef;

if (sdata->vif.type != NL80211_IFTYPE_AP)
return;

- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
- vlan->vif.link_conf[link_id]->chandef = *chandef;
+ rcu_read_lock();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ struct ieee80211_bss_conf *vlan_conf;
+
+ vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]);
+ if (WARN_ON(!vlan_conf))
+ continue;
+
+ vlan_conf->chandef = *chandef;
+ }
+ rcu_read_unlock();
}

static int
ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
- unsigned int link_id = link->link_id;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
struct ieee80211_chanctx *old_ctx, *new_ctx;
@@ -1296,7 +1306,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
ieee80211_recalc_radar_chanctx(local, new_ctx);

if (changed)
- ieee80211_link_info_change_notify(sdata, link_id, changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);

out:
ieee80211_link_chanctx_reservation_complete(link);
@@ -1307,13 +1317,12 @@ static int
ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
- unsigned int link_id = link->link_id;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *old_ctx, *new_ctx;
const struct cfg80211_chan_def *chandef;
int err;

- old_ctx = ieee80211_vif_get_chanctx(sdata, link_id);
+ old_ctx = ieee80211_link_get_chanctx(link);
new_ctx = link->reserved_chanctx;

if (WARN_ON(!link->reserved_ready))
@@ -1625,8 +1634,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
struct ieee80211_sub_if_data *sdata = link->sdata;
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link->link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
u32 changed = 0;

if (!ieee80211_link_has_in_place_reservation(link))
@@ -1649,7 +1657,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_link_update_chandef(link, &link->reserved_chandef);
if (changed)
ieee80211_link_info_change_notify(sdata,
- link->link_id,
+ link,
changed);

ieee80211_recalc_txpower(sdata, false);
@@ -1746,8 +1754,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
static void __ieee80211_link_release_channel(struct ieee80211_link_data *link)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
- unsigned int link_id = link->link_id;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
@@ -1786,7 +1793,6 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
- unsigned int link_id = link->link_id;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
u8 radar_detect_width = 0;
@@ -1806,7 +1812,7 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,
if (ret > 0)
radar_detect_width = BIT(chandef->width);

- sdata->link[link_id]->radar_required = ret;
+ link->radar_required = ret;

ret = ieee80211_check_combinations(sdata, chandef, mode,
radar_detect_width);
@@ -1910,8 +1916,7 @@ int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
u32 *changed)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
- unsigned int link_id = link->link_id;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
@@ -1997,7 +2002,8 @@ void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
unsigned int link_id = link->link_id;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
+ struct ieee80211_bss_conf *ap_conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *ap;
struct ieee80211_chanctx_conf *conf;
@@ -2009,9 +2015,12 @@ void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)

mutex_lock(&local->chanctx_mtx);

- conf = rcu_dereference_protected(ap->vif.link_conf[link_id]->chanctx_conf,
+ rcu_read_lock();
+ ap_conf = rcu_dereference(ap->vif.link_conf[link_id]);
+ conf = rcu_dereference_protected(ap_conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
rcu_assign_pointer(link_conf->chanctx_conf, conf);
+ rcu_read_unlock();
mutex_unlock(&local->chanctx_mtx);
}

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ead917501d6c..1e5b041a5cea 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -256,7 +256,7 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
return -EOPNOTSUPP;

sdata_lock(sdata);
- err = __ieee80211_request_smps_mgd(sdata, 0, smps_mode);
+ err = __ieee80211_request_smps_mgd(sdata, &sdata->deflink, smps_mode);
sdata_unlock(sdata);

return err;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index db38c8cc9d8f..ee3ac1a01bb0 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -167,6 +167,7 @@ static inline void drv_vif_cfg_changed(struct ieee80211_local *local,

static inline void drv_link_info_changed(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *info,
int link_id, u64 changed)
{
might_sleep();
@@ -189,13 +190,13 @@ static inline void drv_link_info_changed(struct ieee80211_local *local,
if (!check_sdata_in_driver(sdata))
return;

- trace_drv_link_info_changed(local, sdata, link_id, changed);
+ trace_drv_link_info_changed(local, sdata, info, link_id, changed);
if (local->ops->link_info_changed)
local->ops->link_info_changed(&local->hw, &sdata->vif,
- link_id, changed);
+ info, link_id, changed);
else if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif,
- &sdata->vif.bss_conf, changed);
+ info, changed);
trace_drv_return_void(local);
}

@@ -995,8 +996,7 @@ static inline int drv_start_ap(struct ieee80211_local *local,
if (!check_sdata_in_driver(sdata))
return -EIO;

- trace_drv_start_ap(local, sdata, sdata->vif.link_conf[link_id],
- link_id);
+ trace_drv_start_ap(local, sdata, link_id);
if (local->ops->start_ap)
ret = local->ops->start_ap(&local->hw, &sdata->vif, link_id);
trace_drv_return_int(local, ret);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 2eb3a409b70f..ea7ce87b7ec4 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -140,12 +140,14 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_ht_cap *ht_cap_ie,
struct link_sta_info *link_sta)
{
+ struct ieee80211_bss_conf *link_conf;
struct sta_info *sta = link_sta->sta;
struct ieee80211_sta_ht_cap ht_cap, own_cap;
u8 ampdu_info, tx_mcs_set_cap;
int i, max_tx_streams;
bool changed;
enum ieee80211_sta_rx_bandwidth bw;
+ enum nl80211_chan_width width;

memset(&ht_cap, 0, sizeof(ht_cap));

@@ -248,7 +250,14 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,

memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap));

- switch (sdata->vif.link_conf[link_sta->link_id]->chandef.width) {
+ rcu_read_lock();
+ link_conf = rcu_dereference(sdata->vif.link_conf[link_sta->link_id]);
+ if (WARN_ON(!link_conf))
+ width = NL80211_CHAN_WIDTH_20_NOHT;
+ else
+ width = link_conf->chandef.width;
+
+ switch (width) {
default:
WARN_ON_ONCE(1);
fallthrough;
@@ -264,6 +273,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
break;
}
+ rcu_read_unlock();

link_sta->pub->bandwidth = bw;

@@ -547,7 +557,7 @@ void ieee80211_request_smps_mgd_work(struct work_struct *work)
u.mgd.request_smps_work);

sdata_lock(link->sdata);
- __ieee80211_request_smps_mgd(link->sdata, link->link_id,
+ __ieee80211_request_smps_mgd(link->sdata, link,
link->u.mgd.driver_smps_mode);
sdata_unlock(link->sdata);
}
@@ -556,19 +566,23 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id,
enum ieee80211_smps_mode smps_mode)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- struct ieee80211_link_data *link = sdata->link[link_id];
+ struct ieee80211_link_data *link;

if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION))
return;

+ rcu_read_lock();
+ link = rcu_dereference(sdata->link[link_id]);
if (WARN_ON(!link))
- return;
+ goto out;

if (link->u.mgd.driver_smps_mode == smps_mode)
- return;
+ goto out;

link->u.mgd.driver_smps_mode = smps_mode;
ieee80211_queue_work(&sdata->local->hw, &link->u.mgd.request_smps_work);
+out:
+ rcu_read_unlock();
}
/* this might change ... don't want non-open drivers using it */
EXPORT_SYMBOL_GPL(ieee80211_request_smps);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d30a82f1620b..393c7595bfa4 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -300,7 +300,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
radar_required = err;

mutex_lock(&local->mtx);
- if (ieee80211_link_use_channel(sdata->link[0], &chandef,
+ if (ieee80211_link_use_channel(&sdata->deflink, &chandef,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -370,7 +370,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
RCU_INIT_POINTER(ifibss->presp, NULL);
kfree_rcu(presp, rcu_head);
mutex_lock(&local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&local->mtx);
sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
err);
@@ -722,7 +722,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
BSS_CHANGED_IBSS);
drv_leave_ibss(local, sdata);
mutex_lock(&local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&local->mtx);
}

@@ -1848,7 +1848,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
| IEEE80211_HT_PARAM_RIFS_MODE;

changed |= BSS_CHANGED_HT | BSS_CHANGED_MCAST_RATE;
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);

sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
sdata->deflink.needed_rx_chains = local->rx_chains;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a0023ad7ca1c..aa1e438ee61e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -961,6 +961,8 @@ struct ieee80211_link_data {
struct ieee80211_link_data_managed mgd;
struct ieee80211_link_data_ap ap;
} u;
+
+ struct ieee80211_bss_conf *conf;
};

struct ieee80211_sub_if_data {
@@ -1045,7 +1047,7 @@ struct ieee80211_sub_if_data {
} u;

struct ieee80211_link_data deflink;
- struct ieee80211_link_data *link[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ieee80211_link_data __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];

#ifdef CONFIG_MAC80211_DEBUGFS
struct {
@@ -1544,16 +1546,14 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
}

static inline struct ieee80211_supported_band *
-ieee80211_get_link_sband(struct ieee80211_sub_if_data *sdata, u32 link_id)
+ieee80211_get_link_sband(struct ieee80211_link_data *link)
{
- struct ieee80211_local *local = sdata->local;
+ struct ieee80211_local *local = link->sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
enum nl80211_band band;

rcu_read_lock();
- chanctx_conf =
- rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf);
-
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return NULL;
@@ -1721,7 +1721,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata,
u64 changed);
void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata,
- int link_id, u64 changed);
+ struct ieee80211_link_data *link,
+ u64 changed);
void ieee80211_configure_filter(struct ieee80211_local *local);
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);

@@ -2002,7 +2003,7 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width);
enum nl80211_chan_width
ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta);
void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_link_data *link,
struct ieee80211_mgmt *mgmt);
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct link_sta_info *sta,
@@ -2277,10 +2278,10 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum nl80211_band band, u32 *basic_rates);
int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_link_data *link,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id);
+ struct ieee80211_link_data *link);
void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);

size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 56dd831fe45f..12789a62366c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -80,7 +80,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
{
if (__ieee80211_recalc_txpower(sdata) ||
(update_bss && ieee80211_sdata_running(sdata)))
- ieee80211_link_info_change_notify(sdata, 0,
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_TXPOWER);
}

@@ -478,7 +478,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
chandef = sdata->vif.bss_conf.chandef;
WARN_ON(local->suspended);
mutex_lock(&local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&local->mtx);
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_ABORTED,
@@ -1029,11 +1029,12 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
if (link_id < 0)
link_id = 0;

- sdata->vif.link_conf[link_id] = link_conf;
- sdata->link[link_id] = link;
+ rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
+ rcu_assign_pointer(sdata->link[link_id], link);

link->sdata = sdata;
link->link_id = link_id;
+ link->conf = link_conf;

INIT_WORK(&link->csa_finalize_work,
ieee80211_csa_finalize_work);
@@ -1126,7 +1127,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
mutex_unlock(&local->iflist_mtx);

mutex_lock(&local->mtx);
- ret = ieee80211_link_use_channel(sdata->link[0], &local->monitor_chandef,
+ ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
mutex_unlock(&local->mtx);
if (ret) {
@@ -1171,7 +1172,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
synchronize_net();

mutex_lock(&local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&local->mtx);

drv_remove_interface(local, sdata);
@@ -1277,7 +1278,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_AP_VLAN:
/* no need to tell driver, but set carrier and chanctx */
if (sdata->bss->active) {
- ieee80211_link_vlan_copy_chanctx(sdata->link[0]);
+ ieee80211_link_vlan_copy_chanctx(&sdata->deflink);
netif_carrier_on(dev);
ieee80211_set_vif_encap_ops(sdata);
} else {
@@ -1349,7 +1350,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
sdata->vif.type != NL80211_IFTYPE_NAN)
changed |= ieee80211_reset_erp_info(sdata);
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ changed);

switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -1533,7 +1535,8 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
break;
}
case WLAN_VHT_ACTION_GROUPID_MGMT:
- ieee80211_process_mu_groups(sdata, 0, mgmt);
+ ieee80211_process_mu_groups(sdata, &sdata->deflink,
+ mgmt);
break;
default:
WARN_ON(1);
@@ -1687,7 +1690,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data, recalc_smps);

- ieee80211_recalc_smps(sdata, 0);
+ ieee80211_recalc_smps(sdata, &sdata->deflink);
}

/*
@@ -2362,6 +2365,7 @@ int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
struct {
struct ieee80211_link_data data;
struct ieee80211_bss_conf conf;
+ struct rcu_head rcu_head;
} *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -2392,15 +2396,15 @@ int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
/* link them into data structures */
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
WARN_ON(!use_deflink &&
- sdata->link[link_id] == &sdata->deflink);
+ rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);

link = links[link_id];
ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
}

for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- sdata->link[link_id] = NULL;
- sdata->vif.link_conf[link_id] = NULL;
+ RCU_INIT_POINTER(sdata->link[link_id], NULL);
+ RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
}

sdata->vif.valid_links = new_links;
@@ -2424,20 +2428,20 @@ int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
/* now use this to free the old links */
memset(links, 0, sizeof(links));
for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- if (sdata->link[link_id] == &sdata->deflink)
+ if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
continue;
/*
* we must have allocated the data through this path so
* we know we can free both at the same time
*/
- links[link_id] = container_of(sdata->link[link_id],
+ links[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
typeof(*links[link_id]),
data);
}

free:
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
- kfree(links[link_id]);
+ kfree_rcu(links[link_id], rcu_head);
if (use_deflink)
ieee80211_link_init(sdata, -1, &sdata->deflink,
&sdata->vif.bss_conf);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c34f06039dda..191f4d35ef60 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -246,9 +246,11 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
u64 ch = changed & ~BSS_CHANGED_VIF_CFG_FLAGS;

/* FIXME: should be for each link */
- trace_drv_link_info_changed(local, sdata, 0, changed);
+ trace_drv_link_info_changed(local, sdata, &sdata->vif.bss_conf,
+ 0, changed);
if (local->ops->link_info_changed)
local->ops->link_info_changed(&local->hw, &sdata->vif,
+ &sdata->vif.bss_conf,
0, ch);
}

@@ -272,7 +274,8 @@ void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata,
}

void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata,
- int link_id, u64 changed)
+ struct ieee80211_link_data *link,
+ u64 changed)
{
struct ieee80211_local *local = sdata->local;

@@ -284,7 +287,7 @@ void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata,
if (!check_sdata_in_driver(sdata))
return;

- drv_link_info_changed(local, sdata, link_id, changed);
+ drv_link_info_changed(local, sdata, link->conf, link->link_id, changed);
}

u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 6160211a7eee..ba4e0921fa5d 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1056,7 +1056,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
}

ieee80211_recalc_dtim(local, sdata);
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);

netif_carrier_on(sdata->dev);
return 0;
@@ -1080,7 +1080,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
sdata->vif.bss_conf.enable_beacon = false;
sdata->beacon_rate_set = false;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_BEACON_ENABLED);

/* remove beacon */
bcn = sdata_dereference(ifmsh->beacon, sdata);
@@ -1578,7 +1579,7 @@ static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
if (ieee80211_mesh_rebuild_beacon(sdata))
return;

- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);
}

void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8980dfef1ff1..28bb7609cd4c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1867,7 +1867,8 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)

if (sdata->vif.bss_conf.ps != ps_allowed) {
sdata->vif.bss_conf.ps = ps_allowed;
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_PS);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_PS);
}
}

@@ -2063,7 +2064,8 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
{
if (__ieee80211_sta_handle_tspec_ac_params(sdata))
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_QOS);
}

static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
@@ -2369,7 +2371,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_ps(local);
mutex_unlock(&local->iflist_mtx);

- ieee80211_recalc_smps(sdata, 0);
+ ieee80211_recalc_smps(sdata, &sdata->deflink);
ieee80211_recalc_ps_vif(sdata);

netif_carrier_on(sdata->dev);
@@ -2952,7 +2954,8 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
sta_info_destroy_addr(sdata, auth_data->bss->bssid);

eth_zero_addr(sdata->deflink.u.mgd.bssid);
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
mutex_lock(&sdata->local->mtx);
ieee80211_link_release_channel(&sdata->deflink);
@@ -2981,7 +2984,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
sta_info_destroy_addr(sdata, assoc_data->bss->bssid);

eth_zero_addr(sdata->deflink.u.mgd.bssid);
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
sdata->vif.bss_conf.mu_mimo_owner = false;

@@ -4423,7 +4427,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
elems->pwr_constr_elem,
elems->cisco_dtpc_elem);

- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ changed);
free:
kfree(elems);
}
@@ -5733,9 +5738,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
* tell driver about BSSID, basic rates and timing
* this was set up above, before setting the channel
*/
- ieee80211_link_info_change_notify(sdata, 0,
- BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES |
- BSS_CHANGED_BEACON_INT);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_BSSID |
+ BSS_CHANGED_BASIC_RATES |
+ BSS_CHANGED_BEACON_INT);

if (assoc)
sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH);
@@ -5901,7 +5907,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,

err_clear:
eth_zero_addr(sdata->deflink.u.mgd.bssid);
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_BSSID);
ifmgd->auth_data = NULL;
mutex_lock(&sdata->local->mtx);
ieee80211_link_release_channel(&sdata->deflink);
@@ -6248,7 +6255,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
return 0;
err_clear:
eth_zero_addr(sdata->deflink.u.mgd.bssid);
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_BSSID);
ifmgd->assoc_data = NULL;
err_free:
kfree(assoc_data);
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
index 0fd29d9c496c..2ca2164a3098 100644
--- a/net/mac80211/ocb.c
+++ b/net/mac80211/ocb.c
@@ -186,7 +186,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
sdata->deflink.needed_rx_chains = sdata->local->rx_chains;

mutex_lock(&sdata->local->mtx);
- err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef,
+ err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef,
IEEE80211_CHANCTX_SHARED);
mutex_unlock(&sdata->local->mtx);
if (err)
@@ -229,7 +229,7 @@ int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB);

mutex_lock(&sdata->local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&sdata->local->mtx);

skb_queue_purge(&sdata->skb_queue);
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index aff5d3c39902..be79ae68754e 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -119,7 +119,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
&sdata->state);
sdata->vif.bss_conf.enable_beacon = false;
ieee80211_link_info_change_notify(
- sdata, 0, BSS_CHANGED_BEACON_ENABLED);
+ sdata, &sdata->deflink,
+ BSS_CHANGED_BEACON_ENABLED);
}

if (sdata->vif.type == NL80211_IFTYPE_STATION &&
@@ -156,7 +157,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
&sdata->state)) {
sdata->vif.bss_conf.enable_beacon = true;
ieee80211_link_info_change_notify(
- sdata, 0, BSS_CHANGED_BEACON_ENABLED);
+ sdata, &sdata->deflink,
+ BSS_CHANGED_BEACON_ENABLED);
}
}
mutex_unlock(&local->iflist_mtx);
@@ -848,14 +850,17 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
rcu_read_lock();
/* Check all the links first */
for (i = 0; i < ARRAY_SIZE(sdata->vif.link_conf); i++) {
- if (!sdata->vif.link_conf[i])
+ struct ieee80211_bss_conf *conf;
+
+ conf = rcu_dereference(sdata->vif.link_conf[i]);
+ if (!conf)
continue;

- chanctx_conf = rcu_dereference(sdata->vif.link_conf[i]->chanctx_conf);
+ chanctx_conf = rcu_dereference(conf->chanctx_conf);
if (!chanctx_conf)
continue;

- if (ether_addr_equal(sdata->vif.link_conf[i]->addr, mgmt->sa))
+ if (ether_addr_equal(conf->addr, mgmt->sa))
break;

chanctx_conf = NULL;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2aa593294a29..9f7ce1377604 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4155,9 +4155,13 @@ static bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
return false;

for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
- if (!sdata->vif.link_conf[link_id])
+ struct ieee80211_bss_conf *conf;
+
+ conf = rcu_dereference(sdata->vif.link_conf[link_id]);
+
+ if (!conf)
continue;
- if (ether_addr_equal(sdata->vif.link_conf[link_id]->addr, addr)) {
+ if (ether_addr_equal(conf->addr, addr)) {
if (out_link_id)
*out_link_id = link_id;
return true;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a4fa0ce7bd92..20aad688c9c9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -731,7 +731,8 @@ ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata)

if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) {
sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps;
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_P2P_PS);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_P2P_PS);
}
}

diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index c531fa17f426..71883ffd7061 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1336,7 +1336,8 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata,
return;

sdata->vif.bss_conf.ht_operation_mode = opmode;
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_HT);
}

int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index f96e7cdca4c2..6aa06fba5b50 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -446,9 +446,10 @@ TRACE_EVENT(drv_vif_cfg_changed,
TRACE_EVENT(drv_link_info_changed,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *link_conf,
int link_id, u64 changed),

- TP_ARGS(local, sdata, link_id, changed),
+ TP_ARGS(local, sdata, link_conf, link_id, changed),

TP_STRUCT__entry(
LOCAL_ENTRY
@@ -481,8 +482,6 @@ TRACE_EVENT(drv_link_info_changed,
),

TP_fast_assign(
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
-
LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->changed = changed;
@@ -1752,10 +1751,9 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
TRACE_EVENT(drv_start_ap,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss_conf *info,
unsigned int link_id),

- TP_ARGS(local, sdata, info, link_id),
+ TP_ARGS(local, sdata, link_id),

TP_STRUCT__entry(
LOCAL_ENTRY
@@ -1768,15 +1766,20 @@ TRACE_EVENT(drv_start_ap,
),

TP_fast_assign(
+ struct ieee80211_bss_conf *info =
+ sdata_dereference(sdata->vif.link_conf[link_id], sdata);
+
LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->link_id = link_id;
- __entry->dtimper = info->dtim_period;
- __entry->bcnint = info->beacon_int;
+ if (info) {
+ __entry->dtimper = info->dtim_period;
+ __entry->bcnint = info->beacon_int;
+ __entry->hidden_ssid = info->hidden_ssid;
+ }
memcpy(__get_dynamic_array(ssid),
sdata->vif.cfg.ssid,
sdata->vif.cfg.ssid_len);
- __entry->hidden_ssid = info->hidden_ssid;
),

TP_printk(
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index b2430cf8332b..a077399ed065 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4608,13 +4608,14 @@ void ieee80211_tx_pending(struct tasklet_struct *t)
/* functions for drivers to get certain frames */

static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link,
struct ps_data *ps, struct sk_buff *skb,
- bool is_template, unsigned int link_id)
+ bool is_template)
{
u8 *pos, *tim;
int aid0 = 0;
int i, have_bits = 0, n1, n2;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;

/* Generate bitmap for TIM only if there are any STAs in power save
* mode. */
@@ -4674,8 +4675,9 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
}

static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link,
struct ps_data *ps, struct sk_buff *skb,
- bool is_template, unsigned int link_id)
+ bool is_template)
{
struct ieee80211_local *local = sdata->local;

@@ -4687,12 +4689,10 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
- __ieee80211_beacon_add_tim(sdata, ps, skb, is_template,
- link_id);
+ __ieee80211_beacon_add_tim(sdata, link, ps, skb, is_template);
} else {
spin_lock_bh(&local->tim_lock);
- __ieee80211_beacon_add_tim(sdata, ps, skb, is_template,
- link_id);
+ __ieee80211_beacon_add_tim(sdata, link, ps, skb, is_template);
spin_unlock_bh(&local->tim_lock);
}

@@ -4701,7 +4701,7 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,

static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
struct beacon_data *beacon,
- unsigned int link_id)
+ struct ieee80211_link_data *link)
{
u8 *beacon_data, count, max_count = 1;
struct probe_resp *resp;
@@ -4726,20 +4726,17 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
return;
}

- rcu_read_lock();
- resp = rcu_dereference(sdata->link[link_id]->u.ap.probe_resp);
+ resp = rcu_dereference(link->u.ap.probe_resp);

bcn_offsets = beacon->cntdwn_counter_offsets;
count = beacon->cntdwn_current_counter;
- if (sdata->vif.link_conf[link_id]->csa_active)
+ if (link->conf->csa_active)
max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM;

for (i = 0; i < max_count; ++i) {
if (bcn_offsets[i]) {
- if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len)) {
- rcu_read_unlock();
+ if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len))
return;
- }
beacon_data[bcn_offsets[i]] = count;
}

@@ -4749,7 +4746,6 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
resp->data[resp_offsets[i]] = count;
}
}
- rcu_read_unlock();
}

static u8 __ieee80211_beacon_update_cntdwn(struct beacon_data *beacon)
@@ -4873,14 +4869,14 @@ EXPORT_SYMBOL(ieee80211_beacon_cntdwn_is_complete);
static int ieee80211_beacon_protect(struct sk_buff *skb,
struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ struct ieee80211_link_data *link)
{
ieee80211_tx_result res;
struct ieee80211_tx_data tx;
struct sk_buff *check_skb;

memset(&tx, 0, sizeof(tx));
- tx.key = rcu_dereference(sdata->link[link_id]->default_beacon_key);
+ tx.key = rcu_dereference(link->default_beacon_key);
if (!tx.key)
return 0;
tx.local = local;
@@ -4900,12 +4896,12 @@ static int ieee80211_beacon_protect(struct sk_buff *skb,
static void
ieee80211_beacon_get_finish(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
+ struct ieee80211_link_data *link,
struct ieee80211_mutable_offsets *offs,
struct beacon_data *beacon,
struct sk_buff *skb,
struct ieee80211_chanctx_conf *chanctx_conf,
- u16 csa_off_base,
- unsigned int link_id)
+ u16 csa_off_base)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -4936,7 +4932,7 @@ ieee80211_beacon_get_finish(struct ieee80211_hw *hw,
memset(&txrc, 0, sizeof(txrc));
txrc.hw = hw;
txrc.sband = local->hw.wiphy->bands[band];
- txrc.bss_conf = sdata->vif.link_conf[link_id];
+ txrc.bss_conf = link->conf;
txrc.skb = skb;
txrc.reported_rate.idx = -1;
if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
@@ -4968,11 +4964,11 @@ ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon)
static struct sk_buff *
ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
+ struct ieee80211_link_data *link,
struct ieee80211_mutable_offsets *offs,
bool is_template,
struct beacon_data *beacon,
- struct ieee80211_chanctx_conf *chanctx_conf,
- unsigned int link_id)
+ struct ieee80211_chanctx_conf *chanctx_conf)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -4985,7 +4981,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
if (!is_template)
ieee80211_beacon_update_cntdwn(vif);

- ieee80211_set_beacon_cntdwn(sdata, beacon, link_id);
+ ieee80211_set_beacon_cntdwn(sdata, beacon, link);
}

/* headroom, head length,
@@ -5001,7 +4997,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
skb_reserve(skb, local->tx_headroom);
skb_put_data(skb, beacon->head, beacon->head_len);

- ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template, link_id);
+ ieee80211_beacon_add_tim(sdata, link, &ap->ps, skb, is_template);

if (offs) {
offs->tim_offset = beacon->head_len;
@@ -5020,11 +5016,11 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
if (beacon->tail)
skb_put_data(skb, beacon->tail, beacon->tail_len);

- if (ieee80211_beacon_protect(skb, local, sdata, link_id) < 0)
+ if (ieee80211_beacon_protect(skb, local, sdata, link) < 0)
return NULL;

- ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf,
- csa_off_base, link_id);
+ ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb,
+ chanctx_conf, csa_off_base);
return skb;
}

@@ -5040,12 +5036,16 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
struct sk_buff *skb = NULL;
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_link_data *link;

rcu_read_lock();

sdata = vif_to_sdata(vif);
+ link = rcu_dereference(sdata->link[link_id]);
+ if (!link)
+ goto out;
chanctx_conf =
- rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf);
+ rcu_dereference(link->conf->chanctx_conf);

if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
goto out;
@@ -5054,12 +5054,12 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
memset(offs, 0, sizeof(*offs));

if (sdata->vif.type == NL80211_IFTYPE_AP) {
- beacon = rcu_dereference(sdata->link[link_id]->u.ap.beacon);
+ beacon = rcu_dereference(link->u.ap.beacon);
if (!beacon)
goto out;

- skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template,
- beacon, chanctx_conf, link_id);
+ skb = ieee80211_beacon_get_ap(hw, vif, link, offs, is_template,
+ beacon, chanctx_conf);
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_hdr *hdr;
@@ -5072,7 +5072,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
if (!is_template)
__ieee80211_beacon_update_cntdwn(beacon);

- ieee80211_set_beacon_cntdwn(sdata, beacon, link_id);
+ ieee80211_set_beacon_cntdwn(sdata, beacon, link);
}

skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
@@ -5086,8 +5086,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON);

- ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb,
- chanctx_conf, 0, link_id);
+ ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb,
+ chanctx_conf, 0);
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;

@@ -5104,7 +5104,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
*/
__ieee80211_beacon_update_cntdwn(beacon);

- ieee80211_set_beacon_cntdwn(sdata, beacon, link_id);
+ ieee80211_set_beacon_cntdwn(sdata, beacon, link);
}

if (ifmsh->sync_ops)
@@ -5119,8 +5119,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
goto out;
skb_reserve(skb, local->tx_headroom);
skb_put_data(skb, beacon->head, beacon->head_len);
- ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template,
- link_id);
+ ieee80211_beacon_add_tim(sdata, link, &ifmsh->ps, skb,
+ is_template);

if (offs) {
offs->tim_offset = beacon->head_len;
@@ -5128,8 +5128,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
}

skb_put_data(skb, beacon->tail, beacon->tail_len);
- ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb,
- chanctx_conf, 0, link_id);
+ ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb,
+ chanctx_conf, 0);
} else {
WARN_ON(1);
goto out;
@@ -5626,11 +5626,17 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
link = IEEE80211_LINK_UNSPECIFIED;
} else {
/* otherwise must be addressed from a link */
+ rcu_read_lock();
for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) {
- if (memcmp(sdata->vif.link_conf[link]->addr,
- hdr->addr2, ETH_ALEN) == 0)
+ struct ieee80211_bss_conf *link_conf;
+
+ link_conf = rcu_dereference(sdata->vif.link_conf[link]);
+ if (!link_conf)
+ continue;
+ if (memcmp(link_conf->addr, hdr->addr2, ETH_ALEN) == 0)
break;
}
+ rcu_read_unlock();

if (WARN_ON_ONCE(link == ARRAY_SIZE(sdata->vif.link_conf)))
link = ffs(sdata->vif.valid_links) - 1;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7b39e464fb1e..24b5e5d10d66 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1699,7 +1699,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
sdata->vif.type != NL80211_IFTYPE_NAN) {
sdata->vif.bss_conf.qos = enable_qos;
if (bss_notify)
- ieee80211_link_info_change_notify(sdata, 0,
+ ieee80211_link_info_change_notify(sdata,
+ &sdata->deflink,
BSS_CHANGED_QOS);
}
}
@@ -2256,7 +2257,7 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)

static void ieee80211_assign_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ struct ieee80211_link_data *link)
{
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
@@ -2265,11 +2266,11 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local,
return;

mutex_lock(&local->chanctx_mtx);
- conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (conf) {
ctx = container_of(conf, struct ieee80211_chanctx, conf);
- drv_assign_vif_chanctx(local, sdata, link_id, ctx);
+ drv_assign_vif_chanctx(local, sdata, link->link_id, ctx);
}
mutex_unlock(&local->chanctx_mtx);
}
@@ -2475,7 +2476,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
sdata = wiphy_dereference(local->hw.wiphy,
local->monitor_sdata);
if (sdata && ieee80211_sdata_running(sdata))
- ieee80211_assign_chanctx(local, sdata, 0);
+ ieee80211_assign_chanctx(local, sdata, &sdata->deflink);
}

/* reconfigure hardware */
@@ -2485,16 +2486,23 @@ int ieee80211_reconfig(struct ieee80211_local *local)

/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
- unsigned int link;
+ unsigned int link_id;
u32 changed;

if (!ieee80211_sdata_running(sdata))
continue;

- for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) {
- if (sdata->vif.link_conf[link])
+ sdata_lock(sdata);
+ for (link_id = 0;
+ link_id < ARRAY_SIZE(sdata->vif.link_conf);
+ link_id++) {
+ struct ieee80211_link_data *link;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (link)
ieee80211_assign_chanctx(local, sdata, link);
}
+ sdata_unlock(sdata);

switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
@@ -2804,7 +2812,7 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);

void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ struct ieee80211_link_data *link)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -2812,7 +2820,7 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata,

mutex_lock(&local->chanctx_mtx);

- chanctx_conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf,
+ chanctx_conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));

/*
@@ -4006,7 +4014,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)

if (sdata->wdev.cac_started) {
chandef = sdata->vif.bss_conf.chandef;
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
cfg80211_cac_event(sdata->dev,
&chandef,
NL80211_RADAR_CAC_ABORTED,
@@ -4452,13 +4460,11 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
!list_empty(&ctx->assigned_links));

list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
- struct ieee80211_sub_if_data *sdata = link->sdata;
-
if (!link->radar_required)
continue;

radar_detect |=
- BIT(sdata->vif.link_conf[link->link_id]->chandef.width);
+ BIT(link->conf->chandef.width);
}

return radar_detect;
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index fa14627b499a..c804890dc623 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -341,39 +341,50 @@ ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta)
{
unsigned int link_id = link_sta->link_id;
struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap;
u32 cap_width;

if (he_cap->has_he) {
+ struct ieee80211_bss_conf *link_conf;
+ enum ieee80211_sta_rx_bandwidth ret;
u8 info;

+ rcu_read_lock();
+ link_conf = rcu_dereference(sdata->vif.link_conf[link_id]);
+
if (eht_cap->has_eht &&
link_conf->chandef.chan->band == NL80211_BAND_6GHZ) {
info = eht_cap->eht_cap_elem.phy_cap_info[0];

- if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
- return IEEE80211_STA_RX_BW_320;
+ if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) {
+ ret = IEEE80211_STA_RX_BW_320;
+ goto out;
+ }
}

info = he_cap->he_cap_elem.phy_cap_info[0];

if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ) {
if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)
- return IEEE80211_STA_RX_BW_40;
+ ret = IEEE80211_STA_RX_BW_40;
else
- return IEEE80211_STA_RX_BW_20;
+ ret = IEEE80211_STA_RX_BW_20;
+ goto out;
}

if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G ||
info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
- return IEEE80211_STA_RX_BW_160;
+ ret = IEEE80211_STA_RX_BW_160;
else if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)
- return IEEE80211_STA_RX_BW_80;
+ ret = IEEE80211_STA_RX_BW_80;
+ else
+ ret = IEEE80211_STA_RX_BW_20;
+out:
+ rcu_read_unlock();

- return IEEE80211_STA_RX_BW_20;
+ return ret;
}

if (!vht_cap->vht_supported)
@@ -481,11 +492,18 @@ enum ieee80211_sta_rx_bandwidth
ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta)
{
struct sta_info *sta = link_sta->sta;
- struct ieee80211_bss_conf *link_conf =
- sta->sdata->vif.link_conf[link_sta->link_id];
- enum nl80211_chan_width bss_width = link_conf->chandef.width;
+ struct ieee80211_bss_conf *link_conf;
+ enum nl80211_chan_width bss_width;
enum ieee80211_sta_rx_bandwidth bw;

+ rcu_read_lock();
+ link_conf = rcu_dereference(sta->sdata->vif.link_conf[link_sta->link_id]);
+ if (WARN_ON(!link_conf))
+ bss_width = NL80211_CHAN_WIDTH_20_NOHT;
+ else
+ bss_width = link_conf->chandef.width;
+ rcu_read_unlock();
+
bw = ieee80211_sta_cap_rx_bw(link_sta);
bw = min(bw, link_sta->cur_max_bandwidth);

@@ -659,10 +677,10 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
}

void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_link_data *link,
struct ieee80211_mgmt *mgmt)
{
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;

if (!link_conf->mu_mimo_owner)
return;
@@ -680,19 +698,25 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
mgmt->u.action.u.vht_group_notif.position,
WLAN_USER_POSITION_LEN);

- ieee80211_link_info_change_notify(sdata, link_id, BSS_CHANGED_MU_GROUPS);
+ ieee80211_link_info_change_notify(sdata, link,
+ BSS_CHANGED_MU_GROUPS);
}

void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id,
const u8 *membership, const u8 *position)
{
- struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf;

- if (WARN_ON_ONCE(!link_conf->mu_mimo_owner))
- return;
+ rcu_read_lock();
+ link_conf = rcu_dereference(vif->link_conf[link_id]);

- memcpy(link_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN);
- memcpy(link_conf->mu_group.position, position, WLAN_USER_POSITION_LEN);
+ if (!WARN_ON_ONCE(!link_conf || !link_conf->mu_mimo_owner)) {
+ memcpy(link_conf->mu_group.membership, membership,
+ WLAN_MEMBERSHIP_LEN);
+ memcpy(link_conf->mu_group.position, position,
+ WLAN_USER_POSITION_LEN);
+ }
+ rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups);

--
2.36.1

2022-07-13 09:47:24

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 31/76] wifi: mac80211: mlme: track AP (MLD) address separately

From: Johannes Berg <[email protected]>

To prepare a bit more for MLO in the client code,
track the AP's address (for now only the BSSID, but
will track the AP MLD's address later) separately
from the per-link BSSID.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 3 +++
net/mac80211/mlme.c | 30 ++++++++++++++++--------------
2 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c4ed5afba380..398da2336707 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1728,6 +1728,8 @@ enum ieee80211_offload_flags {
* @idle: This interface is idle. There's also a global idle flag in the
* hardware config which may be more appropriate depending on what
* your driver/device needs to do.
+ * @ap_addr: AP MLD address, or BSSID for non-MLO connections
+ * (station mode only)
*/
struct ieee80211_vif_cfg {
/* association related data */
@@ -1742,6 +1744,7 @@ struct ieee80211_vif_cfg {
size_t ssid_len;
bool s1g;
bool idle;
+ u8 ap_addr[ETH_ALEN] __aligned(2);
};

/**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index bfb29d09bd1d..52dc336cadfa 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1807,7 +1807,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
return false;

rcu_read_lock();
- sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid);
+ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
if (sta)
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
rcu_read_unlock();
@@ -2312,6 +2312,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.associated = true;
sdata->deflink.u.mgd.bss = cbss;
memcpy(sdata->deflink.u.mgd.bssid, cbss->bssid, ETH_ALEN);
+ memcpy(sdata->vif.cfg.ap_addr, cbss->bssid, ETH_ALEN);

ieee80211_check_rate_mask(sdata);

@@ -2462,6 +2463,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* clear bssid only after building the needed mgmt frames */
eth_zero_addr(sdata->deflink.u.mgd.bssid);

+ eth_zero_addr(sdata->vif.cfg.ap_addr);
sdata->vif.cfg.ssid_len = 0;

/* remove AP and TDLS peers */
@@ -2652,7 +2654,7 @@ static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- u8 *dst = sdata->deflink.u.mgd.bssid;
+ u8 *dst = sdata->vif.cfg.ap_addr;
u8 unicast_limit = max(1, max_probe_tries - 3);
struct sta_info *sta;

@@ -2881,13 +2883,13 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)

if (ifmgd->connection_loss) {
sdata_info(sdata, "Connection to AP %pM lost\n",
- sdata->deflink.u.mgd.bssid);
+ sdata->vif.cfg.ap_addr);
__ieee80211_disconnect(sdata);
ifmgd->connection_loss = false;
} else if (ifmgd->driver_disconnect) {
sdata_info(sdata,
"Driver requested disconnection from AP %pM\n",
- sdata->deflink.u.mgd.bssid);
+ sdata->vif.cfg.ap_addr);
__ieee80211_disconnect(sdata);
ifmgd->driver_disconnect = false;
} else {
@@ -3041,7 +3043,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
}

static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata,
- const u8 *bssid)
+ const u8 *ap_addr)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct sta_info *sta;
@@ -3055,14 +3057,14 @@ static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata,

/* move station state to auth */
mutex_lock(&sdata->local->sta_mtx);
- sta = sta_info_get(sdata, bssid);
+ sta = sta_info_get(sdata, ap_addr);
if (!sta) {
- WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid);
+ WARN_ONCE(1, "%s: STA %pM not found", sdata->name, ap_addr);
result = false;
goto out;
}
if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
- sdata_info(sdata, "failed moving %pM to auth\n", bssid);
+ sdata_info(sdata, "failed moving %pM to auth\n", ap_addr);
result = false;
goto out;
}
@@ -4401,7 +4403,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
erp_valid, erp_value);

mutex_lock(&local->sta_mtx);
- sta = sta_info_get(sdata, bssid);
+ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);

changed |= ieee80211_recalc_twt_req(sdata, sta, elems);

@@ -4884,7 +4886,7 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
!sdata->deflink.u.mgd.csa_waiting_bcn)
return;

- sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid);
+ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
if (!sta)
return;

@@ -4980,7 +4982,7 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
.bssid = bssid,
};

- memcpy(bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN);
+ memcpy(bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
ieee80211_mgd_deauth(sdata, &req);
}

@@ -5908,7 +5910,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,

sdata_info(sdata,
"disconnect from AP %pM for new auth to %pM\n",
- sdata->deflink.u.mgd.bssid, req->bss->bssid);
+ sdata->vif.cfg.ap_addr, req->bss->bssid);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_UNSPECIFIED,
false, frame_buf);
@@ -5985,7 +5987,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,

sdata_info(sdata,
"disconnect from AP %pM for new assoc to %pM\n",
- sdata->deflink.u.mgd.bssid, req->bss->bssid);
+ sdata->vif.cfg.ap_addr, req->bss->bssid);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_UNSPECIFIED,
false, frame_buf);
@@ -6343,7 +6345,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
}

if (ifmgd->associated &&
- ether_addr_equal(sdata->deflink.u.mgd.bssid, req->bssid)) {
+ ether_addr_equal(sdata->vif.cfg.ap_addr, req->bssid)) {
sdata_info(sdata,
"deauthenticating from %pM by local choice (Reason: %u=%s)\n",
req->bssid, req->reason_code,
--
2.36.1

2022-07-13 09:47:25

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 32/76] wifi: mac80211: mlme: do IEEE80211_STA_RESET_SIGNAL_AVE per link

From: Johannes Berg <[email protected]>

Remove the IEEE80211_STA_RESET_SIGNAL_AVE flag and use
a bool instead, but invert the polarity (now calling it
tracking_signal_avg) so we don't have to initialize it,
and put that into the link instead.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/mlme.c | 7 +++----
2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 699dabaa9f0d..711129edd923 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -361,7 +361,6 @@ enum ieee80211_sta_flags {
IEEE80211_STA_MFP_ENABLED = BIT(6),
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
- IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9),
IEEE80211_STA_DISABLE_WMM = BIT(14),
IEEE80211_STA_ENABLE_RRM = BIT(15),
};
@@ -885,6 +884,7 @@ struct ieee80211_link_data_managed {
s16 p2p_noa_index;

bool have_beacon;
+ bool tracking_signal_avg;

bool csa_waiting_bcn;
bool csa_ignored_same_chan;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 52dc336cadfa..bcc817de6bd0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2316,8 +2316,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,

ieee80211_check_rate_mask(sdata);

- sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
-
if (sdata->vif.p2p ||
sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) {
const struct cfg80211_bss_ies *ies;
@@ -2522,6 +2520,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.beacon_rate = NULL;

sdata->deflink.u.mgd.have_beacon = false;
+ sdata->deflink.u.mgd.tracking_signal_avg = false;

ifmgd->flags = 0;
sdata->deflink.u.mgd.conn_flags = 0;
@@ -4051,8 +4050,8 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
{
/* Track average RSSI from the Beacon frames of the current AP */

- if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
- ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
+ if (!sdata->deflink.u.mgd.tracking_signal_avg) {
+ sdata->deflink.u.mgd.tracking_signal_avg = true;
ewma_beacon_signal_init(&sdata->deflink.u.mgd.ave_beacon_signal);
sdata->deflink.u.mgd.last_cqm_event_signal = 0;
sdata->deflink.u.mgd.count_beacon_signal = 1;
--
2.36.1

2022-07-13 09:47:29

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 36/76] wifi: mac80211: mlme: remove sta argument from ieee80211_config_bw

From: Johannes Berg <[email protected]>

The argument is unused except for NULL checking, but we already
do that anyway, so it's not needed. Remove the argument.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index edd7f74f1ef3..fcd964e634d5 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -405,7 +405,6 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link,
}

static int ieee80211_config_bw(struct ieee80211_link_data *link,
- struct sta_info *sta,
const struct ieee80211_ht_cap *ht_cap,
const struct ieee80211_vht_cap *vht_cap,
const struct ieee80211_ht_operation *ht_oper,
@@ -449,9 +448,6 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
ieee80211_vif_type_p2p(&sdata->vif)))
eht_oper = NULL;

- if (WARN_ON_ONCE(!sta))
- return -EINVAL;
-
/*
* if bss configuration changed store the new one -
* this may be applicable even if channel is identical
@@ -4438,7 +4434,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,

changed |= ieee80211_recalc_twt_req(link, sta, elems);

- if (ieee80211_config_bw(link, sta, elems->ht_cap_elem,
+ if (ieee80211_config_bw(link, elems->ht_cap_elem,
elems->vht_cap_elem, elems->ht_operation,
elems->vht_operation, elems->he_operation,
elems->eht_operation,
--
2.36.1

2022-07-13 09:47:19

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 16/76] wifi: cfg80211: make cfg80211_auth_request::key_idx signed

From: Johannes Berg <[email protected]>

We might assign -1 to it in some cases when key is NULL,
which means the key_idx isn't used but can lead to a
warning from static checkers such as smatch.

Make the struct member signed simply to avoid that, we
only need a range of -1..3 anyway.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d4632b391a15..e50b93160319 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2773,7 +2773,8 @@ struct cfg80211_auth_request {
size_t ie_len;
enum nl80211_auth_type auth_type;
const u8 *key;
- u8 key_len, key_idx;
+ u8 key_len;
+ s8 key_idx;
const u8 *auth_data;
size_t auth_data_len;
s8 link_id;
--
2.36.1

2022-07-13 09:47:37

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 43/76] wifi: cfg80211: extend cfg80211_rx_assoc_resp() for MLO

From: Johannes Berg <[email protected]>

Extend the cfg80211_rx_assoc_resp() to cover multiple
BSSes, the AP MLD address and local link addresses
for MLO.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 9 +++++-
net/mac80211/mlme.c | 2 +-
net/wireless/mlme.c | 64 +++++++++++++++++++++++++++---------------
net/wireless/trace.h | 16 +++++------
4 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1a0bdff1569c..09f2e2f031b6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6886,14 +6886,21 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
* as the AC bitmap in the QoS info field
* @req_ies: information elements from the (Re)Association Request frame
* @req_ies_len: length of req_ies data
+ * @ap_mld_addr: AP MLD address (in case of MLO)
+ * @links: per-link information indexed by link ID, use links[0] for
+ * non-MLO connections
*/
struct cfg80211_rx_assoc_resp {
- struct cfg80211_bss *bss;
const u8 *buf;
size_t len;
const u8 *req_ies;
size_t req_ies_len;
int uapsd_queues;
+ const u8 *ap_mld_addr;
+ struct {
+ const u8 *addr;
+ struct cfg80211_bss *bss;
+ } links[IEEE80211_MLD_MAX_NUM_LINKS];
};

/**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a47836730493..1819a8161e12 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3994,7 +3994,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
info.success = 1;
}

- resp.bss = cbss;
+ resp.links[0].bss = cbss;
resp.buf = (u8 *)mgmt;
resp.len = len;
resp.req_ies = ifmgd->assoc_req_ies;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index a6ad696f131b..80f11a29cb86 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -28,28 +28,41 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)data->buf;
- struct cfg80211_connect_resp_params cr;
- const u8 *resp_ie = mgmt->u.assoc_resp.variable;
- size_t resp_ie_len = data->len - offsetof(struct ieee80211_mgmt,
- u.assoc_resp.variable);
-
- if (data->bss->channel->band == NL80211_BAND_S1GHZ) {
- resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
- resp_ie_len = data->len - offsetof(struct ieee80211_mgmt,
- u.s1g_assoc_resp.variable);
- }
+ struct cfg80211_connect_resp_params cr = {
+ .timeout_reason = NL80211_TIMEOUT_UNSPECIFIED,
+ .req_ie = data->req_ies,
+ .req_ie_len = data->req_ies_len,
+ .resp_ie = mgmt->u.assoc_resp.variable,
+ .resp_ie_len = data->len -
+ offsetof(struct ieee80211_mgmt,
+ u.assoc_resp.variable),
+ .status = le16_to_cpu(mgmt->u.assoc_resp.status_code),
+ .ap_mld_addr = data->ap_mld_addr,
+ };
+ unsigned int link_id;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
+ cr.links[link_id].bss = data->links[link_id].bss;
+ if (!cr.links[link_id].bss)
+ continue;
+ cr.links[link_id].bssid = data->links[link_id].bss->bssid;
+ cr.links[link_id].addr = data->links[link_id].addr;
+ /* need to have local link addresses for MLO connections */
+ WARN_ON(cr.ap_mld_addr && !cr.links[link_id].addr);
+
+ if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) {
+ WARN_ON(link_id);
+ cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
+ cr.resp_ie_len = data->len -
+ offsetof(struct ieee80211_mgmt,
+ u.s1g_assoc_resp.variable);
+ }

- memset(&cr, 0, sizeof(cr));
- cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
- cr.links[0].bssid = mgmt->bssid;
- cr.links[0].bss = data->bss;
- cr.req_ie = data->req_ies;
- cr.req_ie_len = data->req_ies_len;
- cr.resp_ie = resp_ie;
- cr.resp_ie_len = resp_ie_len;
- cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
+ if (cr.ap_mld_addr)
+ cr.valid_links |= BIT(link_id);
+ }

- trace_cfg80211_send_rx_assoc(dev, data->bss);
+ trace_cfg80211_send_rx_assoc(dev, data);

/*
* This is a bit of a hack, we don't notify userspace of
@@ -58,8 +71,15 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
* frame instead of reassoc.
*/
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
- cfg80211_unhold_bss(bss_from_pub(data->bss));
- cfg80211_put_bss(wiphy, data->bss);
+ for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
+ struct cfg80211_bss *bss = data->links[link_id].bss;
+
+ if (!bss)
+ continue;
+
+ cfg80211_unhold_bss(bss_from_pub(bss));
+ cfg80211_put_bss(wiphy, bss);
+ }
return;
}

diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 94d107cab72c..dac66ad5937d 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2887,20 +2887,20 @@ DEFINE_EVENT(netdev_evt_only, cfg80211_send_rx_auth,
);

TRACE_EVENT(cfg80211_send_rx_assoc,
- TP_PROTO(struct net_device *netdev, struct cfg80211_bss *bss),
- TP_ARGS(netdev, bss),
+ TP_PROTO(struct net_device *netdev,
+ struct cfg80211_rx_assoc_resp *data),
+ TP_ARGS(netdev, data),
TP_STRUCT__entry(
NETDEV_ENTRY
- MAC_ENTRY(bssid)
- CHAN_ENTRY
+ MAC_ENTRY(ap_addr)
),
TP_fast_assign(
NETDEV_ASSIGN;
- MAC_ASSIGN(bssid, bss->bssid);
- CHAN_ASSIGN(bss->channel);
+ MAC_ASSIGN(ap_addr,
+ data->ap_mld_addr ?: data->links[0].bss->bssid);
),
- TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", " CHAN_PR_FMT,
- NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
+ TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT,
+ NETDEV_PR_ARG, MAC_PR_ARG(ap_addr))
);

DECLARE_EVENT_CLASS(netdev_frame_event,
--
2.36.1

2022-07-13 09:47:47

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 40/76] wifi: mac80211: mlme: unify assoc data event sending

From: Johannes Berg <[email protected]>

There are a few cases where we send an event to cfg80211
manually, but ieee80211_destroy_assoc_data() also handles
the case of abandoning; some cases don't need an event
and success is handled yet differently.

Unify this by providing a single status argument to the
ieee80211_destroy_assoc_data() function and then handling
all the different cases of events (or no events) there.

This will help simplify the code when MLO support is
added.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 51 ++++++++++++++++++---------------------------
1 file changed, 20 insertions(+), 31 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8d339d3f89ab..772584732b6e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2998,14 +2998,21 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.auth_data = NULL;
}

+enum assoc_status {
+ ASSOC_SUCCESS,
+ ASSOC_REJECTED,
+ ASSOC_TIMEOUT,
+ ASSOC_ABANDON,
+};
+
static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
- bool assoc, bool abandon)
+ enum assoc_status status)
{
struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;

sdata_assert_lock(sdata);

- if (!assoc) {
+ if (status != ASSOC_SUCCESS) {
/*
* we are not associated yet, the only timer that could be
* running is the timeout for the association response which
@@ -3026,9 +3033,10 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&sdata->local->mtx);

- if (abandon) {
+ if (status != ASSOC_REJECTED) {
struct cfg80211_assoc_failure data = {
.bss[0] = assoc_data->bss,
+ .timeout = status == ASSOC_TIMEOUT,
};

cfg80211_assoc_failure(sdata->dev, &data);
@@ -3309,7 +3317,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
bssid, reason_code,
ieee80211_get_reason_code_string(reason_code));

- ieee80211_destroy_assoc_data(sdata, false, true);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_ABANDON);

cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
return;
@@ -3953,19 +3961,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (status_code != WLAN_STATUS_SUCCESS) {
sdata_info(sdata, "%pM denied association (code=%d)\n",
mgmt->sa, status_code);
- ieee80211_destroy_assoc_data(sdata, false, false);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_REJECTED);
event.u.mlme.status = MLME_DENIED;
event.u.mlme.reason = status_code;
drv_event_callback(sdata->local, sdata, &event);
} else {
if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
/* oops -- internal error -- send timeout for now */
- struct cfg80211_assoc_failure data = {
- .timeout = true,
- .bss[0] = cbss,
- };
- ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_failure(sdata->dev, &data);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT);
goto notify_driver;
}
event.u.mlme.status = MLME_SUCCESS;
@@ -3977,7 +3980,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
* recalc after assoc_data is NULL but before associated
* is set can cause the interface to go idle
*/
- ieee80211_destroy_assoc_data(sdata, true, false);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_SUCCESS);

/* get uapsd queues configuration */
uapsd_queues = 0;
@@ -4835,19 +4838,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
if ((ifmgd->assoc_data->need_beacon &&
!sdata->deflink.u.mgd.have_beacon) ||
ieee80211_do_assoc(sdata)) {
- struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
struct ieee80211_event event = {
.type = MLME_EVENT,
.u.mlme.data = ASSOC_EVENT,
.u.mlme.status = MLME_TIMEOUT,
};
- struct cfg80211_assoc_failure data = {
- .bss[0] = bss,
- .timeout = true,
- };

- ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_failure(sdata->dev, &data);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT);
drv_event_callback(sdata->local, sdata, &event);
}
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
@@ -5012,7 +5009,7 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
WLAN_REASON_DEAUTH_LEAVING,
false, frame_buf);
if (ifmgd->assoc_data)
- ieee80211_destroy_assoc_data(sdata, false, true);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_ABANDON);
if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false);
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
@@ -6407,7 +6404,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
IEEE80211_STYPE_DEAUTH,
req->reason_code, tx,
frame_buf);
- ieee80211_destroy_assoc_data(sdata, false, true);
+ ieee80211_destroy_assoc_data(sdata, ASSOC_ABANDON);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
req->reason_code, false);
@@ -6478,16 +6475,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);

sdata_lock(sdata);
- if (ifmgd->assoc_data) {
- struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
- struct cfg80211_assoc_failure data = {
- .bss[0] = bss,
- .timeout = true,
- };
-
- ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_failure(sdata->dev, &data);
- }
+ if (ifmgd->assoc_data)
+ ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT);
if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false);
spin_lock_bh(&ifmgd->teardown_lock);
--
2.36.1

2022-07-13 09:47:52

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 47/76] wifi: mac80211: move tdls_chan_switch_prohibited to link data

From: Johannes Berg <[email protected]>

This value should be per link, since a TDLS connection is
only established on a given link.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/cfg.c | 2 +-
net/mac80211/ieee80211_i.h | 3 ++-
net/mac80211/mlme.c | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 873e1acc8c30..555c135e9fcd 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1759,7 +1759,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,

/* mark TDLS channel switch support, if the AP allows it */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
- !sdata->u.mgd.tdls_chan_switch_prohibited &&
+ !sdata->deflink.u.mgd.tdls_chan_switch_prohibited &&
params->ext_capab_len >= 4 &&
params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)
set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2cf13ea4c9f7..a8211ced719e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -514,7 +514,6 @@ struct ieee80211_if_managed {
struct sk_buff *orig_teardown_skb; /* The original teardown skb */
struct sk_buff *teardown_skb; /* A copy to send through the AP */
spinlock_t teardown_lock; /* To lock changing teardown_skb */
- bool tdls_chan_switch_prohibited;
bool tdls_wider_bw_prohibited;

/* WMM-AC TSPEC support */
@@ -880,6 +879,8 @@ struct ieee80211_link_data_managed {

s16 p2p_noa_index;

+ bool tdls_chan_switch_prohibited;
+
bool have_beacon;
bool tracking_signal_avg;
bool disable_wmm_tracking;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index aec77e81df99..404edb975a2f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3503,7 +3503,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}

sdata->vif.cfg.aid = aid;
- ifmgd->tdls_chan_switch_prohibited =
+ sdata->deflink.u.mgd.tdls_chan_switch_prohibited =
elems->ext_capab && elems->ext_capab_len >= 5 &&
(elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);

--
2.36.1

2022-07-13 09:47:56

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 74/76] wifi: mac80211: replace link_id with link_conf in switch/(un)assign_vif_chanctx()

From: Gregory Greenman <[email protected]>

Since mac80211 already has a protected pointer to link_conf,
pass it to the driver to avoid additional RCU locking.

Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 4 +--
drivers/net/wireless/ath/ath11k/mac.c | 4 +--
drivers/net/wireless/ath/ath9k/main.c | 4 +--
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +--
drivers/net/wireless/mac80211_hwsim.c | 4 +--
drivers/net/wireless/silabs/wfx/sta.c | 4 +--
drivers/net/wireless/silabs/wfx/sta.h | 4 +--
drivers/net/wireless/ti/wlcore/main.c | 4 +--
include/net/mac80211.h | 8 +++---
net/mac80211/chan.c | 9 +++----
net/mac80211/driver-ops.h | 26 +++++++++++++------
net/mac80211/trace.h | 16 ++++++------
net/mac80211/util.c | 2 +-
13 files changed, 51 insertions(+), 42 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index ac54396418c9..9dd3b8fba4b0 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8920,7 +8920,7 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
static int
ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct ath10k *ar = hw->priv;
@@ -9000,7 +9000,7 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
static void
ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct ath10k *ar = hw->priv;
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index ec7b3a3629f3..92e17d3c634e 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -7073,7 +7073,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
static int
ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct ath11k *ar = hw->priv;
@@ -7163,7 +7163,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
static void
ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct ath11k *ar = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d2c20c332c7a..a4197c14f0a9 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2597,7 +2597,7 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw,

static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
@@ -2629,7 +2629,7 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,

static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 126106ea62d3..5eb28f8ee87e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -4264,7 +4264,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
}
static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@@ -4338,7 +4338,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,

static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 5243508bbfab..715661298f2a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2794,7 +2794,7 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,

static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
hwsim_check_magic(vif);
@@ -2805,7 +2805,7 @@ static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,

static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
hwsim_check_magic(vif);
diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
index 920bd1a4a1b1..626dfb4b7a55 100644
--- a/drivers/net/wireless/silabs/wfx/sta.c
+++ b/drivers/net/wireless/silabs/wfx/sta.c
@@ -683,7 +683,7 @@ void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *
}

int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *conf)
{
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
@@ -696,7 +696,7 @@ int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}

void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *conf)
{
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h
index bf2e76167a6f..888db5cd3206 100644
--- a/drivers/net/wireless/silabs/wfx/sta.h
+++ b/drivers/net/wireless/silabs/wfx/sta.h
@@ -51,10 +51,10 @@ int wfx_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf
void wfx_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf);
void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf, u32 changed);
int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *conf);
void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *conf);

/* Hardware API Callbacks */
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 1edec9f3c0d8..3e3922d4c788 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4701,7 +4701,7 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,

static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct wl1271 *wl = hw->priv;
@@ -4752,7 +4752,7 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,

static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
struct wl1271 *wl = hw->priv;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d080d7e38d0f..6e5e0708cfff 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -261,13 +261,13 @@ enum ieee80211_chanctx_switch_mode {
* done.
*
* @vif: the vif that should be switched from old_ctx to new_ctx
- * @link_id: the link ID that's switching
+ * @link_conf: the link conf that's switching
* @old_ctx: the old context to which the vif was assigned
* @new_ctx: the new context to which the vif must be assigned
*/
struct ieee80211_vif_chanctx_switch {
struct ieee80211_vif *vif;
- unsigned int link_id;
+ struct ieee80211_bss_conf *link_conf;
struct ieee80211_chanctx_conf *old_ctx;
struct ieee80211_chanctx_conf *new_ctx;
};
@@ -4297,11 +4297,11 @@ struct ieee80211_ops {
u32 changed);
int (*assign_vif_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx);
void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx);
int (*switch_vif_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 2e9bc285f0a5..f247daa41563 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -835,7 +835,6 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
struct ieee80211_chanctx *new_ctx)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
- unsigned int link_id = link->link_id;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *curr_ctx = NULL;
@@ -850,13 +849,13 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
if (conf) {
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);

- drv_unassign_vif_chanctx(local, sdata, link_id, curr_ctx);
+ drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
conf = NULL;
list_del(&link->assigned_chanctx_list);
}

if (new_ctx) {
- ret = drv_assign_vif_chanctx(local, sdata, link_id, new_ctx);
+ ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
if (ret)
goto out;

@@ -1276,7 +1275,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
vif_chsw[0].vif = &sdata->vif;
vif_chsw[0].old_ctx = &old_ctx->conf;
vif_chsw[0].new_ctx = &new_ctx->conf;
- vif_chsw[0].link_id = link->link_id;
+ vif_chsw[0].link_conf = link->conf;

list_del(&link->reserved_chanctx_list);
link->reserved_chanctx = NULL;
@@ -1440,7 +1439,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
vif_chsw[i].vif = &link->sdata->vif;
vif_chsw[i].old_ctx = &old_ctx->conf;
vif_chsw[i].new_ctx = &ctx->conf;
- vif_chsw[i].link_id = link->link_id;
+ vif_chsw[i].link_conf = link->conf;

i++;
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index a04a88d122b7..0f06081c68ca 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -937,22 +937,31 @@ static inline void drv_change_chanctx(struct ieee80211_local *local,
trace_drv_return_void(local);
}

+static inline void drv_verify_link_exists(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *link_conf)
+{
+ /* deflink always exists, so need to check only for other links */
+ if (sdata->deflink.conf != link_conf)
+ sdata_assert_lock(sdata);
+}
+
static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx)
{
int ret = 0;

+ drv_verify_link_exists(sdata, link_conf);
if (!check_sdata_in_driver(sdata))
return -EIO;

- trace_drv_assign_vif_chanctx(local, sdata, link_id, ctx);
+ trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
if (local->ops->assign_vif_chanctx) {
WARN_ON_ONCE(!ctx->driver_present);
ret = local->ops->assign_vif_chanctx(&local->hw,
&sdata->vif,
- link_id,
+ link_conf,
&ctx->conf);
}
trace_drv_return_int(local, ret);
@@ -962,20 +971,21 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,

static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx)
{
might_sleep();

+ drv_verify_link_exists(sdata, link_conf);
if (!check_sdata_in_driver(sdata))
return;

- trace_drv_unassign_vif_chanctx(local, sdata, link_id, ctx);
+ trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
if (local->ops->unassign_vif_chanctx) {
WARN_ON_ONCE(!ctx->driver_present);
local->ops->unassign_vif_chanctx(&local->hw,
&sdata->vif,
- link_id,
+ link_conf,
&ctx->conf);
}
trace_drv_return_void(local);
@@ -992,7 +1002,7 @@ static inline int drv_start_ap(struct ieee80211_local *local,
int ret = 0;

/* make sure link_conf is protected */
- sdata_assert_lock(sdata);
+ drv_verify_link_exists(sdata, link_conf);

might_sleep();

@@ -1011,7 +1021,7 @@ static inline void drv_stop_ap(struct ieee80211_local *local,
struct ieee80211_bss_conf *link_conf)
{
/* make sure link_conf is protected */
- sdata_assert_lock(sdata);
+ drv_verify_link_exists(sdata, link_conf);

if (!check_sdata_in_driver(sdata))
return;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 75e5c1376351..402110f439f8 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1669,7 +1669,7 @@ TRACE_EVENT(drv_switch_vif_chanctx,

SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type);
SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p);
- SWITCH_ENTRY_ASSIGN(link_id, link_id);
+ SWITCH_ENTRY_ASSIGN(link_id, link_conf->link_id);
strncpy(local_vifs[i].vif.vif_name,
sdata->name,
sizeof(local_vifs[i].vif.vif_name));
@@ -1710,10 +1710,10 @@ TRACE_EVENT(drv_switch_vif_chanctx,
DECLARE_EVENT_CLASS(local_sdata_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx),

- TP_ARGS(local, sdata, link_id, ctx),
+ TP_ARGS(local, sdata, link_conf, ctx),

TP_STRUCT__entry(
LOCAL_ENTRY
@@ -1726,7 +1726,7 @@ DECLARE_EVENT_CLASS(local_sdata_chanctx,
LOCAL_ASSIGN;
VIF_ASSIGN;
CHANCTX_ASSIGN;
- __entry->link_id = link_id;
+ __entry->link_id = link_conf->link_id;
),

TP_printk(
@@ -1738,17 +1738,17 @@ DECLARE_EVENT_CLASS(local_sdata_chanctx,
DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx),
- TP_ARGS(local, sdata, link_id, ctx)
+ TP_ARGS(local, sdata, link_conf, ctx)
);

DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx),
- TP_ARGS(local, sdata, link_id, ctx)
+ TP_ARGS(local, sdata, link_conf, ctx)
);

TRACE_EVENT(drv_start_ap,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index cb44fa9a5048..994a49b892a6 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2267,7 +2267,7 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local,
lockdep_is_held(&local->chanctx_mtx));
if (conf) {
ctx = container_of(conf, struct ieee80211_chanctx, conf);
- drv_assign_vif_chanctx(local, sdata, link->link_id, ctx);
+ drv_assign_vif_chanctx(local, sdata, link->conf, ctx);
}
mutex_unlock(&local->chanctx_mtx);
}
--
2.36.1

2022-07-13 09:48:18

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 49/76] wifi: mac80211: don't set link address for station

From: Johannes Berg <[email protected]>

We need to handle the link addresses for station differently,
they will be determined by the association code, stored, and
then applied when the links are actually created on success,
cfg80211 will fill in the right addresses per the data we're
sending back to it.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/iface.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 4b4a36692c68..fc5869f40279 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -409,9 +409,6 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
break;
case NL80211_IFTYPE_STATION:
- eth_random_addr(link_conf->addr);
- ether_addr_copy(sdata->wdev.links[link_id].addr,
- link_conf->addr);
break;
default:
WARN_ON(1);
--
2.36.1

2022-07-13 09:48:26

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 23/76] wifi: nl80211: acquire wdev mutex for dump_survey

From: Johannes Berg <[email protected]>

At least the quantenna driver calls wdev_chandef() here
which now requires the lock, so acquire it.

Fixes: 7b0a0e3c3a88 ("wifi: cfg80211: do some rework towards MLO link APIs")
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b50ba1803595..886d964242ae 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10233,7 +10233,9 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
}

while (1) {
+ wdev_lock(wdev);
res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
+ wdev_unlock(wdev);
if (res == -ENOENT)
break;
if (res)
--
2.36.1

2022-07-13 09:48:26

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 24/76] wifi: mac80211: move ieee80211_request_smps_mgd_work

From: Johannes Berg <[email protected]>

This function can be static.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ht.c | 12 ------------
net/mac80211/ieee80211_i.h | 1 -
net/mac80211/mlme.c | 12 ++++++++++++
3 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index ea7ce87b7ec4..8c24817cd497 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -550,18 +550,6 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
return 0;
}

-void ieee80211_request_smps_mgd_work(struct work_struct *work)
-{
- struct ieee80211_link_data *link =
- container_of(work, struct ieee80211_link_data,
- u.mgd.request_smps_work);
-
- sdata_lock(link->sdata);
- __ieee80211_request_smps_mgd(link->sdata, link,
- link->u.mgd.driver_smps_mode);
- sdata_unlock(link->sdata);
-}
-
void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id,
enum ieee80211_smps_mode smps_mode)
{
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 154ff50e99a0..8c14274c9aaf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1951,7 +1951,6 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid);
-void ieee80211_request_smps_mgd_work(struct work_struct *work);
bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
enum ieee80211_smps_mode smps_mode_new);

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 5a208a01e278..73742f1a88ff 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5017,6 +5017,18 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
sdata_unlock(sdata);
}

+static void ieee80211_request_smps_mgd_work(struct work_struct *work)
+{
+ struct ieee80211_link_data *link =
+ container_of(work, struct ieee80211_link_data,
+ u.mgd.request_smps_work);
+
+ sdata_lock(link->sdata);
+ __ieee80211_request_smps_mgd(link->sdata, link,
+ link->u.mgd.driver_smps_mode);
+ sdata_unlock(link->sdata);
+}
+
/* interface setup */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
--
2.36.1

2022-07-13 09:48:26

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 30/76] wifi: mac80211: remove unused bssid variable

From: Johannes Berg <[email protected]>

This variable is only written to, remove it.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0992a3ff3a98..bfb29d09bd1d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6364,7 +6364,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
struct cfg80211_disassoc_request *req)
{
- u8 bssid[ETH_ALEN];
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];

/*
@@ -6380,7 +6379,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
"disassociating from %pM by local choice (Reason: %u=%s)\n",
req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));

- memcpy(bssid, req->bss->bssid, ETH_ALEN);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
req->reason_code, !req->local_state_change,
frame_buf);
--
2.36.1

2022-07-13 09:48:26

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 25/76] wifi: mac80211: set up/tear down client vif links properly

From: Johannes Berg <[email protected]>

In station/client mode, the link data needs a bit more
initialization and destruction than just zero-init and
kfree() respectively, implement that.

This required some shuffling of the link data handling
in general, as we should set it up in setup and do the
teardown in teardown, otherwise we're asymmetric in
case of interface type changes.

Also stop using kfree_rcu(), we cannot guarantee that
nothing is scheduling things that live within the link
(e.g. the u.mgd.request_smps_work) until we're sure it
cannot be referenced anymore, therefore synchronize
instead. This isn't very efficient, but we can always
optimize it later.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/iface.c | 346 ++++++++++++++++++++++---------------
net/mac80211/mlme.c | 35 ++--
3 files changed, 232 insertions(+), 151 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8c14274c9aaf..05996df627ea 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1772,6 +1772,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
u8 reason, bool tx);
+void ieee80211_mgd_setup_link(struct ieee80211_link_data *link);
+void ieee80211_mgd_stop_link(struct ieee80211_link_data *link);

/* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 12789a62366c..3e1d46119f7a 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -368,6 +368,208 @@ static int ieee80211_open(struct net_device *dev)
return err;
}

+static void ieee80211_link_setup(struct ieee80211_link_data *link)
+{
+ if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_mgd_setup_link(link);
+}
+
+static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
+ int link_id,
+ struct ieee80211_link_data *link,
+ struct ieee80211_bss_conf *link_conf)
+{
+ bool deflink = link_id < 0;
+
+ if (link_id < 0)
+ link_id = 0;
+
+ rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
+ rcu_assign_pointer(sdata->link[link_id], link);
+
+ link->sdata = sdata;
+ link->link_id = link_id;
+ link->conf = link_conf;
+
+ INIT_WORK(&link->csa_finalize_work,
+ ieee80211_csa_finalize_work);
+ INIT_WORK(&link->color_change_finalize_work,
+ ieee80211_color_change_finalize_work);
+ INIT_LIST_HEAD(&link->assigned_chanctx_list);
+ INIT_LIST_HEAD(&link->reserved_chanctx_list);
+ INIT_DELAYED_WORK(&link->dfs_cac_timer_work,
+ ieee80211_dfs_cac_timer_work);
+
+ if (!deflink) {
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ ether_addr_copy(link_conf->addr,
+ sdata->wdev.links[link_id].addr);
+ WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
+ break;
+ case NL80211_IFTYPE_STATION:
+ eth_random_addr(link_conf->addr);
+ ether_addr_copy(sdata->wdev.links[link_id].addr,
+ link_conf->addr);
+ break;
+ default:
+ WARN_ON(1);
+ }
+ }
+}
+
+static void ieee80211_link_stop(struct ieee80211_link_data *link)
+{
+ if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_mgd_stop_link(link);
+}
+
+struct link_container {
+ struct ieee80211_link_data data;
+ struct ieee80211_bss_conf conf;
+};
+
+static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
+ struct link_container **links)
+{
+ unsigned int link_id;
+
+ synchronize_rcu();
+
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
+ if (!links[link_id])
+ continue;
+ ieee80211_link_stop(&links[link_id]->data);
+ kfree(links[link_id]);
+ }
+}
+
+static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
+ struct link_container **to_free,
+ u16 new_links)
+{
+ u16 old_links = sdata->vif.valid_links;
+ unsigned long add = new_links & ~old_links;
+ unsigned long rem = old_links & ~new_links;
+ unsigned int link_id;
+ int ret;
+ struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
+ struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
+ bool use_deflink = old_links == 0; /* set for error case */
+
+ sdata_assert_lock(sdata);
+
+ memset(to_free, 0, sizeof(links));
+
+ if (old_links == new_links)
+ return 0;
+
+ /* allocate new link structures first */
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link) {
+ ret = -ENOMEM;
+ goto free;
+ }
+ links[link_id] = link;
+ }
+
+ /* keep track of the old pointers for the driver */
+ BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf));
+ memcpy(old, sdata->vif.link_conf, sizeof(old));
+ /* and for us in error cases */
+ BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
+ memcpy(old_data, sdata->link, sizeof(old_data));
+
+ /* link them into data structures */
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ WARN_ON(!use_deflink &&
+ rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);
+
+ link = links[link_id];
+ ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
+ ieee80211_link_setup(&link->data);
+ }
+
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ RCU_INIT_POINTER(sdata->link[link_id], NULL);
+ RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
+ }
+
+ sdata->vif.valid_links = new_links;
+
+ /* tell the driver */
+ ret = drv_change_vif_links(sdata->local, sdata,
+ old_links, new_links,
+ old);
+ if (ret) {
+ /* restore config */
+ memcpy(sdata->link, old_data, sizeof(old_data));
+ memcpy(sdata->vif.link_conf, old, sizeof(old));
+ sdata->vif.valid_links = old_links;
+ /* and free the newly allocated links */
+ goto deinit;
+ }
+
+ /* use deflink/bss_conf again if and only if there are no more links */
+ use_deflink = new_links == 0;
+
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
+ continue;
+ /*
+ * we must have allocated the data through this path so
+ * we know we can free both at the same time
+ */
+ to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
+ typeof(*links[link_id]),
+ data);
+ }
+
+ goto deinit;
+free:
+ /* if we failed during allocation, only free all */
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
+ kfree(links[link_id]);
+ links[link_id] = NULL;
+ }
+deinit:
+ if (use_deflink)
+ ieee80211_link_init(sdata, -1, &sdata->deflink,
+ &sdata->vif.bss_conf);
+ return ret;
+}
+
+int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
+ u16 new_links)
+{
+ struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
+ int ret;
+
+ ret = ieee80211_vif_update_links(sdata, links, new_links);
+ ieee80211_free_links(sdata, links);
+
+ return ret;
+}
+
+static void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata)
+{
+ struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
+
+ /*
+ * The locking here is different because when we free links
+ * in the station case we need to be able to cancel_work_sync()
+ * something that also takes the lock.
+ */
+
+ sdata_lock(sdata);
+ ieee80211_vif_update_links(sdata, links, 0);
+ sdata_unlock(sdata);
+
+ ieee80211_free_links(sdata, links);
+}
+
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
{
struct ieee80211_local *local = sdata->local;
@@ -727,6 +929,9 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)

if (ieee80211_vif_is_mesh(&sdata->vif))
ieee80211_mesh_teardown_sdata(sdata);
+
+ ieee80211_vif_clear_links(sdata);
+ ieee80211_link_stop(&sdata->deflink);
}

static void ieee80211_uninit(struct net_device *dev)
@@ -1019,50 +1224,6 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
}

-static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
- int link_id,
- struct ieee80211_link_data *link,
- struct ieee80211_bss_conf *link_conf)
-{
- bool deflink = link_id < 0;
-
- if (link_id < 0)
- link_id = 0;
-
- rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
- rcu_assign_pointer(sdata->link[link_id], link);
-
- link->sdata = sdata;
- link->link_id = link_id;
- link->conf = link_conf;
-
- INIT_WORK(&link->csa_finalize_work,
- ieee80211_csa_finalize_work);
- INIT_WORK(&link->color_change_finalize_work,
- ieee80211_color_change_finalize_work);
- INIT_LIST_HEAD(&link->assigned_chanctx_list);
- INIT_LIST_HEAD(&link->reserved_chanctx_list);
- INIT_DELAYED_WORK(&link->dfs_cac_timer_work,
- ieee80211_dfs_cac_timer_work);
-
- if (!deflink) {
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- ether_addr_copy(link_conf->addr,
- sdata->wdev.links[link_id].addr);
- WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
- break;
- case NL80211_IFTYPE_STATION:
- eth_random_addr(link_conf->addr);
- ether_addr_copy(sdata->wdev.links[link_id].addr,
- link_conf->addr);
- break;
- default:
- WARN_ON(1);
- }
- }
-}
-
static void ieee80211_sdata_init(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
@@ -1785,6 +1946,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
break;
}

+ /* need to do this after the switch so vif.type is correct */
+ ieee80211_link_setup(&sdata->deflink);
+
ieee80211_debugfs_add_netdev(sdata);
}

@@ -2353,97 +2517,3 @@ void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata)
else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
atomic_dec(&sdata->u.vlan.num_mcast_sta);
}
-
-int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
- u16 new_links)
-{
- u16 old_links = sdata->vif.valid_links;
- unsigned long add = new_links & ~old_links;
- unsigned long rem = old_links & ~new_links;
- unsigned int link_id;
- int ret;
- struct {
- struct ieee80211_link_data data;
- struct ieee80211_bss_conf conf;
- struct rcu_head rcu_head;
- } *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
- struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
- struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
- bool use_deflink = old_links == 0; /* set for error case */
-
- sdata_assert_lock(sdata);
-
- if (old_links == new_links)
- return 0;
-
- /* allocate new link structures first */
- for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
- link = kzalloc(sizeof(*link), GFP_KERNEL);
- if (!link) {
- ret = -ENOMEM;
- goto free;
- }
- links[link_id] = link;
- }
-
- /* keep track of the old pointers for the driver */
- BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf));
- memcpy(old, sdata->vif.link_conf, sizeof(old));
- /* and for us in error cases */
- BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
- memcpy(old_data, sdata->link, sizeof(old_data));
-
- /* link them into data structures */
- for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
- WARN_ON(!use_deflink &&
- rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);
-
- link = links[link_id];
- ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
- }
-
- for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- RCU_INIT_POINTER(sdata->link[link_id], NULL);
- RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
- }
-
- sdata->vif.valid_links = new_links;
-
- /* tell the driver */
- ret = drv_change_vif_links(sdata->local, sdata,
- old_links, new_links,
- old);
- if (ret) {
- /* restore config */
- memcpy(sdata->link, old_data, sizeof(old_data));
- memcpy(sdata->vif.link_conf, old, sizeof(old));
- sdata->vif.valid_links = old_links;
- /* and free the newly allocated links */
- goto free;
- }
-
- /* use deflink/bss_conf again if and only if there are no more links */
- use_deflink = new_links == 0;
-
- /* now use this to free the old links */
- memset(links, 0, sizeof(links));
- for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
- continue;
- /*
- * we must have allocated the data through this path so
- * we know we can free both at the same time
- */
- links[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
- typeof(*links[link_id]),
- data);
- }
-
-free:
- for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
- kfree_rcu(links[link_id], rcu_head);
- if (use_deflink)
- ieee80211_link_init(sdata, -1, &sdata->deflink,
- &sdata->vif.bss_conf);
- return ret;
-}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 73742f1a88ff..f994945039cd 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5032,17 +5032,14 @@ static void ieee80211_request_smps_mgd_work(struct work_struct *work)
/* interface setup */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_if_managed *ifmgd;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

- ifmgd = &sdata->u.mgd;
INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
ieee80211_beacon_connection_loss_work);
INIT_WORK(&ifmgd->csa_connection_drop_work,
ieee80211_csa_connection_drop_work);
- INIT_WORK(&sdata->deflink.u.mgd.request_smps_work,
- ieee80211_request_smps_mgd_work);
INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
ieee80211_tdls_peer_del_work);
timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
@@ -5056,20 +5053,28 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd->powersave = sdata->wdev.ps;
ifmgd->uapsd_queues = sdata->local->hw.uapsd_queues;
ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
- sdata->deflink.u.mgd.p2p_noa_index = -1;
- sdata->deflink.u.mgd.conn_flags = 0;
-
- if (sdata->local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
- sdata->deflink.u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC;
- else
- sdata->deflink.u.mgd.req_smps = IEEE80211_SMPS_OFF;
-
/* Setup TDLS data */
spin_lock_init(&ifmgd->teardown_lock);
ifmgd->teardown_skb = NULL;
ifmgd->orig_teardown_skb = NULL;
}

+void ieee80211_mgd_setup_link(struct ieee80211_link_data *link)
+{
+ struct ieee80211_local *local = link->sdata->local;
+
+ link->u.mgd.p2p_noa_index = -1;
+ link->u.mgd.conn_flags = 0;
+ link->conf->bssid = link->u.mgd.bssid;
+
+ INIT_WORK(&link->u.mgd.request_smps_work,
+ ieee80211_request_smps_mgd_work);
+ if (local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
+ link->u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC;
+ else
+ link->u.mgd.req_smps = IEEE80211_SMPS_OFF;
+}
+
/* scan finished notification */
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
{
@@ -6382,6 +6387,11 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
return 0;
}

+void ieee80211_mgd_stop_link(struct ieee80211_link_data *link)
+{
+ cancel_work_sync(&link->u.mgd.request_smps_work);
+}
+
void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -6393,7 +6403,6 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
*/
cancel_work_sync(&ifmgd->monitor_work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
- cancel_work_sync(&sdata->deflink.u.mgd.request_smps_work);
cancel_work_sync(&ifmgd->csa_connection_drop_work);
cancel_work_sync(&ifmgd->chswitch_work);
cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
--
2.36.1

2022-07-13 09:48:27

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 17/76] wifi: cfg80211: drop BSS elements from assoc trace for now

From: Johannes Berg <[email protected]>

For multi-link operation, this cannot work as the req->bss pointer
will be NULL, and we'll need to do more work on this to really add
tracing for the MLO case here. Drop the BSS elements for now as
they're not the most useful thing, and it's hard to size things
correctly for the MLO case (without adding a lot of code that's
also executed when tracing isn't enabled.)

Reported-by: Dan Carpenter <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/rdev-ops.h | 11 +----------
net/wireless/trace.h | 13 ++-----------
2 files changed, 3 insertions(+), 21 deletions(-)

diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 6221a996c19f..53f5a0126dfd 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -469,18 +469,9 @@ static inline int rdev_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_assoc_request *req)
{
- const struct cfg80211_bss_ies *bss_ies;
int ret;

- /*
- * Note: we might trace not exactly the data that's processed,
- * due to races and the driver/mac80211 getting a newer copy.
- */
- rcu_read_lock();
- bss_ies = rcu_dereference(req->bss->ies);
- trace_rdev_assoc(&rdev->wiphy, dev, req, bss_ies);
- rcu_read_unlock();
-
+ trace_rdev_assoc(&rdev->wiphy, dev, req);
ret = rdev->ops->assoc(&rdev->wiphy, dev, req);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index e78bffbc6f95..c50e8a04199e 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1232,9 +1232,8 @@ TRACE_EVENT(rdev_auth,

TRACE_EVENT(rdev_assoc,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_assoc_request *req,
- const struct cfg80211_bss_ies *bss_ies),
- TP_ARGS(wiphy, netdev, req, bss_ies),
+ struct cfg80211_assoc_request *req),
+ TP_ARGS(wiphy, netdev, req),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
@@ -1242,9 +1241,6 @@ TRACE_EVENT(rdev_assoc,
MAC_ENTRY(prev_bssid)
__field(bool, use_mfp)
__field(u32, flags)
- __dynamic_array(u8, bss_elements, bss_ies->len)
- __field(bool, bss_elements_bcon)
- __field(u64, bss_elements_tsf)
__dynamic_array(u8, elements, req->ie_len)
__array(u8, ht_capa, sizeof(struct ieee80211_ht_cap))
__array(u8, ht_capa_mask, sizeof(struct ieee80211_ht_cap))
@@ -1264,11 +1260,6 @@ TRACE_EVENT(rdev_assoc,
MAC_ASSIGN(prev_bssid, req->prev_bssid);
__entry->use_mfp = req->use_mfp;
__entry->flags = req->flags;
- if (bss_ies->len)
- memcpy(__get_dynamic_array(bss_elements),
- bss_ies->data, bss_ies->len);
- __entry->bss_elements_bcon = bss_ies->from_beacon;
- __entry->bss_elements_tsf = bss_ies->tsf;
if (req->ie)
memcpy(__get_dynamic_array(elements),
req->ie, req->ie_len);
--
2.36.1

2022-07-13 09:48:27

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 10/76] wifi: mac80211: implement callbacks for <add/mod/del>_link_station

From: Shaul Triebitz <[email protected]>

Implement callbacks for cfg80211 add_link_station, mod_link_station,
and del_link_station API.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/cfg.c | 105 ++++++++++++++++++++++++++++++++++++++++
net/mac80211/sta_info.c | 7 +++
net/mac80211/sta_info.h | 1 +
3 files changed, 113 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a63f9235bcc3..777c133c3f0b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4588,6 +4588,108 @@ static void ieee80211_del_intf_link(struct wiphy *wiphy,
ieee80211_vif_set_links(sdata, wdev->valid_links);
}

+static int sta_add_link_station(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct link_station_parameters *params)
+{
+ struct sta_info *sta;
+ int ret;
+
+ sta = sta_info_get_bss(sdata, params->mld_mac);
+ if (!sta)
+ return -ENOENT;
+
+ ret = ieee80211_sta_allocate_link(sta, params->link_id);
+ if (ret)
+ return ret;
+
+ ret = sta_link_apply_parameters(local, sta, params);
+ if (ret) {
+ ieee80211_sta_free_link(sta, params->link_id);
+ return ret;
+ }
+
+ /* ieee80211_sta_activate_link frees the link upon failure */
+ return ieee80211_sta_activate_link(sta, params->link_id);
+}
+
+static int
+ieee80211_add_link_station(struct wiphy *wiphy, struct net_device *dev,
+ struct link_station_parameters *params)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ int ret;
+
+ mutex_lock(&sdata->local->sta_mtx);
+ ret = sta_add_link_station(local, sdata, params);
+ mutex_unlock(&sdata->local->sta_mtx);
+
+ return ret;
+}
+
+static int sta_mod_link_station(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct link_station_parameters *params)
+{
+ struct sta_info *sta;
+
+ sta = sta_info_get_bss(sdata, params->mld_mac);
+ if (!sta)
+ return -ENOENT;
+
+ if (!(sta->sta.valid_links & BIT(params->link_id)))
+ return -EINVAL;
+
+ return sta_link_apply_parameters(local, sta, params);
+}
+
+static int
+ieee80211_mod_link_station(struct wiphy *wiphy, struct net_device *dev,
+ struct link_station_parameters *params)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ int ret;
+
+ mutex_lock(&sdata->local->sta_mtx);
+ ret = sta_mod_link_station(local, sdata, params);
+ mutex_unlock(&sdata->local->sta_mtx);
+
+ return ret;
+}
+
+static int sta_del_link_station(struct ieee80211_sub_if_data *sdata,
+ struct link_station_del_parameters *params)
+{
+ struct sta_info *sta;
+
+ sta = sta_info_get_bss(sdata, params->mld_mac);
+ if (!sta)
+ return -ENOENT;
+
+ if (!(sta->sta.valid_links & BIT(params->link_id)))
+ return -EINVAL;
+
+ ieee80211_sta_remove_link(sta, params->link_id);
+
+ return 0;
+}
+
+static int
+ieee80211_del_link_station(struct wiphy *wiphy, struct net_device *dev,
+ struct link_station_del_parameters *params)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int ret;
+
+ mutex_lock(&sdata->local->sta_mtx);
+ ret = sta_del_link_station(sdata, params);
+ mutex_unlock(&sdata->local->sta_mtx);
+
+ return ret;
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -4695,4 +4797,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_radar_background = ieee80211_set_radar_background,
.add_intf_link = ieee80211_add_intf_link,
.del_intf_link = ieee80211_del_intf_link,
+ .add_link_station = ieee80211_add_link_station,
+ .mod_link_station = ieee80211_mod_link_station,
+ .del_link_station = ieee80211_del_link_station,
};
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d738534a709e..a4fa0ce7bd92 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2702,6 +2702,13 @@ static int link_sta_info_hash_add(struct ieee80211_local *local,
link_sta_rht_params);
}

+void ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id)
+{
+ lockdep_assert_held(&sta->sdata->local->sta_mtx);
+
+ sta_remove_link(sta, link_id, false);
+}
+
int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index a1724e366a35..ea0eeee808a5 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -900,6 +900,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time);

int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id);
+void ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id);
int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id);
void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id);

--
2.36.1

2022-07-13 09:48:27

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 35/76] wifi: mac80211: mlme: use ieee80211_get_link_sband()

From: Johannes Berg <[email protected]>

This requires a few more changes.

While at it, also add a warning to ieee80211_get_sband()
to avoid it being used when there are multiple links.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mlme.c | 12 ++++++------
2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3e360bcaa03b..a0743c78d171 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1539,6 +1539,8 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
struct ieee80211_chanctx_conf *chanctx_conf;
enum nl80211_band band;

+ WARN_ON(sdata->vif.valid_links);
+
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 80a31777922e..edd7f74f1ef3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2264,17 +2264,17 @@ static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&sdata->local->mtx);
}

-static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
+static u32 ieee80211_handle_bss_capability(struct ieee80211_link_data *link,
u16 capab, bool erp_valid, u8 erp)
{
- struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+ struct ieee80211_bss_conf *bss_conf = link->conf;
struct ieee80211_supported_band *sband;
u32 changed = 0;
bool use_protection;
bool use_short_preamble;
bool use_short_slot;

- sband = ieee80211_get_sband(sdata);
+ sband = ieee80211_get_link_sband(link);
if (!sband)
return changed;

@@ -2320,7 +2320,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg;

bss_info_changed |= BSS_CHANGED_ASSOC;
- bss_info_changed |= ieee80211_handle_bss_capability(sdata,
+ bss_info_changed |= ieee80211_handle_bss_capability(link,
bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);

sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
@@ -3621,7 +3621,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- sband = ieee80211_get_sband(sdata);
+ sband = ieee80211_get_link_sband(link);
if (!sband) {
mutex_unlock(&sdata->local->sta_mtx);
ret = false;
@@ -4429,7 +4429,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
}

if (!ieee80211_is_s1g_beacon(hdr->frame_control))
- changed |= ieee80211_handle_bss_capability(sdata,
+ changed |= ieee80211_handle_bss_capability(link,
le16_to_cpu(mgmt->u.beacon.capab_info),
erp_valid, erp_value);

--
2.36.1

2022-07-13 09:48:27

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 27/76] wifi: mac80211: move ps setting to vif config

From: Johannes Berg <[email protected]>

This really shouldn't be in a per-link config, we don't want
to let anyone control it that way (if anything, link powersave
could be forced through APIs to activate/deactivate a link),
and we don't support powersave in software with devices that
can do MLO.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
drivers/net/wireless/ath/ath11k/mac.c | 2 +-
drivers/net/wireless/ath/wcn36xx/main.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/power.c | 4 ++--
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +-
drivers/net/wireless/silabs/wfx/sta.c | 6 +++---
drivers/net/wireless/ti/wlcore/main.c | 4 ++--
include/net/mac80211.h | 6 +++---
net/mac80211/main.c | 1 +
net/mac80211/mlme.c | 7 +++----
net/mac80211/trace.h | 4 ++--
13 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 3d111d6447f0..b18f32261d15 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -6252,7 +6252,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
}

if (changed & BSS_CHANGED_PS) {
- arvif->ps = vif->bss_conf.ps;
+ arvif->ps = vif->cfg.ps;

ret = ath10k_config_ps(ar);
if (ret)
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 17dbc7d9cf29..1cf1e1f18dba 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -3292,7 +3292,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,

if (changed & BSS_CHANGED_PS &&
ar->ab->hw_params.supports_sta_ps) {
- arvif->ps = vif->bss_conf.ps;
+ arvif->ps = vif->cfg.ps;

ret = ath11k_mac_config_ps(ar);
if (ret)
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index ace8641909bd..dc59cafd29e3 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -385,7 +385,7 @@ static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable)
list_for_each_entry(tmp, &wcn->vif_list, list) {
vif = wcn36xx_priv_to_vif(tmp);
if (enable && !wcn->sw_scan) {
- if (vif->bss_conf.ps) /* ps allowed ? */
+ if (vif->cfg.ps) /* ps allowed ? */
wcn36xx_pmc_enter_bmps_state(wcn, vif);
} else {
wcn36xx_pmc_exit_bmps_state(wcn, vif);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index b49f265a421f..f5744162d0d8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -359,7 +359,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,

cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);

- if (!vif->bss_conf.ps || !mvmvif->pm_enabled)
+ if (!vif->cfg.ps || !mvmvif->pm_enabled)
return;

if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
@@ -890,7 +890,7 @@ static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,

mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled ||
mvm->ps_disabled ||
- !vif->bss_conf.ps ||
+ !vif->cfg.ps ||
iwl_mvm_vif_low_latency(mvmvif));

return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 303975f9e2b5..a79043f30775 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1861,7 +1861,7 @@ static bool rs_tpc_allowed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int index = rate->index;
bool cam = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);
bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
- !vif->bss_conf.ps);
+ !vif->cfg.ps);

IWL_DEBUG_RATE(mvm, "cam: %d sta_ps_disabled %d\n",
cam, sta_ps_disabled);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index d3da54e6670b..389f8c61939d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -193,7 +193,7 @@ int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif)
*/
} req = {
.bss_idx = mvif->idx,
- .ps_state = vif->bss_conf.ps ? 2 : 0,
+ .ps_state = vif->cfg.ps ? 2 : 0,
};

if (vif->type != NL80211_IFTYPE_STATION)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 3b5b475b0875..976686075dd7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -972,7 +972,7 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
.ps = {
.tag = cpu_to_le16(UNI_BSS_INFO_PS),
.len = cpu_to_le16(sizeof(struct ps_tlv)),
- .ps_state = vif->bss_conf.ps ? 2 : 0,
+ .ps_state = vif->cfg.ps ? 2 : 0,
},
};

diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
index 0378144795ca..47fd887ce6fe 100644
--- a/drivers/net/wireless/silabs/wfx/sta.c
+++ b/drivers/net/wireless/silabs/wfx/sta.c
@@ -175,7 +175,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps)
/* It is useless to enable PS if channels are the same. */
if (enable_ps)
*enable_ps = false;
- if (vif->cfg.assoc && vif->bss_conf.ps)
+ if (vif->cfg.assoc && vif->cfg.ps)
dev_info(wvif->wdev->dev, "ignoring requested PS mode");
return -1;
}
@@ -188,8 +188,8 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps)
return 30;
}
if (enable_ps)
- *enable_ps = vif->bss_conf.ps;
- if (vif->cfg.assoc && vif->bss_conf.ps)
+ *enable_ps = vif->cfg.ps;
+ if (vif->cfg.assoc && vif->cfg.ps)
return conf->dynamic_ps_timeout;
else
return -1;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index a1923ef52d55..d1200080f165 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4481,7 +4481,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
}

if (changed & BSS_CHANGED_PS) {
- if ((bss_conf->ps) &&
+ if (vif->cfg.ps &&
test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
int ps_mode;
@@ -4501,7 +4501,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0)
wl1271_warning("enter %s ps failed %d",
ps_mode_str, ret);
- } else if (!bss_conf->ps &&
+ } else if (!vif->cfg.ps &&
test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
wl1271_debug(DEBUG_PSM, "auto ps disabled");

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f917f7d7614e..210b49c6cd50 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -578,8 +578,6 @@ struct ieee80211_fils_discovery {
* @cqm_rssi_high: Connection quality monitor RSSI upper threshold.
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
* @qos: This is a QoS-enabled BSS.
- * @ps: power-save mode (STA only). This flag is NOT affected by
- * offchannel/dynamic_ps operations.
* @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
* @txpower: TX power in dBm. INT_MIN means not configured.
* @txpower_type: TX power adjustment used to control per packet Transmit
@@ -673,7 +671,6 @@ struct ieee80211_bss_conf {
struct cfg80211_chan_def chandef;
struct ieee80211_mu_group_data mu_group;
bool qos;
- bool ps;
bool hidden_ssid;
int txpower;
enum nl80211_tx_power_setting txpower_type;
@@ -1715,6 +1712,8 @@ enum ieee80211_offload_flags {
* @assoc: association status
* @ibss_joined: indicates whether this station is part of an IBSS or not
* @ibss_creator: indicates if a new IBSS network is being created
+ * @ps: power-save mode (STA only). This flag is NOT affected by
+ * offchannel/dynamic_ps operations.
* @aid: association ID number, valid only when @assoc is true
* @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
* may filter ARP queries targeted for other addresses than listed here.
@@ -1734,6 +1733,7 @@ struct ieee80211_vif_cfg {
/* association related data */
bool assoc, ibss_joined;
bool ibss_creator;
+ bool ps;
u16 aid;

__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 191f4d35ef60..1258e506377e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -202,6 +202,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)

#define BSS_CHANGED_VIF_CFG_FLAGS (BSS_CHANGED_ASSOC |\
BSS_CHANGED_IDLE |\
+ BSS_CHANGED_PS |\
BSS_CHANGED_IBSS |\
BSS_CHANGED_ARP_FILTER |\
BSS_CHANGED_SSID)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f994945039cd..1035d6d433b1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1868,10 +1868,9 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)
{
bool ps_allowed = ieee80211_powersave_allowed(sdata);

- if (sdata->vif.bss_conf.ps != ps_allowed) {
- sdata->vif.bss_conf.ps = ps_allowed;
- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
- BSS_CHANGED_PS);
+ if (sdata->vif.cfg.ps != ps_allowed) {
+ sdata->vif.cfg.ps = ps_allowed;
+ ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_PS);
}
}

diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 6aa06fba5b50..751f08b47d0c 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -413,6 +413,7 @@ TRACE_EVENT(drv_vif_cfg_changed,
__dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len)
__field(int, s1g)
__field(bool, idle)
+ __field(bool, ps)
),

TP_fast_assign(
@@ -423,6 +424,7 @@ TRACE_EVENT(drv_vif_cfg_changed,
__entry->assoc = sdata->vif.cfg.assoc;
__entry->ibss_joined = sdata->vif.cfg.ibss_joined;
__entry->ibss_creator = sdata->vif.cfg.ibss_creator;
+ __entry->ps = sdata->vif.cfg.ps;

__entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt;
memcpy(__get_dynamic_array(arp_addr_list),
@@ -475,7 +477,6 @@ TRACE_EVENT(drv_link_info_changed,
__field(u32, channel_cfreq1)
__field(u32, channel_cfreq1_offset)
__field(bool, qos)
- __field(bool, ps)
__field(bool, hidden_ssid)
__field(int, txpower)
__field(u8, p2p_oppps_ctwindow)
@@ -506,7 +507,6 @@ TRACE_EVENT(drv_link_info_changed,
__entry->channel_cfreq1 = link_conf->chandef.center_freq1;
__entry->channel_cfreq1_offset = link_conf->chandef.freq1_offset;
__entry->qos = link_conf->qos;
- __entry->ps = link_conf->ps;
__entry->hidden_ssid = link_conf->hidden_ssid;
__entry->txpower = link_conf->txpower;
__entry->p2p_oppps_ctwindow = link_conf->p2p_noa_attr.oppps_ctwindow;
--
2.36.1

2022-07-13 09:48:27

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 18/76] wifi: mac80211_hwsim: Ack link addressed frames

From: Andrei Otcheretianski <[email protected]>

Do address matching with link addresses as well.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 8cc813f66010..835422c3a1b2 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1198,10 +1198,27 @@ struct mac80211_hwsim_addr_match_data {
static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
+ int i;
struct mac80211_hwsim_addr_match_data *md = data;

- if (memcmp(mac, md->addr, ETH_ALEN) == 0)
+ if (memcmp(mac, md->addr, ETH_ALEN) == 0) {
md->ret = true;
+ return;
+ }
+
+ /* Match the link address */
+ for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
+ struct ieee80211_bss_conf *conf;
+
+ conf = rcu_dereference(vif->link_conf[i]);
+ if (!conf)
+ continue;
+
+ if (memcmp(conf->addr, md->addr, ETH_ALEN) == 0) {
+ md->ret = true;
+ return;
+ }
+ }
}

static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
--
2.36.1

2022-07-13 09:48:29

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 34/76] wifi: mac80211: split IEEE80211_STA_DISABLE_WMM to link data

From: Johannes Berg <[email protected]>

If we decide to stop tracking QoS/WMM parameters, then
this should be a per-link decision. Move the flag to
the link instead.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/mlme.c | 9 +++++----
2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 20b9979d1506..3e360bcaa03b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -361,7 +361,6 @@ enum ieee80211_sta_flags {
IEEE80211_STA_MFP_ENABLED = BIT(6),
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
- IEEE80211_STA_DISABLE_WMM = BIT(14),
IEEE80211_STA_ENABLE_RRM = BIT(15),
};

@@ -883,6 +882,7 @@ struct ieee80211_link_data_managed {

bool have_beacon;
bool tracking_signal_avg;
+ bool disable_wmm_tracking;

bool csa_waiting_bcn;
bool csa_ignored_same_chan;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f3e901793ae1..80a31777922e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2539,6 +2539,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,

link->u.mgd.have_beacon = false;
link->u.mgd.tracking_signal_avg = false;
+ link->u.mgd.disable_wmm_tracking = false;

ifmgd->flags = 0;
link->u.mgd.conn_flags = 0;
@@ -3794,21 +3795,21 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
link->u.mgd.wmm_last_param_set = -1;
link->u.mgd.mu_edca_last_param_set = -1;

- if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
+ if (link->u.mgd.disable_wmm_tracking) {
ieee80211_set_wmm_default(link, false, false);
} else if (!ieee80211_sta_wmm_params(local, link, elems->wmm_param,
elems->wmm_param_len,
elems->mu_edca_param_set)) {
/* still enable QoS since we might have HT/VHT */
ieee80211_set_wmm_default(link, false, true);
- /* set the disable-WMM flag in this case to disable
+ /* disable WMM tracking in this case to disable
* tracking WMM parameter changes in the beacon if
* the parameters weren't actually valid. Doing so
* avoids changing parameters very strangely when
* the AP is going back and forth between valid and
* invalid parameters.
*/
- ifmgd->flags |= IEEE80211_STA_DISABLE_WMM;
+ link->u.mgd.disable_wmm_tracking = true;
}
changed |= BSS_CHANGED_QOS;

@@ -4396,7 +4397,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
rx_status->device_timestamp,
elems, true);

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
+ if (!link->u.mgd.disable_wmm_tracking &&
ieee80211_sta_wmm_params(local, link, elems->wmm_param,
elems->wmm_param_len,
elems->mu_edca_param_set))
--
2.36.1

2022-07-13 09:48:30

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 41/76] wifi: cfg80211: adjust assoc comeback for MLO

From: Johannes Berg <[email protected]>

We only report the BSSID to userspace, so change the
argument from BSS struct pointer to AP address, which
we'll use to carry either the BSSID or AP MLD address.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 4 ++--
net/mac80211/mlme.c | 2 +-
net/wireless/nl80211.c | 6 +++---
net/wireless/trace.h | 10 +++++-----
4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2a70f8900a4f..e24233b6d4bb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -8592,13 +8592,13 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
* cfg80211_assoc_comeback - notification of association that was
* temporarly rejected with a comeback
* @netdev: network device
- * @bss: the bss entry with which association is in progress.
+ * @ap_addr: AP (MLD) address that rejected the assocation
* @timeout: timeout interval value TUs.
*
* this function may sleep. the caller must hold the corresponding wdev's mutex.
*/
void cfg80211_assoc_comeback(struct net_device *netdev,
- struct cfg80211_bss *bss, u32 timeout);
+ const u8 *ap_addr, u32 timeout);

/* Logging, debugging and troubleshooting/diagnostic helpers. */

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 772584732b6e..feb5929b37e7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3943,7 +3943,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
u32 tu, ms;

- cfg80211_assoc_comeback(sdata->dev, assoc_data->bss,
+ cfg80211_assoc_comeback(sdata->dev, assoc_data->bss->bssid,
le32_to_cpu(elems->timeout_int->value));

tu = le32_to_cpu(elems->timeout_int->value);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 886d964242ae..6c3b47a7960f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -18036,7 +18036,7 @@ static void nl80211_send_remain_on_chan_event(
}

void cfg80211_assoc_comeback(struct net_device *netdev,
- struct cfg80211_bss *bss, u32 timeout)
+ const u8 *ap_addr, u32 timeout)
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
@@ -18044,7 +18044,7 @@ void cfg80211_assoc_comeback(struct net_device *netdev,
struct sk_buff *msg;
void *hdr;

- trace_cfg80211_assoc_comeback(wdev, bss->bssid, timeout);
+ trace_cfg80211_assoc_comeback(wdev, ap_addr, timeout);

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
@@ -18058,7 +18058,7 @@ void cfg80211_assoc_comeback(struct net_device *netdev,

if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bss->bssid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ap_addr) ||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT, timeout))
goto nla_put_failure;

diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 19efb9539533..94d107cab72c 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3764,20 +3764,20 @@ TRACE_EVENT(cfg80211_bss_color_notify,
);

TRACE_EVENT(cfg80211_assoc_comeback,
- TP_PROTO(struct wireless_dev *wdev, const u8 *bssid, u32 timeout),
- TP_ARGS(wdev, bssid, timeout),
+ TP_PROTO(struct wireless_dev *wdev, const u8 *ap_addr, u32 timeout),
+ TP_ARGS(wdev, ap_addr, timeout),
TP_STRUCT__entry(
WDEV_ENTRY
- MAC_ENTRY(bssid)
+ MAC_ENTRY(ap_addr)
__field(u32, timeout)
),
TP_fast_assign(
WDEV_ASSIGN;
- MAC_ASSIGN(bssid, bssid);
+ MAC_ASSIGN(ap_addr, ap_addr);
__entry->timeout = timeout;
),
TP_printk(WDEV_PR_FMT ", " MAC_PR_FMT ", timeout: %u TUs",
- WDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->timeout)
+ WDEV_PR_ARG, MAC_PR_ARG(ap_addr), __entry->timeout)
);

DECLARE_EVENT_CLASS(link_station_add_mod,
--
2.36.1

2022-07-13 09:48:29

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 29/76] wifi: mac80211: change QoS settings API to take link into account

From: Johannes Berg <[email protected]>

Take the link into account in the QoS settings (EDCA parameters)
APIs.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 3 +-
drivers/net/wireless/ath/ath11k/mac.c | 3 +-
drivers/net/wireless/ath/ath5k/mac80211-ops.c | 3 +-
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 +-
drivers/net/wireless/ath/ath9k/main.c | 3 +-
drivers/net/wireless/ath/carl9170/main.c | 3 +-
drivers/net/wireless/broadcom/b43/main.c | 3 +-
.../net/wireless/broadcom/b43legacy/main.c | 3 +-
.../broadcom/brcm80211/brcmsmac/mac80211_if.c | 3 +-
drivers/net/wireless/intel/iwlegacy/common.c | 3 +-
drivers/net/wireless/intel/iwlegacy/common.h | 3 +-
.../net/wireless/intel/iwlwifi/dvm/mac80211.c | 5 +-
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +-
drivers/net/wireless/intersil/p54/main.c | 3 +-
drivers/net/wireless/mac80211_hwsim.c | 8 +--
drivers/net/wireless/marvell/mwl8k.c | 5 +-
.../net/wireless/mediatek/mt76/mt7603/main.c | 3 +-
.../net/wireless/mediatek/mt76/mt7615/main.c | 3 +-
drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +-
.../net/wireless/mediatek/mt76/mt76x02_util.c | 3 +-
.../net/wireless/mediatek/mt76/mt7915/main.c | 3 +-
.../net/wireless/mediatek/mt76/mt7921/main.c | 3 +-
.../net/wireless/mediatek/mt7601u/mt7601u.h | 3 +-
drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +-
.../net/wireless/ralink/rt2x00/rt2400pci.c | 5 +-
.../net/wireless/ralink/rt2x00/rt2800lib.c | 5 +-
.../net/wireless/ralink/rt2x00/rt2800lib.h | 3 +-
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 3 +-
.../net/wireless/ralink/rt2x00/rt2x00mac.c | 3 +-
drivers/net/wireless/ralink/rt2x00/rt61pci.c | 5 +-
drivers/net/wireless/ralink/rt2x00/rt73usb.c | 5 +-
.../wireless/realtek/rtl818x/rtl8180/dev.c | 3 +-
.../wireless/realtek/rtl818x/rtl8187/dev.c | 3 +-
.../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 +-
drivers/net/wireless/realtek/rtlwifi/core.c | 3 +-
drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +-
drivers/net/wireless/realtek/rtw89/mac80211.c | 3 +-
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 3 +-
drivers/net/wireless/silabs/wfx/sta.c | 3 +-
drivers/net/wireless/silabs/wfx/sta.h | 3 +-
drivers/net/wireless/st/cw1200/sta.c | 3 +-
drivers/net/wireless/st/cw1200/sta.h | 3 +-
drivers/net/wireless/ti/wl1251/main.c | 3 +-
drivers/net/wireless/ti/wlcore/main.c | 3 +-
include/net/mac80211.h | 3 +-
net/mac80211/cfg.c | 7 ++-
net/mac80211/driver-ops.c | 8 ++-
net/mac80211/driver-ops.h | 2 +-
net/mac80211/ibss.c | 2 +-
net/mac80211/ieee80211_i.h | 5 +-
net/mac80211/iface.c | 2 +-
net/mac80211/mlme.c | 55 ++++++++++---------
net/mac80211/tdls.c | 2 +-
net/mac80211/trace.h | 9 ++-
net/mac80211/util.c | 18 +++---
55 files changed, 158 insertions(+), 104 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b18f32261d15..ac54396418c9 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7814,7 +7814,8 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
}

static int ath10k_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 ac,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct ath10k *ar = hw->priv;
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 1cf1e1f18dba..ec7b3a3629f3 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4822,7 +4822,8 @@ static int ath11k_conf_tx_uapsd(struct ath11k *ar, struct ieee80211_vif *vif,
}

static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 ac,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct ath11k *ar = hw->priv;
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 8da232e81518..acd0e1dafb7f 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -572,7 +572,8 @@ ath5k_get_stats(struct ieee80211_hw *hw,


static int
-ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath5k_hw *ah = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 14d713e03872..61875c45366b 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1369,7 +1369,8 @@ static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw,
}

static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath9k_htc_priv *priv = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index c3d5d9795424..d2c20c332c7a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1712,7 +1712,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
}

static int ath9k_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath_softc *sc = hw->priv;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 3d881028bd00..1540e9827f48 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1365,7 +1365,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
}

static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
struct ar9170 *ar = hw->priv;
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 6b4188066f0b..008ee1f98af4 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -3783,7 +3783,8 @@ static void b43_qos_init(struct b43_wldev *dev)
}

static int b43_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 _queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 _queue,
const struct ieee80211_tx_queue_params *params)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c
index 532013184389..cbc21c7c3138 100644
--- a/drivers/net/wireless/broadcom/b43legacy/main.c
+++ b/drivers/net/wireless/broadcom/b43legacy/main.c
@@ -2505,7 +2505,8 @@ static void b43legacy_op_tx(struct ieee80211_hw *hw,
}

static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
return 0;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index 61d7404aded4..a4034d44609b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -787,7 +787,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw,
}

static int
-brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct brcms_info *wl = hw->priv;
diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 6f007e63f0c2..9aa3359a9adc 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -4480,7 +4480,8 @@ il_clear_isr_stats(struct il_priv *il)
}

int
-il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct il_priv *il = hw->priv;
diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h
index d1383b4f0f05..69687fcf963f 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.h
+++ b/drivers/net/wireless/intel/iwlegacy/common.h
@@ -1683,7 +1683,8 @@ struct il_cfg {
***************************/

int il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
int il_mac_tx_last_beacon(struct ieee80211_hw *hw);

void il_set_rxon_hwcrypto(struct il_priv *il, int hw_decrypt);
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
index e8bd4f0e3d2d..f4070fddc8c7 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
@@ -2,7 +2,7 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2019, 2022 Intel Corporation
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -1153,7 +1153,8 @@ static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
}

static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index eaffc3163bd1..3de558f286a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3349,7 +3349,8 @@ static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw,
}

static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 ac,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
index 115be1f3f33d..0f76d43fda33 100644
--- a/drivers/net/wireless/intersil/p54/main.c
+++ b/drivers/net/wireless/intersil/p54/main.c
@@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
}

static int p54_conf_tx(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct p54_common *priv = dev->priv;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 835422c3a1b2..5243508bbfab 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2340,10 +2340,10 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
return 0;
}

-static int mac80211_hwsim_conf_tx(
- struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
- const struct ieee80211_tx_queue_params *params)
+static int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
wiphy_dbg(hw->wiphy,
"%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n",
diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c
index 293bec9bb8dd..c1bf8998109c 100644
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
@@ -5365,7 +5365,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
}

static int mwl8k_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mwl8k_priv *priv = hw->priv;
@@ -6050,7 +6051,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
goto fail;

for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) {
- rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]);
+ rc = mwl8k_conf_tx(hw, NULL, 0, i, &priv->wmm_params[i]);
if (rc)
goto fail;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 088c0a4cf774..051715ed90dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -527,7 +527,8 @@ mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}

static int
-mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mt7603_dev *dev = hw->priv;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 277c22a4d049..bf1696eb568a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -494,7 +494,8 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
}

static int
-mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 74ad418f5a70..50eaeff11af3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -156,7 +156,8 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index a0e2d042751b..604ddcc21123 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -487,7 +487,8 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
EXPORT_SYMBOL_GPL(mt76x02_set_key);

int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct mt76x02_dev *dev = hw->priv;
u8 cw_min = 5, cw_max = 10, qid;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index fbeac9aa2af6..25323a155a88 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -478,7 +478,8 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
}

static int
-mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 63583605d1cd..1d0daa0c90be 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -567,7 +567,8 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
}

static int
-mt7921_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+mt7921_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
index a122f1dd38f6..118d43707853 100644
--- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
+++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
@@ -368,7 +368,8 @@ void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev);
void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb);
int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb);
void mt7601u_tx_stat(struct work_struct *work);

diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c
index f1fa0442a57f..51d977ffc52f 100644
--- a/drivers/net/wireless/mediatek/mt7601u/tx.c
+++ b/drivers/net/wireless/mediatek/mt7601u/tx.c
@@ -258,7 +258,8 @@ void mt7601u_tx_stat(struct work_struct *work)
}

int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct mt7601u_dev *dev = hw->priv;
u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
index dec6ffdf07c4..273c5eac3362 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
@@ -1654,7 +1654,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* IEEE80211 stack callback functions.
*/
static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1667,7 +1668,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
if (queue != 0)
return -EINVAL;

- if (rt2x00mac_conf_tx(hw, vif, queue, params))
+ if (rt2x00mac_conf_tx(hw, vif, link_id, queue, params))
return -EINVAL;

/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index cbdaf7992f98..18102fbe36d6 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -10395,7 +10395,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);

int rt2800_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue_idx,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -10411,7 +10412,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw,
* we are free to update the registers based on the value
* in the queue parameter.
*/
- retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
+ retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params);
if (retval)
return retval;

diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index 1139405c0ebb..e1761f467b94 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -245,7 +245,8 @@ void rt2800_get_key_seq(struct ieee80211_hw *hw,
struct ieee80211_key_seq *seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
int rt2800_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue_idx,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params);
u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 918e0477bb7d..f7ef2ca38794 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -1481,7 +1481,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf,
u64 changes);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
index 6205d22765c7..c0ab2e6a29ad 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -665,7 +665,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);

int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue_idx,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
index 82cfc2aadc2b..d92f9eb07dc9 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
@@ -2799,7 +2799,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* IEEE80211 stack callback functions.
*/
static int rt61pci_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue_idx,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -2815,7 +2816,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw,
* we are free to update the registers based on the value
* in the queue parameter.
*/
- retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
+ retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params);
if (retval)
return retval;

diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
index 5ff2c740c3ea..e3269fd7c59e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
@@ -2218,7 +2218,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
* IEEE80211 stack callback functions.
*/
static int rt73usb_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue_idx,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -2234,7 +2235,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw,
* we are free to update the registers based on the value
* in the queue parameter.
*/
- retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
+ retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params);
if (retval)
return retval;

diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
index f66cc9083972..cdfe08078c57 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
@@ -1424,7 +1424,8 @@ static void rtl8187se_conf_ac_parm(struct ieee80211_hw *dev, u8 queue)
}

static int rtl8180_conf_tx(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rtl8180_priv *priv = dev->priv;
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index edc84f9dc984..c0f6e9c6d03e 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1338,7 +1338,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
}

static int rtl8187_conf_tx(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rtl8187_priv *priv = dev->priv;
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 65c4cb1e030c..33a1d9143038 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -5957,7 +5957,8 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
}

static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
struct rtl8xxxu_priv *priv = hw->priv;
diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c
index 8537cc6d7a89..519b2643f9f4 100644
--- a/drivers/net/wireless/realtek/rtlwifi/core.c
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -982,7 +982,8 @@ static int _rtl_get_hal_qnum(u16 queue)
*for rtl819x BE = 0, BK = 1, VI = 2, VO = 3
*/
static int rtl_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index ba60ca7ecdbf..bb7291665d37 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -443,7 +443,8 @@ static int rtw_ops_start_ap(struct ieee80211_hw *hw,
}

static int rtw_ops_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 ac,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct rtw_dev *rtwdev = hw->priv;
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 20fb4c550010..f40569c8575c 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -427,7 +427,8 @@ static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
}

static int rtw89_ops_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 ac,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct rtw89_dev *rtwdev = hw->priv;
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 1dff3d263382..bf39c4bda26f 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -895,7 +895,8 @@ static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw,
* Return: 0 on success, negative error code on failure.
*/
static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rsi_hw *adapter = hw->priv;
diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
index 47fd887ce6fe..89402afe4fe6 100644
--- a/drivers/net/wireless/silabs/wfx/sta.c
+++ b/drivers/net/wireless/silabs/wfx/sta.c
@@ -216,7 +216,8 @@ int wfx_update_pm(struct wfx_vif *wvif)
}

int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct wfx_dev *wdev = hw->priv;
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h
index 93ea992de1d7..6558c5698cc8 100644
--- a/drivers/net/wireless/silabs/wfx/sta.h
+++ b/drivers/net/wireless/silabs/wfx/sta.h
@@ -36,7 +36,8 @@ void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u64 changed);
int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
index a3f6942df0c1..26d3614519b1 100644
--- a/drivers/net/wireless/st/cw1200/sta.c
+++ b/drivers/net/wireless/st/cw1200/sta.c
@@ -606,7 +606,8 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
}

int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct cw1200_common *priv = dev->priv;
int ret = 0;
diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h
index 05e3ab7ccef1..a49f187c7049 100644
--- a/drivers/net/wireless/st/cw1200/sta.h
+++ b/drivers/net/wireless/st/cw1200/sta.h
@@ -28,7 +28,8 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
unsigned int *total_flags,
u64 multicast);
int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
int cw1200_get_stats(struct ieee80211_hw *dev,
struct ieee80211_low_level_stats *stats);
int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index d76558964420..9144ef5538a8 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1282,7 +1282,8 @@ static struct ieee80211_channel wl1251_channels[] = {
};

static int wl1251_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
enum wl1251_acx_ps_scheme ps_scheme;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index d1200080f165..1edec9f3c0d8 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4864,7 +4864,8 @@ wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw,
}

static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct wl1271 *wl = hw->priv;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 210b49c6cd50..c4ed5afba380 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4174,7 +4174,8 @@ struct ieee80211_ops {
struct ieee80211_sta *sta,
struct station_info *sinfo);
int (*conf_tx)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 ac,
+ struct ieee80211_vif *vif,
+ unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params);
u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a4e511766008..8a37f1402328 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2570,6 +2570,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_link_data *link = &sdata->deflink;
struct ieee80211_tx_queue_params p;

if (!local->ops->conf_tx)
@@ -2592,15 +2593,15 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,

ieee80211_regulatory_limit_wmm_params(sdata, &p, params->ac);

- sdata->tx_conf[params->ac] = p;
- if (drv_conf_tx(local, sdata, params->ac, &p)) {
+ link->tx_conf[params->ac] = p;
+ if (drv_conf_tx(local, link, params->ac, &p)) {
wiphy_debug(local->hw.wiphy,
"failed to set TX queue parameters for AC %d\n",
params->ac);
return -EINVAL;
}

- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_QOS);

return 0;
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index 48322e45e7dd..9b61dc7889c2 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2015 Intel Deutschland GmbH
+ * Copyright (C) 2022 Intel Corporation
*/
#include <net/mac80211.h>
#include "ieee80211_i.h"
@@ -180,9 +181,10 @@ void drv_sta_rc_update(struct ieee80211_local *local,
}

int drv_conf_tx(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata, u16 ac,
+ struct ieee80211_link_data *link, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
int ret = -EOPNOTSUPP;

might_sleep();
@@ -201,10 +203,10 @@ int drv_conf_tx(struct ieee80211_local *local,
return -EINVAL;
}

- trace_drv_conf_tx(local, sdata, ac, params);
+ trace_drv_conf_tx(local, sdata, link->link_id, ac, params);
if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, &sdata->vif,
- ac, params);
+ link->link_id, ac, params);
trace_drv_return_int(local, ret);
return ret;
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index ee3ac1a01bb0..eb16a354338c 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -590,7 +590,7 @@ static inline void drv_sta_statistics(struct ieee80211_local *local,
}

int drv_conf_tx(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata, u16 ac,
+ struct ieee80211_link_data *link, u16 ac,
const struct ieee80211_tx_queue_params *params);

u64 drv_get_tsf(struct ieee80211_local *local,
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 561abcf4def9..0a1d51c60530 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -356,7 +356,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;

- ieee80211_set_wmm_default(sdata, true, false);
+ ieee80211_set_wmm_default(&sdata->deflink, true, false);

sdata->vif.cfg.ibss_joined = true;
sdata->vif.cfg.ibss_creator = creator;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 05996df627ea..699dabaa9f0d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -969,6 +969,8 @@ struct ieee80211_link_data {
struct ieee80211_link_data_ap ap;
} u;

+ struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
+
struct ieee80211_bss_conf *conf;
};

@@ -1012,7 +1014,6 @@ struct ieee80211_sub_if_data {
bool control_port_over_nl80211;

atomic_t num_tx_queued;
- struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
struct mac80211_qos_map __rcu *qos_map;

/* used to reconfigure hardware SM PS */
@@ -2101,7 +2102,7 @@ int ieee80211_frame_duration(enum nl80211_band band, size_t len,
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_queue_params *qparam,
int ac);
-void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
+void ieee80211_set_wmm_default(struct ieee80211_link_data *link,
bool bss_notify, bool enable_qos);
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 28fe0735b9a8..4b4a36692c68 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1537,7 +1537,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
* doesn't start up with sane defaults.
* Enable QoS for anything but station interfaces.
*/
- ieee80211_set_wmm_default(sdata, true,
+ ieee80211_set_wmm_default(&sdata->deflink, true,
sdata->vif.type != NL80211_IFTYPE_STATION);
}

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7b9211d16193..0992a3ff3a98 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2017,10 +2017,11 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
switch (tx_tspec->action) {
case TX_TSPEC_ACTION_STOP_DOWNGRADE:
/* take the original parameters */
- if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac]))
- sdata_err(sdata,
- "failed to set TX queue parameters for queue %d\n",
- ac);
+ if (drv_conf_tx(local, &sdata->deflink, ac,
+ &sdata->deflink.tx_conf[ac]))
+ link_err(&sdata->deflink,
+ "failed to set TX queue parameters for queue %d\n",
+ ac);
tx_tspec->action = TX_TSPEC_ACTION_NONE;
tx_tspec->downgraded = false;
ret = true;
@@ -2046,11 +2047,11 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
*/
if (non_acm_ac >= IEEE80211_NUM_ACS)
non_acm_ac = IEEE80211_AC_BK;
- if (drv_conf_tx(local, sdata, ac,
- &sdata->tx_conf[non_acm_ac]))
- sdata_err(sdata,
- "failed to set TX queue parameters for queue %d\n",
- ac);
+ if (drv_conf_tx(local, &sdata->deflink, ac,
+ &sdata->deflink.tx_conf[non_acm_ac]))
+ link_err(&sdata->deflink,
+ "failed to set TX queue parameters for queue %d\n",
+ ac);
tx_tspec->action = TX_TSPEC_ACTION_NONE;
ret = true;
schedule_delayed_work(&ifmgd->tx_tspec_wk,
@@ -2084,10 +2085,11 @@ static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
/* MLME */
static bool
ieee80211_sta_wmm_params(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link,
const u8 *wmm_param, size_t wmm_param_len,
const struct ieee80211_mu_edca_param_set *mu_edca)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS];
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
size_t left;
@@ -2116,11 +2118,11 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local,
* the driver about it.
*/
mu_edca_count = mu_edca ? mu_edca->mu_qos_info & 0x0f : -1;
- if (count == sdata->deflink.u.mgd.wmm_last_param_set &&
- mu_edca_count == sdata->deflink.u.mgd.mu_edca_last_param_set)
+ if (count == link->u.mgd.wmm_last_param_set &&
+ mu_edca_count == link->u.mgd.mu_edca_last_param_set)
return false;
- sdata->deflink.u.mgd.wmm_last_param_set = count;
- sdata->deflink.u.mgd.mu_edca_last_param_set = mu_edca_count;
+ link->u.mgd.wmm_last_param_set = count;
+ link->u.mgd.mu_edca_last_param_set = mu_edca_count;

pos = wmm_param + 8;
left = wmm_param_len - 8;
@@ -2218,16 +2220,16 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local,
params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
params[ac].txop, params[ac].uapsd,
ifmgd->tx_tspec[ac].downgraded);
- sdata->tx_conf[ac] = params[ac];
+ link->tx_conf[ac] = params[ac];
if (!ifmgd->tx_tspec[ac].downgraded &&
- drv_conf_tx(local, sdata, ac, &params[ac]))
- sdata_err(sdata,
- "failed to set TX queue parameters for AC %d\n",
- ac);
+ drv_conf_tx(local, link, ac, &params[ac]))
+ link_err(link,
+ "failed to set TX queue parameters for AC %d\n",
+ ac);
}

/* enable WMM or activate new settings */
- sdata->vif.bss_conf.qos = true;
+ link->conf->qos = true;
return true;
}

@@ -2507,7 +2509,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, changed);

/* disassociated - set to defaults now */
- ieee80211_set_wmm_default(sdata, false, false);
+ ieee80211_set_wmm_default(&sdata->deflink, false, false);

del_timer_sync(&sdata->u.mgd.conn_mon_timer);
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
@@ -3765,12 +3767,13 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
sdata->deflink.u.mgd.mu_edca_last_param_set = -1;

if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
- ieee80211_set_wmm_default(sdata, false, false);
- } else if (!ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
+ ieee80211_set_wmm_default(&sdata->deflink, false, false);
+ } else if (!ieee80211_sta_wmm_params(local, &sdata->deflink,
+ elems->wmm_param,
elems->wmm_param_len,
elems->mu_edca_param_set)) {
/* still enable QoS since we might have HT/VHT */
- ieee80211_set_wmm_default(sdata, false, true);
+ ieee80211_set_wmm_default(&sdata->deflink, false, true);
/* set the disable-WMM flag in this case to disable
* tracking WMM parameter changes in the beacon if
* the parameters weren't actually valid. Doing so
@@ -3937,7 +3940,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
/* get uapsd queues configuration */
uapsd_queues = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- if (sdata->tx_conf[ac].uapsd)
+ if (sdata->deflink.tx_conf[ac].uapsd)
uapsd_queues |= ieee80211_ac_to_qos_mask[ac];

info.success = 1;
@@ -4362,7 +4365,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
elems, true);

if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
- ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
+ ieee80211_sta_wmm_params(local, &sdata->deflink, elems->wmm_param,
elems->wmm_param_len,
elems->mu_edca_param_set))
changed |= BSS_CHANGED_QOS;
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 30f2b340017c..e7bdcdb488e2 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -293,7 +293,7 @@ static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata,
* doesn't support it, as mandated by 802.11-2012 section 10.22.4
*/
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- txq = &sdata->tx_conf[ieee80211_ac_from_wmm(i)];
+ txq = &sdata->deflink.tx_conf[ieee80211_ac_from_wmm(i)];
wmm->ac[i].aci_aifsn = ieee80211_wmm_aci_aifsn(txq->aifs,
txq->acm, i);
wmm->ac[i].cw = ieee80211_wmm_ecw(txq->cw_min, txq->cw_max);
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 751f08b47d0c..b6f12ac91849 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1003,13 +1003,15 @@ DEFINE_EVENT(sta_event, drv_sta_rate_tbl_update,
TRACE_EVENT(drv_conf_tx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
+ unsigned int link_id,
u16 ac, const struct ieee80211_tx_queue_params *params),

- TP_ARGS(local, sdata, ac, params),
+ TP_ARGS(local, sdata, link_id, ac, params),

TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
+ __field(unsigned int, link_id)
__field(u16, ac)
__field(u16, txop)
__field(u16, cw_min)
@@ -1021,6 +1023,7 @@ TRACE_EVENT(drv_conf_tx,
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
+ __entry->link_id = link_id;
__entry->ac = ac;
__entry->txop = params->txop;
__entry->cw_max = params->cw_max;
@@ -1030,8 +1033,8 @@ TRACE_EVENT(drv_conf_tx,
),

TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " AC:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac
+ LOCAL_PR_FMT VIF_PR_FMT " link_id: %d, AC:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, __entry->ac
)
);

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 275310b6fc38..85d08cbe0b51 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1593,9 +1593,10 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
}

-void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
+void ieee80211_set_wmm_default(struct ieee80211_link_data *link,
bool bss_notify, bool enable_qos)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -1613,7 +1614,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
memset(&qparam, 0, sizeof(qparam));

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
use_11b = (chanctx_conf &&
chanctx_conf->def.chan->band == NL80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
@@ -1690,17 +1691,16 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,

qparam.uapsd = false;

- sdata->tx_conf[ac] = qparam;
- drv_conf_tx(local, sdata, ac, &qparam);
+ link->tx_conf[ac] = qparam;
+ drv_conf_tx(local, link, ac, &qparam);
}

if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
sdata->vif.type != NL80211_IFTYPE_NAN) {
- sdata->vif.bss_conf.qos = enable_qos;
+ link->conf->qos = enable_qos;
if (bss_notify)
- ieee80211_link_info_change_notify(sdata,
- &sdata->deflink,
+ ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_QOS);
}
}
@@ -2517,8 +2517,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
fallthrough;
case NL80211_IFTYPE_AP: /* AP stations are handled later */
for (i = 0; i < IEEE80211_NUM_ACS; i++)
- drv_conf_tx(local, sdata, i,
- &sdata->tx_conf[i]);
+ drv_conf_tx(local, &sdata->deflink, i,
+ &sdata->deflink.tx_conf[i]);
break;
}

--
2.36.1

2022-07-13 09:48:32

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 38/76] wifi: cfg80211: remove BSS pointer from cfg80211_disassoc_request

From: Johannes Berg <[email protected]>

The race described by the comment in mac80211 hasn't existed
since the locking rework to use the same lock and for MLO we
need to pass the AP MLD address, so just pass the BSSID or
AP MLD address instead of the BSS struct pointer, and adjust
all the code accordingly.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 6 +++---
net/mac80211/mlme.c | 14 +++++---------
net/wireless/core.h | 2 +-
net/wireless/mlme.c | 8 +++-----
net/wireless/trace.h | 5 +----
5 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e50b93160319..cc20f0036e75 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2886,7 +2886,7 @@ struct cfg80211_assoc_request {
* This structure provides information needed to complete IEEE 802.11
* deauthentication.
*
- * @bssid: the BSSID of the BSS to deauthenticate from
+ * @bssid: the BSSID or AP MLD address to deauthenticate from
* @ie: Extra IEs to add to Deauthentication frame or %NULL
* @ie_len: Length of ie buffer in octets
* @reason_code: The reason code for the deauthentication
@@ -2907,7 +2907,7 @@ struct cfg80211_deauth_request {
* This structure provides information needed to complete IEEE 802.11
* disassociation.
*
- * @bss: the BSS to disassociate from
+ * @ap_addr: the BSSID or AP MLD address to disassociate from
* @ie: Extra IEs to add to Disassociation frame or %NULL
* @ie_len: Length of ie buffer in octets
* @reason_code: The reason code for the disassociation
@@ -2915,7 +2915,7 @@ struct cfg80211_deauth_request {
* Disassociation frame is to be transmitted.
*/
struct cfg80211_disassoc_request {
- struct cfg80211_bss *bss;
+ const u8 *ap_addr;
const u8 *ie;
size_t ie_len;
u16 reason_code;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7870e3e23e26..0c432e3abd90 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6425,18 +6425,14 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
{
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];

- /*
- * cfg80211 should catch this ... but it's racy since
- * we can receive a disassoc frame, process it, hand it
- * to cfg80211 while that's in a locked section already
- * trying to tell us that the user wants to disconnect.
- */
- if (sdata->deflink.u.mgd.bss != req->bss)
- return -ENOLINK;
+ if (!sdata->u.mgd.associated ||
+ memcmp(sdata->vif.cfg.ap_addr, req->ap_addr, ETH_ALEN))
+ return -ENOTCONN;

sdata_info(sdata,
"disassociating from %pM by local choice (Reason: %u=%s)\n",
- req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));
+ req->ap_addr, req->reason_code,
+ ieee80211_get_reason_code_string(req->reason_code));

ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
req->reason_code, !req->local_state_change,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index fd723fa5e2d7..e72ca6eefafb 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -372,7 +372,7 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
const u8 *ie, int ie_len, u16 reason,
bool local_state_change);
int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *bssid,
+ struct net_device *dev, const u8 *ap_addr,
const u8 *ie, int ie_len, u16 reason,
bool local_state_change);
void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 935537c64ed8..4a35b3559daa 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -370,7 +370,7 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
}

int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *bssid,
+ struct net_device *dev, const u8 *ap_addr,
const u8 *ie, int ie_len, u16 reason,
bool local_state_change)
{
@@ -380,6 +380,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
.local_state_change = local_state_change,
.ie = ie,
.ie_len = ie_len,
+ .ap_addr = ap_addr,
};
int err;

@@ -388,10 +389,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
if (!wdev->connected)
return -ENOTCONN;

- if (ether_addr_equal(wdev->links[0].client.current_bss->pub.bssid,
- bssid))
- req.bss = &wdev->links[0].client.current_bss->pub;
- else
+ if (memcmp(wdev->u.client.connected_addr, ap_addr, ETH_ALEN))
return -ENOTCONN;

err = rdev_disassoc(rdev, dev, &req);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index c50e8a04199e..4316d3dc31ea 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1318,10 +1318,7 @@ TRACE_EVENT(rdev_disassoc,
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
- if (req->bss)
- MAC_ASSIGN(bssid, req->bss->bssid);
- else
- eth_zero_addr(__entry->bssid);
+ MAC_ASSIGN(bssid, req->ap_addr);
__entry->reason_code = req->reason_code;
__entry->local_state_change = req->local_state_change;
),
--
2.36.1

2022-07-13 09:48:32

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 22/76] wifi: mac80211: fix key lookup

From: Johannes Berg <[email protected]>

With the split into keys[]/deflink.gtk[] arrays, WEP keys are
still installed into the keys[] array, but we didn't look them
up there. This meant they weren't deleted correctly.

Fix this by looking up the key there even if it's not pairwise
so we can be sure we don't have it.

Fixes: bfd8403adddd ("wifi: mac80211: reorg some iface data structs for MLD")
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/cfg.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 058163b97c9a..a4e511766008 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -570,6 +570,10 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata,
if (key)
return key;

+ /* or maybe it was a WEP key */
+ if (key_idx < NUM_DEFAULT_KEYS)
+ return rcu_dereference_check_key_mtx(local, sdata->keys[key_idx]);
+
return NULL;
}

--
2.36.1

2022-07-13 09:48:32

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 44/76] wifi: mac80211: refactor elements parsing with parameter struct

From: Johannes Berg <[email protected]>

Refactor the element parsing into a version that has
a parameter struct so we can add more parameters more
easily in the future.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 50 ++++++++++++++++++++++++++++----
net/mac80211/util.c | 58 +++++++++++++++++++-------------------
2 files changed, 74 insertions(+), 34 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a0743c78d171..2cf13ea4c9f7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2138,11 +2138,51 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb_tid(sdata, skb, 7);
}

-struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
- bool action,
- u64 filter, u32 crc,
- const u8 *transmitter_bssid,
- const u8 *bss_bssid);
+/**
+ * struct ieee80211_elems_parse_params - element parsing parameters
+ * @start: pointer to the elements
+ * @len: length of the elements
+ * @action: %true if the elements came from an action frame
+ * @filter: bitmap of element IDs to filter out while calculating
+ * the element CRC
+ * @crc: CRC starting value
+ * @transmitter_bssid: transmitter BSSID to parse the multi-BSSID
+ * element
+ * @bss_bssid: BSSID of the BSS we want to obtain elements for
+ * when parsing the multi-BSSID element
+ */
+struct ieee80211_elems_parse_params {
+ const u8 *start;
+ size_t len;
+ bool action;
+ u64 filter;
+ u32 crc;
+ const u8 *transmitter_bssid;
+ const u8 *bss_bssid;
+};
+
+struct ieee802_11_elems *
+ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params);
+
+static inline struct ieee802_11_elems *
+ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ u64 filter, u32 crc,
+ const u8 *transmitter_bssid,
+ const u8 *bss_bssid)
+{
+ struct ieee80211_elems_parse_params params = {
+ .start = start,
+ .len = len,
+ .action = action,
+ .filter = filter,
+ .crc = crc,
+ .transmitter_bssid = transmitter_bssid,
+ .bss_bssid = bss_bssid,
+ };
+
+ return ieee802_11_parse_elems_full(&params);
+}
+
static inline struct ieee802_11_elems *
ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
const u8 *transmitter_bssid,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 85d08cbe0b51..78fb0c3aa4ad 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1023,19 +1023,19 @@ static void ieee80211_parse_extension_element(u32 *crc,
}

static u32
-_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
- struct ieee802_11_elems *elems,
- u64 filter, u32 crc,
- const struct element *check_inherit)
+_ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
+ struct ieee802_11_elems *elems,
+ const struct element *check_inherit)
{
const struct element *elem;
- bool calc_crc = filter != 0;
+ bool calc_crc = params->filter != 0;
DECLARE_BITMAP(seen_elems, 256);
+ u32 crc = params->crc;
const u8 *ie;

bitmap_zero(seen_elems, 256);

- for_each_element(elem, start, len) {
+ for_each_element(elem, params->start, params->len) {
bool elem_parse_failed;
u8 id = elem->id;
u8 elen = elem->datalen;
@@ -1098,7 +1098,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
break;
}

- if (calc_crc && id < 64 && (filter & (1ULL << id)))
+ if (calc_crc && id < 64 && (params->filter & (1ULL << id)))
crc = crc32_be(crc, pos - 2, elen + 2);

elem_parse_failed = false;
@@ -1279,7 +1279,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
elems->mesh_chansw_params_ie = (void *)pos;
break;
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
- if (!action ||
+ if (!params->action ||
elen < sizeof(*elems->wide_bw_chansw_ie)) {
elem_parse_failed = true;
break;
@@ -1287,7 +1287,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
elems->wide_bw_chansw_ie = (void *)pos;
break;
case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
- if (action) {
+ if (params->action) {
elem_parse_failed = true;
break;
}
@@ -1414,7 +1414,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
__set_bit(id, seen_elems);
}

- if (!for_each_element_completed(elem, start, len))
+ if (!for_each_element_completed(elem, params->start, params->len))
elems->parse_error = true;

return crc;
@@ -1488,11 +1488,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
return found ? profile_len : 0;
}

-struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
- bool action, u64 filter,
- u32 crc,
- const u8 *transmitter_bssid,
- const u8 *bss_bssid)
+struct ieee802_11_elems *
+ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
{
struct ieee802_11_elems *elems;
const struct element *non_inherit = NULL;
@@ -1502,15 +1499,16 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
if (!elems)
return NULL;
- elems->ie_start = start;
- elems->total_len = len;
+ elems->ie_start = params->start;
+ elems->total_len = params->len;

- nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
+ nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC);
if (nontransmitted_profile) {
nontransmitted_profile_len =
- ieee802_11_find_bssid_profile(start, len, elems,
- transmitter_bssid,
- bss_bssid,
+ ieee802_11_find_bssid_profile(params->start, params->len,
+ elems,
+ params->transmitter_bssid,
+ params->bss_bssid,
nontransmitted_profile);
non_inherit =
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
@@ -1518,14 +1516,18 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
nontransmitted_profile_len);
}

- crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
- crc, non_inherit);
+ elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit);

/* Override with nontransmitted profile, if found */
- if (nontransmitted_profile_len)
- _ieee802_11_parse_elems_crc(nontransmitted_profile,
- nontransmitted_profile_len,
- action, elems, 0, 0, NULL);
+ if (nontransmitted_profile_len) {
+ struct ieee80211_elems_parse_params sub = {
+ .start = nontransmitted_profile,
+ .len = nontransmitted_profile_len,
+ .action = params->action,
+ };
+
+ _ieee802_11_parse_elems_full(&sub, elems, NULL);
+ }

if (elems->tim && !elems->parse_error) {
const struct ieee80211_tim_ie *tim_ie = elems->tim;
@@ -1547,8 +1549,6 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,

kfree(nontransmitted_profile);

- elems->crc = crc;
-
return elems;
}

--
2.36.1

2022-07-13 09:48:33

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 42/76] wifi: cfg80211: put cfg80211_rx_assoc_resp() arguments into a struct

From: Johannes Berg <[email protected]>

For MLO we'll need a lot more arguments, including all the
BSS pointers and link addresses, so move the data to a struct
to be able to extend it more easily later.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 24 +++++++++++++++++-------
net/mac80211/mlme.c | 17 ++++++++++++-----
net/wireless/mlme.c | 32 +++++++++++++++-----------------
net/wireless/nl80211.c | 12 ++++++------
net/wireless/nl80211.h | 4 +---
5 files changed, 51 insertions(+), 38 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e24233b6d4bb..1a0bdff1569c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6877,16 +6877,29 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);

/**
- * cfg80211_rx_assoc_resp - notification of processed association response
- * @dev: network device
+ * struct cfg80211_rx_assoc_resp - association response data
* @bss: the BSS that association was requested with, ownership of the pointer
- * moves to cfg80211 in this call
+ * moves to cfg80211 in the call to cfg80211_rx_assoc_resp()
* @buf: (Re)Association Response frame (header + body)
* @len: length of the frame data
* @uapsd_queues: bitmap of queues configured for uapsd. Same format
* as the AC bitmap in the QoS info field
* @req_ies: information elements from the (Re)Association Request frame
* @req_ies_len: length of req_ies data
+ */
+struct cfg80211_rx_assoc_resp {
+ struct cfg80211_bss *bss;
+ const u8 *buf;
+ size_t len;
+ const u8 *req_ies;
+ size_t req_ies_len;
+ int uapsd_queues;
+};
+
+/**
+ * cfg80211_rx_assoc_resp - notification of processed association response
+ * @dev: network device
+ * @data: association response data, &struct cfg80211_rx_assoc_resp
*
* After being asked to associate via cfg80211_ops::assoc() the driver must
* call either this function or cfg80211_auth_timeout().
@@ -6894,10 +6907,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
* This function may sleep. The caller must hold the corresponding wdev's mutex.
*/
void cfg80211_rx_assoc_resp(struct net_device *dev,
- struct cfg80211_bss *bss,
- const u8 *buf, size_t len,
- int uapsd_queues,
- const u8 *req_ies, size_t req_ies_len);
+ struct cfg80211_rx_assoc_resp *data);

/**
* struct cfg80211_assoc_failure - association failure data
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index feb5929b37e7..a47836730493 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3877,7 +3877,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
u16 capab_info, status_code, aid;
struct ieee802_11_elems *elems;
- int ac, uapsd_queues = -1;
+ int ac;
u8 *pos;
bool reassoc;
struct cfg80211_bss *cbss;
@@ -3886,6 +3886,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
.u.mlme.data = ASSOC_EVENT,
};
struct ieee80211_prep_tx_info info = {};
+ struct cfg80211_rx_assoc_resp resp = {
+ .uapsd_queues = -1,
+ };

sdata_assert_lock(sdata);

@@ -3983,16 +3986,20 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_assoc_data(sdata, ASSOC_SUCCESS);

/* get uapsd queues configuration */
- uapsd_queues = 0;
+ resp.uapsd_queues = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
if (sdata->deflink.tx_conf[ac].uapsd)
- uapsd_queues |= ieee80211_ac_to_qos_mask[ac];
+ resp.uapsd_queues |= ieee80211_ac_to_qos_mask[ac];

info.success = 1;
}

- cfg80211_rx_assoc_resp(sdata->dev, cbss, (u8 *)mgmt, len, uapsd_queues,
- ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
+ resp.bss = cbss;
+ resp.buf = (u8 *)mgmt;
+ resp.len = len;
+ resp.req_ies = ifmgd->assoc_req_ies;
+ resp.req_ies_len = ifmgd->assoc_req_ies_len;
+ cfg80211_rx_assoc_resp(sdata->dev, &resp);
notify_driver:
drv_mgd_complete_tx(sdata->local, sdata, &info);
kfree(elems);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index aefe8b26f0d7..a6ad696f131b 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -21,36 +21,35 @@
#include "rdev-ops.h"


-void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
- const u8 *buf, size_t len, int uapsd_queues,
- const u8 *req_ies, size_t req_ies_len)
+void cfg80211_rx_assoc_resp(struct net_device *dev,
+ struct cfg80211_rx_assoc_resp *data)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
- struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)data->buf;
struct cfg80211_connect_resp_params cr;
const u8 *resp_ie = mgmt->u.assoc_resp.variable;
- size_t resp_ie_len = len - offsetof(struct ieee80211_mgmt,
- u.assoc_resp.variable);
+ size_t resp_ie_len = data->len - offsetof(struct ieee80211_mgmt,
+ u.assoc_resp.variable);

- if (bss->channel->band == NL80211_BAND_S1GHZ) {
+ if (data->bss->channel->band == NL80211_BAND_S1GHZ) {
resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
- resp_ie_len = len - offsetof(struct ieee80211_mgmt,
- u.s1g_assoc_resp.variable);
+ resp_ie_len = data->len - offsetof(struct ieee80211_mgmt,
+ u.s1g_assoc_resp.variable);
}

memset(&cr, 0, sizeof(cr));
cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
cr.links[0].bssid = mgmt->bssid;
- cr.links[0].bss = bss;
- cr.req_ie = req_ies;
- cr.req_ie_len = req_ies_len;
+ cr.links[0].bss = data->bss;
+ cr.req_ie = data->req_ies;
+ cr.req_ie_len = data->req_ies_len;
cr.resp_ie = resp_ie;
cr.resp_ie_len = resp_ie_len;
cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;

- trace_cfg80211_send_rx_assoc(dev, bss);
+ trace_cfg80211_send_rx_assoc(dev, data->bss);

/*
* This is a bit of a hack, we don't notify userspace of
@@ -59,13 +58,12 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
* frame instead of reassoc.
*/
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
- cfg80211_unhold_bss(bss_from_pub(bss));
- cfg80211_put_bss(wiphy, bss);
+ cfg80211_unhold_bss(bss_from_pub(data->bss));
+ cfg80211_put_bss(wiphy, data->bss);
return;
}

- nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues,
- req_ies, req_ies_len);
+ nl80211_send_rx_assoc(rdev, dev, data);
/* update current_bss etc., consumes the bss reference */
__cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6c3b47a7960f..11cad2d46d0e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -17432,13 +17432,13 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
}

void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp, int uapsd_queues,
- const u8 *req_ies, size_t req_ies_len)
+ struct net_device *netdev,
+ struct cfg80211_rx_assoc_resp *data)
{
- nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
- req_ies, req_ies_len, false);
+ nl80211_send_mlme_event(rdev, netdev, data->buf, data->len,
+ NL80211_CMD_ASSOCIATE, GFP_KERNEL,
+ data->uapsd_queues,
+ data->req_ies, data->req_ies_len, false);
}

void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index d642e3be4ee7..a7e8e0917c1c 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -60,9 +60,7 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
const u8 *buf, size_t len, gfp_t gfp);
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
- const u8 *buf, size_t len, gfp_t gfp,
- int uapsd_queues,
- const u8 *req_ies, size_t req_ies_len);
+ struct cfg80211_rx_assoc_resp *data);
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len,
--
2.36.1

2022-07-13 09:48:33

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 45/76] wifi: mac80211: replace link_id with link_conf in start/stop_ap()

From: Gregory Greenman <[email protected]>

When calling start/stop_ap(), mac80211 already has a protected
link_conf pointer. Pass it to the driver, so it shouldn't
handle RCU protection.

Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 ++++++-------
drivers/net/wireless/realtek/rtw88/mac80211.c | 3 ++-
drivers/net/wireless/realtek/rtw89/mac80211.c | 5 ++--
drivers/net/wireless/silabs/wfx/sta.c | 4 ++--
drivers/net/wireless/silabs/wfx/sta.h | 4 ++--
include/net/mac80211.h | 4 ++--
net/mac80211/cfg.c | 4 ++--
net/mac80211/driver-ops.h | 18 ++++++++++-----
net/mac80211/trace.h | 23 ++++++++-----------
net/mac80211/util.c | 3 ++-
10 files changed, 44 insertions(+), 40 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 3de558f286a1..126106ea62d3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2397,7 +2397,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,

static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -2525,20 +2525,20 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,

static int iwl_mvm_start_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
- return iwl_mvm_start_ap_ibss(hw, vif, link_id);
+ return iwl_mvm_start_ap_ibss(hw, vif, link_conf);
}

static int iwl_mvm_start_ibss(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- return iwl_mvm_start_ap_ibss(hw, vif, 0);
+ return iwl_mvm_start_ap_ibss(hw, vif, &vif->bss_conf);
}

static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -2603,15 +2603,15 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,

static void iwl_mvm_stop_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
- iwl_mvm_stop_ap_ibss(hw, vif, link_id);
+ iwl_mvm_stop_ap_ibss(hw, vif, link_conf);
}

static void iwl_mvm_stop_ibss(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- iwl_mvm_stop_ap_ibss(hw, vif, 0);
+ iwl_mvm_stop_ap_ibss(hw, vif, &vif->bss_conf);
}

static void
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index bb7291665d37..c7b98a0599d5 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -430,7 +430,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
}

static int rtw_ops_start_ap(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, unsigned int link_id)
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip;
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index f40569c8575c..cef27e781ae2 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -382,7 +382,8 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
}

static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, unsigned int link_id)
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf)
{
struct rtw89_dev *rtwdev = hw->priv;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
@@ -403,7 +404,7 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,

static
void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
struct rtw89_dev *rtwdev = hw->priv;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
index 89402afe4fe6..920bd1a4a1b1 100644
--- a/drivers/net/wireless/silabs/wfx/sta.c
+++ b/drivers/net/wireless/silabs/wfx/sta.c
@@ -380,7 +380,7 @@ static void wfx_set_mfp_ap(struct wfx_vif *wvif)
}

int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
struct wfx_dev *wdev = wvif->wdev;
@@ -399,7 +399,7 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}

void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;

diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h
index 6558c5698cc8..bf2e76167a6f 100644
--- a/drivers/net/wireless/silabs/wfx/sta.h
+++ b/drivers/net/wireless/silabs/wfx/sta.h
@@ -30,9 +30,9 @@ void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id);
+ struct ieee80211_bss_conf *link_conf);
void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id);
+ struct ieee80211_bss_conf *link_conf);
int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 398da2336707..d080d7e38d0f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4092,9 +4092,9 @@ struct ieee80211_ops {
u64 changed);

int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id);
+ struct ieee80211_bss_conf *link_conf);
void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id);
+ struct ieee80211_bss_conf *link_conf);

u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8a37f1402328..873e1acc8c30 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1296,7 +1296,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
}

- err = drv_start_ap(sdata->local, sdata, link_id);
+ err = drv_start_ap(sdata->local, sdata, link_conf);
if (err) {
old = sdata_dereference(link->u.ap.beacon, sdata);

@@ -1457,7 +1457,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
GFP_KERNEL);
}

- drv_stop_ap(sdata->local, sdata, link_id);
+ drv_stop_ap(sdata->local, sdata, link_conf);

/* free all potentially still buffered bcast frames */
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index eb16a354338c..a04a88d122b7 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -987,32 +987,38 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local,

static inline int drv_start_ap(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
int ret = 0;

+ /* make sure link_conf is protected */
+ sdata_assert_lock(sdata);
+
might_sleep();

if (!check_sdata_in_driver(sdata))
return -EIO;

- trace_drv_start_ap(local, sdata, link_id);
+ trace_drv_start_ap(local, sdata, link_conf);
if (local->ops->start_ap)
- ret = local->ops->start_ap(&local->hw, &sdata->vif, link_id);
+ ret = local->ops->start_ap(&local->hw, &sdata->vif, link_conf);
trace_drv_return_int(local, ret);
return ret;
}

static inline void drv_stop_ap(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ struct ieee80211_bss_conf *link_conf)
{
+ /* make sure link_conf is protected */
+ sdata_assert_lock(sdata);
+
if (!check_sdata_in_driver(sdata))
return;

- trace_drv_stop_ap(local, sdata, link_id);
+ trace_drv_stop_ap(local, sdata, link_conf);
if (local->ops->stop_ap)
- local->ops->stop_ap(&local->hw, &sdata->vif, link_id);
+ local->ops->stop_ap(&local->hw, &sdata->vif, link_conf);
trace_drv_return_void(local);
}

diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index b6f12ac91849..75e5c1376351 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1754,9 +1754,9 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
TRACE_EVENT(drv_start_ap,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id),
+ struct ieee80211_bss_conf *link_conf),

- TP_ARGS(local, sdata, link_id),
+ TP_ARGS(local, sdata, link_conf),

TP_STRUCT__entry(
LOCAL_ENTRY
@@ -1769,17 +1769,12 @@ TRACE_EVENT(drv_start_ap,
),

TP_fast_assign(
- struct ieee80211_bss_conf *info =
- sdata_dereference(sdata->vif.link_conf[link_id], sdata);
-
LOCAL_ASSIGN;
VIF_ASSIGN;
- __entry->link_id = link_id;
- if (info) {
- __entry->dtimper = info->dtim_period;
- __entry->bcnint = info->beacon_int;
- __entry->hidden_ssid = info->hidden_ssid;
- }
+ __entry->link_id = link_conf->link_id;
+ __entry->dtimper = link_conf->dtim_period;
+ __entry->bcnint = link_conf->beacon_int;
+ __entry->hidden_ssid = link_conf->hidden_ssid;
memcpy(__get_dynamic_array(ssid),
sdata->vif.cfg.ssid,
sdata->vif.cfg.ssid_len);
@@ -1794,9 +1789,9 @@ TRACE_EVENT(drv_start_ap,
TRACE_EVENT(drv_stop_ap,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int link_id),
+ struct ieee80211_bss_conf *link_conf),

- TP_ARGS(local, sdata, link_id),
+ TP_ARGS(local, sdata, link_conf),

TP_STRUCT__entry(
LOCAL_ENTRY
@@ -1807,7 +1802,7 @@ TRACE_EVENT(drv_stop_ap,
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
- __entry->link_id = link_id;
+ __entry->link_id = link_conf->link_id;
),

TP_printk(
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 78fb0c3aa4ad..f7c127a434b8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2576,7 +2576,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
changed |= BSS_CHANGED_AP_PROBE_RESP;

if (rcu_access_pointer(sdata->deflink.u.ap.beacon))
- drv_start_ap(local, sdata, 0);
+ drv_start_ap(local, sdata,
+ sdata->deflink.conf);
}
fallthrough;
case NL80211_IFTYPE_MESH_POINT:
--
2.36.1

2022-07-13 09:48:35

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 46/76] wifi: mac80211: don't re-parse elems in ieee80211_assoc_success()

From: Johannes Berg <[email protected]>

We're already passing the elems pointer, and have parsed
them from the same frame with exactly the same parameters,
so don't need to do that again.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1819a8161e12..aec77e81df99 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3469,27 +3469,17 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
struct ieee80211_link_data *link = &sdata->deflink;
u32 changed = 0;
- u8 *pos;
int err;
bool ret;

- /* AssocResp and ReassocResp have identical structure */
-
- pos = mgmt->u.assoc_resp.variable;
- aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
- if (is_s1g) {
- pos = (u8 *) mgmt->u.s1g_assoc_resp.variable;
- aid = 0; /* TODO */
- }
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
- elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
- mgmt->bssid, assoc_data->bss->bssid);
-
- if (!elems)
- return false;

if (elems->aid_resp)
aid = le16_to_cpu(elems->aid_resp->aid);
+ else if (is_s1g)
+ aid = 0; /* TODO */
+ else
+ aid = le16_to_cpu(mgmt->u.assoc_resp.aid);

/*
* The 5 MSB of the AID field are reserved
@@ -3864,7 +3854,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,

ret = true;
out:
- kfree(elems);
kfree(bss_ies);
return ret;
}
--
2.36.1

2022-07-13 09:48:37

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 48/76] wifi: mac80211: fix multi-BSSID element parsing

From: Johannes Berg <[email protected]>

When parsing a frame containing a multi-BSSID element, we
need to know both the transmitted and non-transmitted BSSID
so we can parse it correctly.

Unfortunately, in quite a number of cases, we got this wrong
and were passing the wrong BSSID or useless information:
* the mgmt->bssid from a frame is only the transmitted
BSSID if the frame is a beacon
* passing just one of the parameters as non-NULL isn't
useful and ignored

In those case where we need to parse for a specific BSS we
always have a BSS structure pointer, representing the BSS
we need, whether transmitted or not. Thus, pass that pointer
to the parsing function instead of the two BSSIDs.

Also fix two bugs:
* we need to re-parse all the elements for the other BSS
when iterating the non-transmitted BSSes in scan
* we need to parse for the correct BSS when setting up
the channel data in client code

Fixes: 78ac51f81532 ("mac80211: support multi-bssid")
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/agg-rx.c | 2 +-
net/mac80211/ibss.c | 5 ++---
net/mac80211/ieee80211_i.h | 22 ++++++++--------------
net/mac80211/mesh.c | 8 +++-----
net/mac80211/mesh_hwmp.c | 2 +-
net/mac80211/mesh_plink.c | 3 +--
net/mac80211/mlme.c | 17 +++++++----------
net/mac80211/scan.c | 12 ++++++++----
net/mac80211/tdls.c | 4 ++--
net/mac80211/util.c | 13 +++++--------
10 files changed, 38 insertions(+), 50 deletions(-)

diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index b7c50646063d..9414d3bbd65f 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -502,7 +502,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
u.action.u.addba_req.variable);
if (ies_len) {
elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
- ies_len, true, mgmt->bssid, NULL);
+ ies_len, true, NULL);
if (!elems || elems->parse_error)
goto free;
}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 0a1d51c60530..e8df4ce33984 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1601,8 +1601,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
return;

elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
- len - baselen, false,
- mgmt->bssid, NULL);
+ len - baselen, false, NULL);

if (elems) {
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
@@ -1655,7 +1654,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,

elems = ieee802_11_parse_elems(
mgmt->u.action.u.chan_switch.variable,
- ies_len, true, mgmt->bssid, NULL);
+ ies_len, true, NULL);

if (elems && !elems->parse_error)
ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a8211ced719e..dc38f57fcdc9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2147,10 +2147,9 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
* @filter: bitmap of element IDs to filter out while calculating
* the element CRC
* @crc: CRC starting value
- * @transmitter_bssid: transmitter BSSID to parse the multi-BSSID
- * element
- * @bss_bssid: BSSID of the BSS we want to obtain elements for
- * when parsing the multi-BSSID element
+ * @bss: the BSS to parse this as, for multi-BSSID cases this can
+ * represent a non-transmitting BSS in which case the data
+ * for that non-transmitting BSS is returned
*/
struct ieee80211_elems_parse_params {
const u8 *start;
@@ -2158,8 +2157,7 @@ struct ieee80211_elems_parse_params {
bool action;
u64 filter;
u32 crc;
- const u8 *transmitter_bssid;
- const u8 *bss_bssid;
+ struct cfg80211_bss *bss;
};

struct ieee802_11_elems *
@@ -2168,8 +2166,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params);
static inline struct ieee802_11_elems *
ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
u64 filter, u32 crc,
- const u8 *transmitter_bssid,
- const u8 *bss_bssid)
+ struct cfg80211_bss *bss)
{
struct ieee80211_elems_parse_params params = {
.start = start,
@@ -2177,8 +2174,7 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
.action = action,
.filter = filter,
.crc = crc,
- .transmitter_bssid = transmitter_bssid,
- .bss_bssid = bss_bssid,
+ .bss = bss,
};

return ieee802_11_parse_elems_full(&params);
@@ -2186,11 +2182,9 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,

static inline struct ieee802_11_elems *
ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
- const u8 *transmitter_bssid,
- const u8 *bss_bssid)
+ struct cfg80211_bss *bss)
{
- return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
- transmitter_bssid, bss_bssid);
+ return ieee802_11_parse_elems_crc(start, len, action, 0, 0, bss);
}


diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index b656cb647763..6991c4c479da 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1256,8 +1256,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;

- elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
- NULL);
+ elems = ieee802_11_parse_elems(pos, len - baselen, false, NULL);
if (!elems)
return;

@@ -1326,7 +1325,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,

elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
len - baselen,
- false, mgmt->bssid, NULL);
+ false, NULL);
if (!elems)
return;

@@ -1468,8 +1467,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
pos = mgmt->u.action.u.chan_switch.variable;
baselen = offsetof(struct ieee80211_mgmt,
u.action.u.chan_switch.variable);
- elems = ieee802_11_parse_elems(pos, len - baselen, true,
- mgmt->bssid, NULL);
+ elems = ieee802_11_parse_elems(pos, len - baselen, true, NULL);
if (!elems)
return;

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 45e7c1b307bc..b8fe13777cbe 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -927,7 +927,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,

baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
- len - baselen, false, mgmt->bssid, NULL);
+ len - baselen, false, NULL);
if (!elems)
return;

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index d67011745048..84e3f43fd5c6 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -1229,8 +1229,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;
}
- elems = ieee802_11_parse_elems(baseaddr, len - baselen, true,
- mgmt->bssid, NULL);
+ elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, NULL);
mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
kfree(elems);
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 404edb975a2f..d4a54375b9d2 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3535,8 +3535,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}

bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
- false, mgmt->bssid,
- assoc_data->bss->bssid);
+ false, assoc_data->bss);
if (!bss_elems) {
ret = false;
goto out;
@@ -3926,7 +3925,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
return;

elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
- mgmt->bssid, assoc_data->bss->bssid);
+ assoc_data->bss);
if (!elems)
goto notify_driver;

@@ -4251,8 +4250,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) {
elems = ieee802_11_parse_elems(variable, len - baselen, false,
- bssid,
- ifmgd->assoc_data->bss->bssid);
+ ifmgd->assoc_data->bss);
if (!elems)
return;

@@ -4320,7 +4318,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
elems = ieee802_11_parse_elems_crc(variable, len - baselen,
false, care_about_ies, ncrc,
- mgmt->bssid, bssid);
+ link->u.mgd.bss);
if (!elems)
return;
ncrc = elems->crc;
@@ -4565,7 +4563,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
/* CSA IE cannot be overridden, no need for BSSID */
elems = ieee802_11_parse_elems(
mgmt->u.action.u.chan_switch.variable,
- ies_len, true, mgmt->bssid, NULL);
+ ies_len, true, NULL);

if (elems && !elems->parse_error)
ieee80211_sta_process_chanswitch(link,
@@ -4589,7 +4587,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
*/
elems = ieee802_11_parse_elems(
mgmt->u.action.u.ext_chan_switch.variable,
- ies_len, true, mgmt->bssid, NULL);
+ ies_len, true, NULL);

if (elems && !elems->parse_error) {
/* for the handling code pretend it was an IE */
@@ -5444,8 +5442,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();

ies = rcu_dereference(cbss->ies);
- elems = ieee802_11_parse_elems(ies->data, ies->len, false,
- NULL, NULL);
+ elems = ieee802_11_parse_elems(ies->data, ies->len, false, cbss);
if (!elems) {
rcu_read_unlock();
return -ENOMEM;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index f80284eee055..fa8ddf576bc1 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -209,8 +209,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
if (baselen > len)
return NULL;

- elems = ieee802_11_parse_elems(elements, len - baselen, false,
- mgmt->bssid, cbss->bssid);
+ elems = ieee802_11_parse_elems(elements, len - baselen, false, cbss);
if (!elems)
return NULL;

@@ -221,16 +220,21 @@ ieee80211_bss_info_update(struct ieee80211_local *local,

bss = (void *)cbss->priv;
ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon);
+ kfree(elems);

list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
non_tx_bss = (void *)non_tx_cbss->priv;

+ elems = ieee802_11_parse_elems(elements, len - baselen, false,
+ non_tx_cbss);
+ if (!elems)
+ continue;
+
ieee80211_update_bss_from_elems(local, non_tx_bss, elems,
rx_status, beacon);
+ kfree(elems);
}

- kfree(elems);
-
return bss;
}

diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index e7bdcdb488e2..36bfc54b3d2d 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1720,7 +1720,7 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
}

elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
- skb->len - baselen, false, NULL, NULL);
+ skb->len - baselen, false, NULL);
if (!elems) {
ret = -ENOMEM;
goto out;
@@ -1838,7 +1838,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
}

elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
- skb->len - baselen, false, NULL, NULL);
+ skb->len - baselen, false, NULL);
if (!elems)
return -ENOMEM;

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index f7c127a434b8..1de6b6256acc 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1422,15 +1422,14 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,

static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
- const u8 *transmitter_bssid,
- const u8 *bss_bssid,
+ struct cfg80211_bss *bss,
u8 *nontransmitted_profile)
{
const struct element *elem, *sub;
size_t profile_len = 0;
bool found = false;

- if (!bss_bssid || !transmitter_bssid)
+ if (!bss || !bss->transmitted_bss)
return profile_len;

for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
@@ -1472,11 +1471,11 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
continue;
}

- cfg80211_gen_new_bssid(transmitter_bssid,
+ cfg80211_gen_new_bssid(bss->transmitted_bss->bssid,
elem->data[0],
index[2],
new_bssid);
- if (ether_addr_equal(new_bssid, bss_bssid)) {
+ if (ether_addr_equal(new_bssid, bss->bssid)) {
found = true;
elems->bssid_index_len = index[1];
elems->bssid_index = (void *)&index[2];
@@ -1506,9 +1505,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
if (nontransmitted_profile) {
nontransmitted_profile_len =
ieee802_11_find_bssid_profile(params->start, params->len,
- elems,
- params->transmitter_bssid,
- params->bss_bssid,
+ elems, params->bss,
nontransmitted_profile);
non_inherit =
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
--
2.36.1

2022-07-13 09:48:39

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 56/76] wifi: mac80211: consider EHT element size in assoc request

From: Johannes Berg <[email protected]>

We need to consider the (maximum) size of the EHT element
we'll add for the association request, otherwise we may run
out of space.

Fixes: 820acc810fb6 ("mac80211: Add EHT capabilities to association/probe request")
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b56f2cefee44..f83d361ad50d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -987,6 +987,9 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
sizeof(struct ieee80211_he_mcs_nss_supp) +
IEEE80211_HE_PPE_THRES_MAX_LEN +
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
+ 2 + 1 + sizeof(struct ieee80211_eht_cap_elem) + /* EHT */
+ sizeof(struct ieee80211_eht_mcs_nss_supp) +
+ IEEE80211_EHT_PPE_THRES_MAX_LEN +
assoc_data->ie_len + /* extra IEs */
(assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
9 + /* WMM */
--
2.36.1

2022-07-13 09:48:43

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 59/76] wifi: mac80211: fix link manipulation

From: Johannes Berg <[email protected]>

When we add non-deflink pointers, we need to remove the
link[0] pointer to deflink in case link[0] is not valid
afterwards. Also, we need to add that back when there
are no more valid links. Reorg the code to fix that.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/iface.c | 44 ++++++++++++++++++++++++++------------------
1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index fc5869f40279..271fc81a5ea4 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -463,6 +463,10 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
if (old_links == new_links)
return 0;

+ /* if there were no old links, need to clear the pointers to deflink */
+ if (!old_links)
+ rem |= BIT(0);
+
/* allocate new link structures first */
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
link = kzalloc(sizeof(*link), GFP_KERNEL);
@@ -480,6 +484,22 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
memcpy(old_data, sdata->link, sizeof(old_data));

+ /* grab old links to free later */
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ RCU_INIT_POINTER(sdata->link[link_id], NULL);
+ RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
+
+ if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
+ continue;
+ /*
+ * we must have allocated the data through this path so
+ * we know we can free both at the same time
+ */
+ to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
+ typeof(*links[link_id]),
+ data);
+ }
+
/* link them into data structures */
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
WARN_ON(!use_deflink &&
@@ -490,10 +510,9 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
ieee80211_link_setup(&link->data);
}

- for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- RCU_INIT_POINTER(sdata->link[link_id], NULL);
- RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
- }
+ if (new_links == 0)
+ ieee80211_link_init(sdata, -1, &sdata->deflink,
+ &sdata->vif.bss_conf);

sdata->vif.valid_links = new_links;

@@ -506,25 +525,14 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
memcpy(sdata->link, old_data, sizeof(old_data));
memcpy(sdata->vif.link_conf, old, sizeof(old));
sdata->vif.valid_links = old_links;
- /* and free the newly allocated links */
- goto deinit;
+ /* and free (only) the newly allocated links */
+ memset(to_free, 0, sizeof(links));
+ goto free;
}

/* use deflink/bss_conf again if and only if there are no more links */
use_deflink = new_links == 0;

- for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
- continue;
- /*
- * we must have allocated the data through this path so
- * we know we can free both at the same time
- */
- to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
- typeof(*links[link_id]),
- data);
- }
-
goto deinit;
free:
/* if we failed during allocation, only free all */
--
2.36.1

2022-07-13 09:48:43

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 63/76] wifi: mac80211: skip rate statistics for MLD STAs

From: Johannes Berg <[email protected]>

For now, skip rate statistics here to avoid warnings in
the called code, we'll need to adjust this to have all
the statistics for link stations.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/sta_info.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 20aad688c9c9..88ff61aadd96 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2507,13 +2507,15 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
}
}

- if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))) {
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) &&
+ !sta->sta.valid_links) {
sta_set_rate_info_tx(sta, &sta->deflink.tx_stats.last_rate,
&sinfo->txrate);
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}

- if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE))) {
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) &&
+ !sta->sta.valid_links) {
if (sta_set_rate_info_rx(sta, &sinfo->rxrate) == 0)
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
}
--
2.36.1

2022-07-13 09:48:43

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 60/76] wifi: nl80211: better validate link ID for stations

From: Johannes Berg <[email protected]>

If we add a station on an MLD, we need a link ID to see
where it lives (by default). Validate the link ID against
the valid_links.

Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d774e9a95492..37ec8b3897b4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6991,6 +6991,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
struct station_parameters params;
u8 *mac_addr = NULL;
u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
@@ -7018,14 +7019,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
nl80211_link_id_or_invalid(info->attrs);

if (info->attrs[NL80211_ATTR_MLD_ADDR]) {
- /* If MLD_ADDR attribute is set then this is an MLD station
- * and the MLD_ADDR attribute holds the MLD address and the
- * MAC attribute holds for the LINK address.
- * In that case, the link_id is also expected to be valid.
- */
- if (params.link_sta_params.link_id < 0)
- return -EINVAL;
-
mac_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
params.link_sta_params.mld_mac = mac_addr;
params.link_sta_params.link_mac =
@@ -7253,9 +7246,24 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
/* be aware of params.vlan when changing code here */

wdev_lock(dev->ieee80211_ptr);
+ if (wdev->valid_links) {
+ if (params.link_sta_params.link_id < 0) {
+ err = -EINVAL;
+ goto out;
+ }
+ if (!(wdev->valid_links & BIT(params.link_sta_params.link_id))) {
+ err = -ENOLINK;
+ goto out;
+ }
+ } else {
+ if (params.link_sta_params.link_id >= 0) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
err = rdev_add_station(rdev, dev, mac_addr, &params);
+out:
wdev_unlock(dev->ieee80211_ptr);
-
dev_put(params.vlan);
return err;
}
--
2.36.1

2022-07-13 09:48:43

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 57/76] wifi: cfg80211: clean up links appropriately

From: Johannes Berg <[email protected]>

This was missing earlier, we need to remove links when
interfaces are being destroyed, and we also need to
stop (AP) operations when a link is being destroyed.
Address these issues to remove many warnings that will
otherwise appear in mac80211.

Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/core.c | 3 ++-
net/wireless/core.h | 5 +++++
net/wireless/nl80211.c | 11 ++---------
net/wireless/util.c | 43 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6b5321bb1176..eefd6d8ff465 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -342,7 +342,7 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)

wiphy_lock(&rdev->wiphy);
cfg80211_leave(rdev, wdev);
- rdev_del_virtual_intf(rdev, wdev);
+ cfg80211_remove_virtual_intf(rdev, wdev);
wiphy_unlock(&rdev->wiphy);
}
}
@@ -1437,6 +1437,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
case NETDEV_GOING_DOWN:
wiphy_lock(&rdev->wiphy);
cfg80211_leave(rdev, wdev);
+ cfg80211_remove_links(wdev);
wiphy_unlock(&rdev->wiphy);
break;
case NETDEV_DOWN:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index e72ca6eefafb..775e16cb99ed 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -562,4 +562,9 @@ void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
void cfg80211_pmsr_free_wk(struct work_struct *work);

+void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id);
+void cfg80211_remove_links(struct wireless_dev *wdev);
+int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+
#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 11cad2d46d0e..d774e9a95492 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4279,7 +4279,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)

mutex_lock(&rdev->wiphy.mtx);

- return rdev_del_virtual_intf(rdev, wdev);
+ return cfg80211_remove_virtual_intf(rdev, wdev);
}

static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
@@ -15707,7 +15707,6 @@ static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info)

static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
unsigned int link_id = nl80211_link_id(info->attrs);
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -15723,14 +15722,8 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}

- /* FIXME: stop the link operations first */
-
wdev_lock(wdev);
- wdev->valid_links &= ~BIT(link_id);
-
- rdev_del_intf_link(rdev, wdev, link_id);
-
- eth_zero_addr(wdev->links[link_id].addr);
+ cfg80211_remove_link(wdev, link_id);
wdev_unlock(wdev);

return 0;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index b7257862e0fe..fe7956c8c6da 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2447,3 +2447,46 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
return false;
}
EXPORT_SYMBOL(cfg80211_iftype_allowed);
+
+void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ __cfg80211_stop_ap(rdev, wdev->netdev, link_id, true);
+ break;
+ default:
+ /* per-link not relevant */
+ break;
+ }
+
+ wdev->valid_links &= ~BIT(link_id);
+
+ rdev_del_intf_link(rdev, wdev, link_id);
+
+ eth_zero_addr(wdev->links[link_id].addr);
+}
+
+void cfg80211_remove_links(struct wireless_dev *wdev)
+{
+ unsigned int link_id;
+
+ wdev_lock(wdev);
+ if (wdev->valid_links) {
+ for_each_valid_link(wdev, link_id)
+ cfg80211_remove_link(wdev, link_id);
+ }
+ wdev_unlock(wdev);
+}
+
+int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ cfg80211_remove_links(wdev);
+
+ return rdev_del_virtual_intf(rdev, wdev);
+}
--
2.36.1

2022-07-13 09:48:43

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

From: Johannes Berg <[email protected]>

We have the per-interface type capabilities, currently for
extended capabilities, add the EML/MLD capabilities there
to have this advertised by the driver.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 4 ++++
include/uapi/linux/nl80211.h | 12 ++++++++++--
net/wireless/nl80211.c | 9 +++++++++
3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ca26e3b7341a..44abaa9d74ea 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4993,12 +4993,16 @@ struct wiphy_vendor_command {
* 802.11-2012 8.4.2.29 for the defined fields.
* @extended_capabilities_mask: mask of the valid values
* @extended_capabilities_len: length of the extended capabilities
+ * @eml_capabilities: EML capabilities (for MLO)
+ * @mld_capa_and_ops: MLD capabilities and operations (for MLO)
*/
struct wiphy_iftype_ext_capab {
enum nl80211_iftype iftype;
const u8 *extended_capabilities;
const u8 *extended_capabilities_mask;
u8 extended_capabilities_len;
+ u16 eml_capabilities;
+ u16 mld_capa_and_ops;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 37bfc934325a..3fa586e38f88 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2368,8 +2368,10 @@ enum nl80211_commands {
*
* @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
* %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
- * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
- * interface type.
+ * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities and
+ * other interface-type specific capabilities per interface type. For MLO,
+ * %NL80211_ATTR_EML_CAPABILITY and %NL80211_ATTR_MLD_CAPA_AND_OPS are
+ * present.
*
* @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO
* groupID for monitor mode.
@@ -2709,6 +2711,9 @@ enum nl80211_commands {
* suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum
* number prior to the introduction of this attribute.
*
+ * @NL80211_ATTR_EML_CAPABILITY: EML Capability information (u16)
+ * @NL80211_ATTR_MLD_CAPA_AND_OPS: MLD Capabilities and Operations (u16)
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3231,6 +3236,9 @@ enum nl80211_attrs {

NL80211_ATTR_MAX_NUM_AKM_SUITES,

+ NL80211_ATTR_EML_CAPABILITY,
+ NL80211_ATTR_MLD_CAPA_AND_OPS,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 37ec8b3897b4..35fb2b0517d9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2867,6 +2867,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
capab->extended_capabilities_mask))
goto nla_put_failure;

+ if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO &&
+ (nla_put_u16(msg,
+ NL80211_ATTR_EML_CAPABILITY,
+ capab->eml_capabilities) ||
+ nla_put_u16(msg,
+ NL80211_ATTR_MLD_CAPA_AND_OPS,
+ capab->mld_capa_and_ops)))
+ goto nla_put_failure;
+
nla_nest_end(msg, nested_ext_capab);
if (state->split)
break;
--
2.36.1

2022-07-13 09:48:46

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 68/76] wifi: mac80211: Allow EAPOL frames from link addresses

From: Andrei Otcheretianski <[email protected]>

Allow transmitting EAPOL frames not only from the interface
address (which is the MLD address) but also any link addresses,
in order to support non-MLO stations on AP interfaces.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rx.c | 60 +++++++++++++++++++++++------------------------
1 file changed, 30 insertions(+), 30 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9f7ce1377604..97046d30c9ca 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2532,6 +2532,35 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
return 0;
}

+static bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr, int *out_link_id)
+{
+ unsigned int link_id;
+
+ /* non-MLO, or MLD address replaced by hardware */
+ if (ether_addr_equal(sdata->vif.addr, addr))
+ return true;
+
+ if (!sdata->vif.valid_links)
+ return false;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
+ struct ieee80211_bss_conf *conf;
+
+ conf = rcu_dereference(sdata->vif.link_conf[link_id]);
+
+ if (!conf)
+ continue;
+ if (ether_addr_equal(conf->addr, addr)) {
+ if (out_link_id)
+ *out_link_id = link_id;
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*
* requires that rx->skb is a frame with ethernet header
*/
@@ -2547,7 +2576,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
* all other destination addresses for them.
*/
if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
- return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
+ return ieee80211_is_our_addr(rx->sdata, ehdr->h_dest, NULL) ||
ether_addr_equal(ehdr->h_dest, pae_group_addr);

if (ieee80211_802_1x_port_control(rx) ||
@@ -4142,35 +4171,6 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
is_broadcast_ether_addr(raddr);
}

-static bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
- const u8 *addr, int *out_link_id)
-{
- unsigned int link_id;
-
- /* non-MLO, or MLD address replaced by hardware */
- if (ether_addr_equal(sdata->vif.addr, addr))
- return true;
-
- if (!sdata->vif.valid_links)
- return false;
-
- for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
- struct ieee80211_bss_conf *conf;
-
- conf = rcu_dereference(sdata->vif.link_conf[link_id]);
-
- if (!conf)
- continue;
- if (ether_addr_equal(conf->addr, addr)) {
- if (out_link_id)
- *out_link_id = link_id;
- return true;
- }
- }
-
- return false;
-}
-
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
--
2.36.1

2022-07-13 09:48:47

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 54/76] wifi: mac80211: refactor adding custom elements

From: Johannes Berg <[email protected]>

Rework the sorting of custom elements into the association
request by moving the elements before HT/VHT/HE to each
their own function. While at it, fix the placement of the
ones that should be between VHT and HE.

This doesn't fix the placement of elements that should be
between HE and EHT yet, a similar change might be needed
in the future.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 212 ++++++++++++++++++++++++++------------------
1 file changed, 125 insertions(+), 87 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a442de3670b9..36cce750528a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -839,6 +839,120 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb,
}
}

+static size_t ieee80211_add_before_ht_elems(struct sk_buff *skb,
+ const u8 *elems,
+ size_t elems_len,
+ size_t offset)
+{
+ size_t noffset;
+
+ static const u8 before_ht[] = {
+ WLAN_EID_SSID,
+ WLAN_EID_SUPP_RATES,
+ WLAN_EID_EXT_SUPP_RATES,
+ WLAN_EID_PWR_CAPABILITY,
+ WLAN_EID_SUPPORTED_CHANNELS,
+ WLAN_EID_RSN,
+ WLAN_EID_QOS_CAPA,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES,
+ WLAN_EID_MOBILITY_DOMAIN,
+ WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */
+ WLAN_EID_RIC_DATA, /* reassoc only */
+ WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+ };
+ static const u8 after_ric[] = {
+ WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+ WLAN_EID_HT_CAPABILITY,
+ WLAN_EID_BSS_COEX_2040,
+ /* luckily this is almost always there */
+ WLAN_EID_EXT_CAPABILITY,
+ WLAN_EID_QOS_TRAFFIC_CAPA,
+ WLAN_EID_TIM_BCAST_REQ,
+ WLAN_EID_INTERWORKING,
+ /* 60 GHz (Multi-band, DMG, MMS) can't happen */
+ WLAN_EID_VHT_CAPABILITY,
+ WLAN_EID_OPMODE_NOTIF,
+ };
+
+ if (!elems_len)
+ return offset;
+
+ noffset = ieee80211_ie_split_ric(elems, elems_len,
+ before_ht,
+ ARRAY_SIZE(before_ht),
+ after_ric,
+ ARRAY_SIZE(after_ric),
+ offset);
+ skb_put_data(skb, elems + offset, noffset - offset);
+
+ return noffset;
+}
+
+static size_t ieee80211_add_before_vht_elems(struct sk_buff *skb,
+ const u8 *elems,
+ size_t elems_len,
+ size_t offset)
+{
+ static const u8 before_vht[] = {
+ /*
+ * no need to list the ones split off before HT
+ * or generated here
+ */
+ WLAN_EID_BSS_COEX_2040,
+ WLAN_EID_EXT_CAPABILITY,
+ WLAN_EID_QOS_TRAFFIC_CAPA,
+ WLAN_EID_TIM_BCAST_REQ,
+ WLAN_EID_INTERWORKING,
+ /* 60 GHz (Multi-band, DMG, MMS) can't happen */
+ };
+ size_t noffset;
+
+ if (!elems_len)
+ return offset;
+
+ /* RIC already taken care of in ieee80211_add_before_ht_elems() */
+ noffset = ieee80211_ie_split(elems, elems_len,
+ before_vht, ARRAY_SIZE(before_vht),
+ offset);
+ skb_put_data(skb, elems + offset, noffset - offset);
+
+ return noffset;
+}
+
+static size_t ieee80211_add_before_he_elems(struct sk_buff *skb,
+ const u8 *elems,
+ size_t elems_len,
+ size_t offset)
+{
+ static const u8 before_he[] = {
+ /*
+ * no need to list the ones split off before VHT
+ * or generated here
+ */
+ WLAN_EID_OPMODE_NOTIF,
+ WLAN_EID_EXTENSION, WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE,
+ /* 11ai elements */
+ WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_SESSION,
+ WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_PUBLIC_KEY,
+ WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_KEY_CONFIRM,
+ WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_HLP_CONTAINER,
+ WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN,
+ /* TODO: add 11ah/11aj/11ak elements */
+ };
+ size_t noffset;
+
+ if (!elems_len)
+ return offset;
+
+ /* RIC already taken care of in ieee80211_add_before_ht_elems() */
+ noffset = ieee80211_ie_split(elems, elems_len,
+ before_he, ARRAY_SIZE(before_he),
+ offset);
+ skb_put_data(skb, elems + offset, noffset - offset);
+
+ return noffset;
+}
+
static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@@ -994,45 +1108,9 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;

/* if present, add any custom IEs that go before HT */
- if (assoc_data->ie_len) {
- static const u8 before_ht[] = {
- WLAN_EID_SSID,
- WLAN_EID_SUPP_RATES,
- WLAN_EID_EXT_SUPP_RATES,
- WLAN_EID_PWR_CAPABILITY,
- WLAN_EID_SUPPORTED_CHANNELS,
- WLAN_EID_RSN,
- WLAN_EID_QOS_CAPA,
- WLAN_EID_RRM_ENABLED_CAPABILITIES,
- WLAN_EID_MOBILITY_DOMAIN,
- WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */
- WLAN_EID_RIC_DATA, /* reassoc only */
- WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
- };
- static const u8 after_ric[] = {
- WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
- WLAN_EID_HT_CAPABILITY,
- WLAN_EID_BSS_COEX_2040,
- /* luckily this is almost always there */
- WLAN_EID_EXT_CAPABILITY,
- WLAN_EID_QOS_TRAFFIC_CAPA,
- WLAN_EID_TIM_BCAST_REQ,
- WLAN_EID_INTERWORKING,
- /* 60 GHz (Multi-band, DMG, MMS) can't happen */
- WLAN_EID_VHT_CAPABILITY,
- WLAN_EID_OPMODE_NOTIF,
- };
-
- noffset = ieee80211_ie_split_ric(assoc_data->ie,
- assoc_data->ie_len,
- before_ht,
- ARRAY_SIZE(before_ht),
- after_ric,
- ARRAY_SIZE(after_ric),
- offset);
- skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
- offset = noffset;
- }
+ offset = ieee80211_add_before_ht_elems(skb, assoc_data->ie,
+ assoc_data->ie_len,
+ offset);

if (WARN_ON_ONCE((link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)))
@@ -1044,54 +1122,9 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
sband, chan, link->smps_mode);

/* if present, add any custom IEs that go before VHT */
- if (assoc_data->ie_len) {
- static const u8 before_vht[] = {
- /*
- * no need to list the ones split off before HT
- * or generated here
- */
- WLAN_EID_BSS_COEX_2040,
- WLAN_EID_EXT_CAPABILITY,
- WLAN_EID_QOS_TRAFFIC_CAPA,
- WLAN_EID_TIM_BCAST_REQ,
- WLAN_EID_INTERWORKING,
- /* 60 GHz (Multi-band, DMG, MMS) can't happen */
- };
-
- /* RIC already taken above, so no need to handle here anymore */
- noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
- before_vht, ARRAY_SIZE(before_vht),
- offset);
- skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
- offset = noffset;
- }
-
- /* if present, add any custom IEs that go before HE */
- if (assoc_data->ie_len) {
- static const u8 before_he[] = {
- /*
- * no need to list the ones split off before VHT
- * or generated here
- */
- WLAN_EID_OPMODE_NOTIF,
- WLAN_EID_EXTENSION, WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE,
- /* 11ai elements */
- WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_SESSION,
- WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_PUBLIC_KEY,
- WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_KEY_CONFIRM,
- WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_HLP_CONTAINER,
- WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN,
- /* TODO: add 11ah/11aj/11ak elements */
- };
-
- /* RIC already taken above, so no need to handle here anymore */
- noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
- before_he, ARRAY_SIZE(before_he),
- offset);
- pos = skb_put(skb, noffset - offset);
- memcpy(pos, assoc_data->ie + offset, noffset - offset);
- offset = noffset;
- }
+ offset = ieee80211_add_before_vht_elems(skb, assoc_data->ie,
+ assoc_data->ie_len,
+ offset);

if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
@@ -1108,6 +1141,11 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
IEEE80211_CONN_DISABLE_EHT;

+ /* if present, add any custom IEs that go before HE */
+ offset = ieee80211_add_before_he_elems(skb, assoc_data->ie,
+ assoc_data->ie_len,
+ offset);
+
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
ieee80211_add_he_ie(link, skb, sband);

--
2.36.1

2022-07-13 09:48:48

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 66/76] wifi: nl80211: Support MLD parameters in nl80211_set_station()

From: Andrei Otcheretianski <[email protected]>

Set the MLD parameters in NL80211_CMD_SET_STATION handling
to be able to change an MLD station.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ee3826e8e52b..35fcf36bbaad 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6894,7 +6894,28 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;

- mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ params.link_sta_params.link_id =
+ nl80211_link_id_or_invalid(info->attrs);
+
+ if (info->attrs[NL80211_ATTR_MLD_ADDR]) {
+ /* If MLD_ADDR attribute is set then this is an MLD station
+ * and the MLD_ADDR attribute holds the MLD address and the
+ * MAC attribute holds for the LINK address.
+ * In that case, the link_id is also expected to be valid.
+ */
+ if (params.link_sta_params.link_id < 0)
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+ params.link_sta_params.mld_mac = mac_addr;
+ params.link_sta_params.link_mac =
+ nla_data(info->attrs[NL80211_ATTR_MAC]);
+ if (!is_valid_ether_addr(params.link_sta_params.link_mac))
+ return -EINVAL;
+ } else {
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ }
+

if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
params.link_sta_params.supported_rates =
--
2.36.1

2022-07-13 09:48:48

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 58/76] wifi: mac80211: tighten locking check

From: Johannes Berg <[email protected]>

When we remove a link that doesn't have a channel context,
we don't really need the local->mtx locking. Tighten the
check here.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 92fe40539091..5ab210706123 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1991,10 +1991,11 @@ void ieee80211_link_release_channel(struct ieee80211_link_data *link)

WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));

- lockdep_assert_held(&sdata->local->mtx);
-
mutex_lock(&sdata->local->chanctx_mtx);
- __ieee80211_link_release_channel(link);
+ if (rcu_access_pointer(link->conf->chanctx_conf)) {
+ lockdep_assert_held(&sdata->local->mtx);
+ __ieee80211_link_release_channel(link);
+ }
mutex_unlock(&sdata->local->chanctx_mtx);
}

--
2.36.1

2022-07-13 09:48:48

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 70/76] wifi: nl80211: allow link ID in set_wiphy with frequency

From: Ilan Peer <[email protected]>

This simplifies hostapd implementation, since it didn't
switch to NL80211_CMD_SET_CHANNEL.

Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 53d63effbca9..0bf1f7267b89 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3475,16 +3475,19 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
}

if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ int link_id = nl80211_link_id_or_invalid(info->attrs);
+
if (wdev) {
wdev_lock(wdev);
result = __nl80211_set_channel(
rdev,
nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
- info, -1);
+ info, link_id);
wdev_unlock(wdev);
} else {
- result = __nl80211_set_channel(rdev, netdev, info, -1);
+ result = __nl80211_set_channel(rdev, netdev, info, link_id);
}
+
if (result)
goto out;
}
--
2.36.1

2022-07-13 09:48:49

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 71/76] wifi: mac80211: don't check carrier in chanctx code

From: Andrei Otcheretianski <[email protected]>

We check here that we don't enable TX (netif_carrier_ok())
before we actually start using some channel context, but to
our knowledge this check has never triggered, and with MLO
it's just wrong since links can be added and removed much
more dynamically than before.

Simply remove the checks, there's no really good way to do
anything that would replace them.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 5ab210706123..2e9bc285f0a5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1800,8 +1800,6 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,

lockdep_assert_held(&local->mtx);

- WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
-
mutex_lock(&local->chanctx_mtx);

ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
@@ -1989,8 +1987,6 @@ void ieee80211_link_release_channel(struct ieee80211_link_data *link)
{
struct ieee80211_sub_if_data *sdata = link->sdata;

- WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
-
mutex_lock(&sdata->local->chanctx_mtx);
if (rcu_access_pointer(link->conf->chanctx_conf)) {
lockdep_assert_held(&sdata->local->mtx);
--
2.36.1

2022-07-13 09:48:49

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 72/76] wifi: mac80211: Support multi link in ieee80211_recalc_min_chandef()

From: Andrei Otcheretianski <[email protected]>

Recalculate min channel context for the given or all interface
links, depending on the caller. For a station state change, we
need to recalculate all of them since we don't know which link
(or multiple) it might be on.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 3 ++-
net/mac80211/sta_info.c | 6 +++---
net/mac80211/util.c | 40 +++++++++++++++++++++++++++++++-------
net/mac80211/vht.c | 2 +-
4 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 163e62dab045..877f2441b74b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2335,7 +2335,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link);
-void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);
+void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
+ int link_id);

size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 88ff61aadd96..f52a7fa6dde5 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -780,7 +780,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
* change, this enables driver using the updated channel context right away.
*/
if (sta->sta_state >= IEEE80211_STA_ASSOC) {
- ieee80211_recalc_min_chandef(sta->sdata);
+ ieee80211_recalc_min_chandef(sta->sdata, -1);
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
}
@@ -2136,7 +2136,7 @@ int sta_info_move_state(struct sta_info *sta,
set_bit(WLAN_STA_AUTH, &sta->_flags);
} else if (sta->sta_state == IEEE80211_STA_ASSOC) {
clear_bit(WLAN_STA_ASSOC, &sta->_flags);
- ieee80211_recalc_min_chandef(sta->sdata);
+ ieee80211_recalc_min_chandef(sta->sdata, -1);
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
}
@@ -2145,7 +2145,7 @@ int sta_info_move_state(struct sta_info *sta,
if (sta->sta_state == IEEE80211_STA_AUTH) {
set_bit(WLAN_STA_ASSOC, &sta->_flags);
sta->assoc_at = ktime_get_boottime_ns();
- ieee80211_recalc_min_chandef(sta->sdata);
+ ieee80211_recalc_min_chandef(sta->sdata, -1);
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4b11cf57f4fe..cb44fa9a5048 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2836,22 +2836,48 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->chanctx_mtx);
}

-void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
+void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
+ int link_id)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
+ int i;

mutex_lock(&local->chanctx_mtx);

- chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf,
- lockdep_is_held(&local->chanctx_mtx));
+ for (i = 0; i < ARRAY_SIZE(sdata->vif.link_conf); i++) {
+ struct ieee80211_bss_conf *bss_conf;

- if (WARN_ON_ONCE(!chanctx_conf))
- goto unlock;
+ if (link_id >= 0 && link_id != i)
+ continue;

- chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
- ieee80211_recalc_chanctx_min_def(local, chanctx);
+ rcu_read_lock();
+ bss_conf = rcu_dereference(sdata->vif.link_conf[i]);
+ if (!bss_conf) {
+ rcu_read_unlock();
+ continue;
+ }
+
+ chanctx_conf = rcu_dereference_protected(bss_conf->chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ /*
+ * Since we hold the chanctx_mtx (checked above)
+ * we can take the chanctx_conf pointer out of the
+ * RCU critical section, it cannot go away without
+ * the mutex. Just the way we reached it could - in
+ * theory - go away, but we don't really care and
+ * it really shouldn't happen anyway.
+ */
+ rcu_read_unlock();
+
+ if (WARN_ON_ONCE(!chanctx_conf))
+ goto unlock;
+
+ chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
+ conf);
+ ieee80211_recalc_chanctx_min_def(local, chanctx);
+ }
unlock:
mutex_unlock(&local->chanctx_mtx);
}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index c804890dc623..b2b09d421e8b 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -731,7 +731,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
opmode, band);

if (changed > 0) {
- ieee80211_recalc_min_chandef(sdata);
+ ieee80211_recalc_min_chandef(sdata, link_sta->link_id);
rate_control_rate_update(local, sband, link_sta->sta,
link_sta->link_id, changed);
}
--
2.36.1

2022-07-13 09:48:51

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 55/76] wifi: mac80211: mlme: simplify adding ht/vht/he/eht elements

From: Johannes Berg <[email protected]>

The functions currently take a link and check data
from it, but this needs to change for MLO. Simplify
the prototypes by passing only the needed arguments.

Remove the regulatory checks, the warnings shouldn't
trigger, and haven't as far as I know.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 79 ++++++++++++++++++---------------------------
1 file changed, 31 insertions(+), 48 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 36cce750528a..b56f2cefee44 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -524,13 +524,13 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,

/* frame sending functions */

-static void ieee80211_add_ht_ie(struct ieee80211_link_data *link,
+static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u8 ap_ht_param,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
- enum ieee80211_smps_mode smps)
+ enum ieee80211_smps_mode smps,
+ ieee80211_conn_flags_t conn_flags)
{
- struct ieee80211_sub_if_data *sdata = link->sdata;
u8 *pos;
u32 flags = channel->flags;
u16 cap;
@@ -564,7 +564,7 @@ static void ieee80211_add_ht_ie(struct ieee80211_link_data *link,
* capable of 40 MHz -- some broken APs will never fall
* back to trying to transmit in 20 MHz.
*/
- if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) {
+ if (conn_flags & IEEE80211_CONN_DISABLE_40MHZ) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
@@ -597,19 +597,20 @@ static void ieee80211_add_ht_ie(struct ieee80211_link_data *link,

/* This function determines vht capability flags for the association
* and builds the IE.
- * Note - the function may set the owner of the MU-MIMO capability
+ * Note - the function returns true to own the MU-MIMO capability
*/
-static void ieee80211_add_vht_ie(struct ieee80211_link_data *link,
+static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_supported_band *sband,
- struct ieee80211_vht_cap *ap_vht_cap)
+ struct ieee80211_vht_cap *ap_vht_cap,
+ ieee80211_conn_flags_t conn_flags)
{
- struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
u8 *pos;
u32 cap;
struct ieee80211_sta_vht_cap vht_cap;
u32 mask, ap_bf_sts, our_bf_sts;
+ bool mu_mimo_owner = false;

BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));

@@ -619,7 +620,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_link_data *link,
/* determine capability flags */
cap = vht_cap.cap;

- if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ) {
+ if (conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ) {
u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;

cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
@@ -628,7 +629,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_link_data *link,
cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
}

- if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ) {
+ if (conn_flags & IEEE80211_CONN_DISABLE_160MHZ) {
cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
}
@@ -665,7 +666,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_link_data *link,
if (disable_mu_mimo)
cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
else
- link->conf->mu_mimo_owner = true;
+ mu_mimo_owner = true;
}

mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
@@ -681,34 +682,25 @@ static void ieee80211_add_vht_ie(struct ieee80211_link_data *link,
/* reserve and fill IE */
pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
+
+ return mu_mimo_owner;
}

/* This function determines HE capability flags for the association
* and builds the IE.
*/
-static void ieee80211_add_he_ie(struct ieee80211_link_data *link,
+static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
- struct ieee80211_supported_band *sband)
+ struct ieee80211_supported_band *sband,
+ ieee80211_conn_flags_t conn_flags)
{
- struct ieee80211_sub_if_data *sdata = link->sdata;
u8 *pos, *pre_he_pos;
- const struct ieee80211_sta_he_cap *he_cap = NULL;
- struct ieee80211_chanctx_conf *chanctx_conf;
+ const struct ieee80211_sta_he_cap *he_cap;
u8 he_cap_size;
- bool reg_cap = false;
-
- rcu_read_lock();
- chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
- if (!WARN_ON_ONCE(!chanctx_conf))
- reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy,
- &chanctx_conf->def,
- IEEE80211_CHAN_NO_HE);
-
- rcu_read_unlock();

he_cap = ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif));
- if (!he_cap || !chanctx_conf || !reg_cap)
+ if (WARN_ON(!he_cap))
return;

/* get a max size estimate */
@@ -719,7 +711,7 @@ static void ieee80211_add_he_ie(struct ieee80211_link_data *link,
he_cap->he_cap_elem.phy_cap_info);
pos = skb_put(skb, he_cap_size);
pre_he_pos = pos;
- pos = ieee80211_ie_build_he_cap(link->u.mgd.conn_flags,
+ pos = ieee80211_ie_build_he_cap(conn_flags,
pos, he_cap, pos + he_cap_size);
/* trim excess if any */
skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
@@ -727,26 +719,14 @@ static void ieee80211_add_he_ie(struct ieee80211_link_data *link,
ieee80211_ie_build_he_6ghz_cap(sdata, skb);
}

-static void ieee80211_add_eht_ie(struct ieee80211_link_data *link,
+static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_supported_band *sband)
{
- struct ieee80211_sub_if_data *sdata = link->sdata;
u8 *pos;
const struct ieee80211_sta_he_cap *he_cap;
const struct ieee80211_sta_eht_cap *eht_cap;
- struct ieee80211_chanctx_conf *chanctx_conf;
u8 eht_cap_size;
- bool reg_cap = false;
-
- rcu_read_lock();
- chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
- if (!WARN_ON_ONCE(!chanctx_conf))
- reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy,
- &chanctx_conf->def,
- IEEE80211_CHAN_NO_HE |
- IEEE80211_CHAN_NO_EHT);
- rcu_read_unlock();

he_cap = ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif));
@@ -757,7 +737,7 @@ static void ieee80211_add_eht_ie(struct ieee80211_link_data *link,
* EHT capabilities element is only added if the HE capabilities element
* was added so assume that 'he_cap' is valid and don't check it.
*/
- if (WARN_ON(!he_cap || !eht_cap || !reg_cap))
+ if (WARN_ON(!he_cap || !eht_cap))
return;

eht_cap_size =
@@ -1118,8 +1098,9 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)

if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
- ieee80211_add_ht_ie(link, skb, assoc_data->ap_ht_param,
- sband, chan, link->smps_mode);
+ ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
+ sband, chan, link->smps_mode,
+ link->u.mgd.conn_flags);

/* if present, add any custom IEs that go before VHT */
offset = ieee80211_add_before_vht_elems(skb, assoc_data->ie,
@@ -1128,8 +1109,10 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)

if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
- ieee80211_add_vht_ie(link, skb, sband,
- &assoc_data->ap_vht_cap);
+ link->conf->mu_mimo_owner =
+ ieee80211_add_vht_ie(sdata, skb, sband,
+ &assoc_data->ap_vht_cap,
+ link->u.mgd.conn_flags);

/*
* If AP doesn't support HT, mark HE and EHT as disabled.
@@ -1147,10 +1130,10 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
offset);

if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
- ieee80211_add_he_ie(link, skb, sband);
+ ieee80211_add_he_ie(sdata, skb, sband, link->u.mgd.conn_flags);

if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
- ieee80211_add_eht_ie(link, skb, sband);
+ ieee80211_add_eht_ie(sdata, skb, sband);
}

/* if present, add any custom non-vendor IEs that go after HE */
--
2.36.1

2022-07-13 09:48:51

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 75/76] wifi: mac80211: remove link_id parameter from link_info_changed()

From: Gregory Greenman <[email protected]>

Since struct ieee80211_bss_conf already contains link_id,
passing link_id is not necessary.

Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 3 ++-
include/net/mac80211.h | 1 -
net/mac80211/driver-ops.h | 4 ++--
net/mac80211/main.c | 5 ++---
net/mac80211/trace.h | 6 +++---
5 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 715661298f2a..adadd03c50e4 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2178,10 +2178,11 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw,
static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
- u32 link_id, u64 changed)
+ u64 changed)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
struct mac80211_hwsim_data *data = hw->priv;
+ unsigned int link_id = info->link_id;
struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id];

hwsim_check_magic(vif);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6e5e0708cfff..8a69ef867e87 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4088,7 +4088,6 @@ struct ieee80211_ops {
void (*link_info_changed)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
- unsigned int link_id,
u64 changed);

int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 0f06081c68ca..482f5c97a72b 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -190,10 +190,10 @@ static inline void drv_link_info_changed(struct ieee80211_local *local,
if (!check_sdata_in_driver(sdata))
return;

- trace_drv_link_info_changed(local, sdata, info, link_id, changed);
+ trace_drv_link_info_changed(local, sdata, info, changed);
if (local->ops->link_info_changed)
local->ops->link_info_changed(&local->hw, &sdata->vif,
- info, link_id, changed);
+ info, changed);
else if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif,
info, changed);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8d5b18318b20..26bb30606282 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -248,11 +248,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,

/* FIXME: should be for each link */
trace_drv_link_info_changed(local, sdata, &sdata->vif.bss_conf,
- 0, changed);
+ changed);
if (local->ops->link_info_changed)
local->ops->link_info_changed(&local->hw, &sdata->vif,
- &sdata->vif.bss_conf,
- 0, ch);
+ &sdata->vif.bss_conf, ch);
}

if (local->ops->bss_info_changed)
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 402110f439f8..9f4377566c42 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -449,9 +449,9 @@ TRACE_EVENT(drv_link_info_changed,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *link_conf,
- int link_id, u64 changed),
+ u64 changed),

- TP_ARGS(local, sdata, link_conf, link_id, changed),
+ TP_ARGS(local, sdata, link_conf, changed),

TP_STRUCT__entry(
LOCAL_ENTRY
@@ -486,7 +486,7 @@ TRACE_EVENT(drv_link_info_changed,
LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->changed = changed;
- __entry->link_id = link_id;
+ __entry->link_id = link_conf->link_id;
__entry->shortpre = link_conf->use_short_preamble;
__entry->cts = link_conf->use_cts_prot;
__entry->shortslot = link_conf->use_short_slot;
--
2.36.1

2022-07-13 09:48:52

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 76/76] wifi: cfg80211: set country_elem to NULL

From: Johannes Berg <[email protected]>

The link loop will always have a valid link so that
it's always set, but static checkers don't always
see that, so set it to NULL explicitly.

Fixes: efbabc116500 ("cfg80211: Indicate MLO connection info in connect and roam callbacks")
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/sme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 00be498aab2e..8e8a79bd237c 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -723,7 +723,7 @@ void __cfg80211_connect_result(struct net_device *dev,
bool wextev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- const struct element *country_elem;
+ const struct element *country_elem = NULL;
const u8 *country_data;
u8 country_datalen;
#ifdef CONFIG_CFG80211_WEXT
--
2.36.1

2022-07-13 09:49:50

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 39/76] wifi: cfg80211: prepare association failure APIs for MLO

From: Johannes Berg <[email protected]>

For MLO, we need the ability to report back multiple BSS
structures to release, as well as the AP MLD address (if
attempting to make an MLO connection).

Unify cfg80211_assoc_timeout() and cfg80211_abandon_assoc()
into a new cfg80211_assoc_failure() that gets a structure
parameter with the necessary data.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 29 +++++++++++++++++------------
net/mac80211/mlme.c | 28 +++++++++++++++++++++++-----
net/wireless/mlme.c | 36 +++++++++++++++++++-----------------
net/wireless/trace.h | 19 ++++++++++++++++---
4 files changed, 75 insertions(+), 37 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index cc20f0036e75..2a70f8900a4f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6900,24 +6900,29 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
const u8 *req_ies, size_t req_ies_len);

/**
- * cfg80211_assoc_timeout - notification of timed out association
- * @dev: network device
- * @bss: The BSS entry with which association timed out.
- *
- * This function may sleep. The caller must hold the corresponding wdev's mutex.
- */
-void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss);
+ * struct cfg80211_assoc_failure - association failure data
+ * @ap_mld_addr: AP MLD address, or %NULL
+ * @bss: list of BSSes, must use entry 0 for non-MLO connections
+ * (@ap_mld_addr is %NULL)
+ * @timeout: indicates the association failed due to timeout, otherwise
+ * the association was abandoned for a reason reported through some
+ * other API (e.g. deauth RX)
+ */
+struct cfg80211_assoc_failure {
+ const u8 *ap_mld_addr;
+ struct cfg80211_bss *bss[IEEE80211_MLD_MAX_NUM_LINKS];
+ bool timeout;
+};

/**
- * cfg80211_abandon_assoc - notify cfg80211 of abandoned association attempt
+ * cfg80211_assoc_failure - notification of association failure
* @dev: network device
- * @bss: The BSS entry with which association was abandoned.
+ * @data: data describing the association failure
*
- * Call this whenever - for reasons reported through other API, like deauth RX,
- * an association attempt was abandoned.
* This function may sleep. The caller must hold the corresponding wdev's mutex.
*/
-void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss);
+void cfg80211_assoc_failure(struct net_device *dev,
+ struct cfg80211_assoc_failure *data);

/**
* cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0c432e3abd90..8d339d3f89ab 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3026,8 +3026,13 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&sdata->local->mtx);

- if (abandon)
- cfg80211_abandon_assoc(sdata->dev, assoc_data->bss);
+ if (abandon) {
+ struct cfg80211_assoc_failure data = {
+ .bss[0] = assoc_data->bss,
+ };
+
+ cfg80211_assoc_failure(sdata->dev, &data);
+ }
}

kfree(assoc_data);
@@ -3955,8 +3960,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
} else {
if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
/* oops -- internal error -- send timeout for now */
+ struct cfg80211_assoc_failure data = {
+ .timeout = true,
+ .bss[0] = cbss,
+ };
ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_timeout(sdata->dev, cbss);
+ cfg80211_assoc_failure(sdata->dev, &data);
goto notify_driver;
}
event.u.mlme.status = MLME_SUCCESS;
@@ -4832,9 +4841,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
.u.mlme.data = ASSOC_EVENT,
.u.mlme.status = MLME_TIMEOUT,
};
+ struct cfg80211_assoc_failure data = {
+ .bss[0] = bss,
+ .timeout = true,
+ };

ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_timeout(sdata->dev, bss);
+ cfg80211_assoc_failure(sdata->dev, &data);
drv_event_callback(sdata->local, sdata, &event);
}
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
@@ -6467,8 +6480,13 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
sdata_lock(sdata);
if (ifmgd->assoc_data) {
struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
+ struct cfg80211_assoc_failure data = {
+ .bss[0] = bss,
+ .timeout = true,
+ };
+
ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_timeout(sdata->dev, bss);
+ cfg80211_assoc_failure(sdata->dev, &data);
}
if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 4a35b3559daa..aefe8b26f0d7 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -154,33 +154,35 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
}
EXPORT_SYMBOL(cfg80211_auth_timeout);

-void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss)
+void cfg80211_assoc_failure(struct net_device *dev,
+ struct cfg80211_assoc_failure *data)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+ const u8 *addr = data->ap_mld_addr ?: data->bss[0]->bssid;
+ int i;

- trace_cfg80211_send_assoc_timeout(dev, bss->bssid);
-
- nl80211_send_assoc_timeout(rdev, dev, bss->bssid, GFP_KERNEL);
- cfg80211_sme_assoc_timeout(wdev);
+ trace_cfg80211_send_assoc_failure(dev, data);

- cfg80211_unhold_bss(bss_from_pub(bss));
- cfg80211_put_bss(wiphy, bss);
-}
-EXPORT_SYMBOL(cfg80211_assoc_timeout);
+ if (data->timeout) {
+ nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
+ cfg80211_sme_assoc_timeout(wdev);
+ } else {
+ cfg80211_sme_abandon_assoc(wdev);
+ }

-void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
+ for (i = 0; i < ARRAY_SIZE(data->bss); i++) {
+ struct cfg80211_bss *bss = data->bss[i];

- cfg80211_sme_abandon_assoc(wdev);
+ if (!bss)
+ continue;

- cfg80211_unhold_bss(bss_from_pub(bss));
- cfg80211_put_bss(wiphy, bss);
+ cfg80211_unhold_bss(bss_from_pub(bss));
+ cfg80211_put_bss(wiphy, bss);
+ }
}
-EXPORT_SYMBOL(cfg80211_abandon_assoc);
+EXPORT_SYMBOL(cfg80211_assoc_failure);

void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
bool reconnect)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 4316d3dc31ea..19efb9539533 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2969,9 +2969,22 @@ DEFINE_EVENT(netdev_mac_evt, cfg80211_send_auth_timeout,
TP_ARGS(netdev, mac)
);

-DEFINE_EVENT(netdev_mac_evt, cfg80211_send_assoc_timeout,
- TP_PROTO(struct net_device *netdev, const u8 *mac),
- TP_ARGS(netdev, mac)
+TRACE_EVENT(cfg80211_send_assoc_failure,
+ TP_PROTO(struct net_device *netdev,
+ struct cfg80211_assoc_failure *data),
+ TP_ARGS(netdev, data),
+ TP_STRUCT__entry(
+ NETDEV_ENTRY
+ MAC_ENTRY(ap_addr)
+ __field(bool, timeout)
+ ),
+ TP_fast_assign(
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(ap_addr, data->ap_mld_addr ?: data->bss[0]->bssid);
+ __entry->timeout = data->timeout;
+ ),
+ TP_printk(NETDEV_PR_FMT ", mac: " MAC_PR_FMT ", timeout: %d",
+ NETDEV_PR_ARG, MAC_PR_ARG(ap_addr), __entry->timeout)
);

TRACE_EVENT(cfg80211_michael_mic_failure,
--
2.36.1

2022-07-13 09:49:51

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 37/76] wifi: mac80211: mlme: use correct link_sta

From: Johannes Berg <[email protected]>

For station capabilities, e.g. TWT, we need to use the correct
link station instead of deflink. Switch the code to do that.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 46 ++++++++++++++++++++++++++++++---------------
1 file changed, 31 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fcd964e634d5..7870e3e23e26 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3395,7 +3395,7 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
}
}

-static bool ieee80211_twt_req_supported(const struct sta_info *sta,
+static bool ieee80211_twt_req_supported(const struct link_sta_info *link_sta,
const struct ieee802_11_elems *elems)
{
if (elems->ext_capab_len < 10)
@@ -3404,15 +3404,15 @@ static bool ieee80211_twt_req_supported(const struct sta_info *sta,
if (!(elems->ext_capab[9] & WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT))
return false;

- return sta->sta.deflink.he_cap.he_cap_elem.mac_cap_info[0] &
+ return link_sta->pub->he_cap.he_cap_elem.mac_cap_info[0] &
IEEE80211_HE_MAC_CAP0_TWT_RES;
}

static int ieee80211_recalc_twt_req(struct ieee80211_link_data *link,
- struct sta_info *sta,
+ struct link_sta_info *link_sta,
struct ieee802_11_elems *elems)
{
- bool twt = ieee80211_twt_req_supported(sta, elems);
+ bool twt = ieee80211_twt_req_supported(link_sta, elems);

if (link->conf->twt_requester != twt) {
link->conf->twt_requester = twt;
@@ -3424,14 +3424,14 @@ static int ieee80211_recalc_twt_req(struct ieee80211_link_data *link,
static bool ieee80211_twt_bcast_support(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *bss_conf,
struct ieee80211_supported_band *sband,
- struct sta_info *sta)
+ struct link_sta_info *link_sta)
{
const struct ieee80211_sta_he_cap *own_he_cap =
ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif));

return bss_conf->he_support &&
- (sta->sta.deflink.he_cap.he_cap_elem.mac_cap_info[2] &
+ (link_sta->pub->he_cap.he_cap_elem.mac_cap_info[2] &
IEEE80211_HE_MAC_CAP2_BCAST_TWT) &&
own_he_cap &&
(own_he_cap->he_cap_elem.mac_cap_info[2] &
@@ -3446,6 +3446,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
+ struct link_sta_info *link_sta;
struct sta_info *sta;
u16 capab_info, aid;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
@@ -3617,6 +3618,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

+ link_sta = rcu_dereference_protected(sta->link[link->link_id],
+ lockdep_is_held(&local->sta_mtx));
+ if (WARN_ON(!link_sta)) {
+ mutex_unlock(&sdata->local->sta_mtx);
+ ret = false;
+ goto out;
+ }
+
sband = ieee80211_get_link_sband(link);
if (!sband) {
mutex_unlock(&sdata->local->sta_mtx);
@@ -3637,12 +3646,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
if (elems->ht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
- &sta->deflink);
+ link_sta);

if (elems->vht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
elems->vht_cap_elem,
- &sta->deflink);
+ link_sta);

if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
elems->he_cap) {
@@ -3650,9 +3659,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
elems->he_cap,
elems->he_cap_len,
elems->he_6ghz_capa,
- &sta->deflink);
+ link_sta);

- bss_conf->he_support = sta->sta.deflink.he_cap.has_he;
+ bss_conf->he_support = link_sta->pub->he_cap.has_he;
if (elems->rsnx && elems->rsnx_len &&
(elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) &&
wiphy_ext_feature_isset(local->hw.wiphy,
@@ -3661,7 +3670,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
else
bss_conf->twt_protected = false;

- changed |= ieee80211_recalc_twt_req(link, sta, elems);
+ changed |= ieee80211_recalc_twt_req(link, link_sta, elems);

if (elems->eht_operation && elems->eht_cap &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
@@ -3684,7 +3693,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}

bss_conf->twt_broadcast =
- ieee80211_twt_bcast_support(sdata, bss_conf, sband, sta);
+ ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta);

if (bss_conf->he_support) {
bss_conf->he_bss_color.color =
@@ -3749,7 +3758,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
nss += 1;
- sta->sta.deflink.rx_nss = nss;
+ link_sta->pub->rx_nss = nss;
}

rate_control_rate_init(sta);
@@ -4190,6 +4199,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
+ struct link_sta_info *link_sta;
struct sta_info *sta;
u32 changed = 0;
bool erp_valid;
@@ -4431,8 +4441,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,

mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
+ if (WARN_ON(!sta))
+ goto free;
+ link_sta = rcu_dereference_protected(sta->link[link->link_id],
+ lockdep_is_held(&local->sta_mtx));
+ if (WARN_ON(!link_sta))
+ goto free;

- changed |= ieee80211_recalc_twt_req(link, sta, elems);
+ changed |= ieee80211_recalc_twt_req(link, link_sta, elems);

if (ieee80211_config_bw(link, elems->ht_cap_elem,
elems->vht_cap_elem, elems->ht_operation,
@@ -4454,7 +4470,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
}

if (sta && elems->opmode_notif)
- ieee80211_vht_handle_opmode(sdata, &sta->deflink,
+ ieee80211_vht_handle_opmode(sdata, link_sta,
*elems->opmode_notif,
rx_status->band);
mutex_unlock(&local->sta_mtx);
--
2.36.1

2022-07-13 09:49:53

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 13/76] wifi: nl80211: hold wdev mutex for station APIs

From: Johannes Berg <[email protected]>

Since this will need to refer - at least in part - to the link
stations of an MLD, hold the wdev mutex for driver convenience.

Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 59ea1157969e..9eee853efd57 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6976,7 +6976,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
}

/* driver will call cfg80211_check_station_change() */
+ wdev_lock(dev->ieee80211_ptr);
err = rdev_change_station(rdev, dev, mac_addr, &params);
+ wdev_unlock(dev->ieee80211_ptr);

out_put_vlan:
dev_put(params.vlan);
@@ -7232,7 +7234,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)

/* be aware of params.vlan when changing code here */

+ wdev_lock(dev->ieee80211_ptr);
err = rdev_add_station(rdev, dev, mac_addr, &params);
+ wdev_unlock(dev->ieee80211_ptr);

dev_put(params.vlan);
return err;
@@ -7243,6 +7247,7 @@ static int nl80211_del_station(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 station_del_parameters params;
+ int ret;

memset(&params, 0, sizeof(params));

@@ -7290,7 +7295,11 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
}

- return rdev_del_station(rdev, dev, &params);
+ wdev_lock(dev->ieee80211_ptr);
+ ret = rdev_del_station(rdev, dev, &params);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return ret;
}

static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
--
2.36.1

2022-07-13 09:49:57

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 12/76] wifi: nl80211: hold wdev mutex for channel switch APIs

From: Johannes Berg <[email protected]>

Since we deal with links in an MLD here, hold the wdev
mutex now.

Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 26d277c14fd4..59ea1157969e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3348,8 +3348,13 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
int link_id = nl80211_link_id_or_invalid(info->attrs);
struct net_device *netdev = info->user_ptr[1];
+ int ret;
+
+ wdev_lock(netdev->ieee80211_ptr);
+ ret = __nl80211_set_channel(rdev, netdev, info, link_id);
+ wdev_unlock(netdev->ieee80211_ptr);

- return __nl80211_set_channel(rdev, netdev, info, link_id);
+ return ret;
}

static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
@@ -3461,10 +3466,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
}

if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- result = __nl80211_set_channel(
- rdev,
- nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
- info, -1);
+ if (wdev) {
+ wdev_lock(wdev);
+ result = __nl80211_set_channel(
+ rdev,
+ nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
+ info, -1);
+ wdev_unlock(wdev);
+ } else {
+ result = __nl80211_set_channel(rdev, netdev, info, -1);
+ }
if (result)
goto out;
}
--
2.36.1

2022-07-13 09:49:58

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 20/76] wifi: mac80211: skip powersave recalc if driver SUPPORTS_DYNAMIC_PS

From: Johannes Berg <[email protected]>

There are a few places that check ps_sdata and/or the dynamic
PS timeout, but they're erroneous in case SUPPORTS_DYNAMIC_PS
is set by the driver.

Skip the entire recalculation in this case so we cannot get
into those paths elsewhere, and so we simplify this for the
purpose of implementing MLO.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 28bb7609cd4c..74676bbd6e23 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1818,7 +1818,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local)
int count = 0;
int timeout;

- if (!ieee80211_hw_check(&local->hw, SUPPORTS_PS)) {
+ if (!ieee80211_hw_check(&local->hw, SUPPORTS_PS) ||
+ ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS)) {
local->ps_sdata = NULL;
return;
}
--
2.36.1

2022-07-13 09:50:06

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 50/76] wifi: mac80211: remove redundant condition

From: Johannes Berg <[email protected]>

Here, ext_capa is checked and can only be non-NULL if
assoc_data->ie_len was set before, so the check here
is redundant.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d4a54375b9d2..fd8d7545a896 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -981,7 +981,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)

/* Set MBSSID support for HE AP if needed */
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
- !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && assoc_data->ie_len &&
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
ext_capa && ext_capa->datalen >= 3)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;

--
2.36.1

2022-07-13 09:50:12

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 73/76] wifi: nl80211: advertise MLO support

From: Johannes Berg <[email protected]>

At least while we don't have any more specific interface
combinations support, add a simple flag for MLO support,
we can keep this later based on something other than the
wiphy flag.

Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0bf1f7267b89..ead9bd111280 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2946,6 +2946,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
rdev->wiphy.max_num_akm_suites))
goto nla_put_failure;

+ if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO)
+ nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT);
+
/* done */
state->split_start = 0;
break;
--
2.36.1

2022-07-13 09:50:15

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 62/76] wifi: nl80211: set BSS to NULL if IS_ERR()

From: Johannes Berg <[email protected]>

If the BSS lookup returned an error, set it to NULL so we
don't try to free it.

Fixes: d648c23024bd ("wifi: nl80211: support MLO in auth/assoc")
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 35fb2b0517d9..b75398f0d5b4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10767,6 +10767,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
&bssid);
if (IS_ERR(req.links[link_id].bss)) {
err = PTR_ERR(req.links[link_id].bss);
+ req.links[link_id].bss = NULL;
goto free;
}

--
2.36.1

2022-07-13 09:50:15

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 52/76] wifi: mac80211: use only channel width in ieee80211_parse_bitrates()

From: Johannes Berg <[email protected]>

For MLO, we may not have a full chandef here later, so change
the API to pass only the width.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/cfg.c | 4 ++--
net/mac80211/ieee80211_i.h | 12 +++++++++---
net/mac80211/mlme.c | 3 ++-
net/mac80211/util.c | 6 +++---
4 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 555c135e9fcd..498dce37adad 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1633,7 +1633,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,

if (params->supported_rates &&
params->supported_rates_len) {
- ieee80211_parse_bitrates(&link->conf->chandef,
+ ieee80211_parse_bitrates(link->conf->chandef.width,
sband, params->supported_rates,
params->supported_rates_len,
&link_sta->pub->supp_rates[sband->band]);
@@ -2518,7 +2518,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
}

if (params->basic_rates) {
- ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
+ ieee80211_parse_bitrates(sdata->vif.bss_conf.chandef.width,
wiphy->bands[sband->band],
params->basic_rates,
params->basic_rates_len,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index dc38f57fcdc9..74d5fc5889bb 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1102,9 +1102,9 @@ sdata_assert_lock(struct ieee80211_sub_if_data *sdata)
}

static inline int
-ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef)
+ieee80211_chanwidth_get_shift(enum nl80211_chan_width width)
{
- switch (chandef->width) {
+ switch (width) {
case NL80211_CHAN_WIDTH_5:
return 2;
case NL80211_CHAN_WIDTH_10:
@@ -1114,6 +1114,12 @@ ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef)
}
}

+static inline int
+ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef)
+{
+ return ieee80211_chanwidth_get_shift(chandef->width);
+}
+
static inline int
ieee80211_vif_get_shift(struct ieee80211_vif *vif)
{
@@ -2346,7 +2352,7 @@ u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos,
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef);
-int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
+int ieee80211_parse_bitrates(enum nl80211_chan_width width,
const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates);
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fd8d7545a896..c65fe9f6f000 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -819,7 +819,8 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
* in the association request (e.g. D-Link DAP 1353 in
* b-only mode)...
*/
- rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband,
+ rates_len = ieee80211_parse_bitrates(chanctx_conf->def.width,
+ sband,
assoc_data->supp_rates,
assoc_data->supp_rates_len,
&rates);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 1de6b6256acc..86b6ee7e8156 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3686,12 +3686,12 @@ bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
return true;
}

-int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
+int ieee80211_parse_bitrates(enum nl80211_chan_width width,
const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates)
{
- u32 rate_flags = ieee80211_chandef_rate_flags(chandef);
- int shift = ieee80211_chandef_get_shift(chandef);
+ u32 rate_flags = ieee80211_chanwidth_rate_flags(width);
+ int shift = ieee80211_chanwidth_get_shift(width);
struct ieee80211_rate *br;
int brate, rate, i, j, count = 0;

--
2.36.1

2022-07-13 09:50:17

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

From: Johannes Berg <[email protected]>

When checking whether or not to accept a frame in RX,
take into account the configured link addresses. Also
look up the link station correctly.

Signed-off-by: Johannes Berg <[email protected]>
---
include/linux/ieee80211.h | 52 ++++++++++++++++-------
net/mac80211/ieee80211_i.h | 6 +++
net/mac80211/mlme.c | 32 ++++++++++++++
net/mac80211/rx.c | 63 ++++++++++++++++++++++++---
net/mac80211/util.c | 87 ++++++++++++++++++++++++--------------
5 files changed, 187 insertions(+), 53 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index f386f9ed41f3..e75c73ca11ec 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2046,25 +2046,38 @@ struct ieee80211_eht_cap_elem {
u8 optional[];
} __packed;

+#define IEEE80211_EHT_OPER_INFO_PRESENT 0x1
+#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x2
+
/**
* struct ieee80211_eht_operation - eht operation element
*
* This structure is the "EHT Operation Element" fields as
- * described in P802.11be_D1.4 section 9.4.2.311
+ * described in P802.11be_D1.5 section 9.4.2.311
*
- * FIXME: The spec is unclear how big the fields are, and doesn't
- * indicate the "Disabled Subchannel Bitmap Present" in the
- * structure (Figure 9-1002a) at all ...
+ * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_*
+ * @optional: optional parts
*/
struct ieee80211_eht_operation {
- u8 chan_width;
- u8 ccfs;
- u8 present_bm;
-
- u8 disable_subchannel_bitmap[];
+ u8 params;
+ u8 optional[];
} __packed;

-#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x1
+/**
+ * struct ieee80211_eht_operation_info - eht operation information
+ *
+ * @control: EHT operation information control.
+ * @ccfs0: defines a channel center frequency for a 20, 40, 80, 160, or 320 MHz
+ * EHT BSS.
+ * @ccfs1: defines a channel center frequency for a 160 or 320 MHz EHT BSS.
+ * @optional: optional parts
+ */
+struct ieee80211_eht_operation_info {
+ u8 control;
+ u8 ccfs0;
+ u8 ccfs1;
+ u8 optional[];
+} __packed;

/* 802.11ac VHT Capabilities */
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
@@ -2773,10 +2786,12 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 0x08
#define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT 0x10
#define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC 0x20
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_MASK 0xc0
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_3895 0
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_7991 1
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_11454 2
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK 0xc0
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895 0
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991 1
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454 2
+
+#define IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK 0x01

/* EHT PHY capabilities as defined in P802.11be_D1.4 section 9.4.2.313.3 */
#define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02
@@ -2949,8 +2964,13 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len)
if (len < needed)
return false;

- if (elem->present_bm & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
- needed += 2;
+ if (elem->params & IEEE80211_EHT_OPER_INFO_PRESENT) {
+ needed += 3;
+
+ if (elem->params &
+ IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
+ needed += 2;
+ }

return len >= needed;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f08060a36ef2..46413b6a8de3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -231,6 +231,8 @@ struct ieee80211_rx_data {
*/
int security_idx;

+ int link_id;
+
union {
struct {
u32 iv32;
@@ -2302,6 +2304,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
const struct ieee80211_vht_operation *oper,
const struct ieee80211_ht_operation *htop,
struct cfg80211_chan_def *chandef);
+void ieee80211_chandef_eht_oper(struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_eht_operation *eht_oper,
+ bool support_160, bool support_320,
+ struct cfg80211_chan_def *chandef);
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 01a72d1fcfcc..8980dfef1ff1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -303,6 +303,38 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,

*chandef = vht_chandef;

+ /*
+ * handle the case that the EHT operation indicates that it holds EHT
+ * operation information (in case that the channel width differs from
+ * the channel width reported in HT/VHT/HE).
+ */
+ if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
+ struct cfg80211_chan_def eht_chandef = *chandef;
+
+ ieee80211_chandef_eht_oper(sdata, eht_oper,
+ eht_chandef.width ==
+ NL80211_CHAN_WIDTH_160,
+ false, &eht_chandef);
+
+ if (!cfg80211_chandef_valid(&eht_chandef)) {
+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ sdata_info(sdata,
+ "AP EHT information is invalid, disabling EHT\n");
+ ret = IEEE80211_STA_DISABLE_EHT;
+ goto out;
+ }
+
+ if (!cfg80211_chandef_compatible(chandef, &eht_chandef)) {
+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ sdata_info(sdata,
+ "AP EHT information is incompatible, disabling EHT\n");
+ ret = IEEE80211_STA_DISABLE_EHT;
+ goto out;
+ }
+
+ *chandef = eht_chandef;
+ }
+
ret = 0;

out:
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 834d2171f344..2aa593294a29 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4028,6 +4028,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
/* This is OK -- must be QoS data frame */
.security_idx = tid,
.seqno_idx = tid,
+ .link_id = -1,
};
struct tid_ampdu_rx *tid_agg_rx;

@@ -4064,6 +4065,7 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
/* This is OK -- must be QoS data frame */
.security_idx = tid,
.seqno_idx = tid,
+ .link_id = -1,
};
int i, diff;

@@ -4140,6 +4142,31 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
is_broadcast_ether_addr(raddr);
}

+static bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr, int *out_link_id)
+{
+ unsigned int link_id;
+
+ /* non-MLO, or MLD address replaced by hardware */
+ if (ether_addr_equal(sdata->vif.addr, addr))
+ return true;
+
+ if (!sdata->vif.valid_links)
+ return false;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) {
+ if (!sdata->vif.link_conf[link_id])
+ continue;
+ if (ether_addr_equal(sdata->vif.link_conf[link_id]->addr, addr)) {
+ if (out_link_id)
+ *out_link_id = link_id;
+ return true;
+ }
+ }
+
+ return false;
+}
+
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
@@ -4158,7 +4185,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
if (multicast)
return true;
- return ether_addr_equal(sdata->vif.addr, hdr->addr1);
+ return ieee80211_is_our_addr(sdata, hdr->addr1, &rx->link_id);
case NL80211_IFTYPE_ADHOC:
if (!bssid)
return false;
@@ -4212,9 +4239,11 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_AP:
if (!bssid)
- return ether_addr_equal(sdata->vif.addr, hdr->addr1);
+ return ieee80211_is_our_addr(sdata, hdr->addr1,
+ &rx->link_id);

- if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
+ if (!is_broadcast_ether_addr(bssid) &&
+ !ieee80211_is_our_addr(sdata, bssid, NULL)) {
/*
* Accept public action frames even when the
* BSSID doesn't match, this is used for P2P
@@ -4222,7 +4251,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
* itself never looks at these frames.
*/
if (!multicast &&
- !ether_addr_equal(sdata->vif.addr, hdr->addr1))
+ !ieee80211_is_our_addr(sdata, hdr->addr1,
+ &rx->link_id))
return false;
if (ieee80211_is_public_action(hdr, skb->len))
return true;
@@ -4740,6 +4770,7 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
rx.skb = skb;
rx.local = local;
rx.list = list;
+ rx.link_id = -1;

I802_DEBUG_INC(local->dot11ReceivedFragmentCount);

@@ -4779,6 +4810,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
__le16 fc;
struct ieee80211_rx_data rx;
struct ieee80211_sub_if_data *prev;
+ struct link_sta_info *link_sta;
struct rhlist_head *tmp;
int err = 0;

@@ -4787,6 +4819,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
rx.skb = skb;
rx.local = local;
rx.list = list;
+ rx.link_id = -1;

if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
@@ -4872,7 +4905,19 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
}

- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ /*
+ * Look up link station first, in case there's a
+ * chance that they might have a link address that
+ * is identical to the MLD address, that way we'll
+ * have the link information if needed.
+ */
+ link_sta = link_sta_info_get_bss(prev, hdr->addr2);
+ if (link_sta) {
+ rx.sta = link_sta->sta;
+ rx.link_id = link_sta->link_id;
+ } else {
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ }
rx.sdata = prev;
ieee80211_prepare_and_rx_handle(&rx, skb, false);

@@ -4880,7 +4925,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}

if (prev) {
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ link_sta = link_sta_info_get_bss(prev, hdr->addr2);
+ if (link_sta) {
+ rx.sta = link_sta->sta;
+ rx.link_id = link_sta->link_id;
+ } else {
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ }
rx.sdata = prev;

if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index bcb4aa7d7599..7b39e464fb1e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3448,6 +3448,58 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
return true;
}

+void ieee80211_chandef_eht_oper(struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_eht_operation *eht_oper,
+ bool support_160, bool support_320,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ieee80211_eht_operation_info *info = (void *)eht_oper->optional;
+
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(info->ccfs0,
+ chandef->chan->band);
+
+ switch (u8_get_bits(info->control,
+ IEEE80211_EHT_OPER_CHAN_WIDTH)) {
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_20;
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
+ if (support_160) {
+ chandef->width = NL80211_CHAN_WIDTH_160;
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(info->ccfs1,
+ chandef->chan->band);
+ } else {
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ }
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
+ if (support_320) {
+ chandef->width = NL80211_CHAN_WIDTH_320;
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(info->ccfs1,
+ chandef->chan->band);
+ } else if (support_160) {
+ chandef->width = NL80211_CHAN_WIDTH_160;
+ } else {
+ chandef->width = NL80211_CHAN_WIDTH_80;
+
+ if (chandef->center_freq1 > chandef->chan->center_freq)
+ chandef->center_freq1 -= 40;
+ else
+ chandef->center_freq1 += 40;
+ }
+ break;
+ }
+}
+
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper,
@@ -3528,7 +3580,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
break;
}

- if (!eht_oper) {
+ if (!eht_oper ||
+ !(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
@@ -3572,36 +3625,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
support_320 =
eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;

- switch (u8_get_bits(eht_oper->chan_width,
- IEEE80211_EHT_OPER_CHAN_WIDTH)) {
- case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
- he_chandef.width = NL80211_CHAN_WIDTH_20;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
- he_chandef.width = NL80211_CHAN_WIDTH_40;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
- he_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
- if (support_160)
- he_chandef.width = NL80211_CHAN_WIDTH_160;
- else
- he_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
- if (support_320)
- he_chandef.width = NL80211_CHAN_WIDTH_320;
- else if (support_160)
- he_chandef.width = NL80211_CHAN_WIDTH_160;
- else
- he_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- }
-
- he_chandef.center_freq1 =
- ieee80211_channel_to_frequency(eht_oper->ccfs,
- NL80211_BAND_6GHZ);
+ ieee80211_chandef_eht_oper(sdata, eht_oper, support_160,
+ support_320, &he_chandef);
}

if (!cfg80211_chandef_valid(&he_chandef)) {
--
2.36.1

2022-07-13 09:50:19

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 07/76] wifi: mac80211: add an ieee80211_get_link_sband

From: Shaul Triebitz <[email protected]>

Similar to ieee80211_get_sband but get the sband of the link_conf.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 18bab27eda4f..a0023ad7ca1c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1543,6 +1543,28 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
return local->hw.wiphy->bands[band];
}

+static inline struct ieee80211_supported_band *
+ieee80211_get_link_sband(struct ieee80211_sub_if_data *sdata, u32 link_id)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ enum nl80211_band band;
+
+ rcu_read_lock();
+ chanctx_conf =
+ rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf);
+
+ if (!chanctx_conf) {
+ rcu_read_unlock();
+ return NULL;
+ }
+
+ band = chanctx_conf->def.chan->band;
+ rcu_read_unlock();
+
+ return local->hw.wiphy->bands[band];
+}
+
/* this struct holds the value parsing from channel switch IE */
struct ieee80211_csa_ie {
struct cfg80211_chan_def chandef;
--
2.36.1

2022-07-13 09:50:20

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 65/76] wifi: nl80211: check MLO support in authenticate

From: Johannes Berg <[email protected]>

We should check that MLO connections are supported before
attempting to authenticate with MLO parameters, check that.

Fixes: d648c23024bd ("wifi: nl80211: support MLO in auth/assoc")
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b75398f0d5b4..ee3826e8e52b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10410,6 +10410,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
req.key_idx = key.idx;
req.link_id = nl80211_link_id_or_invalid(info->attrs);
if (req.link_id >= 0) {
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO))
+ return -EINVAL;
if (!info->attrs[NL80211_ATTR_MLD_ADDR])
return -EINVAL;
req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
--
2.36.1

2022-07-13 09:50:26

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 28/76] wifi: mac80211: expect powersave handling in driver for MLO

From: Johannes Berg <[email protected]>

In MLO, expect the driver fully handles powersave handling,
including tracking whether or not a beacon was received,
the DTIM period, etc.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/main.c | 3 ++-
net/mac80211/mlme.c | 4 +++-
2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 1258e506377e..8d5b18318b20 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -984,7 +984,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
return -EINVAL;

if (WARN_ON(ieee80211_hw_check(hw, SUPPORTS_PS) &&
- !ieee80211_hw_check(hw, SUPPORTS_DYNAMIC_PS)))
+ (!ieee80211_hw_check(hw, SUPPORTS_DYNAMIC_PS) ||
+ ieee80211_hw_check(hw, PS_NULLFUNC_STACK))))
return -EINVAL;

if (WARN_ON(!ieee80211_hw_check(hw, MFP_CAPABLE)))
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1035d6d433b1..7b9211d16193 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1785,6 +1785,7 @@ static void ieee80211_change_ps(struct ieee80211_local *local)

static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
{
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *mgd = &sdata->u.mgd;
struct sta_info *sta = NULL;
bool authorized = false;
@@ -1801,7 +1802,8 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
if (mgd->flags & IEEE80211_STA_CONNECTION_POLL)
return false;

- if (!sdata->deflink.u.mgd.have_beacon)
+ if (!(local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) &&
+ !sdata->deflink.u.mgd.have_beacon)
return false;

rcu_read_lock();
--
2.36.1

2022-07-13 09:50:29

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 21/76] wifi: mac80211: separate out connection downgrade flags

From: Johannes Berg <[email protected]>

Separate out the connection downgrade flags from the ifmgd->flags
and put them into the link information instead. While at it, make
them a separate sparse type so we don't get confused about where
they belong and have static checking on correct handling.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ibss.c | 13 +-
net/mac80211/ieee80211_i.h | 38 +++--
net/mac80211/mesh.c | 12 +-
net/mac80211/mlme.c | 314 +++++++++++++++++++------------------
net/mac80211/spectmgmt.c | 16 +-
net/mac80211/tdls.c | 3 +-
net/mac80211/util.c | 34 ++--
7 files changed, 221 insertions(+), 209 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 393c7595bfa4..561abcf4def9 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -770,20 +770,21 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
enum nl80211_channel_type ch_type;
int err;
- u32 sta_flags;
+ ieee80211_conn_flags_t conn_flags;
u32 vht_cap_info = 0;

sdata_assert_lock(sdata);

- sta_flags = IEEE80211_STA_DISABLE_VHT;
+ conn_flags = IEEE80211_CONN_DISABLE_VHT;
+
switch (ifibss->chandef.width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20_NOHT:
- sta_flags |= IEEE80211_STA_DISABLE_HT;
+ conn_flags |= IEEE80211_CONN_DISABLE_HT;
fallthrough;
case NL80211_CHAN_WIDTH_20:
- sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+ conn_flags |= IEEE80211_CONN_DISABLE_40MHZ;
break;
default:
break;
@@ -796,7 +797,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
err = ieee80211_parse_ch_switch_ie(sdata, elems,
ifibss->chandef.chan->band,
vht_cap_info,
- sta_flags, ifibss->bssid, &csa_ie);
+ conn_flags, ifibss->bssid, &csa_ie);
/* can't switch to destination channel, fail */
if (err < 0)
goto disconnect;
@@ -839,7 +840,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
break;
default:
- /* should not happen, sta_flags should prevent VHT modes. */
+ /* should not happen, conn_flags should prevent VHT modes. */
WARN_ON(1);
goto disconnect;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index aa1e438ee61e..154ff50e99a0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -358,20 +358,25 @@ struct ieee80211_roc_work {
enum ieee80211_sta_flags {
IEEE80211_STA_CONNECTION_POLL = BIT(1),
IEEE80211_STA_CONTROL_PORT = BIT(2),
- IEEE80211_STA_DISABLE_HT = BIT(4),
IEEE80211_STA_MFP_ENABLED = BIT(6),
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9),
- IEEE80211_STA_DISABLE_40MHZ = BIT(10),
- IEEE80211_STA_DISABLE_VHT = BIT(11),
- IEEE80211_STA_DISABLE_80P80MHZ = BIT(12),
- IEEE80211_STA_DISABLE_160MHZ = BIT(13),
IEEE80211_STA_DISABLE_WMM = BIT(14),
IEEE80211_STA_ENABLE_RRM = BIT(15),
- IEEE80211_STA_DISABLE_HE = BIT(16),
- IEEE80211_STA_DISABLE_EHT = BIT(17),
- IEEE80211_STA_DISABLE_320MHZ = BIT(18),
+};
+
+typedef u32 __bitwise ieee80211_conn_flags_t;
+
+enum ieee80211_conn_flags {
+ IEEE80211_CONN_DISABLE_HT = (__force ieee80211_conn_flags_t)BIT(0),
+ IEEE80211_CONN_DISABLE_40MHZ = (__force ieee80211_conn_flags_t)BIT(1),
+ IEEE80211_CONN_DISABLE_VHT = (__force ieee80211_conn_flags_t)BIT(2),
+ IEEE80211_CONN_DISABLE_80P80MHZ = (__force ieee80211_conn_flags_t)BIT(3),
+ IEEE80211_CONN_DISABLE_160MHZ = (__force ieee80211_conn_flags_t)BIT(4),
+ IEEE80211_CONN_DISABLE_HE = (__force ieee80211_conn_flags_t)BIT(5),
+ IEEE80211_CONN_DISABLE_EHT = (__force ieee80211_conn_flags_t)BIT(6),
+ IEEE80211_CONN_DISABLE_320MHZ = (__force ieee80211_conn_flags_t)BIT(7),
};

struct ieee80211_mgd_auth_data {
@@ -875,6 +880,8 @@ struct ieee80211_link_data_managed {
enum ieee80211_smps_mode req_smps, /* requested smps mode */
driver_smps_mode; /* smps mode request */

+ ieee80211_conn_flags_t conn_flags;
+
s16 p2p_noa_index;

bool have_beacon;
@@ -2051,12 +2058,9 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
* @elems: parsed 802.11 elements received with the frame
* @current_band: indicates the current band
* @vht_cap_info: VHT capabilities of the transmitter
- * @sta_flags: contains information about own capabilities and restrictions
- * to decide which channel switch announcements can be accepted. Only the
- * following subset of &enum ieee80211_sta_flags are evaluated:
- * %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
- * %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
- * %IEEE80211_STA_DISABLE_160MHZ.
+ * @conn_flags: contains information about own capabilities and restrictions
+ * to decide which channel switch announcements can be accepted, using
+ * flags from &enum ieee80211_conn_flags.
* @bssid: the currently connected bssid (for reporting)
* @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl.
All of them will be filled with if success only.
@@ -2066,7 +2070,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum nl80211_band current_band,
u32 vht_cap_info,
- u32 sta_flags, u8 *bssid,
+ ieee80211_conn_flags_t conn_flags, u8 *bssid,
struct ieee80211_csa_ie *csa_ie);

/* Suspend/resume and hw reconfiguration */
@@ -2297,7 +2301,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
const struct cfg80211_chan_def *chandef);
u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
-u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
+u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos,
const struct ieee80211_sta_he_cap *he_cap,
u8 *end);
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
@@ -2336,7 +2340,7 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def *chandef);
bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
struct cfg80211_chan_def *chandef);
-u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
+ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);

int __must_check
ieee80211_link_use_channel(struct ieee80211_link_data *link,
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index ba4e0921fa5d..b656cb647763 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1129,7 +1129,8 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_supported_band *sband;
int err;
- u32 sta_flags, vht_cap_info = 0;
+ ieee80211_conn_flags_t conn_flags = 0;
+ u32 vht_cap_info = 0;

sdata_assert_lock(sdata);

@@ -1137,16 +1138,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
if (!sband)
return false;

- sta_flags = 0;
switch (sdata->vif.bss_conf.chandef.width) {
case NL80211_CHAN_WIDTH_20_NOHT:
- sta_flags |= IEEE80211_STA_DISABLE_HT;
+ conn_flags |= IEEE80211_CONN_DISABLE_HT;
fallthrough;
case NL80211_CHAN_WIDTH_20:
- sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+ conn_flags |= IEEE80211_CONN_DISABLE_40MHZ;
fallthrough;
case NL80211_CHAN_WIDTH_40:
- sta_flags |= IEEE80211_STA_DISABLE_VHT;
+ conn_flags |= IEEE80211_CONN_DISABLE_VHT;
break;
default:
break;
@@ -1159,7 +1159,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
memset(&params, 0, sizeof(params));
err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band,
vht_cap_info,
- sta_flags, sdata->vif.addr,
+ conn_flags, sdata->vif.addr,
&csa_ie);
if (err < 0)
return false;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 74676bbd6e23..5a208a01e278 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -142,7 +142,7 @@ static int ecw2cw(int ecw)
return (1 << ecw) - 1;
}

-static u32
+static ieee80211_conn_flags_t
ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
@@ -154,10 +154,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_s1g_oper_ie *s1g_oper,
struct cfg80211_chan_def *chandef, bool tracking)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct cfg80211_chan_def vht_chandef;
struct ieee80211_sta_ht_cap sta_ht_cap;
- u32 ht_cfreq, ret;
+ ieee80211_conn_flags_t ret;
+ u32 ht_cfreq;

memset(chandef, 0, sizeof(struct cfg80211_chan_def));
chandef->chan = channel;
@@ -170,10 +170,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef)) {
mlme_dbg(sdata,
"bad 6 GHz operation, disabling HT/VHT/HE/EHT\n");
- ret = IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_HT |
+ IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
} else {
ret = 0;
}
@@ -186,10 +186,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef->width = ieee80211_s1g_channel_width(channel);
}

- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_40MHZ |
- IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ;
+ ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_40MHZ |
+ IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_80P80MHZ |
+ IEEE80211_CONN_DISABLE_160MHZ;
goto out;
}

@@ -198,10 +198,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,

if (!ht_oper || !sta_ht_cap.ht_supported) {
mlme_dbg(sdata, "HT operation missing / HT not supported\n");
- ret = IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_HT |
+ IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
goto out;
}

@@ -222,10 +222,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
"Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
channel->center_freq, ht_cfreq,
ht_oper->primary_chan, channel->band);
- ret = IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_HT |
+ IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
goto out;
}

@@ -235,20 +235,21 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
} else {
mlme_dbg(sdata, "40 MHz not supported\n");
/* 40 MHz (and 80 MHz) must be supported for VHT */
- ret = IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_VHT;
/* also mark 40 MHz disabled */
- ret |= IEEE80211_STA_DISABLE_40MHZ;
+ ret |= IEEE80211_CONN_DISABLE_40MHZ;
goto out;
}

if (!vht_oper || !sband->vht_cap.vht_supported) {
mlme_dbg(sdata, "VHT operation missing / VHT not supported\n");
- ret = IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_VHT;
goto out;
}

vht_chandef = *chandef;
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && he_oper &&
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
+ he_oper &&
(le32_to_cpu(he_oper->he_oper_params) &
IEEE80211_HE_OPERATION_VHT_OPER_INFO)) {
struct ieee80211_vht_operation he_oper_vht_cap;
@@ -263,28 +264,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
&he_oper_vht_cap, ht_oper,
&vht_chandef)) {
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE))
sdata_info(sdata,
"HE AP VHT information is invalid, disabling HE\n");
- ret = IEEE80211_STA_DISABLE_HE | IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT;
goto out;
}
} else if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
vht_cap_info,
vht_oper, ht_oper,
&vht_chandef)) {
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disabling VHT\n");
- ret = IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_VHT;
goto out;
}

if (!cfg80211_chandef_valid(&vht_chandef)) {
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disabling VHT\n");
- ret = IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_VHT;
goto out;
}

@@ -294,10 +295,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}

if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information doesn't match HT, disabling VHT\n");
- ret = IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_VHT;
goto out;
}

@@ -317,18 +318,18 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
false, &eht_chandef);

if (!cfg80211_chandef_valid(&eht_chandef)) {
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
sdata_info(sdata,
"AP EHT information is invalid, disabling EHT\n");
- ret = IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_EHT;
goto out;
}

if (!cfg80211_chandef_compatible(chandef, &eht_chandef)) {
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
sdata_info(sdata,
"AP EHT information is incompatible, disabling EHT\n");
- ret = IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_EHT;
goto out;
}

@@ -361,7 +362,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
return ret;

/* don't print the message below for VHT mismatch if VHT is disabled */
- if (ret & IEEE80211_STA_DISABLE_VHT)
+ if (ret & IEEE80211_CONN_DISABLE_VHT)
vht_chandef = *chandef;

/*
@@ -376,10 +377,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
tracking ? 0 :
IEEE80211_CHAN_DISABLED)) {
if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
- ret = IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ ret = IEEE80211_CONN_DISABLE_HT |
+ IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
break;
}

@@ -388,11 +389,11 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,

if (!he_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef,
IEEE80211_CHAN_NO_HE))
- ret |= IEEE80211_STA_DISABLE_HE | IEEE80211_STA_DISABLE_EHT;
+ ret |= IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT;

if (!eht_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef,
IEEE80211_CHAN_NO_EHT))
- ret |= IEEE80211_STA_DISABLE_EHT;
+ ret |= IEEE80211_CONN_DISABLE_EHT;

if (chandef->width != vht_chandef.width && !tracking)
sdata_info(sdata,
@@ -420,20 +421,20 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
local->hw.wiphy->bands[chan->band];
struct cfg80211_chan_def chandef;
u16 ht_opmode;
- u32 flags;
+ ieee80211_conn_flags_t flags;
u32 vht_cap_info = 0;
int ret;

/* if HT was/is disabled, don't track any bandwidth changes */
- if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || !ht_oper)
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || !ht_oper)
return 0;

/* don't check VHT if we associated as non-VHT station */
- if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
vht_oper = NULL;

/* don't check HE if we associated as non-HE station */
- if (ifmgd->flags & IEEE80211_STA_DISABLE_HE ||
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE ||
!ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif))) {
he_oper = NULL;
@@ -441,7 +442,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
}

/* don't check EHT if we associated as non-EHT station */
- if (ifmgd->flags & IEEE80211_STA_DISABLE_EHT ||
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT ||
!ieee80211_get_eht_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif)))
eht_oper = NULL;
@@ -475,13 +476,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
* reasons) then switching to a 40 MHz channel now won't do us
* any good -- we couldn't use it with the AP.
*/
- if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ &&
chandef.width == NL80211_CHAN_WIDTH_80P80)
flags |= ieee80211_chandef_downgrade(&chandef);
- if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ &&
chandef.width == NL80211_CHAN_WIDTH_160)
flags |= ieee80211_chandef_downgrade(&chandef);
- if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ &&
chandef.width > NL80211_CHAN_WIDTH_20)
flags |= ieee80211_chandef_downgrade(&chandef);

@@ -496,14 +497,15 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
chandef.center_freq1, chandef.freq1_offset,
chandef.center_freq2);

- if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT |
- IEEE80211_STA_DISABLE_40MHZ |
- IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ |
- IEEE80211_STA_DISABLE_320MHZ)) ||
+ if (flags != (sdata->deflink.u.mgd.conn_flags &
+ (IEEE80211_CONN_DISABLE_HT |
+ IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT |
+ IEEE80211_CONN_DISABLE_40MHZ |
+ IEEE80211_CONN_DISABLE_80P80MHZ |
+ IEEE80211_CONN_DISABLE_160MHZ |
+ IEEE80211_CONN_DISABLE_320MHZ)) ||
!cfg80211_chandef_valid(&chandef)) {
sdata_info(sdata,
"AP %pM changed caps/bw in a way we can't support (0x%x/0x%x) - disconnect\n",
@@ -564,7 +566,7 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
* capable of 40 MHz -- some broken APs will never fall
* back to trying to transmit in 20 MHz.
*/
- if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) {
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
@@ -618,7 +620,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
/* determine capability flags */
cap = vht_cap.cap;

- if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) {
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ) {
u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;

cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
@@ -627,7 +629,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
}

- if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) {
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ) {
cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
}
@@ -717,7 +719,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
he_cap->he_cap_elem.phy_cap_info);
pos = skb_put(skb, he_cap_size);
pre_he_pos = pos;
- pos = ieee80211_ie_build_he_cap(sdata->u.mgd.flags,
+ pos = ieee80211_ie_build_he_cap(sdata->deflink.u.mgd.conn_flags,
pos, he_cap, pos + he_cap_size);
/* trim excess if any */
skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
@@ -977,7 +979,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)

/* Set MBSSID support for HE AP if needed */
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len &&
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && assoc_data->ie_len &&
ext_capa && ext_capa->datalen >= 3)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;

@@ -1022,12 +1024,12 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
offset = noffset;
}

- if (WARN_ON_ONCE((ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)))
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+ if (WARN_ON_ONCE((sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)))
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;

if (sband->band != NL80211_BAND_6GHZ &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
sband, chan, sdata->deflink.smps_mode);

@@ -1082,7 +1084,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}

if (sband->band != NL80211_BAND_6GHZ &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
ieee80211_add_vht_ie(sdata, skb, sband,
&assoc_data->ap_vht_cap);

@@ -1090,16 +1092,16 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
* If AP doesn't support HT, mark HE and EHT as disabled.
* If on the 5GHz band, make sure it supports VHT.
*/
- if (ifmgd->flags & IEEE80211_STA_DISABLE_HT ||
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT ||
(sband->band == NL80211_BAND_5GHZ &&
- ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) {
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
ieee80211_add_he_ie(sdata, skb, sband);

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
ieee80211_add_eht_ie(sdata, skb, sband);
}

@@ -1430,7 +1432,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
bss = (void *)cbss->priv;
res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band,
bss->vht_cap_info,
- ifmgd->flags,
+ sdata->deflink.u.mgd.conn_flags,
sdata->deflink.u.mgd.bssid, &csa_ie);

if (!res) {
@@ -2517,6 +2519,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sdata->deflink.u.mgd.have_beacon = false;

ifmgd->flags = 0;
+ sdata->deflink.u.mgd.conn_flags = 0;
mutex_lock(&local->mtx);
ieee80211_link_release_channel(&sdata->deflink);

@@ -2958,6 +2961,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
+ sdata->deflink.u.mgd.conn_flags = 0;
mutex_lock(&sdata->local->mtx);
ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&sdata->local->mtx);
@@ -2988,6 +2992,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
+ sdata->deflink.u.mgd.conn_flags = 0;
sdata->vif.bss_conf.mu_mimo_owner = false;

mutex_lock(&sdata->local->mtx);
@@ -3479,9 +3484,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
*/
if (!is_6ghz &&
((assoc_data->wmm && !elems->wmm_param) ||
- (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
+ (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
(!elems->ht_cap_elem || !elems->ht_operation)) ||
- (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
+ (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
(!elems->vht_cap_elem || !elems->vht_operation)))) {
const struct cfg80211_bss_ies *ies;
struct ieee802_11_elems *bss_elems;
@@ -3517,25 +3522,25 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
* have to include the IEs in the (re)association response.
*/
if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
elems->ht_cap_elem = bss_elems->ht_cap_elem;
sdata_info(sdata,
"AP bug: HT capability missing from AssocResp\n");
}
if (!elems->ht_operation && bss_elems->ht_operation &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
elems->ht_operation = bss_elems->ht_operation;
sdata_info(sdata,
"AP bug: HT operation missing from AssocResp\n");
}
if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
elems->vht_cap_elem = bss_elems->vht_cap_elem;
sdata_info(sdata,
"AP bug: VHT capa missing from AssocResp\n");
}
if (!elems->vht_operation && bss_elems->vht_operation &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
elems->vht_operation = bss_elems->vht_operation;
sdata_info(sdata,
"AP bug: VHT operation missing from AssocResp\n");
@@ -3548,7 +3553,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
* We previously checked these in the beacon/probe response, so
* they should be present here. This is just a safety net.
*/
- if (!is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
+ if (!is_6ghz && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
(!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) {
sdata_info(sdata,
"HT AP is missing WMM params or HT capability/operation\n");
@@ -3556,7 +3561,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- if (!is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
+ if (!is_6ghz && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
(!elems->vht_cap_elem || !elems->vht_operation)) {
sdata_info(sdata,
"VHT AP is missing VHT capability/operation\n");
@@ -3564,7 +3569,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- if (is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
+ if (is_6ghz && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
!elems->he_6ghz_capa) {
sdata_info(sdata,
"HE 6 GHz AP is missing HE 6 GHz band capability\n");
@@ -3591,7 +3596,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
(!elems->he_cap || !elems->he_operation)) {
mutex_unlock(&sdata->local->sta_mtx);
sdata_info(sdata,
@@ -3601,17 +3606,17 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}

/* Set up internal HT/VHT capabilities */
- if (elems->ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
+ if (elems->ht_cap_elem && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
&sta->deflink);

- if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ if (elems->vht_cap_elem && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
elems->vht_cap_elem,
&sta->deflink);

- if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
+ if (elems->he_operation && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
elems->he_cap) {
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
elems->he_cap,
@@ -3631,7 +3636,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
changed |= ieee80211_recalc_twt_req(sdata, sta, elems);

if (elems->eht_operation && elems->eht_cap &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_EHT)) {
+ !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
elems->he_cap,
elems->he_cap_len,
@@ -5040,6 +5045,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd->uapsd_queues = sdata->local->hw.uapsd_queues;
ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
sdata->deflink.u.mgd.p2p_noa_index = -1;
+ sdata->deflink.u.mgd.conn_flags = 0;

if (sdata->local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
sdata->deflink.u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC;
@@ -5070,7 +5076,6 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *cbss)
{
struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
const struct element *ht_cap_elem, *vht_cap_elem;
const struct cfg80211_bss_ies *ies;
const struct ieee80211_ht_cap *ht_cap;
@@ -5082,7 +5087,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
bool support_160;
u8 chains = 1;

- if (ifmgd->flags & IEEE80211_STA_DISABLE_HT)
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)
return chains;

ht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_CAPABILITY);
@@ -5095,7 +5100,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
*/
}

- if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
return chains;

vht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY);
@@ -5114,7 +5119,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
chains = max(chains, nss);
}

- if (ifmgd->flags & IEEE80211_STA_DISABLE_HE)
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)
return chains;

ies = rcu_dereference(cbss->ies);
@@ -5339,7 +5344,6 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *cbss)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
const struct ieee80211_ht_cap *ht_cap = NULL;
const struct ieee80211_ht_operation *ht_oper = NULL;
const struct ieee80211_vht_operation *vht_oper = NULL;
@@ -5369,70 +5373,70 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,

sband = local->hw.wiphy->bands[cbss->channel->band];

- ifmgd->flags &= ~(IEEE80211_STA_DISABLE_40MHZ |
- IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ);
+ sdata->deflink.u.mgd.conn_flags &= ~(IEEE80211_CONN_DISABLE_40MHZ |
+ IEEE80211_CONN_DISABLE_80P80MHZ |
+ IEEE80211_CONN_DISABLE_160MHZ);

/* disable HT/VHT/HE if we don't support them */
if (!sband->ht_cap.ht_supported && !is_6ghz) {
mlme_dbg(sdata, "HT not supported, disabling HT/VHT/HE/EHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!sband->vht_cap.vht_supported && is_5ghz) {
mlme_dbg(sdata, "VHT not supported, disabling VHT/HE/EHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif))) {
mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!ieee80211_get_eht_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif))) {
mlme_dbg(sdata, "EHT not supported, disabling EHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && !is_6ghz) {
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) {
ht_oper = elems->ht_operation;
ht_cap = elems->ht_cap_elem;

if (!ht_cap) {
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
ht_oper = NULL;
}
}

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && !is_6ghz) {
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && !is_6ghz) {
vht_oper = elems->vht_operation;
if (vht_oper && !ht_oper) {
vht_oper = NULL;
sdata_info(sdata,
"AP advertised VHT without HT, disabling HT/VHT/HE\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!elems->vht_cap_elem) {
sdata_info(sdata,
"bad VHT capabilities, disabling VHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
vht_oper = NULL;
}
}

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) {
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
he_oper = elems->he_operation;

if (is_6ghz) {
@@ -5461,8 +5465,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,

if (!ieee80211_verify_peer_he_mcs_support(sdata, ies, he_oper) ||
!ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper))
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
}

/*
@@ -5471,8 +5475,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
* both the 6 GHz operation information (from the HE operation IE) and
* EHT operation.
*/
- if (!(ifmgd->flags & (IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT)) && he_oper) {
+ if (!(sdata->deflink.u.mgd.conn_flags &
+ (IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT)) &&
+ he_oper) {
const struct cfg80211_bss_ies *ies;
const u8 *eht_oper_ie;

@@ -5499,7 +5505,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,

if (!have_80mhz) {
sdata_info(sdata, "80 MHz not supported, disabling VHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
}

if (sband->band == NL80211_BAND_S1GHZ) {
@@ -5509,13 +5515,14 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
"AP missing S1G operation element?\n");
}

- ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
- cbss->channel,
- bss->vht_cap_info,
- ht_oper, vht_oper,
- he_oper, eht_oper,
- s1g_oper,
- &chandef, false);
+ sdata->deflink.u.mgd.conn_flags |=
+ ieee80211_determine_chantype(sdata, sband,
+ cbss->channel,
+ bss->vht_cap_info,
+ ht_oper, vht_oper,
+ he_oper, eht_oper,
+ s1g_oper,
+ &chandef, false);

sdata->deflink.needed_rx_chains =
min(ieee80211_max_rx_chains(sdata, cbss), local->rx_chains);
@@ -5525,7 +5532,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
kfree(elems);
elems = NULL;

- if (ifmgd->flags & IEEE80211_STA_DISABLE_HE && is_6ghz) {
+ if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) {
sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection");
return -EINVAL;
}
@@ -5548,7 +5555,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
goto out;

while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
- ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
+ sdata->deflink.u.mgd.conn_flags |=
+ ieee80211_chandef_downgrade(&chandef);
ret = ieee80211_link_use_channel(&sdata->deflink, &chandef,
IEEE80211_CHANCTX_SHARED);
}
@@ -6004,10 +6012,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
netdev_info(sdata->dev,
"disabling HT/VHT/HE due to WEP/TKIP use\n");
}
@@ -6017,10 +6025,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,

/* also disable HT/VHT/HE/EHT if the AP doesn't use WMM */
if (!bss->wmm_used) {
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
netdev_info(sdata->dev,
"disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n");
}
@@ -6068,7 +6076,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
assoc_data->ap_ht_param =
((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param;
else if (!is_6ghz)
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
vht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_VHT_CAPABILITY);
if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) {
memcpy(&assoc_data->ap_vht_cap, vht_elem->data,
@@ -6076,9 +6084,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
} else if (is_5ghz) {
sdata_info(sdata,
"VHT capa missing/short, disabling VHT/HE/EHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT |
- IEEE80211_STA_DISABLE_HE |
- IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT |
+ IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
}
rcu_read_unlock();

@@ -6130,7 +6138,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
sdata->deflink.u.mgd.have_beacon = false;

/* override HT/VHT configuration only if the AP and we support it */
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
struct ieee80211_sta_ht_cap sta_ht_cap;

if (req->flags & ASSOC_REQ_DISABLE_HT)
@@ -6140,37 +6148,37 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);

/* check for 40 MHz disable override */
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ) &&
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) &&
sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
!(sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
override = true;

- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
req->flags & ASSOC_REQ_DISABLE_VHT)
override = true;
}

if (req->flags & ASSOC_REQ_DISABLE_HT) {
mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (req->flags & ASSOC_REQ_DISABLE_VHT) {
mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
}

if (req->flags & ASSOC_REQ_DISABLE_HE) {
mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n");
- ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (req->flags & ASSOC_REQ_DISABLE_EHT)
- ifmgd->flags |= IEEE80211_STA_DISABLE_EHT;
+ sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;

err = ieee80211_prep_connection(sdata, req->bss, true, override);
if (err)
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 76747bfdaddd..871cdac2d0f4 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <[email protected]>
* Copyright 2007-2008, Intel Corporation
* Copyright 2008, Johannes Berg <[email protected]>
- * Copyright (C) 2018, 2020 Intel Corporation
+ * Copyright (C) 2018, 2020, 2022 Intel Corporation
*/

#include <linux/ieee80211.h>
@@ -23,7 +23,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum nl80211_band current_band,
u32 vht_cap_info,
- u32 sta_flags, u8 *bssid,
+ ieee80211_conn_flags_t conn_flags, u8 *bssid,
struct ieee80211_csa_ie *csa_ie)
{
enum nl80211_band new_band = current_band;
@@ -40,13 +40,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
sec_chan_offs = elems->sec_chan_offs;
wide_bw_chansw_ie = elems->wide_bw_chansw_ie;

- if (sta_flags & (IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_40MHZ)) {
+ if (conn_flags & (IEEE80211_CONN_DISABLE_HT |
+ IEEE80211_CONN_DISABLE_40MHZ)) {
sec_chan_offs = NULL;
wide_bw_chansw_ie = NULL;
}

- if (sta_flags & IEEE80211_STA_DISABLE_VHT)
+ if (conn_flags & IEEE80211_CONN_DISABLE_VHT)
wide_bw_chansw_ie = NULL;

if (elems->ext_chansw_ie) {
@@ -93,7 +93,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,

if (sec_chan_offs) {
secondary_channel_offset = sec_chan_offs->sec_chan_offs;
- } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) {
+ } else if (!(conn_flags & IEEE80211_CONN_DISABLE_HT)) {
/* If the secondary channel offset IE is not present,
* we can't know what's the post-CSA offset, so the
* best we can do is use 20MHz.
@@ -160,10 +160,10 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
&new_vht_chandef))
new_vht_chandef.chan = NULL;

- if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+ if (conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
ieee80211_chandef_downgrade(&new_vht_chandef);
- if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
+ if (conn_flags & IEEE80211_CONN_DISABLE_160MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
ieee80211_chandef_downgrade(&new_vht_chandef);
}
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 71883ffd7061..30f2b340017c 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1311,7 +1311,6 @@ static void
iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
bool tdls_ht;
u16 protection = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED |
IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
@@ -1319,7 +1318,7 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata,
u16 opmode;

/* Nothing to do if the BSS connection uses HT */
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
+ if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
return;

tdls_ht = (sta && sta->sta.deflink.ht_cap.ht_supported) ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 24b5e5d10d66..275310b6fc38 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2945,7 +2945,7 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
he_cap->he_cap_elem.phy_cap_info);
}

-u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
+u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos,
const struct ieee80211_sta_he_cap *he_cap,
u8 *end)
{
@@ -2965,16 +2965,16 @@ u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
/* modify on stack first to calculate 'n' and 'ie_len' correctly */
elem = he_cap->he_cap_elem;

- if (disable_flags & IEEE80211_STA_DISABLE_40MHZ)
+ if (disable_flags & IEEE80211_CONN_DISABLE_40MHZ)
elem.phy_cap_info[0] &=
~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G);

- if (disable_flags & IEEE80211_STA_DISABLE_160MHZ)
+ if (disable_flags & IEEE80211_CONN_DISABLE_160MHZ)
elem.phy_cap_info[0] &=
~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;

- if (disable_flags & IEEE80211_STA_DISABLE_80P80MHZ)
+ if (disable_flags & IEEE80211_CONN_DISABLE_80P80MHZ)
elem.phy_cap_info[0] &=
~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;

@@ -4063,21 +4063,21 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(ieee80211_radar_detected);

-u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
+ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
{
- u32 ret;
+ ieee80211_conn_flags_t ret;
int tmp;

switch (c->width) {
case NL80211_CHAN_WIDTH_20:
c->width = NL80211_CHAN_WIDTH_20_NOHT;
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT;
break;
case NL80211_CHAN_WIDTH_40:
c->width = NL80211_CHAN_WIDTH_20;
c->center_freq1 = c->chan->center_freq;
- ret = IEEE80211_STA_DISABLE_40MHZ |
- IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_40MHZ |
+ IEEE80211_CONN_DISABLE_VHT;
break;
case NL80211_CHAN_WIDTH_80:
tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
@@ -4086,13 +4086,13 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
/* freq_P40 */
c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
c->width = NL80211_CHAN_WIDTH_40;
- ret = IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_VHT;
break;
case NL80211_CHAN_WIDTH_80P80:
c->center_freq2 = 0;
c->width = NL80211_CHAN_WIDTH_80;
- ret = IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ;
+ ret = IEEE80211_CONN_DISABLE_80P80MHZ |
+ IEEE80211_CONN_DISABLE_160MHZ;
break;
case NL80211_CHAN_WIDTH_160:
/* n_P20 */
@@ -4101,8 +4101,8 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
tmp /= 4;
c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
c->width = NL80211_CHAN_WIDTH_80;
- ret = IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ;
+ ret = IEEE80211_CONN_DISABLE_80P80MHZ |
+ IEEE80211_CONN_DISABLE_160MHZ;
break;
case NL80211_CHAN_WIDTH_320:
/* n_P20 */
@@ -4111,13 +4111,13 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
tmp /= 8;
c->center_freq1 = c->center_freq1 - 80 + 160 * tmp;
c->width = NL80211_CHAN_WIDTH_160;
- ret = IEEE80211_STA_DISABLE_320MHZ;
+ ret = IEEE80211_CONN_DISABLE_320MHZ;
break;
default:
case NL80211_CHAN_WIDTH_20_NOHT:
WARN_ON_ONCE(1);
c->width = NL80211_CHAN_WIDTH_20_NOHT;
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT;
break;
case NL80211_CHAN_WIDTH_1:
case NL80211_CHAN_WIDTH_2:
@@ -4128,7 +4128,7 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
case NL80211_CHAN_WIDTH_10:
WARN_ON_ONCE(1);
/* keep c->width */
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT;
break;
}

--
2.36.1

2022-07-13 09:50:30

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 53/76] wifi: mac80211: refactor adding rates to assoc request

From: Johannes Berg <[email protected]>

There's some awkward code that really only exists
because we want to optimize the allocation size,
but that's not really all that necessary.

Refactor the code that adds rates to the association
request frame to have a separate function, removing
the goto.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mlme.c | 141 +++++++++++++++++++++++---------------------
1 file changed, 74 insertions(+), 67 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c65fe9f6f000..a442de3670b9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -770,6 +770,75 @@ static void ieee80211_add_eht_ie(struct ieee80211_link_data *link,
ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size);
}

+static void ieee80211_assoc_add_rates(struct sk_buff *skb,
+ enum nl80211_chan_width width,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_mgd_assoc_data *assoc_data)
+{
+ unsigned int shift = ieee80211_chanwidth_get_shift(width);
+ unsigned int rates_len, supp_rates_len;
+ u32 rates = 0;
+ int i, count;
+ u8 *pos;
+
+ if (assoc_data->supp_rates_len) {
+ /*
+ * Get all rates supported by the device and the AP as
+ * some APs don't like getting a superset of their rates
+ * in the association request (e.g. D-Link DAP 1353 in
+ * b-only mode)...
+ */
+ rates_len = ieee80211_parse_bitrates(width, sband,
+ assoc_data->supp_rates,
+ assoc_data->supp_rates_len,
+ &rates);
+ } else {
+ /*
+ * In case AP not provide any supported rates information
+ * before association, we send information element(s) with
+ * all rates that we support.
+ */
+ rates_len = sband->n_bitrates;
+ for (i = 0; i < sband->n_bitrates; i++)
+ rates |= BIT(i);
+ }
+
+ supp_rates_len = rates_len;
+ if (supp_rates_len > 8)
+ supp_rates_len = 8;
+
+ pos = skb_put(skb, supp_rates_len + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = supp_rates_len;
+
+ count = 0;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (BIT(i) & rates) {
+ int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+ 5 * (1 << shift));
+ *pos++ = (u8)rate;
+ if (++count == 8)
+ break;
+ }
+ }
+
+ if (rates_len > count) {
+ pos = skb_put(skb, rates_len - count + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = rates_len - count;
+
+ for (i++; i < sband->n_bitrates; i++) {
+ if (BIT(i) & rates) {
+ int rate;
+
+ rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+ 5 * (1 << shift));
+ *pos++ = (u8)rate;
+ }
+ }
+ }
+}
+
static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@@ -779,12 +848,11 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
struct ieee80211_mgmt *mgmt;
u8 *pos, qos_info, *ie_start;
size_t offset = 0, noffset;
- int i, count, rates_len, supp_rates_len, shift;
+ int i;
u16 capab;
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
- u32 rates = 0;
__le16 listen_int;
struct element *ext_capa = NULL;
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
@@ -810,39 +878,13 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
chan = chanctx_conf->def.chan;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];
- shift = ieee80211_vif_get_shift(&sdata->vif);
-
- if (assoc_data->supp_rates_len) {
- /*
- * Get all rates supported by the device and the AP as
- * some APs don't like getting a superset of their rates
- * in the association request (e.g. D-Link DAP 1353 in
- * b-only mode)...
- */
- rates_len = ieee80211_parse_bitrates(chanctx_conf->def.width,
- sband,
- assoc_data->supp_rates,
- assoc_data->supp_rates_len,
- &rates);
- } else {
- /*
- * In case AP not provide any supported rates information
- * before association, we send information element(s) with
- * all rates that we support.
- */
- rates_len = 0;
- for (i = 0; i < sband->n_bitrates; i++) {
- rates |= BIT(i);
- rates_len++;
- }
- }

iftd = ieee80211_get_sband_iftype_data(sband, iftype);

skb = alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + /* bit too much but doesn't matter */
2 + assoc_data->ssid_len + /* SSID */
- 4 + rates_len + /* (extended) rates */
+ 4 + sband->n_bitrates + /* (extended) rates */
4 + /* power capability */
2 + 2 * sband->n_channels + /* supported channels */
2 + sizeof(struct ieee80211_ht_cap) + /* HT */
@@ -911,45 +953,10 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*pos++ = assoc_data->ssid_len;
memcpy(pos, assoc_data->ssid, assoc_data->ssid_len);

- if (sband->band == NL80211_BAND_S1GHZ)
- goto skip_rates;
-
- /* add all rates which were marked to be used above */
- supp_rates_len = rates_len;
- if (supp_rates_len > 8)
- supp_rates_len = 8;
-
- pos = skb_put(skb, supp_rates_len + 2);
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = supp_rates_len;
-
- count = 0;
- for (i = 0; i < sband->n_bitrates; i++) {
- if (BIT(i) & rates) {
- int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
- 5 * (1 << shift));
- *pos++ = (u8) rate;
- if (++count == 8)
- break;
- }
- }
-
- if (rates_len > count) {
- pos = skb_put(skb, rates_len - count + 2);
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = rates_len - count;
-
- for (i++; i < sband->n_bitrates; i++) {
- if (BIT(i) & rates) {
- int rate;
- rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
- 5 * (1 << shift));
- *pos++ = (u8) rate;
- }
- }
- }
+ if (sband->band != NL80211_BAND_S1GHZ)
+ ieee80211_assoc_add_rates(skb, chanctx_conf->def.width,
+ sband, assoc_data);

-skip_rates:
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT ||
capab & WLAN_CAPABILITY_RADIO_MEASURE) {
pos = skb_put(skb, 4);
--
2.36.1

2022-07-13 09:50:29

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 33/76] wifi: mac80211: mlme: first adjustments for MLO

From: Johannes Berg <[email protected]>

Do the first adjustments in the client-side code to pass
the link pointer (instead of sdata) to most places etc.

This is just preparation, so the real MLO patches become
smaller.

Note that this isn't complete, notably there are still
quite a few references to sta->deflink and sta->sta.deflink.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 2 +-
net/mac80211/ieee80211_i.h | 4 +-
net/mac80211/mlme.c | 765 ++++++++++++++++++++-----------------
3 files changed, 408 insertions(+), 363 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 8d384956fde5..92fe40539091 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1188,7 +1188,7 @@ ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link)
break;
case NL80211_IFTYPE_STATION:
ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.mgd.chswitch_work);
+ &link->u.mgd.chswitch_work);
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_AP_VLAN:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 711129edd923..20b9979d1506 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -448,9 +448,7 @@ struct ieee80211_if_managed {
struct timer_list timer;
struct timer_list conn_mon_timer;
struct timer_list bcn_mon_timer;
- struct timer_list chswitch_timer;
struct work_struct monitor_work;
- struct work_struct chswitch_work;
struct work_struct beacon_connection_loss_work;
struct work_struct csa_connection_drop_work;

@@ -888,6 +886,8 @@ struct ieee80211_link_data_managed {

bool csa_waiting_bcn;
bool csa_ignored_same_chan;
+ struct timer_list chswitch_timer;
+ struct work_struct chswitch_work;

struct work_struct request_smps_work;
bool beacon_crc_valid;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index bcc817de6bd0..f3e901793ae1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -143,7 +143,7 @@ static int ecw2cw(int ecw)
}

static ieee80211_conn_flags_t
-ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
+ieee80211_determine_chantype(struct ieee80211_link_data *link,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
u32 vht_cap_info,
@@ -154,6 +154,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_s1g_oper_ie *s1g_oper,
struct cfg80211_chan_def *chandef, bool tracking)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct cfg80211_chan_def vht_chandef;
struct ieee80211_sta_ht_cap sta_ht_cap;
ieee80211_conn_flags_t ret;
@@ -248,7 +249,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}

vht_chandef = *chandef;
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
he_oper &&
(le32_to_cpu(he_oper->he_oper_params) &
IEEE80211_HE_OPERATION_VHT_OPER_INFO)) {
@@ -264,7 +265,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
&he_oper_vht_cap, ht_oper,
&vht_chandef)) {
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE))
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE))
sdata_info(sdata,
"HE AP VHT information is invalid, disabling HE\n");
ret = IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT;
@@ -274,7 +275,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
vht_cap_info,
vht_oper, ht_oper,
&vht_chandef)) {
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disabling VHT\n");
ret = IEEE80211_CONN_DISABLE_VHT;
@@ -282,7 +283,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}

if (!cfg80211_chandef_valid(&vht_chandef)) {
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disabling VHT\n");
ret = IEEE80211_CONN_DISABLE_VHT;
@@ -295,7 +296,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}

if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information doesn't match HT, disabling VHT\n");
ret = IEEE80211_CONN_DISABLE_VHT;
@@ -318,7 +319,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
false, &eht_chandef);

if (!cfg80211_chandef_valid(&eht_chandef)) {
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
sdata_info(sdata,
"AP EHT information is invalid, disabling EHT\n");
ret = IEEE80211_CONN_DISABLE_EHT;
@@ -326,7 +327,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}

if (!cfg80211_chandef_compatible(chandef, &eht_chandef)) {
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
sdata_info(sdata,
"AP EHT information is incompatible, disabling EHT\n");
ret = IEEE80211_CONN_DISABLE_EHT;
@@ -358,7 +359,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
* less common and wouldn't completely prevent using the AP.
*/
if (tracking &&
- cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
+ cfg80211_chandef_identical(chandef, &link->conf->chandef))
return ret;

/* don't print the message below for VHT mismatch if VHT is disabled */
@@ -403,7 +404,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
return ret;
}

-static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
+static int ieee80211_config_bw(struct ieee80211_link_data *link,
struct sta_info *sta,
const struct ieee80211_ht_cap *ht_cap,
const struct ieee80211_vht_cap *vht_cap,
@@ -414,9 +415,10 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_s1g_oper_ie *s1g_oper,
const u8 *bssid, u32 *changed)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_channel *chan = sdata->vif.bss_conf.chandef.chan;
+ struct ieee80211_channel *chan = link->conf->chandef.chan;
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[chan->band];
struct cfg80211_chan_def chandef;
@@ -426,15 +428,15 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
int ret;

/* if HT was/is disabled, don't track any bandwidth changes */
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || !ht_oper)
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || !ht_oper)
return 0;

/* don't check VHT if we associated as non-VHT station */
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
vht_oper = NULL;

/* don't check HE if we associated as non-HE station */
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE ||
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE ||
!ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif))) {
he_oper = NULL;
@@ -442,7 +444,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
}

/* don't check EHT if we associated as non-EHT station */
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT ||
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT ||
!ieee80211_get_eht_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif)))
eht_oper = NULL;
@@ -455,16 +457,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
* this may be applicable even if channel is identical
*/
ht_opmode = le16_to_cpu(ht_oper->operation_mode);
- if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
+ if (link->conf->ht_operation_mode != ht_opmode) {
*changed |= BSS_CHANGED_HT;
- sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
+ link->conf->ht_operation_mode = ht_opmode;
}

if (vht_cap)
vht_cap_info = le32_to_cpu(vht_cap->vht_cap_info);

/* calculate new channel (type) based on HT/VHT/HE operation IEs */
- flags = ieee80211_determine_chantype(sdata, sband, chan, vht_cap_info,
+ flags = ieee80211_determine_chantype(link, sband, chan, vht_cap_info,
ht_oper, vht_oper,
he_oper, eht_oper,
s1g_oper, &chandef, true);
@@ -476,28 +478,27 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
* reasons) then switching to a 40 MHz channel now won't do us
* any good -- we couldn't use it with the AP.
*/
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ &&
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ &&
chandef.width == NL80211_CHAN_WIDTH_80P80)
flags |= ieee80211_chandef_downgrade(&chandef);
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ &&
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ &&
chandef.width == NL80211_CHAN_WIDTH_160)
flags |= ieee80211_chandef_downgrade(&chandef);
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ &&
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ &&
chandef.width > NL80211_CHAN_WIDTH_20)
flags |= ieee80211_chandef_downgrade(&chandef);

- if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef))
+ if (cfg80211_chandef_identical(&chandef, &link->conf->chandef))
return 0;

- sdata_info(sdata,
- "AP %pM changed bandwidth, new config is %d.%03d MHz, "
- "width %d (%d.%03d/%d MHz)\n",
- sdata->deflink.u.mgd.bssid, chandef.chan->center_freq,
- chandef.chan->freq_offset, chandef.width,
- chandef.center_freq1, chandef.freq1_offset,
- chandef.center_freq2);
-
- if (flags != (sdata->deflink.u.mgd.conn_flags &
+ link_info(link,
+ "AP %pM changed bandwidth, new config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n",
+ link->u.mgd.bssid, chandef.chan->center_freq,
+ chandef.chan->freq_offset, chandef.width,
+ chandef.center_freq1, chandef.freq1_offset,
+ chandef.center_freq2);
+
+ if (flags != (link->u.mgd.conn_flags &
(IEEE80211_CONN_DISABLE_HT |
IEEE80211_CONN_DISABLE_VHT |
IEEE80211_CONN_DISABLE_HE |
@@ -509,16 +510,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
!cfg80211_chandef_valid(&chandef)) {
sdata_info(sdata,
"AP %pM changed caps/bw in a way we can't support (0x%x/0x%x) - disconnect\n",
- sdata->deflink.u.mgd.bssid, flags, ifmgd->flags);
+ link->u.mgd.bssid, flags, ifmgd->flags);
return -EINVAL;
}

- ret = ieee80211_link_change_bandwidth(&sdata->deflink, &chandef, changed);
+ ret = ieee80211_link_change_bandwidth(link, &chandef, changed);

if (ret) {
sdata_info(sdata,
"AP %pM changed bandwidth to incompatible one - disconnect\n",
- sdata->deflink.u.mgd.bssid);
+ link->u.mgd.bssid);
return ret;
}

@@ -527,12 +528,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,

/* frame sending functions */

-static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_add_ht_ie(struct ieee80211_link_data *link,
struct sk_buff *skb, u8 ap_ht_param,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
enum ieee80211_smps_mode smps)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
u8 *pos;
u32 flags = channel->flags;
u16 cap;
@@ -566,7 +568,7 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
* capable of 40 MHz -- some broken APs will never fall
* back to trying to transmit in 20 MHz.
*/
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) {
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
@@ -601,11 +603,12 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
* and builds the IE.
* Note - the function may set the owner of the MU-MIMO capability
*/
-static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_add_vht_ie(struct ieee80211_link_data *link,
struct sk_buff *skb,
struct ieee80211_supported_band *sband,
struct ieee80211_vht_cap *ap_vht_cap)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
u8 *pos;
u32 cap;
@@ -620,7 +623,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
/* determine capability flags */
cap = vht_cap.cap;

- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ) {
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ) {
u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;

cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
@@ -629,7 +632,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
}

- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ) {
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_160MHZ) {
cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
}
@@ -666,7 +669,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
if (disable_mu_mimo)
cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
else
- sdata->vif.bss_conf.mu_mimo_owner = true;
+ link->conf->mu_mimo_owner = true;
}

mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
@@ -687,10 +690,11 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
/* This function determines HE capability flags for the association
* and builds the IE.
*/
-static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_add_he_ie(struct ieee80211_link_data *link,
struct sk_buff *skb,
struct ieee80211_supported_band *sband)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
u8 *pos, *pre_he_pos;
const struct ieee80211_sta_he_cap *he_cap = NULL;
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -698,7 +702,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
bool reg_cap = false;

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!WARN_ON_ONCE(!chanctx_conf))
reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy,
&chanctx_conf->def,
@@ -719,7 +723,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
he_cap->he_cap_elem.phy_cap_info);
pos = skb_put(skb, he_cap_size);
pre_he_pos = pos;
- pos = ieee80211_ie_build_he_cap(sdata->deflink.u.mgd.conn_flags,
+ pos = ieee80211_ie_build_he_cap(link->u.mgd.conn_flags,
pos, he_cap, pos + he_cap_size);
/* trim excess if any */
skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
@@ -727,10 +731,11 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
ieee80211_ie_build_he_6ghz_cap(sdata, skb);
}

-static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_add_eht_ie(struct ieee80211_link_data *link,
struct sk_buff *skb,
struct ieee80211_supported_band *sband)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
u8 *pos;
const struct ieee80211_sta_he_cap *he_cap;
const struct ieee80211_sta_eht_cap *eht_cap;
@@ -739,7 +744,7 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
bool reg_cap = false;

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!WARN_ON_ONCE(!chanctx_conf))
reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy,
&chanctx_conf->def,
@@ -789,6 +794,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
const struct ieee80211_sband_iftype_data *iftd;
struct ieee80211_prep_tx_info info = {};
+ struct ieee80211_link_data *link = &sdata->deflink;
int ret;

/* we know it's writable, cast away the const */
@@ -800,7 +806,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
sdata_assert_lock(sdata);

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
@@ -979,7 +985,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)

/* Set MBSSID support for HE AP if needed */
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && assoc_data->ie_len &&
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && assoc_data->ie_len &&
ext_capa && ext_capa->datalen >= 3)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;

@@ -1024,14 +1030,14 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
offset = noffset;
}

- if (WARN_ON_ONCE((sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)))
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ if (WARN_ON_ONCE((link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)))
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;

if (sband->band != NL80211_BAND_6GHZ &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
- ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
- sband, chan, sdata->deflink.smps_mode);
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
+ ieee80211_add_ht_ie(link, skb, assoc_data->ap_ht_param,
+ sband, chan, link->smps_mode);

/* if present, add any custom IEs that go before VHT */
if (assoc_data->ie_len) {
@@ -1084,25 +1090,25 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}

if (sband->band != NL80211_BAND_6GHZ &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
- ieee80211_add_vht_ie(sdata, skb, sband,
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ ieee80211_add_vht_ie(link, skb, sband,
&assoc_data->ap_vht_cap);

/*
* If AP doesn't support HT, mark HE and EHT as disabled.
* If on the 5GHz band, make sure it supports VHT.
*/
- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT ||
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT ||
(sband->band == NL80211_BAND_5GHZ &&
- sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
+ link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
IEEE80211_CONN_DISABLE_EHT;

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
- ieee80211_add_he_ie(sdata, skb, sband);
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
+ ieee80211_add_he_ie(link, skb, sband);

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
- ieee80211_add_eht_ie(sdata, skb, sband);
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
+ ieee80211_add_eht_ie(link, skb, sband);
}

/* if present, add any custom non-vendor IEs that go after HE */
@@ -1247,8 +1253,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
/* spectrum management related things */
static void ieee80211_chswitch_work(struct work_struct *work)
{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
+ struct ieee80211_link_data *link =
+ container_of(work, struct ieee80211_link_data, u.mgd.chswitch_work);
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int ret;
@@ -1263,7 +1270,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
if (!ifmgd->associated)
goto out;

- if (!sdata->vif.bss_conf.csa_active)
+ if (!link->conf->csa_active)
goto out;

/*
@@ -1273,16 +1280,16 @@ static void ieee80211_chswitch_work(struct work_struct *work)
* completed successfully
*/

- if (sdata->deflink.reserved_chanctx) {
+ if (link->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->deflink.reserved_ready)
+ if (link->reserved_ready)
goto out;

- ret = ieee80211_link_use_reserved_context(&sdata->deflink);
+ ret = ieee80211_link_use_reserved_context(link);
if (ret) {
sdata_info(sdata,
"failed to use reserved channel context, disconnecting (err=%d)\n",
@@ -1295,8 +1302,8 @@ static void ieee80211_chswitch_work(struct work_struct *work)
goto out;
}

- if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
- &sdata->deflink.csa_chandef)) {
+ if (!cfg80211_chandef_identical(&link->conf->chandef,
+ &link->csa_chandef)) {
sdata_info(sdata,
"failed to finalize channel switch, disconnecting\n");
ieee80211_queue_work(&sdata->local->hw,
@@ -1304,7 +1311,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
goto out;
}

- sdata->deflink.u.mgd.csa_waiting_bcn = true;
+ link->u.mgd.csa_waiting_bcn = true;

ieee80211_sta_reset_beacon_monitor(sdata);
ieee80211_sta_reset_conn_monitor(sdata);
@@ -1315,29 +1322,30 @@ static void ieee80211_chswitch_work(struct work_struct *work)
sdata_unlock(sdata);
}

-static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int ret;

sdata_assert_lock(sdata);

- WARN_ON(!sdata->vif.bss_conf.csa_active);
+ WARN_ON(!link->conf->csa_active);

- if (sdata->deflink.csa_block_tx) {
+ if (link->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
- sdata->deflink.csa_block_tx = false;
+ link->csa_block_tx = false;
}

- sdata->vif.bss_conf.csa_active = false;
- sdata->deflink.u.mgd.csa_waiting_bcn = false;
+ link->conf->csa_active = false;
+ link->u.mgd.csa_waiting_bcn = false;
/*
* If the CSA IE is still present on the beacon after the switch,
* we need to consider it as a new CSA (possibly to self).
*/
- sdata->deflink.u.mgd.beacon_crc_valid = false;
+ link->u.mgd.beacon_crc_valid = false;

ret = drv_post_channel_switch(sdata);
if (ret) {
@@ -1348,8 +1356,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
return;
}

- cfg80211_ch_switch_notify(sdata->dev, &sdata->deflink.reserved_chandef,
- 0);
+ cfg80211_ch_switch_notify(sdata->dev, &link->reserved_chandef, 0);
}

void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
@@ -1357,6 +1364,9 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

+ if (WARN_ON(sdata->vif.valid_links))
+ success = false;
+
trace_api_chswitch_done(sdata, success);
if (!success) {
sdata_info(sdata,
@@ -1364,22 +1374,25 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
ieee80211_queue_work(&sdata->local->hw,
&ifmgd->csa_connection_drop_work);
} else {
- ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&sdata->local->hw,
+ &sdata->deflink.u.mgd.chswitch_work);
}
}
EXPORT_SYMBOL(ieee80211_chswitch_done);

static void ieee80211_chswitch_timer(struct timer_list *t)
{
- struct ieee80211_sub_if_data *sdata =
- from_timer(sdata, t, u.mgd.chswitch_timer);
+ struct ieee80211_link_data *link =
+ from_timer(link, t, u.mgd.chswitch_timer);

- ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
+ ieee80211_queue_work(&link->sdata->local->hw,
+ &link->u.mgd.chswitch_work);
}

static void
-ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata)
+ieee80211_sta_abort_chanswitch(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;

if (!local->ops->abort_channel_switch)
@@ -1388,15 +1401,15 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata)
mutex_lock(&local->mtx);

mutex_lock(&local->chanctx_mtx);
- ieee80211_link_unreserve_chanctx(&sdata->deflink);
+ ieee80211_link_unreserve_chanctx(link);
mutex_unlock(&local->chanctx_mtx);

- if (sdata->deflink.csa_block_tx)
+ if (link->csa_block_tx)
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);

- sdata->deflink.csa_block_tx = false;
- sdata->vif.bss_conf.csa_active = false;
+ link->csa_block_tx = false;
+ link->conf->csa_active = false;

mutex_unlock(&local->mtx);

@@ -1404,14 +1417,15 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata)
}

static void
-ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
u64 timestamp, u32 device_timestamp,
struct ieee802_11_elems *elems,
bool beacon)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct cfg80211_bss *cbss = sdata->deflink.u.mgd.bss;
+ struct cfg80211_bss *cbss = link->u.mgd.bss;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *chanctx;
enum nl80211_band current_band;
@@ -1432,8 +1446,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
bss = (void *)cbss->priv;
res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band,
bss->vht_cap_info,
- sdata->deflink.u.mgd.conn_flags,
- sdata->deflink.u.mgd.bssid, &csa_ie);
+ link->u.mgd.conn_flags,
+ link->u.mgd.bssid, &csa_ie);

if (!res) {
ch_switch.timestamp = timestamp;
@@ -1447,23 +1461,23 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (res < 0)
goto lock_and_drop_connection;

- if (beacon && sdata->vif.bss_conf.csa_active &&
- !sdata->deflink.u.mgd.csa_waiting_bcn) {
+ if (beacon && link->conf->csa_active &&
+ !link->u.mgd.csa_waiting_bcn) {
if (res)
- ieee80211_sta_abort_chanswitch(sdata);
+ ieee80211_sta_abort_chanswitch(link);
else
drv_channel_switch_rx_beacon(sdata, &ch_switch);
return;
- } else if (sdata->vif.bss_conf.csa_active || res) {
+ } else if (link->conf->csa_active || res) {
/* disregard subsequent announcements if already processing */
return;
}

- if (sdata->vif.bss_conf.chandef.chan->band !=
+ if (link->conf->chandef.chan->band !=
csa_ie.chandef.chan->band) {
sdata_info(sdata,
"AP %pM switches to different band (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
- sdata->deflink.u.mgd.bssid,
+ link->u.mgd.bssid,
csa_ie.chandef.chan->center_freq,
csa_ie.chandef.width, csa_ie.chandef.center_freq1,
csa_ie.chandef.center_freq2);
@@ -1476,7 +1490,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
"AP %pM switches to unsupported channel "
"(%d.%03d MHz, width:%d, CF1/2: %d.%03d/%d MHz), "
"disconnecting\n",
- sdata->deflink.u.mgd.bssid,
+ link->u.mgd.bssid,
csa_ie.chandef.chan->center_freq,
csa_ie.chandef.chan->freq_offset,
csa_ie.chandef.width, csa_ie.chandef.center_freq1,
@@ -1486,14 +1500,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}

if (cfg80211_chandef_identical(&csa_ie.chandef,
- &sdata->vif.bss_conf.chandef) &&
+ &link->conf->chandef) &&
(!csa_ie.mode || !beacon)) {
- if (sdata->deflink.u.mgd.csa_ignored_same_chan)
+ if (link->u.mgd.csa_ignored_same_chan)
return;
sdata_info(sdata,
"AP %pM tries to chanswitch to same channel, ignore\n",
- sdata->deflink.u.mgd.bssid);
- sdata->deflink.u.mgd.csa_ignored_same_chan = true;
+ link->u.mgd.bssid);
+ link->u.mgd.csa_ignored_same_chan = true;
return;
}

@@ -1507,7 +1521,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,

mutex_lock(&local->mtx);
mutex_lock(&local->chanctx_mtx);
- conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
sdata_info(sdata,
@@ -1530,7 +1544,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
goto drop_connection;
}

- res = ieee80211_link_reserve_chanctx(&sdata->deflink, &csa_ie.chandef,
+ res = ieee80211_link_reserve_chanctx(link, &csa_ie.chandef,
chanctx->mode, false);
if (res) {
sdata_info(sdata,
@@ -1540,13 +1554,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
mutex_unlock(&local->chanctx_mtx);

- sdata->vif.bss_conf.csa_active = true;
- sdata->deflink.csa_chandef = csa_ie.chandef;
- sdata->deflink.csa_block_tx = csa_ie.mode;
- sdata->deflink.u.mgd.csa_ignored_same_chan = false;
- sdata->deflink.u.mgd.beacon_crc_valid = false;
+ link->conf->csa_active = true;
+ link->csa_chandef = csa_ie.chandef;
+ link->csa_block_tx = csa_ie.mode;
+ link->u.mgd.csa_ignored_same_chan = false;
+ link->u.mgd.beacon_crc_valid = false;

- if (sdata->deflink.csa_block_tx)
+ if (link->csa_block_tx)
ieee80211_stop_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
mutex_unlock(&local->mtx);
@@ -1562,9 +1576,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,

/* channel switch handled in software */
if (csa_ie.count <= 1)
- ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&local->hw, &link->u.mgd.chswitch_work);
else
- mod_timer(&ifmgd->chswitch_timer,
+ mod_timer(&link->u.mgd.chswitch_timer,
TU_TO_EXP_TIME((csa_ie.count - 1) *
cbss->beacon_interval));
return;
@@ -1579,8 +1593,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
* send a deauthentication frame. Those two fields will be
* reset when the disconnection worker runs.
*/
- sdata->vif.bss_conf.csa_active = true;
- sdata->deflink.csa_block_tx = csa_ie.mode;
+ link->conf->csa_active = true;
+ link->csa_block_tx = csa_ie.mode;

ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
mutex_unlock(&local->chanctx_mtx);
@@ -1673,13 +1687,14 @@ static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
*pwr_level = (__s8)cisco_dtpc_ie[4];
}

-static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+static u32 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link,
struct ieee80211_channel *channel,
struct ieee80211_mgmt *mgmt,
const u8 *country_ie, u8 country_ie_len,
const u8 *pwr_constr_ie,
const u8 *cisco_dtpc_ie)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
bool has_80211h_pwr = false, has_cisco_pwr = false;
int chan_pwr = 0, pwr_reduction_80211h = 0;
int pwr_level_cisco, pwr_level_80211h;
@@ -1715,25 +1730,25 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
(!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
new_ap_level = pwr_level_80211h;

- if (sdata->deflink.ap_power_level == new_ap_level)
+ if (link->ap_power_level == new_ap_level)
return 0;

sdata_dbg(sdata,
"Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
- sdata->deflink.u.mgd.bssid);
+ link->u.mgd.bssid);
} else { /* has_cisco_pwr is always true here. */
new_ap_level = pwr_level_cisco;

- if (sdata->deflink.ap_power_level == new_ap_level)
+ if (link->ap_power_level == new_ap_level)
return 0;

sdata_dbg(sdata,
"Limiting TX power to %d dBm as advertised by %pM\n",
- pwr_level_cisco, sdata->deflink.u.mgd.bssid);
+ pwr_level_cisco, link->u.mgd.bssid);
}

- sdata->deflink.ap_power_level = new_ap_level;
+ link->ap_power_level = new_ap_level;
if (__ieee80211_recalc_txpower(sdata))
return BSS_CHANGED_TXPOWER;
return 0;
@@ -1972,14 +1987,15 @@ void ieee80211_dynamic_ps_timer(struct timer_list *t)
void ieee80211_dfs_cac_timer_work(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
- struct ieee80211_sub_if_data *sdata =
- container_of(delayed_work, struct ieee80211_sub_if_data,
- deflink.dfs_cac_timer_work);
- struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
+ struct ieee80211_link_data *link =
+ container_of(delayed_work, struct ieee80211_link_data,
+ dfs_cac_timer_work);
+ struct cfg80211_chan_def chandef = link->conf->chandef;
+ struct ieee80211_sub_if_data *sdata = link->sdata;

mutex_lock(&sdata->local->mtx);
if (sdata->wdev.cac_started) {
- ieee80211_link_release_channel(&sdata->deflink);
+ ieee80211_link_release_channel(link);
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_FINISHED,
GFP_KERNEL);
@@ -2299,7 +2315,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_bss *bss = (void *)cbss->priv;
struct ieee80211_local *local = sdata->local;
- struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+ struct ieee80211_link_data *link = &sdata->deflink;
+ struct ieee80211_bss_conf *bss_conf = link->conf;
struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg;

bss_info_changed |= BSS_CHANGED_ASSOC;
@@ -2310,8 +2327,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
beacon_loss_count * bss_conf->beacon_int));

sdata->u.mgd.associated = true;
- sdata->deflink.u.mgd.bss = cbss;
- memcpy(sdata->deflink.u.mgd.bssid, cbss->bssid, ETH_ALEN);
+ link->u.mgd.bss = cbss;
+ memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN);
memcpy(sdata->vif.cfg.ap_addr, cbss->bssid, ETH_ALEN);

ieee80211_check_rate_mask(sdata);
@@ -2331,7 +2348,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
(u8 *) &bss_conf->p2p_noa_attr,
sizeof(bss_conf->p2p_noa_attr));
if (ret >= 2) {
- sdata->deflink.u.mgd.p2p_noa_index =
+ link->u.mgd.p2p_noa_index =
bss_conf->p2p_noa_attr.index;
bss_info_changed |= BSS_CHANGED_P2P_PS;
}
@@ -2344,14 +2361,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,

ieee80211_led_assoc(local, 1);

- if (sdata->deflink.u.mgd.have_beacon) {
+ if (link->u.mgd.have_beacon) {
/*
* If the AP is buggy we may get here with no DTIM period
* known, so assume it's 1 which is the only safe assumption
* in that case, although if the TIM IE is broken powersave
* probably just won't work at all.
*/
- bss_conf->dtim_period = sdata->deflink.u.mgd.dtim_period ?: 1;
+ bss_conf->dtim_period = link->u.mgd.dtim_period ?: 1;
bss_conf->beacon_rate = bss->beacon_rate;
bss_info_changed |= BSS_CHANGED_BEACON_INFO;
} else {
@@ -2389,6 +2406,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+ struct ieee80211_link_data *link = &sdata->deflink;
u32 changed = 0;
struct ieee80211_prep_tx_info info = {
.subtype = stype,
@@ -2405,7 +2423,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_stop_poll(sdata);

ifmgd->associated = false;
- sdata->deflink.u.mgd.bss = NULL;
+ link->u.mgd.bss = NULL;
netif_carrier_off(sdata->dev);

/*
@@ -2443,12 +2461,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
* driver requested so.
*/
if (ieee80211_hw_check(&local->hw, DEAUTH_NEED_MGD_TX_PREP) &&
- !sdata->deflink.u.mgd.have_beacon) {
+ !link->u.mgd.have_beacon) {
drv_mgd_prepare_tx(sdata->local, sdata, &info);
}

- ieee80211_send_deauth_disassoc(sdata, sdata->deflink.u.mgd.bssid,
- sdata->deflink.u.mgd.bssid, stype, reason,
+ ieee80211_send_deauth_disassoc(sdata, link->u.mgd.bssid,
+ link->u.mgd.bssid, stype, reason,
tx, frame_buf);
}

@@ -2459,7 +2477,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
drv_mgd_complete_tx(sdata->local, sdata, &info);

/* clear bssid only after building the needed mgmt frames */
- eth_zero_addr(sdata->deflink.u.mgd.bssid);
+ eth_zero_addr(link->u.mgd.bssid);

eth_zero_addr(sdata->vif.cfg.ap_addr);
sdata->vif.cfg.ssid_len = 0;
@@ -2474,9 +2492,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_ASSOC;
sdata->vif.cfg.assoc = false;

- sdata->deflink.u.mgd.p2p_noa_index = -1;
- memset(&sdata->vif.bss_conf.p2p_noa_attr, 0,
- sizeof(sdata->vif.bss_conf.p2p_noa_attr));
+ link->u.mgd.p2p_noa_index = -1;
+ memset(&link->conf->p2p_noa_attr, 0,
+ sizeof(link->conf->p2p_noa_attr));

/* on the next assoc, re-program HT/VHT parameters */
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
@@ -2485,14 +2503,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));

/* reset MU-MIMO ownership and group data */
- memset(sdata->vif.bss_conf.mu_group.membership, 0,
- sizeof(sdata->vif.bss_conf.mu_group.membership));
- memset(sdata->vif.bss_conf.mu_group.position, 0,
- sizeof(sdata->vif.bss_conf.mu_group.position));
+ memset(link->conf->mu_group.membership, 0,
+ sizeof(link->conf->mu_group.membership));
+ memset(link->conf->mu_group.position, 0,
+ sizeof(link->conf->mu_group.position));
changed |= BSS_CHANGED_MU_GROUPS;
- sdata->vif.bss_conf.mu_mimo_owner = false;
+ link->conf->mu_mimo_owner = false;

- sdata->deflink.ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
+ link->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;

del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -2501,7 +2519,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.cfg.arp_addr_cnt)
changed |= BSS_CHANGED_ARP_FILTER;

- sdata->vif.bss_conf.qos = false;
+ link->conf->qos = false;
changed |= BSS_CHANGED_QOS;

/* The BSSID (not really interesting) and HT changed */
@@ -2514,26 +2532,26 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
del_timer_sync(&sdata->u.mgd.timer);
- del_timer_sync(&sdata->u.mgd.chswitch_timer);
+ del_timer_sync(&link->u.mgd.chswitch_timer);

- sdata->vif.bss_conf.dtim_period = 0;
- sdata->vif.bss_conf.beacon_rate = NULL;
+ link->conf->dtim_period = 0;
+ link->conf->beacon_rate = NULL;

- sdata->deflink.u.mgd.have_beacon = false;
- sdata->deflink.u.mgd.tracking_signal_avg = false;
+ link->u.mgd.have_beacon = false;
+ link->u.mgd.tracking_signal_avg = false;

ifmgd->flags = 0;
- sdata->deflink.u.mgd.conn_flags = 0;
+ link->u.mgd.conn_flags = 0;
mutex_lock(&local->mtx);
- ieee80211_link_release_channel(&sdata->deflink);
+ ieee80211_link_release_channel(link);

- sdata->vif.bss_conf.csa_active = false;
- sdata->deflink.u.mgd.csa_waiting_bcn = false;
- sdata->deflink.u.mgd.csa_ignored_same_chan = false;
- if (sdata->deflink.csa_block_tx) {
+ link->conf->csa_active = false;
+ link->u.mgd.csa_waiting_bcn = false;
+ link->u.mgd.csa_ignored_same_chan = false;
+ if (link->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
- sdata->deflink.csa_block_tx = false;
+ link->csa_block_tx = false;
}
mutex_unlock(&local->mtx);

@@ -2657,6 +2675,9 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
u8 unicast_limit = max(1, max_probe_tries - 3);
struct sta_info *sta;

+ if (WARN_ON(sdata->vif.valid_links))
+ return;
+
/*
* Try sending broadcast probe requests for the last three
* probe requests after the first ones failed since some
@@ -2702,6 +2723,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
bool already = false;

+ if (WARN_ON(sdata->vif.valid_links))
+ return;
+
if (!ieee80211_sdata_running(sdata))
return;

@@ -2773,7 +2797,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
const struct element *ssid;
int ssid_len;

- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+ sdata->vif.valid_links))
return NULL;

sdata_assert_lock(sdata);
@@ -2877,9 +2902,6 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
u.mgd.beacon_connection_loss_work);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

- if (ifmgd->associated)
- sdata->deflink.u.mgd.beacon_loss_count++;
-
if (ifmgd->connection_loss) {
sdata_info(sdata, "Connection to AP %pM lost\n",
sdata->vif.cfg.ap_addr);
@@ -2892,6 +2914,8 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
__ieee80211_disconnect(sdata);
ifmgd->driver_disconnect = false;
} else {
+ if (ifmgd->associated)
+ sdata->deflink.u.mgd.beacon_loss_count++;
ieee80211_mgd_probe_ap(sdata, true);
}
}
@@ -2961,11 +2985,12 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
del_timer_sync(&sdata->u.mgd.timer);
sta_info_destroy_addr(sdata, auth_data->bss->bssid);

+ /* FIXME: other links are destroyed? */
+ sdata->deflink.u.mgd.conn_flags = 0;
eth_zero_addr(sdata->deflink.u.mgd.bssid);
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
- sdata->deflink.u.mgd.conn_flags = 0;
mutex_lock(&sdata->local->mtx);
ieee80211_link_release_channel(&sdata->deflink);
mutex_unlock(&sdata->local->mtx);
@@ -2992,11 +3017,12 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
del_timer_sync(&sdata->u.mgd.timer);
sta_info_destroy_addr(sdata, assoc_data->bss->bssid);

+ /* FIXME: other links are destroyed? */
+ sdata->deflink.u.mgd.conn_flags = 0;
eth_zero_addr(sdata->deflink.u.mgd.bssid);
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_BSSID);
sdata->u.mgd.flags = 0;
- sdata->deflink.u.mgd.conn_flags = 0;
sdata->vif.bss_conf.mu_mimo_owner = false;

mutex_lock(&sdata->local->mtx);
@@ -3385,14 +3411,14 @@ static bool ieee80211_twt_req_supported(const struct sta_info *sta,
IEEE80211_HE_MAC_CAP0_TWT_RES;
}

-static int ieee80211_recalc_twt_req(struct ieee80211_sub_if_data *sdata,
+static int ieee80211_recalc_twt_req(struct ieee80211_link_data *link,
struct sta_info *sta,
struct ieee802_11_elems *elems)
{
bool twt = ieee80211_twt_req_supported(sta, elems);

- if (sdata->vif.bss_conf.twt_requester != twt) {
- sdata->vif.bss_conf.twt_requester = twt;
+ if (link->conf->twt_requester != twt) {
+ link->conf->twt_requester = twt;
return BSS_CHANGED_TWT;
}
return 0;
@@ -3430,6 +3456,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
+ struct ieee80211_link_data *link = &sdata->deflink;
u32 changed = 0;
u8 *pos;
int err;
@@ -3488,9 +3515,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
*/
if (!is_6ghz &&
((assoc_data->wmm && !elems->wmm_param) ||
- (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
+ (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
(!elems->ht_cap_elem || !elems->ht_operation)) ||
- (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
+ (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
(!elems->vht_cap_elem || !elems->vht_operation)))) {
const struct cfg80211_bss_ies *ies;
struct ieee802_11_elems *bss_elems;
@@ -3526,25 +3553,25 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
* have to include the IEs in the (re)association response.
*/
if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
elems->ht_cap_elem = bss_elems->ht_cap_elem;
sdata_info(sdata,
"AP bug: HT capability missing from AssocResp\n");
}
if (!elems->ht_operation && bss_elems->ht_operation &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
elems->ht_operation = bss_elems->ht_operation;
sdata_info(sdata,
"AP bug: HT operation missing from AssocResp\n");
}
if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
elems->vht_cap_elem = bss_elems->vht_cap_elem;
sdata_info(sdata,
"AP bug: VHT capa missing from AssocResp\n");
}
if (!elems->vht_operation && bss_elems->vht_operation &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
elems->vht_operation = bss_elems->vht_operation;
sdata_info(sdata,
"AP bug: VHT operation missing from AssocResp\n");
@@ -3557,7 +3584,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
* We previously checked these in the beacon/probe response, so
* they should be present here. This is just a safety net.
*/
- if (!is_6ghz && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
+ if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
(!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) {
sdata_info(sdata,
"HT AP is missing WMM params or HT capability/operation\n");
@@ -3565,7 +3592,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- if (!is_6ghz && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
+ if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
(!elems->vht_cap_elem || !elems->vht_operation)) {
sdata_info(sdata,
"VHT AP is missing VHT capability/operation\n");
@@ -3573,7 +3600,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- if (is_6ghz && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
+ if (is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
!elems->he_6ghz_capa) {
sdata_info(sdata,
"HE 6 GHz AP is missing HE 6 GHz band capability\n");
@@ -3600,7 +3627,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
(!elems->he_cap || !elems->he_operation)) {
mutex_unlock(&sdata->local->sta_mtx);
sdata_info(sdata,
@@ -3610,17 +3637,17 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}

/* Set up internal HT/VHT capabilities */
- if (elems->ht_cap_elem && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
+ if (elems->ht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
&sta->deflink);

- if (elems->vht_cap_elem && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+ if (elems->vht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
elems->vht_cap_elem,
&sta->deflink);

- if (elems->he_operation && !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
+ if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
elems->he_cap) {
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
elems->he_cap,
@@ -3637,10 +3664,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
else
bss_conf->twt_protected = false;

- changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
+ changed |= ieee80211_recalc_twt_req(link, sta, elems);

if (elems->eht_operation && elems->eht_cap &&
- !(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
+ !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
elems->he_cap,
elems->he_cap_len,
@@ -3764,17 +3791,16 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
* that effect because the AP values is an unsigned
* 4-bit value.
*/
- sdata->deflink.u.mgd.wmm_last_param_set = -1;
- sdata->deflink.u.mgd.mu_edca_last_param_set = -1;
+ link->u.mgd.wmm_last_param_set = -1;
+ link->u.mgd.mu_edca_last_param_set = -1;

if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
- ieee80211_set_wmm_default(&sdata->deflink, false, false);
- } else if (!ieee80211_sta_wmm_params(local, &sdata->deflink,
- elems->wmm_param,
+ ieee80211_set_wmm_default(link, false, false);
+ } else if (!ieee80211_sta_wmm_params(local, link, elems->wmm_param,
elems->wmm_param_len,
elems->mu_edca_param_set)) {
/* still enable QoS since we might have HT/VHT */
- ieee80211_set_wmm_default(&sdata->deflink, false, true);
+ ieee80211_set_wmm_default(link, false, true);
/* set the disable-WMM flag in this case to disable
* tracking WMM parameter changes in the beacon if
* the parameters weren't actually valid. Doing so
@@ -3954,10 +3980,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
kfree(elems);
}

-static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_rx_bss_info(struct ieee80211_link_data *link,
struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_rx_status *rx_status)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_bss *bss;
struct ieee80211_channel *channel;
@@ -3971,15 +3998,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,

bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel);
if (bss) {
- sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
+ link->conf->beacon_rate = bss->beacon_rate;
ieee80211_rx_bss_put(local, bss);
}
}


-static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_link_data *link,
struct sk_buff *skb)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_if_managed *ifmgd;
struct ieee80211_rx_status *rx_status = (void *) skb->cb;
@@ -4011,10 +4039,10 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;

- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
+ ieee80211_rx_bss_info(link, mgmt, len, rx_status);

if (ifmgd->associated &&
- ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid))
+ ether_addr_equal(mgmt->bssid, link->u.mgd.bssid))
ieee80211_reset_ap_probe(sdata);
}

@@ -4042,31 +4070,33 @@ static const u64 care_about_ies =
(1ULL << WLAN_EID_HT_OPERATION) |
(1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);

-static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_handle_beacon_sig(struct ieee80211_link_data *link,
struct ieee80211_if_managed *ifmgd,
struct ieee80211_bss_conf *bss_conf,
struct ieee80211_local *local,
struct ieee80211_rx_status *rx_status)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+
/* Track average RSSI from the Beacon frames of the current AP */

- if (!sdata->deflink.u.mgd.tracking_signal_avg) {
- sdata->deflink.u.mgd.tracking_signal_avg = true;
- ewma_beacon_signal_init(&sdata->deflink.u.mgd.ave_beacon_signal);
- sdata->deflink.u.mgd.last_cqm_event_signal = 0;
- sdata->deflink.u.mgd.count_beacon_signal = 1;
- sdata->deflink.u.mgd.last_ave_beacon_signal = 0;
+ if (!link->u.mgd.tracking_signal_avg) {
+ link->u.mgd.tracking_signal_avg = true;
+ ewma_beacon_signal_init(&link->u.mgd.ave_beacon_signal);
+ link->u.mgd.last_cqm_event_signal = 0;
+ link->u.mgd.count_beacon_signal = 1;
+ link->u.mgd.last_ave_beacon_signal = 0;
} else {
- sdata->deflink.u.mgd.count_beacon_signal++;
+ link->u.mgd.count_beacon_signal++;
}

- ewma_beacon_signal_add(&sdata->deflink.u.mgd.ave_beacon_signal,
+ ewma_beacon_signal_add(&link->u.mgd.ave_beacon_signal,
-rx_status->signal);

if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
- sdata->deflink.u.mgd.count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
- int sig = -ewma_beacon_signal_read(&sdata->deflink.u.mgd.ave_beacon_signal);
- int last_sig = sdata->deflink.u.mgd.last_ave_beacon_signal;
+ link->u.mgd.count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+ int sig = -ewma_beacon_signal_read(&link->u.mgd.ave_beacon_signal);
+ int last_sig = link->u.mgd.last_ave_beacon_signal;
struct ieee80211_event event = {
.type = RSSI_EVENT,
};
@@ -4077,36 +4107,36 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
*/
if (sig > ifmgd->rssi_max_thold &&
(last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
- sdata->deflink.u.mgd.last_ave_beacon_signal = sig;
+ link->u.mgd.last_ave_beacon_signal = sig;
event.u.rssi.data = RSSI_EVENT_HIGH;
drv_event_callback(local, sdata, &event);
} else if (sig < ifmgd->rssi_min_thold &&
(last_sig >= ifmgd->rssi_max_thold ||
last_sig == 0)) {
- sdata->deflink.u.mgd.last_ave_beacon_signal = sig;
+ link->u.mgd.last_ave_beacon_signal = sig;
event.u.rssi.data = RSSI_EVENT_LOW;
drv_event_callback(local, sdata, &event);
}
}

if (bss_conf->cqm_rssi_thold &&
- sdata->deflink.u.mgd.count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
+ link->u.mgd.count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
!(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
- int sig = -ewma_beacon_signal_read(&sdata->deflink.u.mgd.ave_beacon_signal);
- int last_event = sdata->deflink.u.mgd.last_cqm_event_signal;
+ int sig = -ewma_beacon_signal_read(&link->u.mgd.ave_beacon_signal);
+ int last_event = link->u.mgd.last_cqm_event_signal;
int thold = bss_conf->cqm_rssi_thold;
int hyst = bss_conf->cqm_rssi_hyst;

if (sig < thold &&
(last_event == 0 || sig < last_event - hyst)) {
- sdata->deflink.u.mgd.last_cqm_event_signal = sig;
+ link->u.mgd.last_cqm_event_signal = sig;
ieee80211_cqm_rssi_notify(
&sdata->vif,
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
sig, GFP_KERNEL);
} else if (sig > thold &&
(last_event == 0 || sig > last_event + hyst)) {
- sdata->deflink.u.mgd.last_cqm_event_signal = sig;
+ link->u.mgd.last_cqm_event_signal = sig;
ieee80211_cqm_rssi_notify(
&sdata->vif,
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
@@ -4115,22 +4145,22 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
}

if (bss_conf->cqm_rssi_low &&
- sdata->deflink.u.mgd.count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
- int sig = -ewma_beacon_signal_read(&sdata->deflink.u.mgd.ave_beacon_signal);
- int last_event = sdata->deflink.u.mgd.last_cqm_event_signal;
+ link->u.mgd.count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+ int sig = -ewma_beacon_signal_read(&link->u.mgd.ave_beacon_signal);
+ int last_event = link->u.mgd.last_cqm_event_signal;
int low = bss_conf->cqm_rssi_low;
int high = bss_conf->cqm_rssi_high;

if (sig < low &&
(last_event == 0 || last_event >= low)) {
- sdata->deflink.u.mgd.last_cqm_event_signal = sig;
+ link->u.mgd.last_cqm_event_signal = sig;
ieee80211_cqm_rssi_notify(
&sdata->vif,
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
sig, GFP_KERNEL);
} else if (sig > high &&
(last_event == 0 || last_event <= high)) {
- sdata->deflink.u.mgd.last_cqm_event_signal = sig;
+ link->u.mgd.last_cqm_event_signal = sig;
ieee80211_cqm_rssi_notify(
&sdata->vif,
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
@@ -4149,10 +4179,11 @@ static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
}

-static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
+static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
struct ieee80211_hdr *hdr, size_t len,
struct ieee80211_rx_status *rx_status)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg;
@@ -4188,7 +4219,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
return;

rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return;
@@ -4210,18 +4241,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (!elems)
return;

- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
+ ieee80211_rx_bss_info(link, mgmt, len, rx_status);

if (elems->dtim_period)
- sdata->deflink.u.mgd.dtim_period = elems->dtim_period;
- sdata->deflink.u.mgd.have_beacon = true;
+ link->u.mgd.dtim_period = elems->dtim_period;
+ link->u.mgd.have_beacon = true;
ifmgd->assoc_data->need_beacon = false;
if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
- sdata->vif.bss_conf.sync_tsf =
+ link->conf->sync_tsf =
le64_to_cpu(mgmt->u.beacon.timestamp);
- sdata->vif.bss_conf.sync_device_ts =
+ link->conf->sync_device_ts =
rx_status->device_timestamp;
- sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
+ link->conf->sync_dtim_count = elems->dtim_count;
}

if (elems->mbssid_config_ie)
@@ -4245,12 +4276,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}

if (!ifmgd->associated ||
- !ieee80211_rx_our_beacon(bssid, sdata->deflink.u.mgd.bss))
+ !ieee80211_rx_our_beacon(bssid, link->u.mgd.bss))
return;
- bssid = sdata->deflink.u.mgd.bssid;
+ bssid = link->u.mgd.bssid;

if (!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL))
- ieee80211_handle_beacon_sig(sdata, ifmgd, bss_conf,
+ ieee80211_handle_beacon_sig(link, ifmgd, bss_conf,
local, rx_status);

if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
@@ -4313,28 +4344,28 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
(u8 *) &noa, sizeof(noa));
if (ret >= 2) {
- if (sdata->deflink.u.mgd.p2p_noa_index != noa.index) {
+ if (link->u.mgd.p2p_noa_index != noa.index) {
/* valid noa_attr and index changed */
- sdata->deflink.u.mgd.p2p_noa_index = noa.index;
+ link->u.mgd.p2p_noa_index = noa.index;
memcpy(&bss_conf->p2p_noa_attr, &noa, sizeof(noa));
changed |= BSS_CHANGED_P2P_PS;
/*
* make sure we update all information, the CRC
* mechanism doesn't look at P2P attributes.
*/
- sdata->deflink.u.mgd.beacon_crc_valid = false;
+ link->u.mgd.beacon_crc_valid = false;
}
- } else if (sdata->deflink.u.mgd.p2p_noa_index != -1) {
+ } else if (link->u.mgd.p2p_noa_index != -1) {
/* noa_attr not found and we had valid noa_attr before */
- sdata->deflink.u.mgd.p2p_noa_index = -1;
+ link->u.mgd.p2p_noa_index = -1;
memset(&bss_conf->p2p_noa_attr, 0, sizeof(bss_conf->p2p_noa_attr));
changed |= BSS_CHANGED_P2P_PS;
- sdata->deflink.u.mgd.beacon_crc_valid = false;
+ link->u.mgd.beacon_crc_valid = false;
}
}

- if (sdata->deflink.u.mgd.csa_waiting_bcn)
- ieee80211_chswitch_post_beacon(sdata);
+ if (link->u.mgd.csa_waiting_bcn)
+ ieee80211_chswitch_post_beacon(link);

/*
* Update beacon timing and dtim count on every beacon appearance. This
@@ -4346,27 +4377,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
*/
if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) &&
!ieee80211_is_s1g_beacon(hdr->frame_control)) {
- sdata->vif.bss_conf.sync_tsf =
+ link->conf->sync_tsf =
le64_to_cpu(mgmt->u.beacon.timestamp);
- sdata->vif.bss_conf.sync_device_ts =
+ link->conf->sync_device_ts =
rx_status->device_timestamp;
- sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
+ link->conf->sync_dtim_count = elems->dtim_count;
}

- if ((ncrc == sdata->deflink.u.mgd.beacon_crc && sdata->deflink.u.mgd.beacon_crc_valid) ||
+ if ((ncrc == link->u.mgd.beacon_crc && link->u.mgd.beacon_crc_valid) ||
ieee80211_is_s1g_short_beacon(mgmt->frame_control))
goto free;
- sdata->deflink.u.mgd.beacon_crc = ncrc;
- sdata->deflink.u.mgd.beacon_crc_valid = true;
+ link->u.mgd.beacon_crc = ncrc;
+ link->u.mgd.beacon_crc_valid = true;

- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
+ ieee80211_rx_bss_info(link, mgmt, len, rx_status);

- ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+ ieee80211_sta_process_chanswitch(link, rx_status->mactime,
rx_status->device_timestamp,
elems, true);

if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
- ieee80211_sta_wmm_params(local, &sdata->deflink, elems->wmm_param,
+ ieee80211_sta_wmm_params(local, link, elems->wmm_param,
elems->wmm_param_len,
elems->mu_edca_param_set))
changed |= BSS_CHANGED_QOS;
@@ -4375,12 +4406,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
* If we haven't had a beacon before, tell the driver about the
* DTIM period (and beacon timing if desired) now.
*/
- if (!sdata->deflink.u.mgd.have_beacon) {
+ if (!link->u.mgd.have_beacon) {
/* a few bogus AP send dtim_period = 0 or no TIM IE */
bss_conf->dtim_period = elems->dtim_period ?: 1;

changed |= BSS_CHANGED_BEACON_INFO;
- sdata->deflink.u.mgd.have_beacon = true;
+ link->u.mgd.have_beacon = true;

mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local);
@@ -4404,9 +4435,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);

- changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
+ changed |= ieee80211_recalc_twt_req(link, sta, elems);

- if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem,
+ if (ieee80211_config_bw(link, sta, elems->ht_cap_elem,
elems->vht_cap_elem, elems->ht_operation,
elems->vht_operation, elems->he_operation,
elems->eht_operation,
@@ -4426,20 +4457,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}

if (sta && elems->opmode_notif)
- ieee80211_vht_handle_opmode(sdata,
- &sta->deflink,
+ ieee80211_vht_handle_opmode(sdata, &sta->deflink,
*elems->opmode_notif,
rx_status->band);
mutex_unlock(&local->sta_mtx);

- changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
+ changed |= ieee80211_handle_pwr_constr(link, chan, mgmt,
elems->country_elem,
elems->country_elem_len,
elems->pwr_constr_elem,
elems->cisco_dtpc_elem);

- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
- changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);
free:
kfree(elems);
}
@@ -4447,6 +4476,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
+ struct ieee80211_link_data *link = &sdata->deflink;
struct ieee80211_rx_status *rx_status;
struct ieee80211_hdr *hdr;
u16 fc;
@@ -4458,7 +4488,7 @@ void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
sdata_lock(sdata);
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_S1G_BEACON:
- ieee80211_rx_mgmt_beacon(sdata, hdr, skb->len, rx_status);
+ ieee80211_rx_mgmt_beacon(link, hdr, skb->len, rx_status);
break;
}
sdata_unlock(sdata);
@@ -4467,6 +4497,7 @@ void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
+ struct ieee80211_link_data *link = &sdata->deflink;
struct ieee80211_rx_status *rx_status;
struct ieee80211_mgmt *mgmt;
u16 fc;
@@ -4480,11 +4511,11 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,

switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_BEACON:
- ieee80211_rx_mgmt_beacon(sdata, (void *)mgmt,
+ ieee80211_rx_mgmt_beacon(link, (void *)mgmt,
skb->len, rx_status);
break;
case IEEE80211_STYPE_PROBE_RESP:
- ieee80211_rx_mgmt_probe_resp(sdata, skb);
+ ieee80211_rx_mgmt_probe_resp(link, skb);
break;
case IEEE80211_STYPE_AUTH:
ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
@@ -4516,7 +4547,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ies_len, true, mgmt->bssid, NULL);

if (elems && !elems->parse_error)
- ieee80211_sta_process_chanswitch(sdata,
+ ieee80211_sta_process_chanswitch(link,
rx_status->mactime,
rx_status->device_timestamp,
elems, false);
@@ -4544,7 +4575,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
elems->ext_chansw_ie =
&mgmt->u.action.u.ext_chan_switch.data;

- ieee80211_sta_process_chanswitch(sdata,
+ ieee80211_sta_process_chanswitch(link,
rx_status->mactime,
rx_status->device_timestamp,
elems, false);
@@ -4860,6 +4891,9 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t)
struct ieee80211_sub_if_data *sdata =
from_timer(sdata, t, u.mgd.bcn_mon_timer);

+ if (WARN_ON(sdata->vif.valid_links))
+ return;
+
if (sdata->vif.bss_conf.csa_active &&
!sdata->deflink.u.mgd.csa_waiting_bcn)
return;
@@ -4881,6 +4915,9 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
struct sta_info *sta;
unsigned long timeout;

+ if (WARN_ON(sdata->vif.valid_links))
+ return;
+
if (sdata->vif.bss_conf.csa_active &&
!sdata->deflink.u.mgd.csa_waiting_bcn)
return;
@@ -5040,7 +5077,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
- INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
ieee80211_beacon_connection_loss_work);
INIT_WORK(&ifmgd->csa_connection_drop_work,
@@ -5050,7 +5086,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0);
timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0);
- timer_setup(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, 0);
INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
ieee80211_sta_handle_tspec_ac_params_wk);

@@ -5078,6 +5113,9 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link)
link->u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC;
else
link->u.mgd.req_smps = IEEE80211_SMPS_OFF;
+
+ INIT_WORK(&link->u.mgd.chswitch_work, ieee80211_chswitch_work);
+ timer_setup(&link->u.mgd.chswitch_timer, ieee80211_chswitch_timer, 0);
}

/* scan finished notification */
@@ -5094,7 +5132,7 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
rcu_read_unlock();
}

-static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
+static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link,
struct cfg80211_bss *cbss)
{
struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp;
@@ -5109,7 +5147,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
bool support_160;
u8 chains = 1;

- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)
return chains;

ht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_CAPABILITY);
@@ -5122,7 +5160,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
*/
}

- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
return chains;

vht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY);
@@ -5141,7 +5179,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_sub_if_data *sdata,
chains = max(chains, nss);
}

- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)
return chains;

ies = rcu_dereference(cbss->ies);
@@ -5363,6 +5401,7 @@ ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata,
}

static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link,
struct cfg80211_bss *cbss)
{
struct ieee80211_local *local = sdata->local;
@@ -5395,77 +5434,77 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,

sband = local->hw.wiphy->bands[cbss->channel->band];

- sdata->deflink.u.mgd.conn_flags &= ~(IEEE80211_CONN_DISABLE_40MHZ |
- IEEE80211_CONN_DISABLE_80P80MHZ |
- IEEE80211_CONN_DISABLE_160MHZ);
+ link->u.mgd.conn_flags &= ~(IEEE80211_CONN_DISABLE_40MHZ |
+ IEEE80211_CONN_DISABLE_80P80MHZ |
+ IEEE80211_CONN_DISABLE_160MHZ);

/* disable HT/VHT/HE if we don't support them */
if (!sband->ht_cap.ht_supported && !is_6ghz) {
mlme_dbg(sdata, "HT not supported, disabling HT/VHT/HE/EHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!sband->vht_cap.vht_supported && is_5ghz) {
mlme_dbg(sdata, "VHT not supported, disabling VHT/HE/EHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif))) {
mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!ieee80211_get_eht_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif))) {
mlme_dbg(sdata, "EHT not supported, disabling EHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) {
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) {
ht_oper = elems->ht_operation;
ht_cap = elems->ht_cap_elem;

if (!ht_cap) {
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
ht_oper = NULL;
}
}

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && !is_6ghz) {
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && !is_6ghz) {
vht_oper = elems->vht_operation;
if (vht_oper && !ht_oper) {
vht_oper = NULL;
sdata_info(sdata,
"AP advertised VHT without HT, disabling HT/VHT/HE\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (!elems->vht_cap_elem) {
sdata_info(sdata,
"bad VHT capabilities, disabling VHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
vht_oper = NULL;
}
}

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
he_oper = elems->he_operation;

if (is_6ghz) {
struct ieee80211_bss_conf *bss_conf;
u8 i, j = 0;

- bss_conf = &sdata->vif.bss_conf;
+ bss_conf = link->conf;

if (elems->pwr_constr_elem)
bss_conf->pwr_reduction = *elems->pwr_constr_elem;
@@ -5487,8 +5526,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,

if (!ieee80211_verify_peer_he_mcs_support(sdata, ies, he_oper) ||
!ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper))
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
- IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
+ IEEE80211_CONN_DISABLE_EHT;
}

/*
@@ -5497,7 +5536,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
* both the 6 GHz operation information (from the HE operation IE) and
* EHT operation.
*/
- if (!(sdata->deflink.u.mgd.conn_flags &
+ if (!(link->u.mgd.conn_flags &
(IEEE80211_CONN_DISABLE_HE |
IEEE80211_CONN_DISABLE_EHT)) &&
he_oper) {
@@ -5527,7 +5566,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,

if (!have_80mhz) {
sdata_info(sdata, "80 MHz not supported, disabling VHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
}

if (sband->band == NL80211_BAND_S1GHZ) {
@@ -5537,8 +5576,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
"AP missing S1G operation element?\n");
}

- sdata->deflink.u.mgd.conn_flags |=
- ieee80211_determine_chantype(sdata, sband,
+ link->u.mgd.conn_flags |=
+ ieee80211_determine_chantype(link, sband,
cbss->channel,
bss->vht_cap_info,
ht_oper, vht_oper,
@@ -5546,21 +5585,21 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
s1g_oper,
&chandef, false);

- sdata->deflink.needed_rx_chains =
- min(ieee80211_max_rx_chains(sdata, cbss), local->rx_chains);
+ link->needed_rx_chains =
+ min(ieee80211_max_rx_chains(link, cbss), local->rx_chains);

rcu_read_unlock();
/* the element data was RCU protected so no longer valid anyway */
kfree(elems);
elems = NULL;

- if (sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) {
+ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) {
sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection");
return -EINVAL;
}

/* will change later if needed */
- sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
+ link->smps_mode = IEEE80211_SMPS_OFF;

mutex_lock(&local->mtx);
/*
@@ -5568,7 +5607,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
* on incompatible channels, e.g. 80+80 and 160 sharing the
* same control channel) try to use a smaller bandwidth.
*/
- ret = ieee80211_link_use_channel(&sdata->deflink, &chandef,
+ ret = ieee80211_link_use_channel(link, &chandef,
IEEE80211_CHANCTX_SHARED);

/* don't downgrade for 5 and 10 MHz channels, though. */
@@ -5577,9 +5616,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
goto out;

while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
- sdata->deflink.u.mgd.conn_flags |=
+ link->u.mgd.conn_flags |=
ieee80211_chandef_downgrade(&chandef);
- ret = ieee80211_link_use_channel(&sdata->deflink, &chandef,
+ ret = ieee80211_link_use_channel(link, &chandef,
IEEE80211_CHANCTX_SHARED);
}
out:
@@ -5630,6 +5669,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss = (void *)cbss->priv;
struct sta_info *new_sta = NULL;
struct ieee80211_supported_band *sband;
+ struct ieee80211_link_data *link = &sdata->deflink;
bool have_sta = false;
int err;

@@ -5673,6 +5713,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
int min_rate = INT_MAX, min_rate_index = -1;
const struct cfg80211_bss_ies *ies;
int shift = ieee80211_vif_get_shift(&sdata->vif);
+ struct ieee80211_link_sta *link_sta = &new_sta->sta.deflink;
+
+ memcpy(link_sta->addr, cbss->bssid, ETH_ALEN);

/* TODO: S1G Basic Rate Set is expressed elsewhere */
if (cbss->channel->band == NL80211_BAND_S1GHZ) {
@@ -5710,12 +5753,12 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
}

if (rates)
- new_sta->sta.deflink.supp_rates[cbss->channel->band] = rates;
+ link_sta->supp_rates[cbss->channel->band] = rates;
else
sdata_info(sdata,
"No rates found, keeping mandatory only\n");

- sdata->vif.bss_conf.basic_rates = basic_rates;
+ link->conf->basic_rates = basic_rates;

/* cf. IEEE 802.11 9.2.12 */
if (cbss->channel->band == NL80211_BAND_2GHZ &&
@@ -5725,38 +5768,38 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;

skip_rates:
- memcpy(sdata->deflink.u.mgd.bssid, cbss->bssid, ETH_ALEN);
+ memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN);

/* set timing information */
- sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
+ link->conf->beacon_int = cbss->beacon_interval;
rcu_read_lock();
ies = rcu_dereference(cbss->beacon_ies);
if (ies) {
- sdata->vif.bss_conf.sync_tsf = ies->tsf;
- sdata->vif.bss_conf.sync_device_ts =
+ link->conf->sync_tsf = ies->tsf;
+ link->conf->sync_device_ts =
bss->device_ts_beacon;

ieee80211_get_dtim(ies,
- &sdata->vif.bss_conf.sync_dtim_count,
+ &link->conf->sync_dtim_count,
NULL);
} else if (!ieee80211_hw_check(&sdata->local->hw,
TIMING_BEACON_ONLY)) {
ies = rcu_dereference(cbss->proberesp_ies);
/* must be non-NULL since beacon IEs were NULL */
- sdata->vif.bss_conf.sync_tsf = ies->tsf;
- sdata->vif.bss_conf.sync_device_ts =
+ link->conf->sync_tsf = ies->tsf;
+ link->conf->sync_device_ts =
bss->device_ts_presp;
- sdata->vif.bss_conf.sync_dtim_count = 0;
+ link->conf->sync_dtim_count = 0;
} else {
- sdata->vif.bss_conf.sync_tsf = 0;
- sdata->vif.bss_conf.sync_device_ts = 0;
- sdata->vif.bss_conf.sync_dtim_count = 0;
+ link->conf->sync_tsf = 0;
+ link->conf->sync_device_ts = 0;
+ link->conf->sync_dtim_count = 0;
}
rcu_read_unlock();
}

if (new_sta || override) {
- err = ieee80211_prep_channel(sdata, cbss);
+ err = ieee80211_prep_channel(sdata, link, cbss);
if (err) {
if (new_sta)
sta_info_free(local, new_sta);
@@ -5769,7 +5812,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
* tell driver about BSSID, basic rates and timing
* this was set up above, before setting the channel
*/
- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_BSSID |
BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT);
@@ -5786,7 +5829,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
return err;
}
} else
- WARN_ON_ONCE(!ether_addr_equal(sdata->deflink.u.mgd.bssid, cbss->bssid));
+ WARN_ON_ONCE(!ether_addr_equal(link->u.mgd.bssid, cbss->bssid));

/* Cancel scan to ensure that nothing interferes with connection */
if (local->scanning)
@@ -5799,6 +5842,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
struct cfg80211_auth_request *req)
{
+ struct ieee80211_link_data *link = &sdata->deflink;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_auth_data *auth_data;
@@ -5937,7 +5981,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
return 0;

err_clear:
- eth_zero_addr(sdata->deflink.u.mgd.bssid);
+ eth_zero_addr(link->u.mgd.bssid);
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_BSSID);
ifmgd->auth_data = NULL;
@@ -5961,6 +6005,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband;
struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg;
const struct element *ssid_elem, *ht_elem, *vht_elem;
+ struct ieee80211_link_data *link = &sdata->deflink;
int i, err;
bool override = false;

@@ -6018,7 +6063,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,

/* prepare assoc data */

- sdata->deflink.u.mgd.beacon_crc_valid = false;
+ link->u.mgd.beacon_crc_valid = false;

assoc_data->wmm = bss->wmm_used &&
(local->hw.queues >= IEEE80211_NUM_ACS);
@@ -6034,10 +6079,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
netdev_info(sdata->dev,
"disabling HT/VHT/HE due to WEP/TKIP use\n");
}
@@ -6047,10 +6092,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,

/* also disable HT/VHT/HE/EHT if the AP doesn't use WMM */
if (!bss->wmm_used) {
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
netdev_info(sdata->dev,
"disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n");
}
@@ -6098,7 +6143,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
assoc_data->ap_ht_param =
((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param;
else if (!is_6ghz)
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
vht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_VHT_CAPABILITY);
if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) {
memcpy(&assoc_data->ap_vht_cap, vht_elem->data,
@@ -6106,7 +6151,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
} else if (is_5ghz) {
sdata_info(sdata,
"VHT capa missing/short, disabling VHT/HE/EHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT |
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT |
IEEE80211_CONN_DISABLE_HE |
IEEE80211_CONN_DISABLE_EHT;
}
@@ -6156,11 +6201,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
/* kick off associate process */

ifmgd->assoc_data = assoc_data;
- sdata->deflink.u.mgd.dtim_period = 0;
- sdata->deflink.u.mgd.have_beacon = false;
+ link->u.mgd.dtim_period = 0;
+ link->u.mgd.have_beacon = false;

/* override HT/VHT configuration only if the AP and we support it */
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
struct ieee80211_sta_ht_cap sta_ht_cap;

if (req->flags & ASSOC_REQ_DISABLE_HT)
@@ -6170,49 +6215,49 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);

/* check for 40 MHz disable override */
- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) &&
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) &&
sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
!(sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
override = true;

- if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
+ if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
req->flags & ASSOC_REQ_DISABLE_VHT)
override = true;
}

if (req->flags & ASSOC_REQ_DISABLE_HT) {
mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (req->flags & ASSOC_REQ_DISABLE_VHT) {
mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
}

if (req->flags & ASSOC_REQ_DISABLE_HE) {
mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n");
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
}

if (req->flags & ASSOC_REQ_DISABLE_EHT)
- sdata->deflink.u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;
+ link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT;

err = ieee80211_prep_connection(sdata, req->bss, true, override);
if (err)
goto err_clear;

- if (sdata->deflink.u.mgd.req_smps == IEEE80211_SMPS_AUTOMATIC) {
+ if (link->u.mgd.req_smps == IEEE80211_SMPS_AUTOMATIC) {
if (ifmgd->powersave)
- sdata->deflink.smps_mode = IEEE80211_SMPS_DYNAMIC;
+ link->smps_mode = IEEE80211_SMPS_DYNAMIC;
else
- sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
+ link->smps_mode = IEEE80211_SMPS_OFF;
} else {
- sdata->deflink.smps_mode = sdata->deflink.u.mgd.req_smps;
+ link->smps_mode = link->u.mgd.req_smps;
}

rcu_read_lock();
@@ -6225,7 +6270,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
* should this be more if we miss one?
*/
sdata_info(sdata, "waiting for beacon from %pM\n",
- sdata->deflink.u.mgd.bssid);
+ link->u.mgd.bssid);
assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
assoc_data->timeout_started = true;
assoc_data->need_beacon = true;
@@ -6234,33 +6279,33 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
u8 dtim_count = 0;

ieee80211_get_dtim(beacon_ies, &dtim_count,
- &sdata->deflink.u.mgd.dtim_period);
+ &link->u.mgd.dtim_period);

- sdata->deflink.u.mgd.have_beacon = true;
+ link->u.mgd.have_beacon = true;
assoc_data->timeout = jiffies;
assoc_data->timeout_started = true;

if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
- sdata->vif.bss_conf.sync_tsf = beacon_ies->tsf;
- sdata->vif.bss_conf.sync_device_ts =
+ link->conf->sync_tsf = beacon_ies->tsf;
+ link->conf->sync_device_ts =
bss->device_ts_beacon;
- sdata->vif.bss_conf.sync_dtim_count = dtim_count;
+ link->conf->sync_dtim_count = dtim_count;
}

elem = cfg80211_find_ext_elem(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION,
beacon_ies->data, beacon_ies->len);
if (elem && elem->datalen >= 3)
- sdata->vif.bss_conf.profile_periodicity = elem->data[2];
+ link->conf->profile_periodicity = elem->data[2];
else
- sdata->vif.bss_conf.profile_periodicity = 0;
+ link->conf->profile_periodicity = 0;

elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
beacon_ies->data, beacon_ies->len);
if (elem && elem->datalen >= 11 &&
(elem->data[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
- sdata->vif.bss_conf.ema_ap = true;
+ link->conf->ema_ap = true;
else
- sdata->vif.bss_conf.ema_ap = false;
+ link->conf->ema_ap = false;
} else {
assoc_data->timeout = jiffies;
assoc_data->timeout_started = true;
@@ -6285,7 +6330,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,

return 0;
err_clear:
- eth_zero_addr(sdata->deflink.u.mgd.bssid);
+ eth_zero_addr(link->u.mgd.bssid);
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_BSSID);
ifmgd->assoc_data = NULL;
@@ -6393,6 +6438,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
void ieee80211_mgd_stop_link(struct ieee80211_link_data *link)
{
cancel_work_sync(&link->u.mgd.request_smps_work);
+ cancel_work_sync(&link->u.mgd.chswitch_work);
}

void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
@@ -6407,7 +6453,6 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&ifmgd->monitor_work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
cancel_work_sync(&ifmgd->csa_connection_drop_work);
- cancel_work_sync(&ifmgd->chswitch_work);
cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);

sdata_lock(sdata);
--
2.36.1

2022-07-13 09:50:34

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 15/76] wifi: nl80211: enable setting the link address at new station

From: Shaul Triebitz <[email protected]>

Since for an MLD station the default link is added together
with the add station command, allow also setting the link
MAC address.
Otherwise, it is needed to use the modify link API only
for setting the link MAC address.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/wireless/nl80211.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9eee853efd57..b50ba1803595 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7017,7 +7017,25 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.link_sta_params.link_id =
nl80211_link_id_or_invalid(info->attrs);

- mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ if (info->attrs[NL80211_ATTR_MLD_ADDR]) {
+ /* If MLD_ADDR attribute is set then this is an MLD station
+ * and the MLD_ADDR attribute holds the MLD address and the
+ * MAC attribute holds for the LINK address.
+ * In that case, the link_id is also expected to be valid.
+ */
+ if (params.link_sta_params.link_id < 0)
+ return -EINVAL;
+
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+ params.link_sta_params.mld_mac = mac_addr;
+ params.link_sta_params.link_mac =
+ nla_data(info->attrs[NL80211_ATTR_MAC]);
+ if (!is_valid_ether_addr(params.link_sta_params.link_mac))
+ return -EINVAL;
+ } else {
+ mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ }
+
params.link_sta_params.supported_rates =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
params.link_sta_params.supported_rates_len =
--
2.36.1

2022-07-13 09:50:35

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 69/76] wifi: mac80211: Allow EAPOL tx from specific link

From: Andrei Otcheretianski <[email protected]>

Allow link source address on TX.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 3 +++
net/mac80211/rx.c | 4 ++--
net/mac80211/tx.c | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 58b08315fa26..163e62dab045 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1752,6 +1752,9 @@ void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_clear_fast_rx(struct sta_info *sta);

+bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr, int *out_link_id);
+
/* STA code */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 97046d30c9ca..fcea7c3f5cd5 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2532,8 +2532,8 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
return 0;
}

-static bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
- const u8 *addr, int *out_link_id)
+bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr, int *out_link_id)
{
unsigned int link_id;

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1ba3bd180bd2..b9cb71dfa6cf 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2781,7 +2781,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
(sdata->vif.type != NL80211_IFTYPE_OCB) &&
!multicast && !authorized &&
(cpu_to_be16(ethertype) != sdata->control_port_protocol ||
- !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
+ !ieee80211_is_our_addr(sdata, skb->data + ETH_ALEN, NULL)))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",
sdata->name, hdr.addr1);
--
2.36.1

2022-07-13 09:50:37

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 51/76] wifi: cfg80211: add ieee80211_chanwidth_rate_flags()

From: Johannes Berg <[email protected]>

To simplify things when we don't have a full chandef,
add ieee80211_chanwidth_rate_flags().

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 09f2e2f031b6..ca26e3b7341a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -939,19 +939,18 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
enum nl80211_iftype iftype);

/**
- * ieee80211_chandef_rate_flags - returns rate flags for a channel
+ * ieee80211_chanwidth_rate_flags - return rate flags for channel width
+ * @width: the channel width of the channel
*
* In some channel types, not all rates may be used - for example CCK
* rates may not be used in 5/10 MHz channels.
*
- * @chandef: channel definition for the channel
- *
- * Returns: rate flags which apply for this channel
+ * Returns: rate flags which apply for this channel width
*/
static inline enum ieee80211_rate_flags
-ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef)
+ieee80211_chanwidth_rate_flags(enum nl80211_chan_width width)
{
- switch (chandef->width) {
+ switch (width) {
case NL80211_CHAN_WIDTH_5:
return IEEE80211_RATE_SUPPORTS_5MHZ;
case NL80211_CHAN_WIDTH_10:
@@ -962,6 +961,20 @@ ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef)
return 0;
}

+/**
+ * ieee80211_chandef_rate_flags - returns rate flags for a channel
+ * @chandef: channel definition for the channel
+ *
+ * See ieee80211_chanwidth_rate_flags().
+ *
+ * Returns: rate flags which apply for this channel
+ */
+static inline enum ieee80211_rate_flags
+ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef)
+{
+ return ieee80211_chanwidth_rate_flags(chandef->width);
+}
+
/**
* ieee80211_chandef_max_power - maximum transmission power for the chandef
*
--
2.36.1

2022-07-13 09:50:46

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 67/76] wifi: cfg80211/mac80211: Support control port TX from specific link

From: Andrei Otcheretianski <[email protected]>

In case of authentication with a legacy station, link addressed EAPOL
frames should be sent. Support it.

Signed-off-by: Andrei Otcheretianski <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
include/net/cfg80211.h | 2 +-
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/tx.c | 20 ++++++++++++++++++--
net/wireless/nl80211.c | 5 ++++-
net/wireless/rdev-ops.h | 7 ++++---
net/wireless/trace.h | 11 +++++++----
6 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 44abaa9d74ea..c2fd971e5c4d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4580,7 +4580,7 @@ struct cfg80211_ops {
struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, const __be16 proto,
- const bool noencrypt,
+ const bool noencrypt, int link_id,
u64 *cookie);

int (*get_ftm_responder_stats)(struct wiphy *wiphy,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d17d73e8d19f..58b08315fa26 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1946,7 +1946,7 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta);
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted,
- u64 *cookie);
+ int link_id, u64 *cookie);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a077399ed065..1ba3bd180bd2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -5684,7 +5684,7 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted,
- u64 *cookie)
+ int link_id, u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@@ -5724,7 +5724,23 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,

ehdr = skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_dest, dest, ETH_ALEN);
- memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
+
+ if (link_id < 0) {
+ memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
+ } else {
+ struct ieee80211_bss_conf *link_conf;
+
+ rcu_read_lock();
+ link_conf = rcu_dereference(sdata->vif.link_conf[link_id]);
+ if (!link_conf) {
+ dev_kfree_skb(skb);
+ rcu_read_unlock();
+ return -ENOLINK;
+ }
+ memcpy(ehdr->h_source, link_conf->addr, ETH_ALEN);
+ rcu_read_unlock();
+ }
+
ehdr->h_proto = proto;

skb->dev = dev;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 35fcf36bbaad..53d63effbca9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -15223,6 +15223,7 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
u16 proto;
bool noencrypt;
u64 cookie = 0;
+ int link_id;
int err;

if (!wiphy_ext_feature_isset(&rdev->wiphy,
@@ -15271,8 +15272,10 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
noencrypt =
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);

+ link_id = nl80211_link_id_or_invalid(info->attrs);
+
err = rdev_tx_control_port(rdev, dev, buf, len,
- dest, cpu_to_be16(proto), noencrypt,
+ dest, cpu_to_be16(proto), noencrypt, link_id,
dont_wait_for_ack ? NULL : &cookie);
if (!err && !dont_wait_for_ack)
nl_set_extack_cookie_u64(info->extack, cookie);
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 53f5a0126dfd..40915a82da73 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -746,13 +746,14 @@ static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev,
struct net_device *dev,
const void *buf, size_t len,
const u8 *dest, __be16 proto,
- const bool noencrypt, u64 *cookie)
+ const bool noencrypt, int link,
+ u64 *cookie)
{
int ret;
trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len,
- dest, proto, noencrypt);
+ dest, proto, noencrypt, link);
ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len,
- dest, proto, noencrypt, cookie);
+ dest, proto, noencrypt, link, cookie);
if (cookie)
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
else
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index dac66ad5937d..592b9e9e821a 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2015,14 +2015,15 @@ TRACE_EVENT(rdev_mgmt_tx,
TRACE_EVENT(rdev_tx_control_port,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const u8 *buf, size_t len, const u8 *dest, __be16 proto,
- bool unencrypted),
- TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted),
+ bool unencrypted, int link_id),
+ TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted, link_id),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(dest)
__field(__be16, proto)
__field(bool, unencrypted)
+ __field(int, link_id)
),
TP_fast_assign(
WIPHY_ASSIGN;
@@ -2030,12 +2031,14 @@ TRACE_EVENT(rdev_tx_control_port,
MAC_ASSIGN(dest, dest);
__entry->proto = proto;
__entry->unencrypted = unencrypted;
+ __entry->link_id = link_id;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ","
- " proto: 0x%x, unencrypted: %s",
+ " proto: 0x%x, unencrypted: %s, link: %d",
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest),
be16_to_cpu(__entry->proto),
- BOOL_TO_STR(__entry->unencrypted))
+ BOOL_TO_STR(__entry->unencrypted),
+ __entry->link_id)
);

TRACE_EVENT(rdev_set_noack_map,
--
2.36.1

2022-07-13 09:50:50

by Johannes Berg

[permalink] [raw]
Subject: [PATCH 64/76] wifi: mac80211: add a helper to fragment an element

From: Johannes Berg <[email protected]>

The way this works is that you add all the element data,
keeping a pointer to the length field of the element.
Then call this helper function, which will fragment the
element if there was more than 255 bytes in the element,
memmove()ing the data back if needed.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/util.c | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 74d5fc5889bb..d17d73e8d19f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2193,6 +2193,7 @@ ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
return ieee802_11_parse_elems_crc(start, len, action, 0, 0, bss);
}

+void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos);

extern const int ieee802_1d_to_ac[8];

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 86b6ee7e8156..4b11cf57f4fe 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4777,3 +4777,31 @@ u8 *ieee80211_ie_build_eht_cap(u8 *pos,

return pos;
}
+
+void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos)
+{
+ unsigned int elem_len;
+
+ if (!len_pos)
+ return;
+
+ elem_len = skb->data + skb->len - len_pos - 1;
+
+ while (elem_len > 255) {
+ /* this one is 255 */
+ *len_pos = 255;
+ /* remaining data gets smaller */
+ elem_len -= 255;
+ /* make space for the fragment ID/len in SKB */
+ skb_put(skb, 2);
+ /* shift back the remaining data to place fragment ID/len */
+ memmove(len_pos + 255 + 3, len_pos + 255 + 1, elem_len);
+ /* place the fragment ID */
+ len_pos += 255 + 1;
+ *len_pos = WLAN_EID_FRAGMENT;
+ /* and point to fragment length to update later */
+ len_pos++;
+ }
+
+ *len_pos = elem_len;
+}
--
2.36.1

2022-07-13 16:26:45

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

On 7/13/2022 2:43 AM, Johannes Berg wrote:
> * This structure is the "EHT Operation Element" fields as
> - * described in P802.11be_D1.4 section 9.4.2.311
> + * described in P802.11be_D1.5 section 9.4.2.311

In D2.0 this has changed to add the fixed 4-octet Basic EHT-MCS
And Nss Set before the variable-length EHT Operation
Information

Do you have a timeline to incorporate D2.0 changes?

2022-07-13 16:26:45

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

On Wed, 2022-07-13 at 09:14 -0700, Jeff Johnson wrote:
> On 7/13/2022 2:43 AM, Johannes Berg wrote:
> > * This structure is the "EHT Operation Element" fields as
> > - * described in P802.11be_D1.4 section 9.4.2.311
> > + * described in P802.11be_D1.5 section 9.4.2.311
>
> In D2.0 this has changed to add the fixed 4-octet Basic EHT-MCS
> And Nss Set before the variable-length EHT Operation
> Information
>
> Do you have a timeline to incorporate D2.0 changes?
>

Erm. I don't know what happened with this patch - it shouldn't have had
this contents ...

But yes we also have D2.0 changes prepared somewhere.

johannes

2022-07-13 16:29:26

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

On Wed, 2022-07-13 at 18:16 +0200, Johannes Berg wrote:
> On Wed, 2022-07-13 at 09:14 -0700, Jeff Johnson wrote:
> > On 7/13/2022 2:43 AM, Johannes Berg wrote:
> > > * This structure is the "EHT Operation Element" fields as
> > > - * described in P802.11be_D1.4 section 9.4.2.311
> > > + * described in P802.11be_D1.5 section 9.4.2.311
> >
> > In D2.0 this has changed to add the fixed 4-octet Basic EHT-MCS
> > And Nss Set before the variable-length EHT Operation
> > Information
> >
> > Do you have a timeline to incorporate D2.0 changes?
> >
>
> Erm. I don't know what happened with this patch - it shouldn't have had
> this contents ...
>
> But yes we also have D2.0 changes prepared somewhere.
>

I'm not going to repost the set, but I pushed those out too now, with
the D1.5 changes broken out from this patch into a proper separate patch
- not sure how that happened, sorry.


https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=d0d0f80a4c685f4bdc7164c15ee6b83b69877e23

https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=ddfde5917e6ac5d081bf771b3a28125d416c625e

johannes

2022-07-13 16:29:48

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

On Wed, 2022-07-13 at 18:23 +0200, Johannes Berg wrote:
> On Wed, 2022-07-13 at 18:16 +0200, Johannes Berg wrote:
> > On Wed, 2022-07-13 at 09:14 -0700, Jeff Johnson wrote:
> > > On 7/13/2022 2:43 AM, Johannes Berg wrote:
> > > > * This structure is the "EHT Operation Element" fields as
> > > > - * described in P802.11be_D1.4 section 9.4.2.311
> > > > + * described in P802.11be_D1.5 section 9.4.2.311
> > >
> > > In D2.0 this has changed to add the fixed 4-octet Basic EHT-MCS
> > > And Nss Set before the variable-length EHT Operation
> > > Information
> > >
> > > Do you have a timeline to incorporate D2.0 changes?
> > >
> >
> > Erm. I don't know what happened with this patch - it shouldn't have had
> > this contents ...
> >
> > But yes we also have D2.0 changes prepared somewhere.
> >
>
> I'm not going to repost the set, but I pushed those out too now, with
> the D1.5 changes broken out from this patch into a proper separate patch
> - not sure how that happened, sorry.
>
>
> https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=d0d0f80a4c685f4bdc7164c15ee6b83b69877e23
>
> https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=ddfde5917e6ac5d081bf771b3a28125d416c625e
>

And this patch fixed as it should be:

https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=937f9f869b54888b2ce5f6af76dab12bf5695452

johannes

2022-07-13 16:32:59

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

On 7/13/2022 9:23 AM, Johannes Berg wrote:
> On Wed, 2022-07-13 at 18:16 +0200, Johannes Berg wrote:
>> On Wed, 2022-07-13 at 09:14 -0700, Jeff Johnson wrote:
>>> On 7/13/2022 2:43 AM, Johannes Berg wrote:
>>>> * This structure is the "EHT Operation Element" fields as
>>>> - * described in P802.11be_D1.4 section 9.4.2.311
>>>> + * described in P802.11be_D1.5 section 9.4.2.311
>>>
>>> In D2.0 this has changed to add the fixed 4-octet Basic EHT-MCS
>>> And Nss Set before the variable-length EHT Operation
>>> Information
>>>
>>> Do you have a timeline to incorporate D2.0 changes?
>>>
>>
>> Erm. I don't know what happened with this patch - it shouldn't have had
>> this contents ...
>>
>> But yes we also have D2.0 changes prepared somewhere.
>>
>
> I'm not going to repost the set, but I pushed those out too now, with
> the D1.5 changes broken out from this patch into a proper separate patch
> - not sure how that happened, sorry.
>
>
> https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=d0d0f80a4c685f4bdc7164c15ee6b83b69877e23
>
> https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=ddfde5917e6ac5d081bf771b3a28125d416c625e

Thanks, Johannes. You're awesome as always!

2022-07-13 16:33:19

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/76] wifi: mac80211: rx: accept link-addressed frames

On Wed, 2022-07-13 at 09:29 -0700, Jeff Johnson wrote:
> On 7/13/2022 9:23 AM, Johannes Berg wrote:
> > On Wed, 2022-07-13 at 18:16 +0200, Johannes Berg wrote:
> > > On Wed, 2022-07-13 at 09:14 -0700, Jeff Johnson wrote:
> > > > On 7/13/2022 2:43 AM, Johannes Berg wrote:
> > > > > * This structure is the "EHT Operation Element" fields as
> > > > > - * described in P802.11be_D1.4 section 9.4.2.311
> > > > > + * described in P802.11be_D1.5 section 9.4.2.311
> > > >
> > > > In D2.0 this has changed to add the fixed 4-octet Basic EHT-MCS
> > > > And Nss Set before the variable-length EHT Operation
> > > > Information
> > > >
> > > > Do you have a timeline to incorporate D2.0 changes?
> > > >
> > >
> > > Erm. I don't know what happened with this patch - it shouldn't have had
> > > this contents ...
> > >
> > > But yes we also have D2.0 changes prepared somewhere.
> > >
> >
> > I'm not going to repost the set, but I pushed those out too now, with
> > the D1.5 changes broken out from this patch into a proper separate patch
> > - not sure how that happened, sorry.
> >
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=d0d0f80a4c685f4bdc7164c15ee6b83b69877e23
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=mld&id=ddfde5917e6ac5d081bf771b3a28125d416c625e
>
> Thanks, Johannes. You're awesome as always!
>
Well these I can't take credit for, it was Ilan's doing :-)

johannes

2022-07-14 08:30:53

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [PATCH 00/76] wifi: more MLO work

On 7/13/2022 11:43 AM, Johannes Berg wrote:
> Hi,
>
> So our MLO work is progressing. Internally, I have limited support
> for MLO connections now (over hwsim), but that's at least another
> 25 patches on top of this series.
>
> But would be good to get things out first anyway. I'm tempted to
> just apply this (after net-next merges wireless-next and we will
> merge back) though - even if we have more fixes to it later.

Just for my own patch submit process. What is the reason I am seeing the
"wifi:" prefix being used with patches on linux-wireless list? Is there
other wireless tech used, eg. "bt:" or so?

Regards,
Arend

2022-07-14 08:37:14

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 00/76] wifi: more MLO work

On Thu, 2022-07-14 at 10:26 +0200, Arend Van Spriel wrote:
>
> Just for my own patch submit process. What is the reason I am seeing the
> "wifi:" prefix being used with patches on linux-wireless list? Is there
> other wireless tech used, eg. "bt:" or so?
>

Well, we had a discussion with Jakub, and he kind of indicated that he'd
like to see a bit more generic prefixes to clarify things.

We've kind of been early adopters to try it out and see what it looks
like, he hasn't pushed it and wanted to have a discussion (e.g. at LPC
or netdevconf) about it first, but it kind of makes sense since not
everyone can know all the different drivers and components.

johannes

2022-07-18 08:57:30

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/76] wifi: more MLO work

Johannes Berg <[email protected]> writes:

> On Thu, 2022-07-14 at 10:26 +0200, Arend Van Spriel wrote:
>>
>> Just for my own patch submit process. What is the reason I am seeing the
>> "wifi:" prefix being used with patches on linux-wireless list? Is there
>> other wireless tech used, eg. "bt:" or so?
>>
>
> Well, we had a discussion with Jakub, and he kind of indicated that he'd
> like to see a bit more generic prefixes to clarify things.
>
> We've kind of been early adopters to try it out and see what it looks
> like, he hasn't pushed it and wanted to have a discussion (e.g. at LPC
> or netdevconf) about it first, but it kind of makes sense since not
> everyone can know all the different drivers and components.

I have been supposed to document this in the wiki and announce it
properly, but as usual I was too busy before the vacation to do
anything. And now I'm on vacation and trying to enjoy the 13 C of
"warmth" here in Finland :D

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2022-09-14 10:12:26

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH 35/76] wifi: mac80211: mlme: use ieee80211_get_link_sband()

On 7/13/2022 5:44 PM, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
>
> This requires a few more changes.
>
> While at it, also add a warning to ieee80211_get_sband()
> to avoid it being used when there are multiple links.
>
> Signed-off-by: Johannes Berg <[email protected]>
> ---
> net/mac80211/ieee80211_i.h | 2 ++
> net/mac80211/mlme.c | 12 ++++++------
> 2 files changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index 3e360bcaa03b..a0743c78d171 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -1539,6 +1539,8 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
> struct ieee80211_chanctx_conf *chanctx_conf;
> enum nl80211_band band;
>
> + WARN_ON(sdata->vif.valid_links);
> +
> rcu_read_lock();
> chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
>
Hi Johannes,

Now I hit below warning here in ieee80211_get_sband() in my MLO test for
station.
Will you have more patch to fix the warning?

[  712.857016] ------------[ cut here ]------------
[  712.857020] ath12k_pci 0000:05:00.0: ext irq:40
[  712.857021] WARNING: CPU: 2 PID: 39 at
net/mac80211/ieee80211_i.h:1572
___ieee80211_start_rx_ba_session+0x8fe/0x930 [mac80211]
[  712.857140] Modules linked in: michael_mic ath12k(OE) qmi_helpers
qrtr_mhi mhi(E) qrtr mac80211(OE) cfg80211(OE) libarc4 rfcomm bnep
nls_iso8859_1 intel_rapl_msr intel_rapl_common x86_pkg_temp_thermal
intel_powerclamp coretemp kvm_intel kvm irqbypass crct10dif_pclmul
ghash_clmulni_intel aesni_intel snd_ctl_led snd_hda_codec_conexant
crypto_simd cryptd rapl intel_cstate uvcvideo btusb snd_hda_codec_hdmi
snd_hda_codec_generic btrtl btbcm snd_hda_intel btintel
videobuf2_vmalloc bluetooth videobuf2_memops snd_intel_dspcfg
ecdh_generic ecc videobuf2_v4l2 i915 videobuf2_common videodev cec mc
rc_core drm_buddy ttm snd_hda_codec drm_display_helper snd_hda_core
drm_kms_helper snd_seq_midi snd_seq_midi_event snd_rawmidi snd_hwdep
i2c_algo_bit snd_seq snd_pcm thinkpad_acpi fb_sys_fops syscopyarea
sysfillrect sysimgblt snd_seq_device snd_timer nvram mei_me at24
ledtrig_audio platform_profile mei joydev input_leds snd soundcore
serio_raw mac_hid wmi_bmof sch_fq_codel parport_pc ppdev lp parport drm
[  712.857298]  ip_tables x_tables autofs4 firewire_ohci sdhci_pci
psmouse ahci firewire_core crc32_pclmul libahci i2c_i801 cqhci crc_itu_t
i2c_smbus e1000e sdhci ptp lpc_ich pps_core wmi video
[  712.857336] CPU: 2 PID: 39 Comm: kworker/u16:1 Kdump: loaded Tainted:
G        W  OE     5.19.0-rc6+ #4
[  712.857344] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW
(1.33 ) 07/29/2011
[  712.857348] Workqueue: phy0 ieee80211_iface_work [mac80211]
[  712.857442] RIP: 0010:___ieee80211_start_rx_ba_session+0x8fe/0x930
[mac80211]
[  712.857526] Code: a1 da 41 be 25 00 00 00 66 44 89 75 88 e9 54 fc ff
ff b9 08 00 00 00 e9 7e fe ff ff e8 4b 91 a1 da 4c 8b 4d 88 e9 d8 fc ff
ff <0f> 0b e9 05 fe ff ff 4c 89 5d a8 e8 32 91 a1 da 4c 8b 5d a8 e9 90
[  712.857533] RSP: 0018:ffffbafa401bbce0 EFLAGS: 00010206
[  712.857539] RAX: 0000000000000000 RBX: 0000000000004018 RCX:
0000000000000000
[  712.857543] RDX: ffff8f48e1489e40 RSI: 0000000000000009 RDI:
0000000000000103
[  712.857546] RBP: ffffbafa401bbd80 R08: ffffbafa401bbbc8 R09:
0000000000004000
[  712.857550] R10: ffff8f49c0042a00 R11: ffff8f48f304c300 R12:
ffff8f49c42f9000
[  712.857554] R13: ffff8f48e2b888e0 R14: 000000000000401b R15:
ffff8f48c714c9c0
[  712.857558] FS:  0000000000000000(0000) GS:ffff8f49fa280000(0000)
knlGS:0000000000000000
[  712.857562] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  712.857566] CR2: 000055a204665fe4 CR3: 000000004e00a003 CR4:
00000000000606e0
[  712.857571] Call Trace:
[  712.857617]  <TASK>
[  712.857639]  ieee80211_process_addba_request+0xb7/0x190 [mac80211]
[  712.857740]  ieee80211_iface_work+0x3d1/0x410 [mac80211]
[  712.857803]  process_one_work+0x227/0x440
[  712.857812]  worker_thread+0x31/0x3e0
[  712.857817]  ? process_one_work+0x440/0x440
[  712.857822]  kthread+0xfe/0x130
[  712.857829]  ? kthread_complete_and_exit+0x20/0x20
[  712.857836]  ret_from_fork+0x22/0x30
[  712.857846]  </TASK>
[  712.857848] ---[ end trace 0000000000000000 ]---
...
>

2022-09-27 08:17:51

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 35/76] wifi: mac80211: mlme: use ieee80211_get_link_sband()

On Wed, 2022-09-14 at 18:00 +0800, Wen Gong wrote:
> On 7/13/2022 5:44 PM, Johannes Berg wrote:
> > From: Johannes Berg <[email protected]>
> >
> > This requires a few more changes.
> >
> > While at it, also add a warning to ieee80211_get_sband()
> > to avoid it being used when there are multiple links.
> >
> > Signed-off-by: Johannes Berg <[email protected]>
> > ---
> > net/mac80211/ieee80211_i.h | 2 ++
> > net/mac80211/mlme.c | 12 ++++++------
> > 2 files changed, 8 insertions(+), 6 deletions(-)
> >
> > diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> > index 3e360bcaa03b..a0743c78d171 100644
> > --- a/net/mac80211/ieee80211_i.h
> > +++ b/net/mac80211/ieee80211_i.h
> > @@ -1539,6 +1539,8 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
> > struct ieee80211_chanctx_conf *chanctx_conf;
> > enum nl80211_band band;
> >
> > + WARN_ON(sdata->vif.valid_links);
> > +
> > rcu_read_lock();
> > chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
> >
> Hi Johannes,
>
> Now I hit below warning here in ieee80211_get_sband() in my MLO test for
> station.
> Will you have more patch to fix the warning?
>

Yeah still working on all this, obviously ...

That should be fairly harmless for now, unless you're trying to use 1k
block-ack.

johannes

2023-08-11 05:43:54

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On 7/13/2022 5:44 PM, Johannes Berg wrote:
> From: Johannes Berg <[email protected]>
>
> We have the per-interface type capabilities, currently for
> extended capabilities, add the EML/MLD capabilities there
> to have this advertised by the driver.
>
> Signed-off-by: Johannes Berg <[email protected]>
> ---
> include/net/cfg80211.h | 4 ++++
> include/uapi/linux/nl80211.h | 12 ++++++++++--
> net/wireless/nl80211.c | 9 +++++++++
> 3 files changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index ca26e3b7341a..44abaa9d74ea 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -4993,12 +4993,16 @@ struct wiphy_vendor_command {
> * 802.11-2012 8.4.2.29 for the defined fields.
> * @extended_capabilities_mask: mask of the valid values
> * @extended_capabilities_len: length of the extended capabilities
> + * @eml_capabilities: EML capabilities (for MLO)
> + * @mld_capa_and_ops: MLD capabilities and operations (for MLO)
> */
> struct wiphy_iftype_ext_capab {
> enum nl80211_iftype iftype;
> const u8 *extended_capabilities;
> const u8 *extended_capabilities_mask;
> u8 extended_capabilities_len;
> + u16 eml_capabilities;
> + u16 mld_capa_and_ops;
> };
>

Now there are many nl80211_band such as NL80211_BAND_2GHZ/
NL80211_BAND_5GHZ/NL80211_BAND_6GHZ... In the same interface, if some bands
support EML, and other bands not support EML, then how to handler this
case?

Could move the "u16 eml_capabilities" into struct
ieee80211_sband_iftype_data
as well as "struct ieee80211_sta_eht_cap eht_cap"? Also same for "u16
mld_capa_and_ops".

[...]


2023-08-11 09:21:14

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On Fri, 2023-08-11 at 11:51 +0800, Wen Gong wrote:
> Now there are many nl80211_band such as NL80211_BAND_2GHZ/
> NL80211_BAND_5GHZ/NL80211_BAND_6GHZ... In the same interface, if some bands
> support EML, and other bands not support EML, then how to handler this
> case?

But ... these are MLD capabilities, not of the (associated) STA?

So not sure how that would make sense? What would you even _do_ with
that?

johannes

2023-08-11 09:27:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On Fri, 2023-08-11 at 17:05 +0800, Wen Gong wrote:
> On 8/11/2023 5:03 PM, Johannes Berg wrote:
> > On Fri, 2023-08-11 at 11:51 +0800, Wen Gong wrote:
> > > Now there are many nl80211_band such as NL80211_BAND_2GHZ/
> > > NL80211_BAND_5GHZ/NL80211_BAND_6GHZ... In the same interface, if some bands
> > > support EML, and other bands not support EML, then how to handler this
> > > case?
> > But ... these are MLD capabilities, not of the (associated) STA?
> Yes, I know it.

Then you can't honestly be suggesting we move "MLD capa and ops" into
per-band, no?

> > So not sure how that would make sense? What would you even _do_ with
> > that?

> I think another change is not move "u16 eml_capabilities", and only add
> a new
> field "u16 eml_supp_bands" together with the "u16 eml_capabilities", the
> eml_supp_bands is filled with the bit map of enum nl80211_band. Is that OK?
>

And again, what would you do with it? Not advertise EML when you have
selected links that are not in the map? And if the links change
dynamically in the future? You'd probably need a bunch of validation for
that.

And usually you'd probably always connect to all the bands?

I really don't get it.

Btw this is all client - so your client implementation can just not send
the EML action frame (forgot the name right now) when the currently
active links are not compatible.

johannes

2023-08-11 09:37:58

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On 8/11/2023 5:03 PM, Johannes Berg wrote:
> On Fri, 2023-08-11 at 11:51 +0800, Wen Gong wrote:
>> Now there are many nl80211_band such as NL80211_BAND_2GHZ/
>> NL80211_BAND_5GHZ/NL80211_BAND_6GHZ... In the same interface, if some bands
>> support EML, and other bands not support EML, then how to handler this
>> case?
> But ... these are MLD capabilities, not of the (associated) STA?
Yes, I know it.
>
> So not sure how that would make sense? What would you even _do_ with
> that?
I think another change is not move "u16 eml_capabilities", and only add
a new
field "u16 eml_supp_bands" together with the "u16 eml_capabilities", the
eml_supp_bands is filled with the bit map of enum nl80211_band. Is that OK?
>
> johannes

2023-08-11 09:37:59

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On 8/11/2023 5:08 PM, Johannes Berg wrote:
> On Fri, 2023-08-11 at 17:05 +0800, Wen Gong wrote:
>> On 8/11/2023 5:03 PM, Johannes Berg wrote:
>>> On Fri, 2023-08-11 at 11:51 +0800, Wen Gong wrote:
>>>> Now there are many nl80211_band such as NL80211_BAND_2GHZ/
>>>> NL80211_BAND_5GHZ/NL80211_BAND_6GHZ... In the same interface, if some bands
>>>> support EML, and other bands not support EML, then how to handler this
>>>> case?
>>> But ... these are MLD capabilities, not of the (associated) STA?
>> Yes, I know it.
> Then you can't honestly be suggesting we move "MLD capa and ops" into
> per-band, no?
I know it just now after I send the suggestion????
>>> So not sure how that would make sense? What would you even _do_ with
>>> that?
>> I think another change is not move "u16 eml_capabilities", and only add
>> a new
>> field "u16 eml_supp_bands" together with the "u16 eml_capabilities", the
>> eml_supp_bands is filled with the bit map of enum nl80211_band. Is that OK?
>>
> And again, what would you do with it? Not advertise EML when you have
> selected links that are not in the map? And if the links change
> dynamically in the future? You'd probably need a bunch of validation for
> that.
For example, for station, NOT support EML on 2 GHz, support EML on 5
GHz/6 GHz.

When connect to 2/3 links AP, then EML should NOT add in assoc req while
connect
to AP which is 2 GHz+5 GHz or 2 GHz+6 GHz or 2 GHz+5 GHz+6 GHz.

EML should add in assoc req while connect to AP which is 5 GHz+6 GHz.

For dynamic link change, it is another new topic, so I have not good advise
for that.????
>
> And usually you'd probably always connect to all the bands?
>
> I really don't get it.

Sometimes AP is 3 links (2 GHz+5 GHz+6 GHz), but station only support 2
links,

then station will not connect all bands, station need choose 2 bands to
connect.

>
> Btw this is all client - so your client implementation can just not send
> the EML action frame (forgot the name right now) when the currently
> active links are not compatible.
I guess you are refer to "EML Operating Mode Notification frame".
> johannes

2023-08-11 09:39:33

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On Fri, 2023-08-11 at 17:24 +0800, Wen Gong wrote:
> >
> > And again, what would you do with it? Not advertise EML when you have
> > selected links that are not in the map? And if the links change
> > dynamically in the future? You'd probably need a bunch of validation for
> > that.
> For example, for station, NOT support EML on 2 GHz, support EML on 5
> GHz/6 GHz.
>
> When connect to 2/3 links AP, then EML should NOT add in assoc req while
> connect to AP which is 2 GHz+5 GHz or 2 GHz+6 GHz or 2 GHz+5 GHz+6 GHz.
>
> EML should add in assoc req while connect to AP which is 5 GHz+6 GHz.

OK, at least that answers the question what you'd want to do with it :)

> For dynamic link change, it is another new topic, so I have not good advise
> for that.????

But everyone's looking at that?

Honestly I'm not even sure - and you might know better - what the EML
capabilities matter for if you never enable EML.

So almost feels like if you never send the EML OMN frame (thanks for the
name!) the AP wouldn't really care, and that's something you could do
very easily without changing it, i.e. you pretend that your 2.4 GHz
actually has EML, you just never enable it in case 2.4 GHz is active?

johannes

2023-08-11 11:04:13

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH 61/76] wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities

On 8/11/2023 5:27 PM, Johannes Berg wrote:
> On Fri, 2023-08-11 at 17:24 +0800, Wen Gong wrote:
>
[...]
> OK, at least that answers the question what you'd want to do with it :)
>
>> For dynamic link change, it is another new topic, so I have not good advise
>> for that.????
> But everyone's looking at that?
I see there hare some patches in mac80211/cfg80211 for dynamic link
removal such as
"wifi: mac80211: Support link removal using Reconfiguration ML element".
For link
removal, it does not effect the EML issue I said. Only link add
operation without (re)assoc
(35.3.6 ML reconfiguration of IEEE P802.11be™/D3.2 disallow (re)assoc
for link add)
will impact the EML issue I said. But I did not see dynamic link add
patch now. Will
you also do the patches for dynamic link add without (re)assoc?
>
> Honestly I'm not even sure - and you might know better - what the EML
> capabilities matter for if you never enable EML.
>
> So almost feels like if you never send the EML OMN frame (thanks for the
> name!) the AP wouldn't really care, and that's something you could do
> very easily without changing it, i.e. you pretend that your 2.4 GHz
> actually has EML, you just never enable it in case 2.4 GHz is active?
Your advise maybe feasible. Then no change is needed in nl80211 here for
the EML.
> johannes