From 63907290faa916ffab1c8455141c79ca8e3a79bb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 17 May 2022 18:05:59 +0200 Subject: mt76: mt7915: fix endianness in mt7915_rf_regval_get Fix the following sparse warning in mt7915_rf_regval_get routine: drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c:979:16: warning: cast to restricted __le32 Fixes: 0a17329ae9c1f ("mt76: mt7915: add debugfs knob for RF registers read/write") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index cab6e02e1f8c..d0c719ecacd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -976,7 +976,7 @@ mt7915_rf_regval_get(void *data, u64 *val) if (ret) return ret; - *val = le32_to_cpu(regval); + *val = regval; return 0; } -- cgit v1.2.3 From cffd93411575afd987788e2ec3cb8eaff70f0215 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 17 May 2022 18:37:07 +0200 Subject: mt76: mt76x02u: fix possible memory leak in __mt76x02u_mcu_send_msg Free the skb if mt76u_bulk_msg fails in __mt76x02u_mcu_send_msg routine. Fixes: 4c89ff2c74e39 ("mt76: split __mt76u_mcu_send_msg and mt76u_mcu_send_msg routines") Co-developed-by: Gergo Koteles Signed-off-by: Gergo Koteles Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 2953df7d8388..c6c16fe8ee85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -108,7 +108,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, ret = mt76u_bulk_msg(dev, skb->data, skb->len, NULL, 500, MT_EP_OUT_INBAND_CMD); if (ret) - return ret; + goto out; if (wait_resp) ret = mt76x02u_mcu_wait_resp(dev, seq); -- cgit v1.2.3 From f572dc969a59a80baa22bf2f7c9af0064402652f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 May 2022 16:57:22 +0300 Subject: mt76: mt7915: fix endian bug in mt7915_rf_regval_set() This code is supposed to set a u32 value, but casting will not work on big endian systems. Fixes: 0a17329ae9c1 ("mt76: mt7915: add debugfs knob for RF registers read/write") Signed-off-by: Dan Carpenter Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index d0c719ecacd0..fd76db8f5269 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -985,8 +985,9 @@ static int mt7915_rf_regval_set(void *data, u64 val) { struct mt7915_dev *dev = data; + u32 val32 = val; - return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, (u32 *)&val, true); + return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true); } DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get, -- cgit v1.2.3 From 162d5c14ba482934334428b3be972571f0c007b0 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 20 May 2022 17:03:37 +0800 Subject: mt76: add 6 GHz band support in mt76_sar_freq_ranges Add new frequencies support in mt76_sar_freq_ranges[] * 5945 - 6165 * 6165 - 6405 * 6405 - 6525 * 6525 - 6705 * 6705 - 6865 * 6865 - 7125 Reviewed-by: Sean Wang Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 5f75a8945a6e..4d301a131a9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -178,6 +178,12 @@ static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { { .start_freq = 5350, .end_freq = 5470, }, { .start_freq = 5470, .end_freq = 5725, }, { .start_freq = 5725, .end_freq = 5950, }, + { .start_freq = 5945, .end_freq = 6165, }, + { .start_freq = 6165, .end_freq = 6405, }, + { .start_freq = 6405, .end_freq = 6525, }, + { .start_freq = 6525, .end_freq = 6705, }, + { .start_freq = 6705, .end_freq = 6865, }, + { .start_freq = 6865, .end_freq = 7125, }, }; static const struct cfg80211_sar_capa mt76_sar_capa = { -- cgit v1.2.3 From f965333e491e36adb0fa91e389fba8685b704fb6 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 20 May 2022 17:03:38 +0800 Subject: mt76: mt7921: introduce ACPI SAR support In ACPI SAR enabled device, mt7921 should read power limit in ACPI config. The limit value would be applied to regular tx power settings in mt76. Two major functionalities added: 1. Get SAR power table through ACPI. 2. Read power in Dynamic/Geo SAR table for tx power limit. Table note MTDS: Dynamic SAR table MTGS: Geo SAR table MTCL: Country List table (for 6GHz support) Reviewed-by: Sean Wang Co-developed-by: Quan Zhou Signed-off-by: Quan Zhou Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 1 + .../net/wireless/mediatek/mt76/mt7921/acpi_sar.c | 279 +++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/acpi_sar.h | 93 +++++++ drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 20 ++ 5 files changed, 395 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 0a146818c623..e5d2d2e131a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -9,6 +9,7 @@ CFLAGS_trace.o := -I$(src) mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o +mt7921-common-$(CONFIG_ACPI) += acpi_sar.o mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o mt7921u-y := usb.o usb_mac.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c new file mode 100644 index 000000000000..be4f07ad3af9 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2022 MediaTek Inc. */ + +#include +#include "mt7921.h" + +static int +mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *sar_root, *sar_unit; + struct mt76_dev *mdev = &dev->mt76; + acpi_handle root, handle; + acpi_status status; + u32 i = 0; + + root = ACPI_HANDLE(mdev->dev); + if (!root) + return -EOPNOTSUPP; + + status = acpi_get_handle(root, method, &handle); + if (ACPI_FAILURE(status)) + return -EIO; + + status = acpi_evaluate_object(handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) + return -EIO; + + sar_root = buf.pointer; + if (sar_root->type != ACPI_TYPE_PACKAGE || + sar_root->package.count < 4 || + sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) { + dev_err(mdev->dev, "sar cnt = %d\n", + sar_root->package.count); + goto free; + } + + if (!*tbl) { + *tbl = devm_kzalloc(mdev->dev, sar_root->package.count, + GFP_KERNEL); + if (!*tbl) + goto free; + } + if (len) + *len = sar_root->package.count; + + for (i = 0; i < sar_root->package.count; i++) { + sar_unit = &sar_root->package.elements[i]; + + if (sar_unit->type != ACPI_TYPE_INTEGER) + break; + *(*tbl + i) = (u8)sar_unit->integer.value; + } +free: + kfree(sar_root); + + return (i == sar_root->package.count) ? 0 : -EINVAL; +} + +/* MTCL : Country List Table for 6G band */ +static int +mt7921_asar_acpi_read_mtcl(struct mt7921_dev *dev, u8 **table, u8 *version) +{ + *version = (mt7921_acpi_read(dev, MT7921_ACPI_MTCL, table, NULL) < 0) + ? 1 : 2; + return 0; +} + +/* MTDS : Dynamic SAR Power Table */ +static int +mt7921_asar_acpi_read_mtds(struct mt7921_dev *dev, u8 **table, u8 version) +{ + int len, ret, sarlen, prelen, tblcnt; + bool enable; + + ret = mt7921_acpi_read(dev, MT7921_ACPI_MTDS, table, &len); + if (ret) + return ret; + + /* Table content validation */ + switch (version) { + case 1: + enable = ((struct mt7921_asar_dyn *)*table)->enable; + sarlen = sizeof(struct mt7921_asar_dyn_limit); + prelen = sizeof(struct mt7921_asar_dyn); + break; + case 2: + enable = ((struct mt7921_asar_dyn_v2 *)*table)->enable; + sarlen = sizeof(struct mt7921_asar_dyn_limit_v2); + prelen = sizeof(struct mt7921_asar_dyn_v2); + break; + default: + return -EINVAL; + } + + tblcnt = (len - prelen) / sarlen; + if (!enable || + tblcnt > MT7921_ASAR_MAX_DYN || tblcnt < MT7921_ASAR_MIN_DYN) + ret = -EINVAL; + + return ret; +} + +/* MTGS : Geo SAR Power Table */ +static int +mt7921_asar_acpi_read_mtgs(struct mt7921_dev *dev, u8 **table, u8 version) +{ + int len, ret = 0, sarlen, prelen, tblcnt; + + ret = mt7921_acpi_read(dev, MT7921_ACPI_MTGS, table, &len); + if (ret) + return ret; + + /* Table content validation */ + switch (version) { + case 1: + sarlen = sizeof(struct mt7921_asar_geo_limit); + prelen = sizeof(struct mt7921_asar_geo); + break; + case 2: + sarlen = sizeof(struct mt7921_asar_geo_limit_v2); + prelen = sizeof(struct mt7921_asar_geo_v2); + break; + default: + return -EINVAL; + } + + tblcnt = (len - prelen) / sarlen; + if (tblcnt > MT7921_ASAR_MAX_GEO || tblcnt < MT7921_ASAR_MIN_GEO) + ret = -EINVAL; + + return ret; +} + +int mt7921_init_acpi_sar(struct mt7921_dev *dev) +{ + struct mt7921_acpi_sar *asar; + int ret; + + asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL); + if (!asar) + return -ENOMEM; + + mt7921_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); + + /* MTDS is mandatory. Return error if table is invalid */ + ret = mt7921_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->dyn); + devm_kfree(dev->mt76.dev, asar->countrylist); + devm_kfree(dev->mt76.dev, asar); + return ret; + } + + /* MTGS is optional */ + ret = mt7921_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->geo); + asar->geo = NULL; + } + + dev->phy.acpisar = asar; + + return 0; +} + +static s8 +mt7921_asar_get_geo_pwr(struct mt7921_phy *phy, + enum nl80211_band band, s8 dyn_power) +{ + struct mt7921_acpi_sar *asar = phy->acpisar; + struct mt7921_asar_geo_band *band_pwr; + s8 geo_power; + u8 idx, max; + + if (!asar->geo) + return dyn_power; + + switch (phy->mt76->dev->region) { + case NL80211_DFS_FCC: + idx = 0; + break; + case NL80211_DFS_ETSI: + idx = 1; + break; + default: /* WW */ + idx = 2; + break; + } + + if (asar->ver == 1) { + band_pwr = &asar->geo->tbl[idx].band[0]; + max = ARRAY_SIZE(asar->geo->tbl[idx].band); + } else { + band_pwr = &asar->geo_v2->tbl[idx].band[0]; + max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band); + } + + switch (band) { + case NL80211_BAND_2GHZ: + idx = 0; + break; + case NL80211_BAND_5GHZ: + idx = 1; + break; + case NL80211_BAND_6GHZ: + idx = 2; + break; + default: + return dyn_power; + } + + if (idx >= max) + return dyn_power; + + geo_power = (band_pwr + idx)->pwr; + dyn_power += (band_pwr + idx)->offset; + + return min(geo_power, dyn_power); +} + +static s8 +mt7921_asar_range_pwr(struct mt7921_phy *phy, + const struct cfg80211_sar_freq_ranges *range, + u8 idx) +{ + const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; + struct mt7921_acpi_sar *asar = phy->acpisar; + u8 *limit, band, max; + + if (!capa) + return 127; + + if (asar->ver == 1) { + limit = &asar->dyn->tbl[0].frp[0]; + max = ARRAY_SIZE(asar->dyn->tbl[0].frp); + } else { + limit = &asar->dyn_v2->tbl[0].frp[0]; + max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp); + } + + if (idx >= max) + return 127; + + if (range->start_freq >= 5945) + band = NL80211_BAND_6GHZ; + else if (range->start_freq >= 5150) + band = NL80211_BAND_5GHZ; + else + band = NL80211_BAND_2GHZ; + + return mt7921_asar_get_geo_pwr(phy, band, limit[idx]); +} + +int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default) +{ + const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; + int i; + + if (!phy->acpisar) + return 0; + + /* When ACPI SAR enabled in HW, we should apply rules for .frp + * 1. w/o .sar_specs : set ACPI SAR power as the defatul value + * 2. w/ .sar_specs : set power with min(.sar_specs, ACPI_SAR) + */ + for (i = 0; i < capa->num_freq_ranges; i++) { + struct mt76_freq_range_power *frp = &phy->mt76->frp[i]; + + frp->range = set_default ? &capa->freq_ranges[i] : frp->range; + if (!frp->range) + continue; + + frp->power = min_t(s8, set_default ? 127 : frp->power, + mt7921_asar_range_pwr(phy, frp->range, i)); + } + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h new file mode 100644 index 000000000000..23f86bfae0c0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2022 MediaTek Inc. */ + +#ifndef __MT7921_ACPI_SAR_H +#define __MT7921_ACPI_SAR_H + +#define MT7921_ASAR_MIN_DYN 1 +#define MT7921_ASAR_MAX_DYN 8 +#define MT7921_ASAR_MIN_GEO 3 +#define MT7921_ASAR_MAX_GEO 8 + +#define MT7921_ACPI_MTCL "MTCL" +#define MT7921_ACPI_MTDS "MTDS" +#define MT7921_ACPI_MTGS "MTGS" + +struct mt7921_asar_dyn_limit { + u8 idx; + u8 frp[5]; +} __packed; + +struct mt7921_asar_dyn { + u8 names[4]; + u8 enable; + u8 nr_tbl; + struct mt7921_asar_dyn_limit tbl[0]; +} __packed; + +struct mt7921_asar_dyn_limit_v2 { + u8 idx; + u8 frp[11]; +} __packed; + +struct mt7921_asar_dyn_v2 { + u8 names[4]; + u8 enable; + u8 rsvd; + u8 nr_tbl; + struct mt7921_asar_dyn_limit_v2 tbl[0]; +} __packed; + +struct mt7921_asar_geo_band { + u8 pwr; + u8 offset; +} __packed; + +struct mt7921_asar_geo_limit { + u8 idx; + /* 0:2G, 1:5G */ + struct mt7921_asar_geo_band band[2]; +} __packed; + +struct mt7921_asar_geo { + u8 names[4]; + u8 version; + u8 nr_tbl; + struct mt7921_asar_geo_limit tbl[0]; +} __packed; + +struct mt7921_asar_geo_limit_v2 { + u8 idx; + /* 0:2G, 1:5G, 2:6G */ + struct mt7921_asar_geo_band band[3]; +} __packed; + +struct mt7921_asar_geo_v2 { + u8 names[4]; + u8 version; + u8 rsvd; + u8 nr_tbl; + struct mt7921_asar_geo_limit_v2 tbl[0]; +} __packed; + +struct mt7921_asar_cl { + u8 names[4]; + u8 version; + u8 mode_6g; + u8 cl6g[6]; +} __packed; + +struct mt7921_acpi_sar { + u8 ver; + union { + struct mt7921_asar_dyn *dyn; + struct mt7921_asar_dyn_v2 *dyn_v2; + }; + union { + struct mt7921_asar_geo *geo; + struct mt7921_asar_geo_v2 *geo_v2; + }; + struct mt7921_asar_cl *countrylist; +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 4a8675634f80..0c4e973d002e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -289,6 +289,8 @@ int mt7921_register_device(struct mt7921_dev *dev) if (!mt76_is_mmio(&dev->mt76)) hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE; + mt7921_init_acpi_sar(dev); + ret = mt7921_init_wcid(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 5ca584bb2fc6..8b26bece28ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -8,6 +8,7 @@ #include #include "../mt76_connac_mcu.h" #include "regs.h" +#include "acpi_sar.h" #define MT7921_MAX_INTERFACES 4 #define MT7921_MAX_WMM_SETS 4 @@ -171,6 +172,9 @@ struct mt7921_phy { struct sk_buff_head scan_event_list; struct delayed_work scan_work; +#ifdef CONFIG_ACPI + struct mt7921_acpi_sar *acpisar; +#endif }; #define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev)) @@ -481,4 +485,20 @@ int mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable); +#ifdef CONFIG_ACPI +int mt7921_init_acpi_sar(struct mt7921_dev *dev); +int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default); +#else +static inline int +mt7921_init_acpi_sar(struct mt7921_dev *dev) +{ + return 0; +} + +static inline int +mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default) +{ + return 0; +} +#endif #endif -- cgit v1.2.3 From 63db9d4012af63b4cc8175ceb8eae8bcf6a8e8f3 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 20 May 2022 17:03:39 +0800 Subject: mt76: mt7921: introduce ACPI SAR config in tx power Add new function mt7921_set_tx_sar_pwr() to update SAR power from .set_sar_specs and ACPI setting. Both settings would be merged into mt76_freq_range_power for final tx power value. Reviewed-by: Sean Wang Co-developed-by: Ming Yen Hsieh Signed-off-by: Ming Yen Hsieh Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 31 +++++++++++++++------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 0c4e973d002e..48a10aaecc62 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -34,14 +34,13 @@ mt7921_regd_notifier(struct wiphy *wiphy, { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt7921_dev *dev = mt7921_hw_dev(hw); - struct mt7921_phy *phy = mt7921_hw_phy(hw); memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; mt7921_mutex_acquire(dev); mt76_connac_mcu_set_channel_domain(hw->priv); - mt76_connac_mcu_set_rate_txpower(phy->mt76); + mt7921_set_tx_sar_pwr(hw, NULL); mt7921_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 63583605d1cd..6b3e88f679f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -257,7 +257,7 @@ int __mt7921_start(struct mt7921_phy *phy) if (err) return err; - err = mt76_connac_mcu_set_rate_txpower(phy->mt76); + err = mt7921_set_tx_sar_pwr(mphy->hw, NULL); if (err) return err; @@ -548,7 +548,7 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed) mt7921_mutex_acquire(dev); if (changed & IEEE80211_CONF_CHANGE_POWER) { - ret = mt76_connac_mcu_set_rate_txpower(phy->mt76); + ret = mt7921_set_tx_sar_pwr(hw, NULL); if (ret) goto out; } @@ -1469,20 +1469,33 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw, } #endif +int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar) +{ + struct mt76_phy *mphy = hw->priv; + int err; + + if (sar) { + err = mt76_init_sar_power(hw, sar); + if (err) + return err; + } + + mt7921_init_acpi_sar_power(mt7921_hw_phy(hw), !sar); + + err = mt76_connac_mcu_set_rate_txpower(mphy); + + return err; +} + static int mt7921_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt7921_dev *dev = mt7921_hw_dev(hw); - struct mt76_phy *mphy = hw->priv; int err; mt7921_mutex_acquire(dev); - err = mt76_init_sar_power(hw, sar); - if (err) - goto out; - - err = mt76_connac_mcu_set_rate_txpower(mphy); -out: + err = mt7921_set_tx_sar_pwr(hw, sar); mt7921_mutex_release(dev); return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 8b26bece28ae..d9fc457e420d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -501,4 +501,6 @@ mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default) return 0; } #endif +int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar); #endif -- cgit v1.2.3 From 3685727c4dcdfefa682828000b16ea468d045056 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 26 May 2022 17:08:54 +0800 Subject: mt76: mt7915: add more ethtool stats Add channel time and MAC ready stats. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 52 ++++++++++++++++++---- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 14 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 7 +++ drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 16 +++---- 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 086244d9be76..f59662af3d9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -2214,7 +2214,8 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) u32 val; cnt = mt76_rr(dev, MT_MIB_SDR3(phy->band_idx)); - mib->fcs_err_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : + mib->fcs_err_cnt += is_mt7915(&dev->mt76) ? + FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR4(phy->band_idx)); @@ -2227,19 +2228,28 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR7(phy->band_idx)); - mib->rx_vector_mismatch_cnt += FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt); + mib->rx_vector_mismatch_cnt += + FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR8(phy->band_idx)); - mib->rx_delimiter_fail_cnt += FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt); + mib->rx_delimiter_fail_cnt += + FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR10(phy->band_idx)); + mib->rx_mrdy_cnt += is_mt7915(&dev->mt76) ? + FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK, cnt) : + FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR11(phy->band_idx)); - mib->rx_len_mismatch_cnt += FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt); + mib->rx_len_mismatch_cnt += + FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR12(phy->band_idx)); mib->tx_ampdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR13(phy->band_idx)); - mib->tx_stop_q_empty_cnt += FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt); + mib->tx_stop_q_empty_cnt += + FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR14(phy->band_idx)); mib->tx_mpdu_attempts_cnt += is_mt7915(&dev->mt76) ? @@ -2251,6 +2261,29 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916, cnt); + cnt = mt76_rr(dev, MT_MIB_SDR16(phy->band_idx)); + mib->primary_cca_busy_time += + FIELD_GET(MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR17(phy->band_idx)); + mib->secondary_cca_busy_time += + FIELD_GET(MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR18(phy->band_idx)); + mib->primary_energy_detect_time += + FIELD_GET(MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR19(phy->band_idx)); + mib->cck_mdrdy_time += FIELD_GET(MT_MIB_SDR19_CCK_MDRDY_TIME_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR20(phy->band_idx)); + mib->ofdm_mdrdy_time += + FIELD_GET(MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR21(phy->band_idx)); + mib->green_mdrdy_time += + FIELD_GET(MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK, cnt); + cnt = mt76_rr(dev, MT_MIB_SDR22(phy->band_idx)); mib->rx_ampdu_cnt += cnt; @@ -2266,10 +2299,12 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR27(phy->band_idx)); - mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt); + mib->tx_rwp_fail_cnt += + FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR28(phy->band_idx)); - mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt); + mib->tx_rwp_need_cnt += + FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR29(phy->band_idx)); mib->rx_pfdrop_cnt += is_mt7915(&dev->mt76) ? @@ -2311,7 +2346,8 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) if (is_mt7915(&dev->mt76)) { for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { val = mt76_rr(dev, MT_MIB_MB_SDR1(phy->band_idx, (i << 4))); - mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); + mib->ba_miss_cnt += + FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index fbeac9aa2af6..8a114dae6110 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1146,8 +1146,15 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_fifo_full_cnt", "rx_mpdu_cnt", "channel_idle_cnt", + "primary_cca_busy_time", + "secondary_cca_busy_time", + "primary_energy_detect_time", + "cck_mdrdy_time", + "ofdm_mdrdy_time", + "green_mdrdy_time", "rx_vector_mismatch_cnt", "rx_delimiter_fail_cnt", + "rx_mrdy_cnt", "rx_len_mismatch_cnt", "rx_ampdu_cnt", "rx_ampdu_bytes_cnt", @@ -1287,8 +1294,15 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, data[ei++] = mib->rx_fifo_full_cnt; data[ei++] = mib->rx_mpdu_cnt; data[ei++] = mib->channel_idle_cnt; + data[ei++] = mib->primary_cca_busy_time; + data[ei++] = mib->secondary_cca_busy_time; + data[ei++] = mib->primary_energy_detect_time; + data[ei++] = mib->cck_mdrdy_time; + data[ei++] = mib->ofdm_mdrdy_time; + data[ei++] = mib->green_mdrdy_time; data[ei++] = mib->rx_vector_mismatch_cnt; data[ei++] = mib->rx_delimiter_fail_cnt; + data[ei++] = mib->rx_mrdy_cnt; data[ei++] = mib->rx_len_mismatch_cnt; data[ei++] = mib->rx_ampdu_cnt; data[ei++] = mib->rx_ampdu_bytes_cnt; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 4dcae6991669..bd985e6ce36a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -200,8 +200,15 @@ struct mib_stats { /* rx stats */ u32 rx_fifo_full_cnt; u32 channel_idle_cnt; + u32 primary_cca_busy_time; + u32 secondary_cca_busy_time; + u32 primary_energy_detect_time; + u32 cck_mdrdy_time; + u32 ofdm_mdrdy_time; + u32 green_mdrdy_time; u32 rx_vector_mismatch_cnt; u32 rx_delimiter_fail_cnt; + u32 rx_mrdy_cnt; u32 rx_len_mismatch_cnt; u32 rx_mpdu_cnt; u32 rx_ampdu_cnt; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 4953be208c5e..77fd448beed7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -305,7 +305,7 @@ enum offs_rev { #define MT_MIB_SDR9_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR9)) #define MT_MIB_SDR9_CCA_BUSY_TIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR10_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR10)) +#define MT_MIB_SDR10(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR10)) #define MT_MIB_SDR10_MRDY_COUNT_MASK GENMASK(25, 0) #define MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916 GENMASK(31, 0) @@ -329,24 +329,24 @@ enum offs_rev { #define MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916 GENMASK(31, 0) /* in units of 'us' */ -#define MT_MIB_SDR16_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR16)) +#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR16)) #define MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR17_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR17)) +#define MT_MIB_SDR17(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR17)) #define MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK GENMASK(23, 0) #define MT_MIB_SDR18(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR18)) #define MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK GENMASK(23, 0) /* units are us */ -#define MT_MIB_SDR19_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR19)) +#define MT_MIB_SDR19(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR19)) #define MT_MIB_SDR19_CCK_MDRDY_TIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR20_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR20)) +#define MT_MIB_SDR20(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR20)) #define MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR21_DNR(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR21)) -#define MT_MIB_SDR20_GREEN_MDRDY_TIME_MASK GENMASK(23, 0) +#define MT_MIB_SDR21(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR21)) +#define MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK GENMASK(23, 0) /* rx ampdu count, 32-bit */ #define MT_MIB_SDR22(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR22)) @@ -940,7 +940,7 @@ enum offs_rev { #define MT_ADIE_TYPE_MASK BIT(1) /* FW MODE SYNC */ -#define MT_FW_EXCEPTION __REG(FW_EXCEPTION_ADDR) +#define MT_FW_EXCEPTION __REG(FW_EXCEPTION_ADDR) #define MT_SWDEF_BASE __REG(SWDEF_BASE_ADDR) -- cgit v1.2.3 From ef55564e2b173d459a4aaae962c84f05aeaf8e36 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 26 May 2022 17:08:55 +0800 Subject: mt76: add DBDC rxq handlings into mac_reset_work Enable/disable rx napi for DBDC. Signed-off-by: Bo Jiao Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c | 14 +++++++------- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 18 +++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index d1806f198aed..73298dce35b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -268,6 +268,7 @@ void mt7615_mac_reset_work(struct work_struct *work) struct mt76_phy *ext_phy; struct mt7615_dev *dev; unsigned long timeout; + int i; dev = container_of(work, struct mt7615_dev, reset_work); ext_phy = dev->mt76.phy2; @@ -299,8 +300,8 @@ void mt7615_mac_reset_work(struct work_struct *work) mt76_txq_schedule_all(ext_phy); mt76_worker_disable(&dev->mt76.tx_worker); - napi_disable(&dev->mt76.napi[0]); - napi_disable(&dev->mt76.napi[1]); + mt76_for_each_q_rx(&dev->mt76, i) + napi_disable(&dev->mt76.napi[i]); napi_disable(&dev->mt76.tx_napi); mt7615_mutex_acquire(dev); @@ -330,11 +331,10 @@ void mt7615_mac_reset_work(struct work_struct *work) napi_enable(&dev->mt76.tx_napi); napi_schedule(&dev->mt76.tx_napi); - napi_enable(&dev->mt76.napi[0]); - napi_schedule(&dev->mt76.napi[0]); - - napi_enable(&dev->mt76.napi[1]); - napi_schedule(&dev->mt76.napi[1]); + mt76_for_each_q_rx(&dev->mt76, i) { + napi_enable(&dev->mt76.napi[i]); + napi_schedule(&dev->mt76.napi[i]); + } local_bh_enable(); ieee80211_wake_queues(mt76_hw(dev)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index f59662af3d9d..27b3080469a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -2124,6 +2124,7 @@ void mt7915_mac_reset_work(struct work_struct *work) struct mt7915_phy *phy2; struct mt76_phy *ext_phy; struct mt7915_dev *dev; + int i; dev = container_of(work, struct mt7915_dev, reset_work); ext_phy = dev->mt76.phy2; @@ -2145,9 +2146,8 @@ void mt7915_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&phy2->mt76->mac_work); } mt76_worker_disable(&dev->mt76.tx_worker); - napi_disable(&dev->mt76.napi[0]); - napi_disable(&dev->mt76.napi[1]); - napi_disable(&dev->mt76.napi[2]); + mt76_for_each_q_rx(&dev->mt76, i) + napi_disable(&dev->mt76.napi[i]); napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); @@ -2170,14 +2170,10 @@ void mt7915_mac_reset_work(struct work_struct *work) clear_bit(MT76_RESET, &phy2->mt76->state); local_bh_disable(); - napi_enable(&dev->mt76.napi[0]); - napi_schedule(&dev->mt76.napi[0]); - - napi_enable(&dev->mt76.napi[1]); - napi_schedule(&dev->mt76.napi[1]); - - napi_enable(&dev->mt76.napi[2]); - napi_schedule(&dev->mt76.napi[2]); + mt76_for_each_q_rx(&dev->mt76, i) { + napi_enable(&dev->mt76.napi[i]); + napi_schedule(&dev->mt76.napi[i]); + } local_bh_enable(); tasklet_schedule(&dev->irq_tasklet); -- cgit v1.2.3 From 45b6f9cb8ffcb65d9a5c5164046016afedac62fc Mon Sep 17 00:00:00 2001 From: YN Chen Date: Sat, 28 May 2022 09:28:53 +0800 Subject: mt76: mt7921: add PATCH_FINISH_REQ cmd response handling add new case to fetch the return value of PATCH_FINISH_REQ Signed-off-by: YN Chen Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 3b5b475b0875..7c55b712a765 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -111,7 +111,8 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, if (seq != rxd->seq) return -EAGAIN; - if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { + if (cmd == MCU_CMD(PATCH_SEM_CONTROL) || + cmd == MCU_CMD(PATCH_FINISH_REQ)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { -- cgit v1.2.3 From a55a0c701c129f8e448f0ec1eb811dba728ace64 Mon Sep 17 00:00:00 2001 From: YN Chen Date: Sat, 28 May 2022 09:28:54 +0800 Subject: mt76: mt7921s: fix firmware download random fail To avoid racing problems in chip, mt7921s should reacquire drv-own after firmware semaphore is released. Fixes: 78b217580c509 ("mt76: mt7921s: fix bus hang with wrong privilege") Signed-off-by: YN Chen Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 7c55b712a765..86d50c28d537 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -583,13 +583,6 @@ static int mt7921_load_patch(struct mt7921_dev *dev) if (ret) dev_err(dev->mt76.dev, "Failed to start patch\n"); - if (mt76_is_sdio(&dev->mt76)) { - /* activate again */ - ret = __mt7921_mcu_fw_pmctrl(dev); - if (!ret) - ret = __mt7921_mcu_drv_pmctrl(dev); - } - out: sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); switch (sem) { @@ -600,6 +593,14 @@ out: dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); break; } + + if (!ret && mt76_is_sdio(&dev->mt76)) { + /* activate again */ + ret = __mt7921_mcu_fw_pmctrl(dev); + if (!ret) + ret = __mt7921_mcu_drv_pmctrl(dev); + } + release_firmware(fw); return ret; -- cgit v1.2.3 From 12fba11c7ebd54389aa990b0bb3c4eb48ec88aba Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 12 May 2022 12:38:59 +0800 Subject: dt-bindings: net: wireless: mt76: add clock description for MT7986. Add clocks and clock-names for MT7986. Reviewed-by: Ryder Lee Signed-off-by: Peter Chiu Acked-by: Rob Herring Signed-off-by: Felix Fietkau --- .../devicetree/bindings/net/wireless/mediatek,mt76.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml index 5a12dc32288a..70e328589cfb 100644 --- a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml +++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml @@ -54,6 +54,16 @@ properties: reset-names: const: consys + clocks: + maxItems: 2 + description: + Specify the consys clocks for mt7986. + + clock-names: + items: + - const: mcu + - const: ap2conn + mediatek,infracfg: $ref: /schemas/types.yaml#/definitions/phandle description: @@ -269,5 +279,8 @@ examples: <0x10003000 0x1000>, <0x11d10000 0x1000>; interrupts = ; + clocks = <&topckgen 50>, + <&topckgen 62>; + clock-names = "mcu", "ap2conn"; memory-region = <&wmcpu_emi>; }; -- cgit v1.2.3 From c0182aa985708d2882eec6f902c61da6b42ae4f0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jun 2022 21:43:04 +0200 Subject: mt76: mt7915: add missing bh-disable around tx napi enable/schedule napi_schedule() can call __raise_softirq_irqoff(), which can perform softirq handling, so it must not be called in a pure process context with BH enabled. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 27b3080469a1..00d670fa26c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -2183,8 +2183,10 @@ void mt7915_mac_reset_work(struct work_struct *work) mt76_worker_enable(&dev->mt76.tx_worker); + local_bh_disable(); napi_enable(&dev->mt76.tx_napi); napi_schedule(&dev->mt76.tx_napi); + local_bh_enable(); ieee80211_wake_queues(mt76_hw(dev)); if (ext_phy) -- cgit v1.2.3 From e55c27ed9ccf37118b80178ec32dfed583171363 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jun 2022 21:44:21 +0200 Subject: mt76: mt7615: add missing bh-disable around rx napi schedule napi_schedule() can call __raise_softirq_irqoff(), which can perform softirq handling, so it must not be called in a pure process context with BH enabled. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index bd687f7de628..f26213c4e64c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2094,8 +2094,10 @@ void mt7615_pm_wake_work(struct work_struct *work) mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_worker_schedule(&mdev->sdio.txrx_worker); } else { + local_bh_disable(); mt76_for_each_q_rx(mdev, i) napi_schedule(&mdev->napi[i]); + local_bh_enable(); mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM], false); -- cgit v1.2.3 From 9ed107e0e98b7e5ee6cb0b738e83e003e543f653 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 09:35:00 +0200 Subject: mt76: mt7921: add missing bh-disable around rx napi schedule napi_schedule() can call __raise_softirq_irqoff(), which can perform softirq handling, so it must not be called in a pure process context with BH enabled. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index a630ddbf19e5..01ed779d3976 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1538,8 +1538,10 @@ void mt7921_pm_wake_work(struct work_struct *work) mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_worker_schedule(&mdev->sdio.txrx_worker); } else { + local_bh_disable(); mt76_for_each_q_rx(mdev, i) napi_schedule(&mdev->napi[i]); + local_bh_enable(); mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt7921_mcu_tx_cleanup(dev); } -- cgit v1.2.3 From 56054087bb17f98d62419acc3d0e5afc9544a4fb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 10:21:37 +0200 Subject: mt76: mt7921: get rid of mt7921_mcu_exit Run skb_queue_purge when needed. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 6 ------ drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 - drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/sdio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c | 4 ++-- 6 files changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 86d50c28d537..09b7bd562a98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -773,12 +773,6 @@ int mt7921_run_firmware(struct mt7921_dev *dev) } EXPORT_SYMBOL_GPL(mt7921_run_firmware); -void mt7921_mcu_exit(struct mt7921_dev *dev) -{ - skb_queue_purge(&dev->mt76.mcu.res_q); -} -EXPORT_SYMBOL_GPL(mt7921_mcu_exit); - int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index d9fc457e420d..f630f0249928 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -305,7 +305,6 @@ int mt7921_mcu_get_rx_rate(struct mt7921_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl); void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb); -void mt7921_mcu_exit(struct mt7921_dev *dev); static inline void mt7921_irq_enable(struct mt7921_dev *dev, u32 mask) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index b5fb22b8e086..624eb75c15cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -116,7 +116,7 @@ static void mt7921e_unregister_device(struct mt7921_dev *dev) mt7921_mcu_drv_pmctrl(dev); mt7921_dma_cleanup(dev); mt7921_wfsys_reset(dev); - mt7921_mcu_exit(dev); + skb_queue_purge(&dev->mt76.mcu.res_q); tasklet_disable(&dev->irq_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index af26d59fa2f0..487acd6e2be8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -48,7 +48,7 @@ static void mt7921s_unregister_device(struct mt7921_dev *dev) mt76s_deinit(&dev->mt76); mt7921s_wfsys_reset(dev); - mt7921_mcu_exit(dev); + skb_queue_purge(&dev->mt76.mcu.res_q); mt76_free_device(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c index dc38baef273a..4e4cd2dc2aeb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c @@ -158,7 +158,7 @@ static void mt7921u_cleanup(struct mt7921_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); mt7921u_wfsys_reset(dev); - mt7921_mcu_exit(dev); + skb_queue_purge(&dev->mt76.mcu.res_q); mt76u_queues_deinit(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c index cd2f09743d2f..efbd3954c883 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c @@ -185,7 +185,7 @@ int mt7921u_init_reset(struct mt7921_dev *dev) set_bit(MT76_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - mt7921_mcu_exit(dev); + skb_queue_purge(&dev->mt76.mcu.res_q); mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); @@ -208,7 +208,7 @@ int mt7921u_mac_reset(struct mt7921_dev *dev) set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - mt7921_mcu_exit(dev); + skb_queue_purge(&dev->mt76.mcu.res_q); mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); -- cgit v1.2.3 From 3d8c636c3e9ef7969c4dc971a82139ba6407e707 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 11:36:42 +0200 Subject: mt76: connac: move shared fw structures in connac module Move mt76_connac2 fw structures in connac module since they are shared between mt7921 and mt7915 drivers. This is a preliminary patch to add mt7902e support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 56 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 85 +++------------------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 81 +++------------------ 3 files changed, 79 insertions(+), 143 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 561fb0368708..ccc17cf2fb0a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -26,6 +26,62 @@ #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) #define PATCH_SEC_TYPE_INFO 0x2 +struct mt76_connac2_patch_hdr { + char build_date[16]; + char platform[4]; + __be32 hw_sw_ver; + __be32 patch_ver; + __be16 checksum; + u16 rsv; + struct { + __be32 patch_ver; + __be32 subsys; + __be32 feature; + __be32 n_region; + __be32 crc; + u32 rsv[11]; + } desc; +} __packed; + +struct mt76_connac2_patch_sec { + __be32 type; + __be32 offs; + __be32 size; + union { + __be32 spec[13]; + struct { + __be32 addr; + __be32 len; + __be32 sec_key_idx; + __be32 align_len; + u32 rsv[9]; + } info; + }; +} __packed; + +struct mt76_connac2_fw_trailer { + u8 chip_id; + u8 eco_code; + u8 n_region; + u8 format_ver; + u8 format_flag; + u8 rsv[2]; + char fw_ver[10]; + char build_date[15]; + __le32 crc; +} __packed; + +struct mt76_connac2_fw_region { + __le32 decomp_crc; + __le32 decomp_len; + __le32 decomp_blk_sz; + u8 rsv[4]; + __le32 addr; + __le32 len; + u8 feature_set; + u8 rsv1[15]; +} __packed; + struct tlv { __le16 tag; __le16 len; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 8c91257ba1c9..df3fee66a8c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -8,62 +8,6 @@ #include "mac.h" #include "eeprom.h" -struct mt7915_patch_hdr { - char build_date[16]; - char platform[4]; - __be32 hw_sw_ver; - __be32 patch_ver; - __be16 checksum; - u16 reserved; - struct { - __be32 patch_ver; - __be32 subsys; - __be32 feature; - __be32 n_region; - __be32 crc; - u32 reserved[11]; - } desc; -} __packed; - -struct mt7915_patch_sec { - __be32 type; - __be32 offs; - __be32 size; - union { - __be32 spec[13]; - struct { - __be32 addr; - __be32 len; - __be32 sec_key_idx; - __be32 align_len; - u32 reserved[9]; - } info; - }; -} __packed; - -struct mt7915_fw_trailer { - u8 chip_id; - u8 eco_code; - u8 n_region; - u8 format_ver; - u8 format_flag; - u8 reserved[2]; - char fw_ver[10]; - char build_date[15]; - u32 crc; -} __packed; - -struct mt7915_fw_region { - __le32 decomp_crc; - __le32 decomp_len; - __le32 decomp_blk_sz; - u8 reserved[4]; - __le32 addr; - __le32 len; - u8 feature_set; - u8 reserved1[15]; -} __packed; - #define fw_name(_dev, name, ...) ({ \ char *_fw; \ switch (mt76_chip(&(_dev)->mt76)) { \ @@ -2136,7 +2080,7 @@ static int mt7915_driver_own(struct mt7915_dev *dev, u8 band) static int mt7915_load_patch(struct mt7915_dev *dev) { - const struct mt7915_patch_hdr *hdr; + const struct mt76_connac2_patch_hdr *hdr; const struct firmware *fw = NULL; int i, ret, sem; @@ -2162,18 +2106,17 @@ static int mt7915_load_patch(struct mt7915_dev *dev) goto out; } - hdr = (const struct mt7915_patch_hdr *)(fw->data); + hdr = (const struct mt76_connac2_patch_hdr *)fw->data; dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { - struct mt7915_patch_sec *sec; + struct mt76_connac2_patch_sec *sec; const u8 *dl; u32 len, addr; - sec = (struct mt7915_patch_sec *)(fw->data + sizeof(*hdr) + - i * sizeof(*sec)); + sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != PATCH_SEC_TYPE_INFO) { ret = -EINVAL; @@ -2220,19 +2163,19 @@ out: static int mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, - const struct mt7915_fw_trailer *hdr, + const struct mt76_connac2_fw_trailer *hdr, const u8 *data, bool is_wa) { int i, offset = 0; u32 override = 0, option = 0; for (i = 0; i < hdr->n_region; i++) { - const struct mt7915_fw_region *region; - int err; + const struct mt76_connac2_fw_region *region; u32 len, addr, mode; + int err; - region = (const struct mt7915_fw_region *)((const u8 *)hdr - - (hdr->n_region - i) * sizeof(*region)); + region = (const void *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, region->feature_set, is_wa); len = le32_to_cpu(region->len); @@ -2269,7 +2212,7 @@ mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, static int mt7915_load_ram(struct mt7915_dev *dev) { - const struct mt7915_fw_trailer *hdr; + const struct mt76_connac2_fw_trailer *hdr; const struct firmware *fw; int ret; @@ -2284,9 +2227,7 @@ static int mt7915_load_ram(struct mt7915_dev *dev) goto out; } - hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - - sizeof(*hdr)); - + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); @@ -2309,9 +2250,7 @@ static int mt7915_load_ram(struct mt7915_dev *dev) goto out; } - hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - - sizeof(*hdr)); - + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 09b7bd562a98..ccf68bdd0e1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -8,62 +8,6 @@ #include "mcu.h" #include "mac.h" -struct mt7921_patch_hdr { - char build_date[16]; - char platform[4]; - __be32 hw_sw_ver; - __be32 patch_ver; - __be16 checksum; - u16 reserved; - struct { - __be32 patch_ver; - __be32 subsys; - __be32 feature; - __be32 n_region; - __be32 crc; - u32 reserved[11]; - } desc; -} __packed; - -struct mt7921_patch_sec { - __be32 type; - __be32 offs; - __be32 size; - union { - __be32 spec[13]; - struct { - __be32 addr; - __be32 len; - __be32 sec_key_idx; - __be32 align_len; - u32 reserved[9]; - } info; - }; -} __packed; - -struct mt7921_fw_trailer { - u8 chip_id; - u8 eco_code; - u8 n_region; - u8 format_ver; - u8 format_flag; - u8 reserved[2]; - char fw_ver[10]; - char build_date[15]; - u32 crc; -} __packed; - -struct mt7921_fw_region { - __le32 decomp_crc; - __le32 decomp_len; - __le32 decomp_blk_sz; - u8 reserved[4]; - __le32 addr; - __le32 len; - u8 feature_set; - u8 reserved1[15]; -} __packed; - #define MT_STA_BFER BIT(0) #define MT_STA_BFEE BIT(1) @@ -512,7 +456,7 @@ static char *mt7921_patch_name(struct mt7921_dev *dev) static int mt7921_load_patch(struct mt7921_dev *dev) { - const struct mt7921_patch_hdr *hdr; + const struct mt76_connac2_patch_hdr *hdr; const struct firmware *fw = NULL; int i, ret, sem, max_len; @@ -539,19 +483,18 @@ static int mt7921_load_patch(struct mt7921_dev *dev) goto out; } - hdr = (const struct mt7921_patch_hdr *)(fw->data); + hdr = (const struct mt76_connac2_patch_hdr *)fw->data; dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { - struct mt7921_patch_sec *sec; + struct mt76_connac2_patch_sec *sec; const u8 *dl; u32 len, addr, mode; u32 sec_info = 0; - sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + - i * sizeof(*sec)); + sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != PATCH_SEC_TYPE_INFO) { ret = -EINVAL; @@ -608,7 +551,7 @@ out: static int mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, - const struct mt7921_fw_trailer *hdr, + const struct mt76_connac2_fw_trailer *hdr, const u8 *data, bool is_wa) { int i, offset = 0, max_len; @@ -617,12 +560,12 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; for (i = 0; i < hdr->n_region; i++) { - const struct mt7921_fw_region *region; - int err; + const struct mt76_connac2_fw_region *region; u32 len, addr, mode; + int err; - region = (const struct mt7921_fw_region *)((const u8 *)hdr - - (hdr->n_region - i) * sizeof(*region)); + region = (const void *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, region->feature_set, is_wa); len = le32_to_cpu(region->len); @@ -671,7 +614,7 @@ static char *mt7921_ram_name(struct mt7921_dev *dev) static int mt7921_load_ram(struct mt7921_dev *dev) { - const struct mt7921_fw_trailer *hdr; + const struct mt76_connac2_fw_trailer *hdr; const struct firmware *fw; int ret; @@ -685,9 +628,7 @@ static int mt7921_load_ram(struct mt7921_dev *dev) goto out; } - hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - - sizeof(*hdr)); - + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); -- cgit v1.2.3 From c132fc7d83bb9f459ef10d7fe082bc301f63cd3b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 11:36:43 +0200 Subject: mt76: mt7921: move fw toggle in mt7921_load_firmware Move drv_own/fw_own toggle in mt7921_load_firmware. This change allow to reuse connac code to load patch for mt7921 driver. Signed-off-by: Lorenzo Bianconi Tested-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ccf68bdd0e1c..eea26b51fed8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -537,13 +537,6 @@ out: break; } - if (!ret && mt76_is_sdio(&dev->mt76)) { - /* activate again */ - ret = __mt7921_mcu_fw_pmctrl(dev); - if (!ret) - ret = __mt7921_mcu_drv_pmctrl(dev); - } - release_firmware(fw); return ret; @@ -662,6 +655,13 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) if (ret) return ret; + if (mt76_is_sdio(&dev->mt76)) { + /* activate again */ + ret = __mt7921_mcu_fw_pmctrl(dev); + if (!ret) + ret = __mt7921_mcu_drv_pmctrl(dev); + } + ret = mt7921_load_ram(dev); if (ret) return ret; -- cgit v1.2.3 From b9ec27102ac0c67f003c007e961ce811572c0cfa Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 11:36:44 +0200 Subject: mt76: connac: move mt76_connac2_load_ram in connac module Move mt76_connac2_load_ram utility routine in mt76_connac module since it is shared between mt7921 and mt7915. This is a preliminary patch to support mt7902e driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 111 ++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 + drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 112 +-------------------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 89 +--------------- 4 files changed, 116 insertions(+), 198 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index d3da54e6670b..7e21c0dbfd22 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ +#include #include "mt76_connac_mcu.h" int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) @@ -2808,5 +2809,115 @@ int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_rdd_cmd); +static int +mt76_connac_mcu_send_ram_firmware(struct mt76_dev *dev, + const struct mt76_connac2_fw_trailer *hdr, + const u8 *data, bool is_wa) +{ + int i, offset = 0, max_len = mt76_is_sdio(dev) ? 2048 : 4096; + u32 override = 0, option = 0; + + for (i = 0; i < hdr->n_region; i++) { + const struct mt76_connac2_fw_region *region; + u32 len, addr, mode; + int err; + + region = (const void *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); + mode = mt76_connac_mcu_gen_dl_mode(dev, region->feature_set, + is_wa); + len = le32_to_cpu(region->len); + addr = le32_to_cpu(region->addr); + + if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) + override = addr; + + err = mt76_connac_mcu_init_download(dev, addr, len, mode); + if (err) { + dev_err(dev->dev, "Download request failed\n"); + return err; + } + + err = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), + data + offset, len, max_len); + if (err) { + dev_err(dev->dev, "Failed to send firmware.\n"); + return err; + } + + offset += len; + } + + if (override) + option |= FW_START_OVERRIDE; + if (is_wa) + option |= FW_START_WORKING_PDA_CR4; + + return mt76_connac_mcu_start_firmware(dev, override, option); +} + +int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, + const char *fw_wa) +{ + const struct mt76_connac2_fw_trailer *hdr; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, fw_wm, dev->dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); + dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false); + if (ret) { + dev_err(dev->dev, "Failed to start WM firmware\n"); + goto out; + } + + release_firmware(fw); + + if (!fw_wa) + return 0; + + ret = request_firmware(&fw, fw_wa, dev->dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); + dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true); + if (ret) { + dev_err(dev->dev, "Failed to start WA firmware\n"); + goto out; + } + + snprintf(dev->hw->wiphy->fw_version, + sizeof(dev->hw->wiphy->fw_version), + "%.10s-%.15s", hdr->fw_ver, hdr->build_date); + +out: + release_firmware(fw); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_connac2_load_ram); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index ccc17cf2fb0a..355ed5e5d0ec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1709,4 +1709,6 @@ int mt76_connac_mcu_set_pm(struct mt76_dev *dev, int band, int enter); int mt76_connac_mcu_restart(struct mt76_dev *dev); int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); +int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, + const char *fw_wa); #endif /* __MT76_CONNAC_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index df3fee66a8c1..b894fa0e9f8d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2161,115 +2161,6 @@ out: return ret; } -static int -mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, - const struct mt76_connac2_fw_trailer *hdr, - const u8 *data, bool is_wa) -{ - int i, offset = 0; - u32 override = 0, option = 0; - - for (i = 0; i < hdr->n_region; i++) { - const struct mt76_connac2_fw_region *region; - u32 len, addr, mode; - int err; - - region = (const void *)((const u8 *)hdr - - (hdr->n_region - i) * sizeof(*region)); - mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, - region->feature_set, is_wa); - len = le32_to_cpu(region->len); - addr = le32_to_cpu(region->addr); - - if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) - override = addr; - - err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, - mode); - if (err) { - dev_err(dev->mt76.dev, "Download request failed\n"); - return err; - } - - err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), - data + offset, len, 4096); - if (err) { - dev_err(dev->mt76.dev, "Failed to send firmware.\n"); - return err; - } - - offset += len; - } - - if (override) - option |= FW_START_OVERRIDE; - - if (is_wa) - option |= FW_START_WORKING_PDA_CR4; - - return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); -} - -static int mt7915_load_ram(struct mt7915_dev *dev) -{ - const struct mt76_connac2_fw_trailer *hdr; - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, fw_name_var(dev, FIRMWARE_WM), - dev->mt76.dev); - if (ret) - return ret; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - dev_err(dev->mt76.dev, "Invalid firmware\n"); - ret = -EINVAL; - goto out; - } - - hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", - hdr->fw_ver, hdr->build_date); - - ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, false); - if (ret) { - dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); - goto out; - } - - release_firmware(fw); - - ret = request_firmware(&fw, fw_name(dev, FIRMWARE_WA), - dev->mt76.dev); - if (ret) - return ret; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - dev_err(dev->mt76.dev, "Invalid firmware\n"); - ret = -EINVAL; - goto out; - } - - hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", - hdr->fw_ver, hdr->build_date); - - ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, true); - if (ret) { - dev_err(dev->mt76.dev, "Failed to start WA firmware\n"); - goto out; - } - - snprintf(dev->mt76.hw->wiphy->fw_version, - sizeof(dev->mt76.hw->wiphy->fw_version), - "%.10s-%.15s", hdr->fw_ver, hdr->build_date); - -out: - release_firmware(fw); - - return ret; -} - static int mt7915_firmware_state(struct mt7915_dev *dev, bool wa) { @@ -2304,7 +2195,8 @@ static int mt7915_load_firmware(struct mt7915_dev *dev) if (ret) return ret; - ret = mt7915_load_ram(dev); + ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM), + fw_name(dev, FIRMWARE_WA)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index eea26b51fed8..ccf0ceeeb88b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -542,57 +542,6 @@ out: return ret; } -static int -mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, - const struct mt76_connac2_fw_trailer *hdr, - const u8 *data, bool is_wa) -{ - int i, offset = 0, max_len; - u32 override = 0, option = 0; - - max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; - - for (i = 0; i < hdr->n_region; i++) { - const struct mt76_connac2_fw_region *region; - u32 len, addr, mode; - int err; - - region = (const void *)((const u8 *)hdr - - (hdr->n_region - i) * sizeof(*region)); - mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, - region->feature_set, is_wa); - len = le32_to_cpu(region->len); - addr = le32_to_cpu(region->addr); - - if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) - override = addr; - - err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, - mode); - if (err) { - dev_err(dev->mt76.dev, "Download request failed\n"); - return err; - } - - err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), - data + offset, len, max_len); - if (err) { - dev_err(dev->mt76.dev, "Failed to send firmware.\n"); - return err; - } - - offset += len; - } - - if (override) - option |= FW_START_OVERRIDE; - - if (is_wa) - option |= FW_START_WORKING_PDA_CR4; - - return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); -} - static char *mt7921_ram_name(struct mt7921_dev *dev) { char *ret; @@ -605,42 +554,6 @@ static char *mt7921_ram_name(struct mt7921_dev *dev) return ret; } -static int mt7921_load_ram(struct mt7921_dev *dev) -{ - const struct mt76_connac2_fw_trailer *hdr; - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, mt7921_ram_name(dev), dev->mt76.dev); - if (ret) - return ret; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - dev_err(dev->mt76.dev, "Invalid firmware\n"); - ret = -EINVAL; - goto out; - } - - hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", - hdr->fw_ver, hdr->build_date); - - ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); - if (ret) { - dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); - goto out; - } - - snprintf(dev->mt76.hw->wiphy->fw_version, - sizeof(dev->mt76.hw->wiphy->fw_version), - "%.10s-%.15s", hdr->fw_ver, hdr->build_date); - -out: - release_firmware(fw); - - return ret; -} - static int mt7921_load_firmware(struct mt7921_dev *dev) { int ret; @@ -662,7 +575,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) ret = __mt7921_mcu_drv_pmctrl(dev); } - ret = mt7921_load_ram(dev); + ret = mt76_connac2_load_ram(&dev->mt76, mt7921_ram_name(dev), NULL); if (ret) return ret; -- cgit v1.2.3 From 28fec923d2400b266a1495e6d8e29cb8cc643145 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 11:36:45 +0200 Subject: mt76: connac: move mt76_connac2_load_patch in connac module Move mt76_connac2_load_patch utility routine in mt76_connac module since it is shared between mt7921 and mt7915. This is a preliminary patch to support mt7902e driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 113 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 8 ++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 86 +------------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 126 +-------------------- 4 files changed, 123 insertions(+), 210 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 7e21c0dbfd22..a963e51b7271 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -2919,5 +2919,118 @@ out: } EXPORT_SYMBOL_GPL(mt76_connac2_load_ram); +static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info) +{ + u32 mode = DL_MODE_NEED_RSP; + + if (!is_mt7921(dev) || info == PATCH_SEC_NOT_SUPPORT) + return mode; + + switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { + case PATCH_SEC_ENC_TYPE_PLAIN: + break; + case PATCH_SEC_ENC_TYPE_AES: + mode |= DL_MODE_ENCRYPT; + mode |= FIELD_PREP(DL_MODE_KEY_IDX, + (info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX; + mode |= DL_MODE_RESET_SEC_IV; + break; + case PATCH_SEC_ENC_TYPE_SCRAMBLE: + mode |= DL_MODE_ENCRYPT; + mode |= DL_CONFIG_ENCRY_MODE_SEL; + mode |= DL_MODE_RESET_SEC_IV; + break; + default: + dev_err(dev->dev, "Encryption type not support!\n"); + } + + return mode; +} + +int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) +{ + int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096; + const struct mt76_connac2_patch_hdr *hdr; + const struct firmware *fw = NULL; + + sem = mt76_connac_mcu_patch_sem_ctrl(dev, true); + switch (sem) { + case PATCH_IS_DL: + return 0; + case PATCH_NOT_DL_SEM_SUCCESS: + break; + default: + dev_err(dev->dev, "Failed to get patch semaphore\n"); + return -EAGAIN; + } + + ret = request_firmware(&fw, fw_name, dev->dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const void *)fw->data; + dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", + be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); + + for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { + struct mt76_connac2_patch_sec *sec; + u32 len, addr, mode; + const u8 *dl; + u32 sec_info; + + sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); + if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != + PATCH_SEC_TYPE_INFO) { + ret = -EINVAL; + goto out; + } + + addr = be32_to_cpu(sec->info.addr); + len = be32_to_cpu(sec->info.len); + dl = fw->data + be32_to_cpu(sec->offs); + sec_info = be32_to_cpu(sec->info.sec_key_idx); + mode = mt76_connac2_get_data_mode(dev, sec_info); + + ret = mt76_connac_mcu_init_download(dev, addr, len, mode); + if (ret) { + dev_err(dev->dev, "Download request failed\n"); + goto out; + } + + ret = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), + dl, len, max_len); + if (ret) { + dev_err(dev->dev, "Failed to send patch\n"); + goto out; + } + } + + ret = mt76_connac_mcu_start_patch(dev); + if (ret) + dev_err(dev->dev, "Failed to start patch\n"); + +out: + sem = mt76_connac_mcu_patch_sem_ctrl(dev, false); + switch (sem) { + case PATCH_REL_SEM_SUCCESS: + break; + default: + ret = -EAGAIN; + dev_err(dev->dev, "Failed to release patch semaphore\n"); + break; + } + + release_firmware(fw); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_connac2_load_patch); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 355ed5e5d0ec..d65b3cba1ace 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -26,6 +26,13 @@ #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) #define PATCH_SEC_TYPE_INFO 0x2 +#define PATCH_SEC_ENC_TYPE_MASK GENMASK(31, 24) +#define PATCH_SEC_ENC_TYPE_PLAIN 0x00 +#define PATCH_SEC_ENC_TYPE_AES 0x01 +#define PATCH_SEC_ENC_TYPE_SCRAMBLE 0x02 +#define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) +#define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) + struct mt76_connac2_patch_hdr { char build_date[16]; char platform[4]; @@ -1711,4 +1718,5 @@ int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa); +int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name); #endif /* __MT76_CONNAC_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b894fa0e9f8d..5badec1347e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ -#include #include #include "mt7915.h" #include "mcu.h" @@ -2078,89 +2077,6 @@ static int mt7915_driver_own(struct mt7915_dev *dev, u8 band) return 0; } -static int mt7915_load_patch(struct mt7915_dev *dev) -{ - const struct mt76_connac2_patch_hdr *hdr; - const struct firmware *fw = NULL; - int i, ret, sem; - - sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, 1); - switch (sem) { - case PATCH_IS_DL: - return 0; - case PATCH_NOT_DL_SEM_SUCCESS: - break; - default: - dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); - return -EAGAIN; - } - - ret = request_firmware(&fw, fw_name_var(dev, ROM_PATCH), - dev->mt76.dev); - if (ret) - goto out; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - dev_err(dev->mt76.dev, "Invalid firmware\n"); - ret = -EINVAL; - goto out; - } - - hdr = (const struct mt76_connac2_patch_hdr *)fw->data; - - dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", - be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); - - for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { - struct mt76_connac2_patch_sec *sec; - const u8 *dl; - u32 len, addr; - - sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); - if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != - PATCH_SEC_TYPE_INFO) { - ret = -EINVAL; - goto out; - } - - addr = be32_to_cpu(sec->info.addr); - len = be32_to_cpu(sec->info.len); - dl = fw->data + be32_to_cpu(sec->offs); - - ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, - DL_MODE_NEED_RSP); - if (ret) { - dev_err(dev->mt76.dev, "Download request failed\n"); - goto out; - } - - ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), - dl, len, 4096); - if (ret) { - dev_err(dev->mt76.dev, "Failed to send patch\n"); - goto out; - } - } - - ret = mt76_connac_mcu_start_patch(&dev->mt76); - if (ret) - dev_err(dev->mt76.dev, "Failed to start patch\n"); - -out: - sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, 0); - switch (sem) { - case PATCH_REL_SEM_SUCCESS: - break; - default: - ret = -EAGAIN; - dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); - break; - } - release_firmware(fw); - - return ret; -} - static int mt7915_firmware_state(struct mt7915_dev *dev, bool wa) { @@ -2191,7 +2107,7 @@ static int mt7915_load_firmware(struct mt7915_dev *dev) } } - ret = mt7915_load_patch(dev); + ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ccf0ceeeb88b..0542aba2e6ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ -#include #include #include "mt7921.h" #include "mt7921_trace.h" @@ -11,13 +10,6 @@ #define MT_STA_BFER BIT(0) #define MT_STA_BFEE BIT(1) -#define PATCH_SEC_ENC_TYPE_MASK GENMASK(31, 24) -#define PATCH_SEC_ENC_TYPE_PLAIN 0x00 -#define PATCH_SEC_ENC_TYPE_AES 0x01 -#define PATCH_SEC_ENC_TYPE_SCRAMBLE 0x02 -#define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) -#define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) - static int mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) { @@ -414,34 +406,6 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, enable, false); } -static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) -{ - u32 mode = DL_MODE_NEED_RSP; - - if (info == PATCH_SEC_NOT_SUPPORT) - return mode; - - switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { - case PATCH_SEC_ENC_TYPE_PLAIN: - break; - case PATCH_SEC_ENC_TYPE_AES: - mode |= DL_MODE_ENCRYPT; - mode |= FIELD_PREP(DL_MODE_KEY_IDX, - (info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX; - mode |= DL_MODE_RESET_SEC_IV; - break; - case PATCH_SEC_ENC_TYPE_SCRAMBLE: - mode |= DL_MODE_ENCRYPT; - mode |= DL_CONFIG_ENCRY_MODE_SEL; - mode |= DL_MODE_RESET_SEC_IV; - break; - default: - dev_err(dev->mt76.dev, "Encryption type not support!\n"); - } - - return mode; -} - static char *mt7921_patch_name(struct mt7921_dev *dev) { char *ret; @@ -454,94 +418,6 @@ static char *mt7921_patch_name(struct mt7921_dev *dev) return ret; } -static int mt7921_load_patch(struct mt7921_dev *dev) -{ - const struct mt76_connac2_patch_hdr *hdr; - const struct firmware *fw = NULL; - int i, ret, sem, max_len; - - max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; - - sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); - switch (sem) { - case PATCH_IS_DL: - return 0; - case PATCH_NOT_DL_SEM_SUCCESS: - break; - default: - dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); - return -EAGAIN; - } - - ret = request_firmware(&fw, mt7921_patch_name(dev), dev->mt76.dev); - if (ret) - goto out; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - dev_err(dev->mt76.dev, "Invalid firmware\n"); - ret = -EINVAL; - goto out; - } - - hdr = (const struct mt76_connac2_patch_hdr *)fw->data; - - dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", - be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); - - for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { - struct mt76_connac2_patch_sec *sec; - const u8 *dl; - u32 len, addr, mode; - u32 sec_info = 0; - - sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); - if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != - PATCH_SEC_TYPE_INFO) { - ret = -EINVAL; - goto out; - } - - addr = be32_to_cpu(sec->info.addr); - len = be32_to_cpu(sec->info.len); - dl = fw->data + be32_to_cpu(sec->offs); - sec_info = be32_to_cpu(sec->info.sec_key_idx); - mode = mt7921_get_data_mode(dev, sec_info); - - ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, - mode); - if (ret) { - dev_err(dev->mt76.dev, "Download request failed\n"); - goto out; - } - - ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), - dl, len, max_len); - if (ret) { - dev_err(dev->mt76.dev, "Failed to send patch\n"); - goto out; - } - } - - ret = mt76_connac_mcu_start_patch(&dev->mt76); - if (ret) - dev_err(dev->mt76.dev, "Failed to start patch\n"); - -out: - sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); - switch (sem) { - case PATCH_REL_SEM_SUCCESS: - break; - default: - ret = -EAGAIN; - dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); - break; - } - - release_firmware(fw); - - return ret; -} - static char *mt7921_ram_name(struct mt7921_dev *dev) { char *ret; @@ -564,7 +440,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) goto fw_loaded; } - ret = mt7921_load_patch(dev); + ret = mt76_connac2_load_patch(&dev->mt76, mt7921_patch_name(dev)); if (ret) return ret; -- cgit v1.2.3 From 049c94f8e914bcd098b33498cd7214674c410877 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jun 2022 11:36:46 +0200 Subject: mt76: mt7663: rely on mt76_connac2_fw_trailer Remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 3f8f06d9628c..b89d21f77e5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -40,18 +40,6 @@ struct mt7615_fw_trailer { #define FW_START_DLYCAL BIT(1) #define FW_START_WORKING_PDA_CR4 BIT(2) -struct mt7663_fw_trailer { - u8 chip_id; - u8 eco_code; - u8 n_region; - u8 format_ver; - u8 format_flag; - u8 reserv[2]; - char fw_ver[10]; - char build_date[15]; - __le32 crc; -} __packed; - struct mt7663_fw_buf { __le32 crc; __le32 d_img_size; @@ -1518,7 +1506,7 @@ static int mt7615_mcu_cal_cache_apply(struct mt7615_dev *dev) static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) { u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL; - const struct mt7663_fw_trailer *hdr; + const struct mt76_connac2_fw_trailer *hdr; const struct mt7663_fw_buf *buf; const struct firmware *fw; const u8 *base_addr; @@ -1534,9 +1522,7 @@ static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) goto out; } - hdr = (const struct mt7663_fw_trailer *)(fw->data + fw->size - - FW_V3_COMMON_TAILER_SIZE); - + hdr = (const void *)(fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE); dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region); -- cgit v1.2.3 From d9fcfc1424aa175665d02c44abc1528aba06d362 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Tue, 7 Jun 2022 13:00:46 +0800 Subject: mt76: enable the VHT extended NSS BW feature According IEEE Std 802.11-2020, its definition is: Indicates whether the STA is capable of interpreting the Extended NSS BW Support subfield of the VHT Capabilities Information field. Some APs, such as Xiaomi AX6000, would check this one for BW settings. mt76 driver can get max BW capability only if the this field is confgured properly. Reviewed-by: Ryder Lee Signed-off-by: Ming Yen Hsieh Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/init.c | 1 + 4 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4d301a131a9d..60da9995357e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -266,6 +266,8 @@ static void mt76_init_stream_cap(struct mt76_phy *phy, } vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); } void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index a06dcbb8c673..3e076092714e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -401,6 +401,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); if (is_mt7615(&phy->dev->mt76)) hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 01169853355e..2764c22179fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -365,6 +365,7 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); hw->max_tx_fragments = 4; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 48a10aaecc62..920fb3a42740 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -96,6 +96,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); if (dev->pm.enable) ieee80211_hw_set(hw, CONNECTION_MONITOR); -- cgit v1.2.3 From e00b3e407efeed81dc30a72e4041ff57bf7068d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jun 2022 11:28:37 +0200 Subject: mt76: mt7921: rely on mt76_dev in mt7921_mac_write_txwi signature This is a preliminary patch to share txwi configuration code. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 23 +++++++++++----------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 01ed779d3976..78c8a7637907 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -809,8 +809,8 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) } static void -mt7921_mac_write_txwi_8023(struct mt7921_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid) +mt7921_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, + struct mt76_wcid *wcid) { u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; u8 fc_type, fc_stype; @@ -848,7 +848,7 @@ mt7921_mac_write_txwi_8023(struct mt7921_dev *dev, __le32 *txwi, } static void -mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, +mt7921_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct ieee80211_key_conf *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -920,7 +920,7 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); } - if (mt76_is_mmio(&dev->mt76)) { + if (mt76_is_mmio(dev)) { val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); txwi[7] |= cpu_to_le32(val); @@ -931,17 +931,16 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, } } -void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, +void mt7921_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, bool beacon) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct mt76_phy *mphy = &dev->mphy; + struct mt76_phy *mphy = &dev->phy; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; - bool is_mmio = mt76_is_mmio(&dev->mt76); - u32 sz_txd = is_mmio ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; + u32 sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; u16 tx_count = 15; u32 val; @@ -957,10 +956,10 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_BCN0; } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { - p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; + p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = MT_LMAC_ALTX0; } else { - p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; + p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT7921_MAX_WMM_SETS + mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); } @@ -995,7 +994,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; if (is_8023) - mt7921_mac_write_txwi_8023(dev, txwi, skb, wcid); + mt7921_mac_write_txwi_8023(txwi, skb, wcid); else mt7921_mac_write_txwi_80211(dev, txwi, skb, key); @@ -1648,7 +1647,7 @@ mt7921_usb_sdio_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid, __le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); memset(txwi, 0, MT_SDIO_TXD_SIZE); - mt7921_mac_write_txwi(dev, txwi, skb, wcid, key, pid, false); + mt7921_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, false); skb_push(skb, MT_SDIO_TXD_SIZE); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 0542aba2e6ef..af43fbc33552 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -994,7 +994,7 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, return -EINVAL; } - mt7921_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb, + mt7921_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt), skb, wcid, NULL, 0, true); memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index f630f0249928..1e4a45e60913 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -427,7 +427,7 @@ int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, struct netlink_callback *cb, void *data, int len); -void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, +void mt7921_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, bool beacon); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 5ca14dbbdd26..f261cbfae2f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -72,7 +72,7 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, } pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, + mt7921_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, pid, false); txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); -- cgit v1.2.3 From d502e30020b85857ead0f9d392d24dba8c0f44cb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jun 2022 11:28:38 +0200 Subject: mt76: mt7915: rely on mt76_dev in mt7915_mac_write_txwi signature This is a preliminary patch to share txwi configuration code. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 23 +++++++++++----------- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 00d670fa26c9..caed0dbee3cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1010,8 +1010,8 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, } static void -mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid) +mt7915_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, + struct mt76_wcid *wcid) { u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; @@ -1050,9 +1050,8 @@ mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi, } static void -mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct ieee80211_key_conf *key, - bool *mcast) +mt7915_mac_write_txwi_80211(__le32 *txwi, struct sk_buff *skb, + struct ieee80211_key_conf *key, bool *mcast) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; @@ -1175,13 +1174,13 @@ out: FIELD_PREP(MT_TX_RATE_MODE, mode); } -void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, +void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct mt76_phy *mphy = &dev->mphy; + struct mt76_phy *mphy = &dev->phy; bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; @@ -1201,8 +1200,8 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, band_idx = mvif->mt76.band_idx; } - if (ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (ext_phy && dev->phy2) + mphy = dev->phy2; if (inband_disc) { p_fmt = MT_TX_TYPE_FW; @@ -1254,9 +1253,9 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; if (is_8023) - mt7915_mac_write_txwi_8023(dev, txwi, skb, wcid); + mt7915_mac_write_txwi_8023(txwi, skb, wcid); else - mt7915_mac_write_txwi_80211(dev, txwi, skb, key, &mcast); + mt7915_mac_write_txwi_80211(txwi, skb, key, &mcast); if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { u16 rate = mt7915_mac_tx_rate_val(mphy, vif, beacon, mcast); @@ -1315,7 +1314,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return id; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, 0); + mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key, 0); txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 5badec1347e1..76ff64703e2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1853,7 +1853,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, } buf = (u8 *)tlv + sizeof(*cont); - mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL, + mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, BSS_CHANGED_BEACON); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } @@ -1992,7 +1992,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi buf = (u8 *)tlv + sizeof(*discov); - mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL, + mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, changed); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index bd985e6ce36a..e0049ab777b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -564,7 +564,7 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); void mt7915_mac_reset_counters(struct mt7915_phy *phy); void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy); -void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, +void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, u32 changed); void mt7915_mac_set_timing(struct mt7915_phy *phy); -- cgit v1.2.3 From 90211957a640e6933b236e06728578d252f7374f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jun 2022 11:28:39 +0200 Subject: mt76: connac: move mac connac2 defs in mt76_connac2_mac.h This is a preliminary patch to share connac2 mac txwi code. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac2_mac.h | 167 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 142 +----------------- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 14 -- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 123 +-------------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 10 -- 5 files changed, 171 insertions(+), 285 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h new file mode 100644 index 000000000000..c9d9c8475a38 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2022 MediaTek Inc. */ + +#ifndef __MT76_CONNAC2_MAC_H +#define __MT76_CONNAC2_MAC_H + +enum tx_header_format { + MT_HDR_FORMAT_802_3, + MT_HDR_FORMAT_CMD, + MT_HDR_FORMAT_802_11, + MT_HDR_FORMAT_802_11_EXT, +}; + +enum tx_pkt_type { + MT_TX_TYPE_CT, + MT_TX_TYPE_SF, + MT_TX_TYPE_CMD, + MT_TX_TYPE_FW, +}; + +enum { + MT_CTX0, + MT_HIF0 = 0x0, + + MT_LMAC_AC00 = 0x0, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0, + MT_LMAC_BCN0, + MT_LMAC_PSMP0, +}; + +#define MT_TXD_SIZE (8 * 4) +#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4) +#define MT_SDIO_TAIL_SIZE 8 +#define MT_SDIO_HDR_SIZE 4 +#define MT_USB_TAIL_SIZE 4 + +#define MT_TXD0_Q_IDX GENMASK(31, 25) +#define MT_TXD0_PKT_FMT GENMASK(24, 23) +#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) +#define MT_TXD0_TX_BYTES GENMASK(15, 0) + +#define MT_TXD1_LONG_FORMAT BIT(31) +#define MT_TXD1_TGID BIT(30) +#define MT_TXD1_OWN_MAC GENMASK(29, 24) +#define MT_TXD1_AMSDU BIT(23) +#define MT_TXD1_TID GENMASK(22, 20) +#define MT_TXD1_HDR_PAD GENMASK(19, 18) +#define MT_TXD1_HDR_FORMAT GENMASK(17, 16) +#define MT_TXD1_HDR_INFO GENMASK(15, 11) +#define MT_TXD1_ETH_802_3 BIT(15) +#define MT_TXD1_VTA BIT(10) +#define MT_TXD1_WLAN_IDX GENMASK(9, 0) + +#define MT_TXD2_FIX_RATE BIT(31) +#define MT_TXD2_FIXED_RATE BIT(30) +#define MT_TXD2_POWER_OFFSET GENMASK(29, 24) +#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) +#define MT_TXD2_FRAG GENMASK(15, 14) +#define MT_TXD2_HTC_VLD BIT(13) +#define MT_TXD2_DURATION BIT(12) +#define MT_TXD2_BIP BIT(11) +#define MT_TXD2_MULTICAST BIT(10) +#define MT_TXD2_RTS BIT(9) +#define MT_TXD2_SOUNDING BIT(8) +#define MT_TXD2_NDPA BIT(7) +#define MT_TXD2_NDP BIT(6) +#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) +#define MT_TXD2_SUB_TYPE GENMASK(3, 0) + +#define MT_TXD3_SN_VALID BIT(31) +#define MT_TXD3_PN_VALID BIT(30) +#define MT_TXD3_SW_POWER_MGMT BIT(29) +#define MT_TXD3_BA_DISABLE BIT(28) +#define MT_TXD3_SEQ GENMASK(27, 16) +#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) +#define MT_TXD3_TX_COUNT GENMASK(10, 6) +#define MT_TXD3_TIMING_MEASURE BIT(5) +#define MT_TXD3_DAS BIT(4) +#define MT_TXD3_EEOSP BIT(3) +#define MT_TXD3_EMRD BIT(2) +#define MT_TXD3_PROTECT_FRAME BIT(1) +#define MT_TXD3_NO_ACK BIT(0) + +#define MT_TXD4_PN_LOW GENMASK(31, 0) + +#define MT_TXD5_PN_HIGH GENMASK(31, 16) +#define MT_TXD5_MD BIT(15) +#define MT_TXD5_ADD_BA BIT(14) +#define MT_TXD5_TX_STATUS_HOST BIT(10) +#define MT_TXD5_TX_STATUS_MCU BIT(9) +#define MT_TXD5_TX_STATUS_FMT BIT(8) +#define MT_TXD5_PID GENMASK(7, 0) + +#define MT_TXD6_TX_IBF BIT(31) +#define MT_TXD6_TX_EBF BIT(30) +#define MT_TXD6_TX_RATE GENMASK(29, 16) +#define MT_TXD6_SGI GENMASK(15, 14) +#define MT_TXD6_HELTF GENMASK(13, 12) +#define MT_TXD6_LDPC BIT(11) +#define MT_TXD6_SPE_ID_IDX BIT(10) +#define MT_TXD6_ANT_ID GENMASK(7, 4) +#define MT_TXD6_DYN_BW BIT(3) +#define MT_TXD6_FIXED_BW BIT(2) +#define MT_TXD6_BW GENMASK(1, 0) + +#define MT_TXD7_TXD_LEN GENMASK(31, 30) +#define MT_TXD7_UDP_TCP_SUM BIT(29) +#define MT_TXD7_IP_SUM BIT(28) +#define MT_TXD7_TYPE GENMASK(21, 20) +#define MT_TXD7_SUB_TYPE GENMASK(19, 16) + +#define MT_TXD7_PSE_FID GENMASK(27, 16) +#define MT_TXD7_SPE_IDX GENMASK(15, 11) +#define MT_TXD7_HW_AMSDU BIT(10) +#define MT_TXD7_TX_TIME GENMASK(9, 0) + +#define MT_TXD8_L_TYPE GENMASK(5, 4) +#define MT_TXD8_L_SUB_TYPE GENMASK(3, 0) + +#define MT_TX_RATE_STBC BIT(13) +#define MT_TX_RATE_NSS GENMASK(12, 10) +#define MT_TX_RATE_MODE GENMASK(9, 6) +#define MT_TX_RATE_SU_EXT_TONE BIT(5) +#define MT_TX_RATE_DCM BIT(4) +/* VHT/HE only use bits 0-3 */ +#define MT_TX_RATE_IDX GENMASK(5, 0) + +#define MT_TXS0_FIXED_RATE BIT(31) +#define MT_TXS0_BW GENMASK(30, 29) +#define MT_TXS0_TID GENMASK(28, 26) +#define MT_TXS0_AMPDU BIT(25) +#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) +#define MT_TXS0_BA_ERROR BIT(22) +#define MT_TXS0_PS_FLAG BIT(21) +#define MT_TXS0_TXOP_TIMEOUT BIT(20) +#define MT_TXS0_BIP_ERROR BIT(19) + +#define MT_TXS0_QUEUE_TIMEOUT BIT(18) +#define MT_TXS0_RTS_TIMEOUT BIT(17) +#define MT_TXS0_ACK_TIMEOUT BIT(16) +#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) + +#define MT_TXS0_TX_STATUS_HOST BIT(15) +#define MT_TXS0_TX_STATUS_MCU BIT(14) +#define MT_TXS0_TX_RATE GENMASK(13, 0) + +#define MT_TXS1_SEQNO GENMASK(31, 20) +#define MT_TXS1_RESP_RATE GENMASK(19, 16) +#define MT_TXS1_RXV_SEQNO GENMASK(15, 8) +#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0) + +#define MT_TXS2_BF_STATUS GENMASK(31, 30) +#define MT_TXS2_LAST_TX_RATE GENMASK(29, 27) +#define MT_TXS2_SHARED_ANTENNA BIT(26) +#define MT_TXS2_WCID GENMASK(25, 16) +#define MT_TXS2_TX_DELAY GENMASK(15, 0) + +#define MT_TXS3_PID GENMASK(31, 24) +#define MT_TXS3_ANT_ID GENMASK(23, 0) + +#define MT_TXS4_TIMESTAMP GENMASK(31, 0) + +#endif /* __MT76_CONNAC2_MAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index c5fd1a618ae7..f581ae27375b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -4,6 +4,8 @@ #ifndef __MT7915_MAC_H #define __MT7915_MAC_H +#include "../mt76_connac2_mac.h" + #define MT_CT_PARSE_LEN 72 #define MT_CT_DMA_BUF_NUM 2 @@ -166,20 +168,6 @@ enum rx_pkt_type { #define MT_CRXV_FOE_HI GENMASK(6, 0) #define MT_CRXV_FOE_SHIFT 13 -enum tx_header_format { - MT_HDR_FORMAT_802_3, - MT_HDR_FORMAT_CMD, - MT_HDR_FORMAT_802_11, - MT_HDR_FORMAT_802_11_EXT, -}; - -enum tx_pkt_type { - MT_TX_TYPE_CT, - MT_TX_TYPE_SF, - MT_TX_TYPE_CMD, - MT_TX_TYPE_FW, -}; - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU @@ -200,97 +188,6 @@ enum tx_mcu_port_q_idx { #define MT_CT_INFO_HSR2_TX BIT(4) #define MT_CT_INFO_FROM_HOST BIT(7) -#define MT_TXD_SIZE (8 * 4) - -#define MT_TXD0_Q_IDX GENMASK(31, 25) -#define MT_TXD0_PKT_FMT GENMASK(24, 23) -#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) -#define MT_TXD0_TX_BYTES GENMASK(15, 0) - -#define MT_TXD1_LONG_FORMAT BIT(31) -#define MT_TXD1_TGID BIT(30) -#define MT_TXD1_OWN_MAC GENMASK(29, 24) -#define MT_TXD1_AMSDU BIT(23) -#define MT_TXD1_TID GENMASK(22, 20) -#define MT_TXD1_HDR_PAD GENMASK(19, 18) -#define MT_TXD1_HDR_FORMAT GENMASK(17, 16) -#define MT_TXD1_HDR_INFO GENMASK(15, 11) -#define MT_TXD1_ETH_802_3 BIT(15) -#define MT_TXD1_VTA BIT(10) -#define MT_TXD1_WLAN_IDX GENMASK(9, 0) - -#define MT_TXD2_FIX_RATE BIT(31) -#define MT_TXD2_FIXED_RATE BIT(30) -#define MT_TXD2_POWER_OFFSET GENMASK(29, 24) -#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) -#define MT_TXD2_FRAG GENMASK(15, 14) -#define MT_TXD2_HTC_VLD BIT(13) -#define MT_TXD2_DURATION BIT(12) -#define MT_TXD2_BIP BIT(11) -#define MT_TXD2_MULTICAST BIT(10) -#define MT_TXD2_RTS BIT(9) -#define MT_TXD2_SOUNDING BIT(8) -#define MT_TXD2_NDPA BIT(7) -#define MT_TXD2_NDP BIT(6) -#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) -#define MT_TXD2_SUB_TYPE GENMASK(3, 0) - -#define MT_TXD3_SN_VALID BIT(31) -#define MT_TXD3_PN_VALID BIT(30) -#define MT_TXD3_SW_POWER_MGMT BIT(29) -#define MT_TXD3_BA_DISABLE BIT(28) -#define MT_TXD3_SEQ GENMASK(27, 16) -#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) -#define MT_TXD3_TX_COUNT GENMASK(10, 6) -#define MT_TXD3_TIMING_MEASURE BIT(5) -#define MT_TXD3_DAS BIT(4) -#define MT_TXD3_EEOSP BIT(3) -#define MT_TXD3_EMRD BIT(2) -#define MT_TXD3_PROTECT_FRAME BIT(1) -#define MT_TXD3_NO_ACK BIT(0) - -#define MT_TXD4_PN_LOW GENMASK(31, 0) - -#define MT_TXD5_PN_HIGH GENMASK(31, 16) -#define MT_TXD5_MD BIT(15) -#define MT_TXD5_ADD_BA BIT(14) -#define MT_TXD5_TX_STATUS_HOST BIT(10) -#define MT_TXD5_TX_STATUS_MCU BIT(9) -#define MT_TXD5_TX_STATUS_FMT BIT(8) -#define MT_TXD5_PID GENMASK(7, 0) - -#define MT_TXD6_TX_IBF BIT(31) -#define MT_TXD6_TX_EBF BIT(30) -#define MT_TXD6_TX_RATE GENMASK(29, 16) -#define MT_TXD6_SGI GENMASK(15, 14) -#define MT_TXD6_HELTF GENMASK(13, 12) -#define MT_TXD6_LDPC BIT(11) -#define MT_TXD6_SPE_ID_IDX BIT(10) -#define MT_TXD6_ANT_ID GENMASK(7, 4) -#define MT_TXD6_DYN_BW BIT(3) -#define MT_TXD6_FIXED_BW BIT(2) -#define MT_TXD6_BW GENMASK(1, 0) - -#define MT_TXD7_TXD_LEN GENMASK(31, 30) -#define MT_TXD7_UDP_TCP_SUM BIT(29) -#define MT_TXD7_IP_SUM BIT(28) - -#define MT_TXD7_TYPE GENMASK(21, 20) -#define MT_TXD7_SUB_TYPE GENMASK(19, 16) - -#define MT_TXD7_PSE_FID GENMASK(27, 16) -#define MT_TXD7_SPE_IDX GENMASK(15, 11) -#define MT_TXD7_HW_AMSDU BIT(10) -#define MT_TXD7_TX_TIME GENMASK(9, 0) - -#define MT_TX_RATE_STBC BIT(13) -#define MT_TX_RATE_NSS GENMASK(12, 10) -#define MT_TX_RATE_MODE GENMASK(9, 6) -#define MT_TX_RATE_SU_EXT_TONE BIT(5) -#define MT_TX_RATE_DCM BIT(4) -/* VHT/HE only use bits 0-3 */ -#define MT_TX_RATE_IDX GENMASK(5, 0) - #define MT_TXP_MAX_BUF_NUM 6 struct mt7915_txp { @@ -324,41 +221,6 @@ struct mt7915_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -#define MT_TXS0_FIXED_RATE BIT(31) -#define MT_TXS0_BW GENMASK(30, 29) -#define MT_TXS0_TID GENMASK(28, 26) -#define MT_TXS0_AMPDU BIT(25) -#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) -#define MT_TXS0_BA_ERROR BIT(22) -#define MT_TXS0_PS_FLAG BIT(21) -#define MT_TXS0_TXOP_TIMEOUT BIT(20) -#define MT_TXS0_BIP_ERROR BIT(19) - -#define MT_TXS0_QUEUE_TIMEOUT BIT(18) -#define MT_TXS0_RTS_TIMEOUT BIT(17) -#define MT_TXS0_ACK_TIMEOUT BIT(16) -#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) - -#define MT_TXS0_TX_STATUS_HOST BIT(15) -#define MT_TXS0_TX_STATUS_MCU BIT(14) -#define MT_TXS0_TX_RATE GENMASK(13, 0) - -#define MT_TXS1_SEQNO GENMASK(31, 20) -#define MT_TXS1_RESP_RATE GENMASK(19, 16) -#define MT_TXS1_RXV_SEQNO GENMASK(15, 8) -#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0) - -#define MT_TXS2_BF_STATUS GENMASK(31, 30) -#define MT_TXS2_LAST_TX_RATE GENMASK(29, 27) -#define MT_TXS2_SHARED_ANTENNA BIT(26) -#define MT_TXS2_WCID GENMASK(25, 16) -#define MT_TXS2_TX_DELAY GENMASK(15, 0) - -#define MT_TXS3_PID GENMASK(31, 24) -#define MT_TXS3_ANT_ID GENMASK(23, 0) - -#define MT_TXS4_TIMESTAMP GENMASK(31, 0) - #define MT_TXS5_F0_FINAL_MPDU BIT(31) #define MT_TXS5_F0_QOS BIT(30) #define MT_TXS5_F0_TX_COUNT GENMASK(29, 25) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index e0049ab777b8..fbd5f123c6a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -348,20 +348,6 @@ enum { __MT_WFDMA_MAX, }; -enum { - MT_CTX0, - MT_HIF0 = 0x0, - - MT_LMAC_AC00 = 0x0, - MT_LMAC_AC01, - MT_LMAC_AC02, - MT_LMAC_AC03, - MT_LMAC_ALTX0 = 0x10, - MT_LMAC_BMC0, - MT_LMAC_BCN0, - MT_LMAC_PSMP0, -}; - enum { MT_RX_SEL0, MT_RX_SEL1, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 79447e2d0143..556e687bd235 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -4,6 +4,8 @@ #ifndef __MT7921_MAC_H #define __MT7921_MAC_H +#include "../mt76_connac2_mac.h" + #define MT_CT_PARSE_LEN 72 #define MT_CT_DMA_BUF_NUM 2 @@ -163,20 +165,6 @@ enum rx_pkt_type { #define MT_CRXV_FOE_HI GENMASK(6, 0) #define MT_CRXV_FOE_SHIFT 13 -enum tx_header_format { - MT_HDR_FORMAT_802_3, - MT_HDR_FORMAT_CMD, - MT_HDR_FORMAT_802_11, - MT_HDR_FORMAT_802_11_EXT, -}; - -enum tx_pkt_type { - MT_TX_TYPE_CT, - MT_TX_TYPE_SF, - MT_TX_TYPE_CMD, - MT_TX_TYPE_FW, -}; - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU @@ -197,104 +185,6 @@ enum tx_mcu_port_q_idx { #define MT_CT_INFO_HSR2_TX BIT(4) #define MT_CT_INFO_FROM_HOST BIT(7) -#define MT_TXD_SIZE (8 * 4) - -#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4) -#define MT_SDIO_TAIL_SIZE 8 -#define MT_SDIO_HDR_SIZE 4 -#define MT_USB_TAIL_SIZE 4 - -#define MT_TXD0_Q_IDX GENMASK(31, 25) -#define MT_TXD0_PKT_FMT GENMASK(24, 23) -#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) -#define MT_TXD0_TX_BYTES GENMASK(15, 0) - -#define MT_TXD1_LONG_FORMAT BIT(31) -#define MT_TXD1_TGID BIT(30) -#define MT_TXD1_OWN_MAC GENMASK(29, 24) -#define MT_TXD1_AMSDU BIT(23) -#define MT_TXD1_TID GENMASK(22, 20) -#define MT_TXD1_HDR_PAD GENMASK(19, 18) -#define MT_TXD1_HDR_FORMAT GENMASK(17, 16) -#define MT_TXD1_HDR_INFO GENMASK(15, 11) -#define MT_TXD1_ETH_802_3 BIT(15) -#define MT_TXD1_VTA BIT(10) -#define MT_TXD1_WLAN_IDX GENMASK(9, 0) - -#define MT_TXD2_FIX_RATE BIT(31) -#define MT_TXD2_FIXED_RATE BIT(30) -#define MT_TXD2_POWER_OFFSET GENMASK(29, 24) -#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) -#define MT_TXD2_FRAG GENMASK(15, 14) -#define MT_TXD2_HTC_VLD BIT(13) -#define MT_TXD2_DURATION BIT(12) -#define MT_TXD2_BIP BIT(11) -#define MT_TXD2_MULTICAST BIT(10) -#define MT_TXD2_RTS BIT(9) -#define MT_TXD2_SOUNDING BIT(8) -#define MT_TXD2_NDPA BIT(7) -#define MT_TXD2_NDP BIT(6) -#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) -#define MT_TXD2_SUB_TYPE GENMASK(3, 0) - -#define MT_TXD3_SN_VALID BIT(31) -#define MT_TXD3_PN_VALID BIT(30) -#define MT_TXD3_SW_POWER_MGMT BIT(29) -#define MT_TXD3_BA_DISABLE BIT(28) -#define MT_TXD3_SEQ GENMASK(27, 16) -#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) -#define MT_TXD3_TX_COUNT GENMASK(10, 6) -#define MT_TXD3_TIMING_MEASURE BIT(5) -#define MT_TXD3_DAS BIT(4) -#define MT_TXD3_EEOSP BIT(3) -#define MT_TXD3_EMRD BIT(2) -#define MT_TXD3_PROTECT_FRAME BIT(1) -#define MT_TXD3_NO_ACK BIT(0) - -#define MT_TXD4_PN_LOW GENMASK(31, 0) - -#define MT_TXD5_PN_HIGH GENMASK(31, 16) -#define MT_TXD5_MD BIT(15) -#define MT_TXD5_ADD_BA BIT(14) -#define MT_TXD5_TX_STATUS_HOST BIT(10) -#define MT_TXD5_TX_STATUS_MCU BIT(9) -#define MT_TXD5_TX_STATUS_FMT BIT(8) -#define MT_TXD5_PID GENMASK(7, 0) - -#define MT_TXD6_TX_IBF BIT(31) -#define MT_TXD6_TX_EBF BIT(30) -#define MT_TXD6_TX_RATE GENMASK(29, 16) -#define MT_TXD6_SGI GENMASK(15, 14) -#define MT_TXD6_HELTF GENMASK(13, 12) -#define MT_TXD6_LDPC BIT(11) -#define MT_TXD6_SPE_ID_IDX BIT(10) -#define MT_TXD6_ANT_ID GENMASK(7, 4) -#define MT_TXD6_DYN_BW BIT(3) -#define MT_TXD6_FIXED_BW BIT(2) -#define MT_TXD6_BW GENMASK(1, 0) - -#define MT_TXD7_TXD_LEN GENMASK(31, 30) -#define MT_TXD7_UDP_TCP_SUM BIT(29) -#define MT_TXD7_IP_SUM BIT(28) - -#define MT_TXD7_TYPE GENMASK(21, 20) -#define MT_TXD7_SUB_TYPE GENMASK(19, 16) - -#define MT_TXD7_PSE_FID GENMASK(27, 16) -#define MT_TXD7_SPE_IDX GENMASK(15, 11) -#define MT_TXD7_HW_AMSDU BIT(10) -#define MT_TXD7_TX_TIME GENMASK(9, 0) - -#define MT_TXD8_L_TYPE GENMASK(5, 4) -#define MT_TXD8_L_SUB_TYPE GENMASK(3, 0) - -#define MT_TX_RATE_STBC BIT(13) -#define MT_TX_RATE_NSS GENMASK(12, 10) -#define MT_TX_RATE_MODE GENMASK(9, 6) -#define MT_TX_RATE_SU_EXT_TONE BIT(5) -#define MT_TX_RATE_DCM BIT(4) -#define MT_TX_RATE_IDX GENMASK(3, 0) - #define MT_TXP_MAX_BUF_NUM 6 struct mt7921_txp { @@ -325,15 +215,6 @@ struct mt7921_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -#define MT_TXS0_BW GENMASK(30, 29) -#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) -#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) -#define MT_TXS0_TX_RATE GENMASK(13, 0) - -#define MT_TXS2_WCID GENMASK(25, 16) - -#define MT_TXS3_PID GENMASK(31, 24) - static inline struct mt7921_txp_common * mt7921_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 1e4a45e60913..8015764997bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -251,16 +251,6 @@ struct mt7921_txpwr { } data[TXPWR_MAX_NUM]; }; -enum { - MT_LMAC_AC00, - MT_LMAC_AC01, - MT_LMAC_AC02, - MT_LMAC_AC03, - MT_LMAC_ALTX0 = 0x10, - MT_LMAC_BMC0, - MT_LMAC_BCN0, -}; - static inline struct mt7921_phy * mt7921_hw_phy(struct ieee80211_hw *hw) { -- cgit v1.2.3 From 182071cdd594bc79f42899c85afa995c370ef82d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jun 2022 11:28:40 +0200 Subject: mt76: connac: move connac2_mac_write_txwi in mt76_connac module mac_write_txwi code is shared between connac2 devices (mt7915 and mt7921). Move it in connac module. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 6 + .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 284 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 251 +----------------- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 - drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 212 +-------------- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 5 - .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 4 +- 10 files changed, 299 insertions(+), 472 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 400ba514460e..a9d7a269fcf3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -12,6 +12,8 @@ #define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10 #define MT76_CONNAC_MAX_SCAN_MATCH 16 +#define MT76_CONNAC_MAX_WMM_SETS 4 + #define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) #define MT76_CONNAC_COREDUMP_SZ (1300 * 1024) @@ -244,5 +246,9 @@ void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, struct sk_buff *skb); void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, struct mt76_connac_pm *pm); +void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, int pid, + u32 changed); #endif /* __MT76_CONNAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 306e9eaea917..0ea795565c88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -2,6 +2,7 @@ /* Copyright (C) 2020 MediaTek Inc. */ #include "mt76_connac.h" +#include "mt76_connac2_mac.h" int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) { @@ -115,3 +116,286 @@ void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, mt76_worker_schedule(&phy->dev->tx_worker); } EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); + +static u16 +mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, + bool beacon, bool mcast) +{ + u8 mode = 0, band = mphy->chandef.chan->band; + int rateidx = 0, mcast_rate; + + if (!vif) + goto legacy; + + if (is_mt7921(mphy->dev)) { + rateidx = ffs(vif->bss_conf.basic_rates) - 1; + goto legacy; + } + + if (beacon) { + struct cfg80211_bitrate_mask *mask; + + mask = &vif->bss_conf.beacon_tx_rate; + if (hweight16(mask->control[band].he_mcs[0]) == 1) { + rateidx = ffs(mask->control[band].he_mcs[0]) - 1; + mode = MT_PHY_TYPE_HE_SU; + goto out; + } else if (hweight16(mask->control[band].vht_mcs[0]) == 1) { + rateidx = ffs(mask->control[band].vht_mcs[0]) - 1; + mode = MT_PHY_TYPE_VHT; + goto out; + } else if (hweight8(mask->control[band].ht_mcs[0]) == 1) { + rateidx = ffs(mask->control[band].ht_mcs[0]) - 1; + mode = MT_PHY_TYPE_HT; + goto out; + } else if (hweight32(mask->control[band].legacy) == 1) { + rateidx = ffs(mask->control[band].legacy) - 1; + goto legacy; + } + } + + mcast_rate = vif->bss_conf.mcast_rate[band]; + if (mcast && mcast_rate > 0) + rateidx = mcast_rate - 1; + else + rateidx = ffs(vif->bss_conf.basic_rates) - 1; + +legacy: + rateidx = mt76_calculate_default_rate(mphy, rateidx); + mode = rateidx >> 8; + rateidx &= GENMASK(7, 0); + +out: + return FIELD_PREP(MT_TX_RATE_IDX, rateidx) | + FIELD_PREP(MT_TX_RATE_MODE, mode); +} + +static void +mt76_connac2_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, + struct mt76_wcid *wcid) +{ + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + u8 fc_type, fc_stype; + u16 ethertype; + bool wmm = false; + u32 val; + + if (wcid->sta) { + struct ieee80211_sta *sta; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + wmm = sta->wme; + } + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | + FIELD_PREP(MT_TXD1_TID, tid); + + ethertype = get_unaligned_be16(&skb->data[12]); + if (ethertype >= ETH_P_802_3_MIN) + val |= MT_TXD1_ETH_802_3; + + txwi[1] |= cpu_to_le32(val); + + fc_type = IEEE80211_FTYPE_DATA >> 2; + fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); + + txwi[2] |= cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + + txwi[7] |= cpu_to_le32(val); +} + +static void +mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, + struct sk_buff *skb, + struct ieee80211_key_conf *key) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool multicast = is_multicast_ether_addr(hdr->addr1); + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + __le16 fc = hdr->frame_control; + u8 fc_type, fc_stype; + u32 val; + + if (ieee80211_is_action(fc) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + + txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA); + tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; + } else if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; + u16 control = le16_to_cpu(bar->control); + + tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); + } + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + FIELD_PREP(MT_TXD1_HDR_INFO, + ieee80211_get_hdrlen_from_skb(skb) / 2) | + FIELD_PREP(MT_TXD1_TID, tid); + + txwi[1] |= cpu_to_le32(val); + + fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; + fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | + FIELD_PREP(MT_TXD2_MULTICAST, multicast); + + if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD2_BIP; + txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); + } + + if (!ieee80211_is_data(fc) || multicast || + info->flags & IEEE80211_TX_CTL_USE_MINRATE) + val |= MT_TXD2_FIX_RATE; + + txwi[2] |= cpu_to_le32(val); + + if (ieee80211_is_beacon(fc)) { + txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); + txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); + if (!is_mt7921(dev)) + txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, + 0x18)); + } + + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + u16 seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val = MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); + txwi[3] |= cpu_to_le32(val); + txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); + } + + if (mt76_is_mmio(dev)) { + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + txwi[7] |= cpu_to_le32(val); + } else { + val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | + FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); + txwi[8] |= cpu_to_le32(val); + } +} + +void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, int pid, + u32 changed) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_phy *mphy = &dev->phy; + u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0; + u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; + bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + bool beacon = !!(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)); + bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | + BSS_CHANGED_FILS_DISCOVERY)); + + if (vif) { + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + + omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; + band_idx = mvif->band_idx; + } + + if (ext_phy && dev->phy2) + mphy = dev->phy2; + + if (inband_disc) { + p_fmt = MT_TX_TYPE_FW; + q_idx = MT_LMAC_ALTX0; + } else if (beacon) { + p_fmt = MT_TX_TYPE_FW; + q_idx = MT_LMAC_BCN0; + } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; + q_idx = MT_LMAC_ALTX0; + } else { + p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; + q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS + + mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); + } + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | + FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, q_idx); + txwi[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | + FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + if (!is_mt7921(dev)) + val |= MT_TXD1_VTA; + if (ext_phy || band_idx) + val |= MT_TXD1_TGID; + + txwi[1] = cpu_to_le32(val); + txwi[2] = 0; + + val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); + if (!is_mt7921(dev)) + val |= MT_TXD3_SW_POWER_MGMT; + if (key) + val |= MT_TXD3_PROTECT_FRAME; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + val |= MT_TXD3_NO_ACK; + + txwi[3] = cpu_to_le32(val); + txwi[4] = 0; + + val = FIELD_PREP(MT_TXD5_PID, pid); + if (pid >= MT_PACKET_ID_FIRST) + val |= MT_TXD5_TX_STATUS_HOST; + + txwi[5] = cpu_to_le32(val); + txwi[6] = 0; + txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; + + if (is_8023) + mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid); + else + mt76_connac2_mac_write_txwi_80211(dev, txwi, skb, key); + + if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { + /* Fixed rata is available just for 802.11 txd */ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool multicast = is_multicast_ether_addr(hdr->addr1); + u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, + multicast); + u32 val = MT_TXD6_FIXED_BW; + + /* hardware won't add HTC for mgmt/ctrl frame */ + txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); + + val |= FIELD_PREP(MT_TXD6_TX_RATE, rate); + txwi[6] |= cpu_to_le32(val); + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); + } +} +EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index caed0dbee3cd..932dfe0eaeff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1009,265 +1009,18 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, #endif } -static void -mt7915_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, - struct mt76_wcid *wcid) -{ - - u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; - u8 fc_type, fc_stype; - u16 ethertype; - bool wmm = false; - u32 val; - - if (wcid->sta) { - struct ieee80211_sta *sta; - - sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); - wmm = sta->wme; - } - - val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | - FIELD_PREP(MT_TXD1_TID, tid); - - ethertype = get_unaligned_be16(&skb->data[12]); - if (ethertype >= ETH_P_802_3_MIN) - val |= MT_TXD1_ETH_802_3; - - txwi[1] |= cpu_to_le32(val); - - fc_type = IEEE80211_FTYPE_DATA >> 2; - fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; - - val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | - FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); - - txwi[2] |= cpu_to_le32(val); - - val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); - txwi[7] |= cpu_to_le32(val); -} - -static void -mt7915_mac_write_txwi_80211(__le32 *txwi, struct sk_buff *skb, - struct ieee80211_key_conf *key, bool *mcast) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; - __le16 fc = hdr->frame_control; - u8 fc_type, fc_stype; - u32 val; - - *mcast = is_multicast_ether_addr(hdr->addr1); - - if (ieee80211_is_action(fc) && - mgmt->u.action.category == WLAN_CATEGORY_BACK && - mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { - u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - - txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA); - tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; - } else if (ieee80211_is_back_req(hdr->frame_control)) { - struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; - u16 control = le16_to_cpu(bar->control); - - tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); - } - - val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | - FIELD_PREP(MT_TXD1_HDR_INFO, - ieee80211_get_hdrlen_from_skb(skb) / 2) | - FIELD_PREP(MT_TXD1_TID, tid); - txwi[1] |= cpu_to_le32(val); - - fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; - fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; - - val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | - FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | - FIELD_PREP(MT_TXD2_MULTICAST, *mcast); - - if (key && *mcast && ieee80211_is_robust_mgmt_frame(skb) && - key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - val |= MT_TXD2_BIP; - txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); - } - - if (!ieee80211_is_data(fc) || *mcast || - info->flags & IEEE80211_TX_CTL_USE_MINRATE) - val |= MT_TXD2_FIX_RATE; - - txwi[2] |= cpu_to_le32(val); - - if (ieee80211_is_beacon(fc)) { - txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); - txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); - txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, 0x18)); - } - - if (info->flags & IEEE80211_TX_CTL_INJECTED) { - u16 seqno = le16_to_cpu(hdr->seq_ctrl); - - if (ieee80211_is_back_req(hdr->frame_control)) { - struct ieee80211_bar *bar; - - bar = (struct ieee80211_bar *)skb->data; - seqno = le16_to_cpu(bar->start_seq_num); - } - - val = MT_TXD3_SN_VALID | - FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); - txwi[3] |= cpu_to_le32(val); - txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); - } - - val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); - txwi[7] |= cpu_to_le32(val); -} - -static u16 -mt7915_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, - bool beacon, bool mcast) -{ - u8 mode = 0, band = mphy->chandef.chan->band; - int rateidx = 0, mcast_rate; - - if (beacon) { - struct cfg80211_bitrate_mask *mask; - - mask = &vif->bss_conf.beacon_tx_rate; - if (hweight16(mask->control[band].he_mcs[0]) == 1) { - rateidx = ffs(mask->control[band].he_mcs[0]) - 1; - mode = MT_PHY_TYPE_HE_SU; - goto out; - } else if (hweight16(mask->control[band].vht_mcs[0]) == 1) { - rateidx = ffs(mask->control[band].vht_mcs[0]) - 1; - mode = MT_PHY_TYPE_VHT; - goto out; - } else if (hweight8(mask->control[band].ht_mcs[0]) == 1) { - rateidx = ffs(mask->control[band].ht_mcs[0]) - 1; - mode = MT_PHY_TYPE_HT; - goto out; - } else if (hweight32(mask->control[band].legacy) == 1) { - rateidx = ffs(mask->control[band].legacy) - 1; - goto legacy; - } - } - - mcast_rate = vif->bss_conf.mcast_rate[band]; - if (mcast && mcast_rate > 0) - rateidx = mcast_rate - 1; - else - rateidx = ffs(vif->bss_conf.basic_rates) - 1; - -legacy: - rateidx = mt76_calculate_default_rate(mphy, rateidx); - mode = rateidx >> 8; - rateidx &= GENMASK(7, 0); - -out: - return FIELD_PREP(MT_TX_RATE_IDX, rateidx) | - FIELD_PREP(MT_TX_RATE_MODE, mode); -} - void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->phy; - bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; - u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0; - bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; - bool mcast = false; - u16 tx_count = 15; - u32 val; - bool beacon = !!(changed & (BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED)); - bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | - BSS_CHANGED_FILS_DISCOVERY)); - - if (vif) { - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - omac_idx = mvif->mt76.omac_idx; - wmm_idx = mvif->mt76.wmm_idx; - band_idx = mvif->mt76.band_idx; - } - - if (ext_phy && dev->phy2) + if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phy2) mphy = dev->phy2; - if (inband_disc) { - p_fmt = MT_TX_TYPE_FW; - q_idx = MT_LMAC_ALTX0; - } else if (beacon) { - p_fmt = MT_TX_TYPE_FW; - q_idx = MT_LMAC_BCN0; - } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { - p_fmt = MT_TX_TYPE_CT; - q_idx = MT_LMAC_ALTX0; - } else { - p_fmt = MT_TX_TYPE_CT; - q_idx = wmm_idx * MT7915_MAX_WMM_SETS + - mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); - } - - val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | - FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | - FIELD_PREP(MT_TXD0_Q_IDX, q_idx); - txwi[0] = cpu_to_le32(val); - - val = MT_TXD1_LONG_FORMAT | MT_TXD1_VTA | - FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | - FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); - - if (ext_phy || band_idx) - val |= MT_TXD1_TGID; - - txwi[1] = cpu_to_le32(val); - - txwi[2] = 0; + mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, changed); - val = MT_TXD3_SW_POWER_MGMT | - FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); - if (key) - val |= MT_TXD3_PROTECT_FRAME; - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - val |= MT_TXD3_NO_ACK; - - txwi[3] = cpu_to_le32(val); - txwi[4] = 0; - - val = FIELD_PREP(MT_TXD5_PID, pid); - if (pid >= MT_PACKET_ID_FIRST) - val |= MT_TXD5_TX_STATUS_HOST; - txwi[5] = cpu_to_le32(val); - - txwi[6] = 0; - txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; - - if (is_8023) - mt7915_mac_write_txwi_8023(txwi, skb, wcid); - else - mt7915_mac_write_txwi_80211(txwi, skb, key, &mcast); - - if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { - u16 rate = mt7915_mac_tx_rate_val(mphy, vif, beacon, mcast); - - /* hardware won't add HTC for mgmt/ctrl frame */ - txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); - - val = MT_TXD6_FIXED_BW | - FIELD_PREP(MT_TXD6_TX_RATE, rate); - txwi[6] |= cpu_to_le32(val); - txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); - } if (mt76_testmode_enabled(mphy)) mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 76ff64703e2c..3a7051858892 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2432,7 +2432,7 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) struct edca *e = &req.edca[ac]; e->set = WMM_PARAM_SET; - e->queue = ac + mvif->mt76.wmm_idx * MT7915_MAX_WMM_SETS; + e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; e->aifs = q->aifs; e->txop = cpu_to_le16(q->txop); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index fbd5f123c6a0..3db0758b75e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -10,7 +10,6 @@ #include "regs.h" #define MT7915_MAX_INTERFACES 19 -#define MT7915_MAX_WMM_SETS 4 #define MT7915_WTBL_SIZE 288 #define MT7916_WTBL_SIZE 544 #define MT7915_WTBL_RESERVED (mt7915_wtbl_size(dev) - 1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 78c8a7637907..ae1dafc536c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -808,216 +808,6 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) return 0; } -static void -mt7921_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, - struct mt76_wcid *wcid) -{ - u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; - u8 fc_type, fc_stype; - u16 ethertype; - bool wmm = false; - u32 val; - - if (wcid->sta) { - struct ieee80211_sta *sta; - - sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); - wmm = sta->wme; - } - - val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | - FIELD_PREP(MT_TXD1_TID, tid); - - ethertype = get_unaligned_be16(&skb->data[12]); - if (ethertype >= ETH_P_802_3_MIN) - val |= MT_TXD1_ETH_802_3; - - txwi[1] |= cpu_to_le32(val); - - fc_type = IEEE80211_FTYPE_DATA >> 2; - fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; - - val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | - FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); - - txwi[2] |= cpu_to_le32(val); - - val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); - txwi[7] |= cpu_to_le32(val); -} - -static void -mt7921_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct ieee80211_key_conf *key) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - bool multicast = is_multicast_ether_addr(hdr->addr1); - u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; - __le16 fc = hdr->frame_control; - u8 fc_type, fc_stype; - u32 val; - - if (ieee80211_is_action(fc) && - mgmt->u.action.category == WLAN_CATEGORY_BACK && - mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { - u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - - txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA); - tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; - } else if (ieee80211_is_back_req(hdr->frame_control)) { - struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; - u16 control = le16_to_cpu(bar->control); - - tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); - } - - val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | - FIELD_PREP(MT_TXD1_HDR_INFO, - ieee80211_get_hdrlen_from_skb(skb) / 2) | - FIELD_PREP(MT_TXD1_TID, tid); - txwi[1] |= cpu_to_le32(val); - - fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; - fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; - - val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | - FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | - FIELD_PREP(MT_TXD2_MULTICAST, multicast); - - if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && - key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - val |= MT_TXD2_BIP; - txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); - } - - if (!ieee80211_is_data(fc) || multicast || - info->flags & IEEE80211_TX_CTL_USE_MINRATE) - val |= MT_TXD2_FIX_RATE; - - txwi[2] |= cpu_to_le32(val); - - if (ieee80211_is_beacon(fc)) { - txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); - txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); - } - - if (info->flags & IEEE80211_TX_CTL_INJECTED) { - u16 seqno = le16_to_cpu(hdr->seq_ctrl); - - if (ieee80211_is_back_req(hdr->frame_control)) { - struct ieee80211_bar *bar; - - bar = (struct ieee80211_bar *)skb->data; - seqno = le16_to_cpu(bar->start_seq_num); - } - - val = MT_TXD3_SN_VALID | - FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); - txwi[3] |= cpu_to_le32(val); - txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); - } - - if (mt76_is_mmio(dev)) { - val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); - txwi[7] |= cpu_to_le32(val); - } else { - val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | - FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); - txwi[8] |= cpu_to_le32(val); - } -} - -void mt7921_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, int pid, - bool beacon) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_vif *vif = info->control.vif; - struct mt76_phy *mphy = &dev->phy; - u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; - u32 sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; - bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; - u16 tx_count = 15; - u32 val; - - if (vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; - - omac_idx = mvif->omac_idx; - wmm_idx = mvif->wmm_idx; - } - - if (beacon) { - p_fmt = MT_TX_TYPE_FW; - q_idx = MT_LMAC_BCN0; - } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { - p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; - q_idx = MT_LMAC_ALTX0; - } else { - p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; - q_idx = wmm_idx * MT7921_MAX_WMM_SETS + - mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); - } - - val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | - FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | - FIELD_PREP(MT_TXD0_Q_IDX, q_idx); - txwi[0] = cpu_to_le32(val); - - val = MT_TXD1_LONG_FORMAT | - FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | - FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); - - txwi[1] = cpu_to_le32(val); - txwi[2] = 0; - - val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); - if (key) - val |= MT_TXD3_PROTECT_FRAME; - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - val |= MT_TXD3_NO_ACK; - - txwi[3] = cpu_to_le32(val); - txwi[4] = 0; - - val = FIELD_PREP(MT_TXD5_PID, pid); - if (pid >= MT_PACKET_ID_FIRST) - val |= MT_TXD5_TX_STATUS_HOST; - txwi[5] = cpu_to_le32(val); - - txwi[6] = 0; - txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; - - if (is_8023) - mt7921_mac_write_txwi_8023(txwi, skb, wcid); - else - mt7921_mac_write_txwi_80211(dev, txwi, skb, key); - - if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { - int rateidx = vif ? ffs(vif->bss_conf.basic_rates) - 1 : 0; - u16 rate, mode; - - /* hardware won't add HTC for mgmt/ctrl frame */ - txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); - - rate = mt76_calculate_default_rate(mphy, rateidx); - mode = rate >> 8; - rate &= GENMASK(7, 0); - rate |= FIELD_PREP(MT_TX_RATE_MODE, mode); - - val = MT_TXD6_FIXED_BW | - FIELD_PREP(MT_TXD6_TX_RATE, rate); - txwi[6] |= cpu_to_le32(val); - txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); - } -} -EXPORT_SYMBOL_GPL(mt7921_mac_write_txwi); - void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) { struct mt7921_sta *msta; @@ -1647,7 +1437,7 @@ mt7921_usb_sdio_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid, __le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); memset(txwi, 0, MT_SDIO_TXD_SIZE); - mt7921_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, false); + mt76_connac2_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, 0); skb_push(skb, MT_SDIO_TXD_SIZE); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 6b3e88f679f4..5163704356d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -322,7 +322,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, mvif->mt76.omac_idx = mvif->mt76.idx; mvif->phy = phy; mvif->mt76.band_idx = 0; - mvif->mt76.wmm_idx = mvif->mt76.idx % MT7921_MAX_WMM_SETS; + mvif->mt76.wmm_idx = mvif->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index af43fbc33552..ef29c3088cc6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -994,8 +994,8 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, return -EINVAL; } - mt7921_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt), skb, - wcid, NULL, 0, true); + mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt), + skb, wcid, NULL, 0, BSS_CHANGED_BEACON); memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 8015764997bc..7da29fadc27f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -11,7 +11,6 @@ #include "acpi_sar.h" #define MT7921_MAX_INTERFACES 4 -#define MT7921_MAX_WMM_SETS 4 #define MT7921_WTBL_SIZE 20 #define MT7921_WTBL_RESERVED (MT7921_WTBL_SIZE - 1) #define MT7921_WTBL_STA (MT7921_WTBL_RESERVED - \ @@ -417,10 +416,6 @@ int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, struct netlink_callback *cb, void *data, int len); -void mt7921_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, int pid, - bool beacon); void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi); void mt7921_mac_sta_poll(struct mt7921_dev *dev); int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index f261cbfae2f3..b0f58bcf70cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -72,8 +72,8 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, } pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - mt7921_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, - pid, false); + mt76_connac2_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, + pid, 0); txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt7921_txp_common)); -- cgit v1.2.3 From b932425b63143ccadbad2d74e499e3c5d6c0c0dc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jun 2022 11:28:41 +0200 Subject: mt76: connac: move mt76_connac2_mac_add_txs_skb in connac module Move mt76_connac2_mac_add_txs_skb in mt76-connac module since it is shared between connac2 devices (mt7921 and mt7915) Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 3 + .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 122 ++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 126 +-------------------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 122 +------------------- 4 files changed, 130 insertions(+), 243 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index a9d7a269fcf3..6b8d6c5d621a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -250,5 +250,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, u32 changed); +bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, + int pid, __le32 *txs_data, + struct mt76_sta_stats *stats); #endif /* __MT76_CONNAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 0ea795565c88..3f2680b8c2c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -399,3 +399,125 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, } } EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi); + +bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, + int pid, __le32 *txs_data, + struct mt76_sta_stats *stats) +{ + struct ieee80211_supported_band *sband; + struct mt76_phy *mphy; + struct ieee80211_tx_info *info; + struct sk_buff_head list; + struct rate_info rate = {}; + struct sk_buff *skb; + bool cck = false; + u32 txrate, txs, mode; + + mt76_tx_status_lock(dev, &list); + skb = mt76_tx_status_skb_get(dev, wcid, pid, &list); + if (!skb) + goto out; + + txs = le32_to_cpu(txs_data[0]); + + info = IEEE80211_SKB_CB(skb); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); + + info->status.rates[0].idx = -1; + + txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); + + rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); + rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; + + if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) + stats->tx_nss[rate.nss - 1]++; + if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) + stats->tx_mcs[rate.mcs]++; + + mode = FIELD_GET(MT_TX_RATE_MODE, txrate); + switch (mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + mphy = &dev->phy; + if (wcid->ext_phy && dev->phy2) + mphy = dev->phy2; + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) + sband = &mphy->sband_6g.sband; + else + sband = &mphy->sband_2g.sband; + + rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck); + rate.legacy = sband->bitrates[rate.mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + if (rate.mcs > 31) + goto out; + + rate.flags = RATE_INFO_FLAGS_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + if (rate.mcs > 9) + goto out; + + rate.flags = RATE_INFO_FLAGS_VHT_MCS; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (rate.mcs > 11) + goto out; + + rate.he_gi = wcid->rate.he_gi; + rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); + rate.flags = RATE_INFO_FLAGS_HE_MCS; + break; + default: + goto out; + } + + stats->tx_mode[mode]++; + + switch (FIELD_GET(MT_TXS0_BW, txs)) { + case IEEE80211_STA_RX_BW_160: + rate.bw = RATE_INFO_BW_160; + stats->tx_bw[3]++; + break; + case IEEE80211_STA_RX_BW_80: + rate.bw = RATE_INFO_BW_80; + stats->tx_bw[2]++; + break; + case IEEE80211_STA_RX_BW_40: + rate.bw = RATE_INFO_BW_40; + stats->tx_bw[1]++; + break; + default: + rate.bw = RATE_INFO_BW_20; + stats->tx_bw[0]++; + break; + } + wcid->rate = rate; + +out: + if (skb) + mt76_tx_status_skb_done(dev, skb, &list); + + mt76_tx_status_unlock(dev, &list); + + return !!skb; +} +EXPORT_SYMBOL_GPL(mt76_connac2_mac_add_txs_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 932dfe0eaeff..428c4fd9a0a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1345,128 +1345,6 @@ mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len) mt7915_mac_tx_free_done(dev, &free_list, wake); } -static bool -mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, - __le32 *txs_data, struct mt76_sta_stats *stats) -{ - struct ieee80211_supported_band *sband; - struct mt76_dev *mdev = &dev->mt76; - struct mt76_phy *mphy; - struct ieee80211_tx_info *info; - struct sk_buff_head list; - struct rate_info rate = {}; - struct sk_buff *skb; - bool cck = false; - u32 txrate, txs, mode; - - mt76_tx_status_lock(mdev, &list); - skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); - if (!skb) - goto out_no_skb; - - txs = le32_to_cpu(txs_data[0]); - - info = IEEE80211_SKB_CB(skb); - if (!(txs & MT_TXS0_ACK_ERROR_MASK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.ampdu_len = 1; - info->status.ampdu_ack_len = !!(info->flags & - IEEE80211_TX_STAT_ACK); - - info->status.rates[0].idx = -1; - - txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); - - rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); - rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; - - if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) - stats->tx_nss[rate.nss - 1]++; - if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) - stats->tx_mcs[rate.mcs]++; - - mode = FIELD_GET(MT_TX_RATE_MODE, txrate); - switch (mode) { - case MT_PHY_TYPE_CCK: - cck = true; - fallthrough; - case MT_PHY_TYPE_OFDM: - mphy = &dev->mphy; - if (wcid->ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; - - if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) - sband = &mphy->sband_5g.sband; - else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) - sband = &mphy->sband_6g.sband; - else - sband = &mphy->sband_2g.sband; - - rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck); - rate.legacy = sband->bitrates[rate.mcs].bitrate; - break; - case MT_PHY_TYPE_HT: - case MT_PHY_TYPE_HT_GF: - if (rate.mcs > 31) - goto out; - - rate.flags = RATE_INFO_FLAGS_MCS; - if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) - rate.flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case MT_PHY_TYPE_VHT: - if (rate.mcs > 9) - goto out; - - rate.flags = RATE_INFO_FLAGS_VHT_MCS; - break; - case MT_PHY_TYPE_HE_SU: - case MT_PHY_TYPE_HE_EXT_SU: - case MT_PHY_TYPE_HE_TB: - case MT_PHY_TYPE_HE_MU: - if (rate.mcs > 11) - goto out; - - rate.he_gi = wcid->rate.he_gi; - rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); - rate.flags = RATE_INFO_FLAGS_HE_MCS; - break; - default: - goto out; - } - - stats->tx_mode[mode]++; - - switch (FIELD_GET(MT_TXS0_BW, txs)) { - case IEEE80211_STA_RX_BW_160: - rate.bw = RATE_INFO_BW_160; - stats->tx_bw[3]++; - break; - case IEEE80211_STA_RX_BW_80: - rate.bw = RATE_INFO_BW_80; - stats->tx_bw[2]++; - break; - case IEEE80211_STA_RX_BW_40: - rate.bw = RATE_INFO_BW_40; - stats->tx_bw[1]++; - break; - default: - rate.bw = RATE_INFO_BW_20; - stats->tx_bw[0]++; - break; - } - wcid->rate = rate; - -out: - mt76_tx_status_skb_done(mdev, skb, &list); - -out_no_skb: - mt76_tx_status_unlock(mdev, &list); - - return !!skb; -} - static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) { struct mt7915_sta *msta = NULL; @@ -1495,8 +1373,8 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) msta = container_of(wcid, struct mt7915_sta, wcid); - mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats); - + mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data, + &msta->stats); if (!wcid->sta) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index ae1dafc536c9..ccaf4d539852 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -833,123 +833,6 @@ void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) } EXPORT_SYMBOL_GPL(mt7921_tx_check_aggr); -static bool -mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, - __le32 *txs_data) -{ - struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid); - struct mt76_sta_stats *stats = &msta->stats; - struct ieee80211_supported_band *sband; - struct mt76_dev *mdev = &dev->mt76; - struct ieee80211_tx_info *info; - struct rate_info rate = {}; - struct sk_buff_head list; - u32 txrate, txs, mode; - struct sk_buff *skb; - bool cck = false; - - mt76_tx_status_lock(mdev, &list); - skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); - if (!skb) - goto out; - - info = IEEE80211_SKB_CB(skb); - txs = le32_to_cpu(txs_data[0]); - if (!(txs & MT_TXS0_ACK_ERROR_MASK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.ampdu_len = 1; - info->status.ampdu_ack_len = !!(info->flags & - IEEE80211_TX_STAT_ACK); - - info->status.rates[0].idx = -1; - - if (!wcid->sta) - goto out; - - txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); - - rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); - rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; - - if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) - stats->tx_nss[rate.nss - 1]++; - if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) - stats->tx_mcs[rate.mcs]++; - - mode = FIELD_GET(MT_TX_RATE_MODE, txrate); - switch (mode) { - case MT_PHY_TYPE_CCK: - cck = true; - fallthrough; - case MT_PHY_TYPE_OFDM: - if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ) - sband = &dev->mphy.sband_5g.sband; - else - sband = &dev->mphy.sband_2g.sband; - - rate.mcs = mt76_get_rate(dev->mphy.dev, sband, rate.mcs, cck); - rate.legacy = sband->bitrates[rate.mcs].bitrate; - break; - case MT_PHY_TYPE_HT: - case MT_PHY_TYPE_HT_GF: - if (rate.mcs > 31) - goto out; - - rate.flags = RATE_INFO_FLAGS_MCS; - if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) - rate.flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case MT_PHY_TYPE_VHT: - if (rate.mcs > 9) - goto out; - - rate.flags = RATE_INFO_FLAGS_VHT_MCS; - break; - case MT_PHY_TYPE_HE_SU: - case MT_PHY_TYPE_HE_EXT_SU: - case MT_PHY_TYPE_HE_TB: - case MT_PHY_TYPE_HE_MU: - if (rate.mcs > 11) - goto out; - - rate.he_gi = wcid->rate.he_gi; - rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); - rate.flags = RATE_INFO_FLAGS_HE_MCS; - break; - default: - goto out; - } - stats->tx_mode[mode]++; - - switch (FIELD_GET(MT_TXS0_BW, txs)) { - case IEEE80211_STA_RX_BW_160: - rate.bw = RATE_INFO_BW_160; - stats->tx_bw[3]++; - break; - case IEEE80211_STA_RX_BW_80: - rate.bw = RATE_INFO_BW_80; - stats->tx_bw[2]++; - break; - case IEEE80211_STA_RX_BW_40: - rate.bw = RATE_INFO_BW_40; - stats->tx_bw[1]++; - break; - default: - rate.bw = RATE_INFO_BW_20; - stats->tx_bw[0]++; - break; - } - wcid->rate = rate; - -out: - if (skb) - mt76_tx_status_skb_done(mdev, skb, &list); - mt76_tx_status_unlock(mdev, &list); - - return !!skb; -} - void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data) { struct mt7921_sta *msta = NULL; @@ -976,12 +859,13 @@ void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data) if (!wcid) goto out; - mt7921_mac_add_txs_skb(dev, wcid, pid, txs_data); + msta = container_of(wcid, struct mt7921_sta, wcid); + mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data, + &msta->stats); if (!wcid->sta) goto out; - msta = container_of(wcid, struct mt7921_sta, wcid); spin_lock_bh(&dev->sta_poll_lock); if (list_empty(&msta->poll_list)) list_add_tail(&msta->poll_list, &dev->sta_poll_list); -- cgit v1.2.3 From c149d3a9058616ff942a6e44b6e968e18a84dd5a Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 8 Jun 2022 20:53:25 +0800 Subject: mt76: mt7921: not support beacon offload disable command Beacon disable flow would be handled in bss stop handler automatically. Force return -EOPNOTSUPP in disable case. Fixes: 116c69603b01 ("mt76: mt7921: Add AP mode support") Reviewed-by: Sean Wang Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ef29c3088cc6..b8e5f550b4d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -981,8 +981,11 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, }; struct sk_buff *skb; + /* support enable/update process only + * disable flow would be handled in bss stop handler automatically + */ if (!enable) - goto out; + return -EOPNOTSUPP; skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) @@ -1008,7 +1011,6 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, } dev_kfree_skb(skb); -out: return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), &req, sizeof(req), true); } -- cgit v1.2.3 From 9d958b60ebc2434f2b7eae83d77849e22d1059eb Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 8 Jun 2022 20:53:26 +0800 Subject: mt76: mt7921: fix command timeout in AP stop period Due to AP stop improperly, mt7921 driver would face random command timeout by chip fw problem. Migrate AP start/stop process to .start_ap/.stop_ap and congiure BSS network settings in both hooks. The new flow is shown below. * AP start .start_ap() configure BSS network resource set BSS to connected state .bss_info_changed() enable fw beacon offload * AP stop .bss_info_changed() disable fw beacon offload (skip this command) .stop_ap() set BSS to disconnected state (beacon offload disabled automatically) destroy BSS network resource Fixes: 116c69603b01 ("mt76: mt7921: Add AP mode support") Signed-off-by: Sean Wang Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 49 ++++++++++++++++++---- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 5 +-- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 + 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index a963e51b7271..8c9b0f0b5c39 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1404,6 +1404,8 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, else conn_type = CONNECTION_INFRA_AP; basic_req.basic.conn_type = cpu_to_le32(conn_type); + /* Fully active/deactivate BSS network in AP mode only */ + basic_req.basic.active = enable; break; case NL80211_IFTYPE_STATION: if (vif->p2p) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 5163704356d8..4be488da0117 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -653,15 +653,6 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { - struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; - - mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, - true); - mt7921_mcu_sta_update(dev, NULL, vif, true, - MT76_STA_INFO_STATE_NONE); - } - if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, @@ -1513,6 +1504,44 @@ mt7921_channel_switch_beacon(struct ieee80211_hw *hw, mt7921_mutex_release(dev); } +static int +mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = mt7921_hw_dev(hw); + int err; + + err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, + true); + if (err) + return err; + + err = mt7921_mcu_set_bss_pm(dev, vif, true); + if (err) + return err; + + return mt7921_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_NONE); +} + +static void +mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = mt7921_hw_dev(hw); + int err; + + err = mt7921_mcu_set_bss_pm(dev, vif, false); + if (err) + return; + + mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false); +} + const struct ieee80211_ops mt7921_ops = { .tx = mt7921_tx, .start = mt7921_start, @@ -1523,6 +1552,8 @@ const struct ieee80211_ops mt7921_ops = { .conf_tx = mt7921_conf_tx, .configure_filter = mt7921_configure_filter, .bss_info_changed = mt7921_bss_info_changed, + .start_ap = mt7921_start_ap, + .stop_ap = mt7921_stop_ap, .sta_state = mt7921_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7921_set_key, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index b8e5f550b4d4..bc434e60dfc6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -745,7 +745,7 @@ mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, &bcnft_req, sizeof(bcnft_req), true); } -static int +int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable) { @@ -774,9 +774,6 @@ mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, }; int err; - if (vif->type != NL80211_IFTYPE_STATION) - return 0; - err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT), &req_hdr, sizeof(req_hdr), false); if (err < 0 || !enable) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 7da29fadc27f..f7609c8ac549 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -284,6 +284,8 @@ int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force); int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev); void mt7921_dma_cleanup(struct mt7921_dev *dev); int mt7921_run_firmware(struct mt7921_dev *dev); +int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable); int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, struct ieee80211_vif *vif, bool enable, enum mt76_sta_info_state state); -- cgit v1.2.3 From f71662de66a63e2776f14e452f1feb601f14e655 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Jun 2022 19:30:29 +0200 Subject: mt76: connac: move HE radiotap parsing in connac module HE radiotap parsing code is shared between connac2 devices. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 3 + .../net/wireless/mediatek/mt76/mt76_connac2_mac.h | 56 ++++++ .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 187 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 180 +------------------- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 52 ------ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 187 +-------------------- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 52 ------ 7 files changed, 251 insertions(+), 466 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 6b8d6c5d621a..c06a320b53bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -253,5 +253,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data, struct mt76_sta_stats *stats); +void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, + struct sk_buff *skb, + __le32 *rxv, u32 mode); #endif /* __MT76_CONNAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h index c9d9c8475a38..f2de2f6d04a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -164,4 +164,60 @@ enum { #define MT_TXS4_TIMESTAMP GENMASK(31, 0) +/* P-RXV DW0 */ +#define MT_PRXV_TX_RATE GENMASK(6, 0) +#define MT_PRXV_TX_DCM BIT(4) +#define MT_PRXV_TX_ER_SU_106T BIT(5) +#define MT_PRXV_NSTS GENMASK(9, 7) +#define MT_PRXV_TXBF BIT(10) +#define MT_PRXV_HT_AD_CODE BIT(11) +#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) + +#define MT_PRXV_FRAME_MODE GENMASK(14, 12) +#define MT_PRXV_HT_SGI GENMASK(16, 15) +#define MT_PRXV_HT_STBC GENMASK(23, 22) +#define MT_PRXV_TX_MODE GENMASK(27, 24) +#define MT_PRXV_DCM BIT(17) +#define MT_PRXV_NUM_RX BIT(20, 18) + +/* P-RXV DW1 */ +#define MT_PRXV_RCPI3 GENMASK(31, 24) +#define MT_PRXV_RCPI2 GENMASK(23, 16) +#define MT_PRXV_RCPI1 GENMASK(15, 8) +#define MT_PRXV_RCPI0 GENMASK(7, 0) +#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) + +/* C-RXV */ +#define MT_CRXV_HT_STBC GENMASK(1, 0) +#define MT_CRXV_TX_MODE GENMASK(7, 4) +#define MT_CRXV_FRAME_MODE GENMASK(10, 8) +#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) +#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) +#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) +#define MT_CRXV_HE_PE_DISAMBIG BIT(23) +#define MT_CRXV_HE_NUM_USER GENMASK(30, 24) +#define MT_CRXV_HE_UPLINK BIT(31) + +#define MT_CRXV_HE_RU0 GENMASK(7, 0) +#define MT_CRXV_HE_RU1 GENMASK(15, 8) +#define MT_CRXV_HE_RU2 GENMASK(23, 16) +#define MT_CRXV_HE_RU3 GENMASK(31, 24) + +#define MT_CRXV_HE_MU_AID GENMASK(30, 20) + +#define MT_CRXV_HE_SR_MASK GENMASK(11, 8) +#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) +#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) +#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) + +#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) +#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) +#define MT_CRXV_HE_BEAM_CHNG BIT(13) +#define MT_CRXV_HE_DOPPLER BIT(16) + +#define MT_CRXV_SNR GENMASK(18, 13) +#define MT_CRXV_FOE_LO GENMASK(31, 19) +#define MT_CRXV_FOE_HI GENMASK(6, 0) +#define MT_CRXV_FOE_SHIFT 13 + #endif /* __MT76_CONNAC2_MAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 3f2680b8c2c2..08cd2e1d8625 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -4,6 +4,10 @@ #include "mt76_connac.h" #include "mt76_connac2_mac.h" +#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) +#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ + IEEE80211_RADIOTAP_HE_##f) + int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) { struct mt76_dev *dev = phy->dev; @@ -521,3 +525,186 @@ out: return !!skb; } EXPORT_SYMBOL_GPL(mt76_connac2_mac_add_txs_skb); + +static void +mt76_connac2_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, + struct ieee80211_radiotap_he *he, + __le32 *rxv) +{ + u32 ru_h, ru_l; + u8 ru, offs = 0; + + ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L); + ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H); + ru = (u8)(ru_l | ru_h << 4); + + status->bw = RATE_INFO_BW_HE_RU; + + switch (ru) { + case 0 ... 36: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; + offs = ru; + break; + case 37 ... 52: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; + offs = ru - 37; + break; + case 53 ... 60: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + offs = ru - 53; + break; + case 61 ... 64: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; + offs = ru - 61; + break; + case 65 ... 66: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; + offs = ru - 65; + break; + case 67: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 68: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + } + + he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); + he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | + le16_encode_bits(offs, + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); +} + +static void +mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb, + __le32 *rxv) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + static struct ieee80211_radiotap_he_mu mu_known = { + .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) | + HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN), + .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), + }; + struct ieee80211_radiotap_he_mu *he_mu; + + if (is_mt7921(dev)) { + mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN); + mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN); + } + + status->flag |= RX_FLAG_RADIOTAP_HE_MU; + + he_mu = skb_push(skb, sizeof(mu_known)); + memcpy(he_mu, &mu_known, sizeof(mu_known)); + +#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) + + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx); + if (status->he_dcm) + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm); + + he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) | + MU_PREP(FLAGS2_SIG_B_SYMS_USERS, + le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER)); + + he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0); + + if (status->bw >= RATE_INFO_BW_40) { + he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN); + he_mu->ru_ch2[0] = + le32_get_bits(rxv[3], MT_CRXV_HE_RU1); + } + + if (status->bw >= RATE_INFO_BW_80) { + he_mu->ru_ch1[1] = + le32_get_bits(rxv[3], MT_CRXV_HE_RU2); + he_mu->ru_ch2[1] = + le32_get_bits(rxv[3], MT_CRXV_HE_RU3); + } +} + +void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, + struct sk_buff *skb, + __le32 *rxv, u32 mode) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + static const struct ieee80211_radiotap_he known = { + .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | + HE_BITS(DATA1_DATA_DCM_KNOWN) | + HE_BITS(DATA1_STBC_KNOWN) | + HE_BITS(DATA1_CODING_KNOWN) | + HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | + HE_BITS(DATA1_DOPPLER_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | + HE_BITS(DATA1_BSS_COLOR_KNOWN), + .data2 = HE_BITS(DATA2_GI_KNOWN) | + HE_BITS(DATA2_TXBF_KNOWN) | + HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | + HE_BITS(DATA2_TXOP_KNOWN), + }; + u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; + struct ieee80211_radiotap_he *he; + + status->flag |= RX_FLAG_RADIOTAP_HE; + + he = skb_push(skb, sizeof(known)); + memcpy(he, &known, sizeof(known)); + + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); + he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | + le16_encode_bits(ltf_size, + IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) + he->data5 |= HE_BITS(DATA5_TXBF); + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | + HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); + + switch (mode) { + case MT_PHY_TYPE_HE_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | + HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); + + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | + HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + break; + case MT_PHY_TYPE_HE_EXT_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + break; + case MT_PHY_TYPE_HE_MU: + he->data1 |= HE_BITS(DATA1_FORMAT_MU) | + HE_BITS(DATA1_UL_DL_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); + + mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv); + mt76_connac2_mac_decode_he_mu_radiotap(dev, skb, rxv); + break; + case MT_PHY_TYPE_HE_TB: + he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | + HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE4_KNOWN); + + he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); + + mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv); + break; + default: + break; + } +} +EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 428c4fd9a0a6..27b2a9edb317 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -10,10 +10,6 @@ #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) -#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) -#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ - IEEE80211_RADIOTAP_HE_##f) - static const struct mt7915_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { @@ -218,178 +214,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } -static void -mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, - struct ieee80211_radiotap_he *he, - __le32 *rxv) -{ - u32 ru_h, ru_l; - u8 ru, offs = 0; - - ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L); - ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H); - ru = (u8)(ru_l | ru_h << 4); - - status->bw = RATE_INFO_BW_HE_RU; - - switch (ru) { - case 0 ... 36: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; - offs = ru; - break; - case 37 ... 52: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; - offs = ru - 37; - break; - case 53 ... 60: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - offs = ru - 53; - break; - case 61 ... 64: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; - offs = ru - 61; - break; - case 65 ... 66: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; - offs = ru - 65; - break; - case 67: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; - break; - case 68: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; - break; - } - - he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); - he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | - le16_encode_bits(offs, - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); -} - -static void -mt7915_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - static const struct ieee80211_radiotap_he_mu mu_known = { - .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) | - HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) | - HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) | - HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN), - .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), - }; - struct ieee80211_radiotap_he_mu *he_mu = NULL; - - status->flag |= RX_FLAG_RADIOTAP_HE_MU; - - he_mu = skb_push(skb, sizeof(mu_known)); - memcpy(he_mu, &mu_known, sizeof(mu_known)); - -#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) - - he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx); - if (status->he_dcm) - he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm); - - he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) | - MU_PREP(FLAGS2_SIG_B_SYMS_USERS, - le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER)); - - he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0); - - if (status->bw >= RATE_INFO_BW_40) { - he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN); - he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1); - } - - if (status->bw >= RATE_INFO_BW_80) { - he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2); - he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3); - } -} - -static void -mt7915_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - static const struct ieee80211_radiotap_he known = { - .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | - HE_BITS(DATA1_DATA_DCM_KNOWN) | - HE_BITS(DATA1_STBC_KNOWN) | - HE_BITS(DATA1_CODING_KNOWN) | - HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | - HE_BITS(DATA1_DOPPLER_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN) | - HE_BITS(DATA1_BSS_COLOR_KNOWN), - .data2 = HE_BITS(DATA2_GI_KNOWN) | - HE_BITS(DATA2_TXBF_KNOWN) | - HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | - HE_BITS(DATA2_TXOP_KNOWN), - }; - struct ieee80211_radiotap_he *he = NULL; - u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; - - status->flag |= RX_FLAG_RADIOTAP_HE; - - he = skb_push(skb, sizeof(known)); - memcpy(he, &known, sizeof(known)); - - he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | - HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); - he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); - he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | - le16_encode_bits(ltf_size, - IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) - he->data5 |= HE_BITS(DATA5_TXBF); - he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | - HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); - - switch (mode) { - case MT_PHY_TYPE_HE_SU: - he->data1 |= HE_BITS(DATA1_FORMAT_SU) | - HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | - HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); - - he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | - HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - break; - case MT_PHY_TYPE_HE_EXT_SU: - he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | - HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); - - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - break; - case MT_PHY_TYPE_HE_MU: - he->data1 |= HE_BITS(DATA1_FORMAT_MU) | - HE_BITS(DATA1_UL_DL_KNOWN); - - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); - - mt7915_mac_decode_he_radiotap_ru(status, he, rxv); - mt7915_mac_decode_he_mu_radiotap(skb, rxv); - break; - case MT_PHY_TYPE_HE_TB: - he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | - HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE4_KNOWN); - - he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); - - mt7915_mac_decode_he_radiotap_ru(status, he, rxv); - break; - default: - break; - } -} - /* The HW does not translate the mac header to 802.3 for mesh point */ static int mt7915_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { @@ -489,7 +313,7 @@ mt7915_mac_fill_rx_rate(struct mt7915_dev *dev, if (!is_mt7915(&dev->mt76)) { stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); - gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v0); + gi = FIELD_GET(MT_PRXV_HT_SGI, v0); *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); dcm = FIELD_GET(MT_PRXV_DCM, v0); bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0); @@ -832,7 +656,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) - mt7915_mac_decode_he_radiotap(skb, rxv, mode); + mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode); if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index f581ae27375b..611bf23b2eb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -116,58 +116,6 @@ enum rx_pkt_type { #define MT_RXD9_HT_CONTROL GENMASK(31, 0) -/* P-RXV */ -#define MT_PRXV_TX_RATE GENMASK(6, 0) -#define MT_PRXV_TX_DCM BIT(4) -#define MT_PRXV_TX_ER_SU_106T BIT(5) -#define MT_PRXV_NSTS GENMASK(9, 7) -#define MT_PRXV_TXBF BIT(10) -#define MT_PRXV_HT_AD_CODE BIT(11) -#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) -#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) -#define MT_PRXV_RCPI3 GENMASK(31, 24) -#define MT_PRXV_RCPI2 GENMASK(23, 16) -#define MT_PRXV_RCPI1 GENMASK(15, 8) -#define MT_PRXV_RCPI0 GENMASK(7, 0) -#define MT_PRXV_HT_SHORT_GI GENMASK(16, 15) -#define MT_PRXV_HT_STBC GENMASK(23, 22) -#define MT_PRXV_TX_MODE GENMASK(27, 24) -#define MT_PRXV_FRAME_MODE GENMASK(14, 12) -#define MT_PRXV_DCM BIT(17) -#define MT_PRXV_NUM_RX BIT(20, 18) - -/* C-RXV */ -#define MT_CRXV_HT_STBC GENMASK(1, 0) -#define MT_CRXV_TX_MODE GENMASK(7, 4) -#define MT_CRXV_FRAME_MODE GENMASK(10, 8) -#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) -#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) -#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) -#define MT_CRXV_HE_PE_DISAMBIG BIT(23) -#define MT_CRXV_HE_NUM_USER GENMASK(30, 24) -#define MT_CRXV_HE_UPLINK BIT(31) -#define MT_CRXV_HE_RU0 GENMASK(7, 0) -#define MT_CRXV_HE_RU1 GENMASK(15, 8) -#define MT_CRXV_HE_RU2 GENMASK(23, 16) -#define MT_CRXV_HE_RU3 GENMASK(31, 24) - -#define MT_CRXV_HE_MU_AID GENMASK(30, 20) - -#define MT_CRXV_HE_SR_MASK GENMASK(11, 8) -#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) -#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) -#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) - -#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) -#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) -#define MT_CRXV_HE_BEAM_CHNG BIT(13) -#define MT_CRXV_HE_DOPPLER BIT(16) - -#define MT_CRXV_SNR GENMASK(18, 13) -#define MT_CRXV_FOE_LO GENMASK(31, 19) -#define MT_CRXV_FOE_HI GENMASK(6, 0) -#define MT_CRXV_FOE_SHIFT 13 - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index ccaf4d539852..4c2f62696b56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -9,10 +9,6 @@ #include "mac.h" #include "mcu.h" -#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) -#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ - IEEE80211_RADIOTAP_HE_##f) - static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev, u16 idx, bool unicast) { @@ -168,183 +164,6 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev) } EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll); -static void -mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, - struct ieee80211_radiotap_he *he, - __le32 *rxv) -{ - u32 ru_h, ru_l; - u8 ru, offs = 0; - - ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L); - ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H); - ru = (u8)(ru_l | ru_h << 4); - - status->bw = RATE_INFO_BW_HE_RU; - - switch (ru) { - case 0 ... 36: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; - offs = ru; - break; - case 37 ... 52: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; - offs = ru - 37; - break; - case 53 ... 60: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - offs = ru - 53; - break; - case 61 ... 64: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; - offs = ru - 61; - break; - case 65 ... 66: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; - offs = ru - 65; - break; - case 67: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; - break; - case 68: - status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; - break; - } - - he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); - he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | - le16_encode_bits(offs, - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); -} - -static void -mt7921_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - static const struct ieee80211_radiotap_he_mu mu_known = { - .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) | - HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) | - HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) | - HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN) | - HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN), - .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN) | - HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN), - }; - struct ieee80211_radiotap_he_mu *he_mu; - - status->flag |= RX_FLAG_RADIOTAP_HE_MU; - - he_mu = skb_push(skb, sizeof(mu_known)); - memcpy(he_mu, &mu_known, sizeof(mu_known)); - -#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) - - he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx); - if (status->he_dcm) - he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm); - - he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) | - MU_PREP(FLAGS2_SIG_B_SYMS_USERS, - le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER)); - - he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0); - - if (status->bw >= RATE_INFO_BW_40) { - he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN); - he_mu->ru_ch2[0] = - le32_get_bits(rxv[3], MT_CRXV_HE_RU1); - } - - if (status->bw >= RATE_INFO_BW_80) { - he_mu->ru_ch1[1] = - le32_get_bits(rxv[3], MT_CRXV_HE_RU2); - he_mu->ru_ch2[1] = - le32_get_bits(rxv[3], MT_CRXV_HE_RU3); - } -} - -static void -mt7921_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u32 mode) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - static const struct ieee80211_radiotap_he known = { - .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | - HE_BITS(DATA1_DATA_DCM_KNOWN) | - HE_BITS(DATA1_STBC_KNOWN) | - HE_BITS(DATA1_CODING_KNOWN) | - HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | - HE_BITS(DATA1_DOPPLER_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN) | - HE_BITS(DATA1_BSS_COLOR_KNOWN), - .data2 = HE_BITS(DATA2_GI_KNOWN) | - HE_BITS(DATA2_TXBF_KNOWN) | - HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | - HE_BITS(DATA2_TXOP_KNOWN), - }; - struct ieee80211_radiotap_he *he = NULL; - u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; - - status->flag |= RX_FLAG_RADIOTAP_HE; - - he = skb_push(skb, sizeof(known)); - memcpy(he, &known, sizeof(known)); - - he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | - HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); - he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); - he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | - le16_encode_bits(ltf_size, - IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) - he->data5 |= HE_BITS(DATA5_TXBF); - he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | - HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); - - switch (mode) { - case MT_PHY_TYPE_HE_SU: - he->data1 |= HE_BITS(DATA1_FORMAT_SU) | - HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | - HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); - - he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | - HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - break; - case MT_PHY_TYPE_HE_EXT_SU: - he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | - HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); - - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - break; - case MT_PHY_TYPE_HE_MU: - he->data1 |= HE_BITS(DATA1_FORMAT_MU) | - HE_BITS(DATA1_UL_DL_KNOWN); - - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); - - mt7921_mac_decode_he_radiotap_ru(status, he, rxv); - mt7921_mac_decode_he_mu_radiotap(skb, rxv); - break; - case MT_PHY_TYPE_HE_TB: - he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | - HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE4_KNOWN); - - he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); - - mt7921_mac_decode_he_radiotap_ru(status, he, rxv); - break; - default: - break; - } -} - static void mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy, struct mt76_rx_status *status, u8 chfreq) @@ -672,8 +491,8 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) status->chain_signal[i]); } - stbc = FIELD_GET(MT_PRXV_STBC, v0); - gi = FIELD_GET(MT_PRXV_SGI, v0); + stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); + gi = FIELD_GET(MT_PRXV_HT_SGI, v0); cck = false; idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); @@ -796,7 +615,7 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_mac_assoc_rssi(dev, skb); if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) - mt7921_mac_decode_he_radiotap(skb, rxv, mode); + mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode); if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 556e687bd235..6e31ae7d39d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -113,58 +113,6 @@ enum rx_pkt_type { #define MT_RXD9_HT_CONTROL GENMASK(31, 0) -/* P-RXV DW0 */ -#define MT_PRXV_TX_RATE GENMASK(6, 0) -#define MT_PRXV_TX_DCM BIT(4) -#define MT_PRXV_TX_ER_SU_106T BIT(5) -#define MT_PRXV_NSTS GENMASK(9, 7) -#define MT_PRXV_TXBF BIT(10) -#define MT_PRXV_HT_AD_CODE BIT(11) -#define MT_PRXV_FRAME_MODE GENMASK(14, 12) -#define MT_PRXV_SGI GENMASK(16, 15) -#define MT_PRXV_STBC GENMASK(23, 22) -#define MT_PRXV_TX_MODE GENMASK(27, 24) -#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) - -/* P-RXV DW1 */ -#define MT_PRXV_RCPI3 GENMASK(31, 24) -#define MT_PRXV_RCPI2 GENMASK(23, 16) -#define MT_PRXV_RCPI1 GENMASK(15, 8) -#define MT_PRXV_RCPI0 GENMASK(7, 0) -#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) - -/* C-RXV */ -#define MT_CRXV_HT_STBC GENMASK(1, 0) -#define MT_CRXV_TX_MODE GENMASK(7, 4) -#define MT_CRXV_FRAME_MODE GENMASK(10, 8) -#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) -#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) -#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) -#define MT_CRXV_HE_PE_DISAMBIG BIT(23) -#define MT_CRXV_HE_NUM_USER GENMASK(30, 24) -#define MT_CRXV_HE_UPLINK BIT(31) - -#define MT_CRXV_HE_RU0 GENMASK(7, 0) -#define MT_CRXV_HE_RU1 GENMASK(15, 8) -#define MT_CRXV_HE_RU2 GENMASK(23, 16) -#define MT_CRXV_HE_RU3 GENMASK(31, 24) -#define MT_CRXV_HE_MU_AID GENMASK(30, 20) - -#define MT_CRXV_HE_SR_MASK GENMASK(11, 8) -#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) -#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) -#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) - -#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) -#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) -#define MT_CRXV_HE_BEAM_CHNG BIT(13) -#define MT_CRXV_HE_DOPPLER BIT(16) - -#define MT_CRXV_SNR GENMASK(18, 13) -#define MT_CRXV_FOE_LO GENMASK(31, 19) -#define MT_CRXV_FOE_HI GENMASK(6, 0) -#define MT_CRXV_FOE_SHIFT 13 - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU -- cgit v1.2.3 From 0880d40871d1d0155c157a68add961d8dbcca2a3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Jun 2022 19:30:30 +0200 Subject: mt76: connac: move mt76_connac2_reverse_frag0_hdr_trans in mt76-connac module mt76_connac2_reverse_frag0_hdr_trans routine is shared between mt7921 and mt7915e drivers. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 2 + .../net/wireless/mediatek/mt76/mt76_connac2_mac.h | 86 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 76 +++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 97 +++------------------- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 87 ------------------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 95 +++------------------ drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 84 ------------------- 7 files changed, 189 insertions(+), 338 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index c06a320b53bc..27ab1f2355ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -256,5 +256,7 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, struct sk_buff *skb, __le32 *rxv, u32 mode); +int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, + struct sk_buff *skb, u16 hdr_offset); #endif /* __MT76_CONNAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h index f2de2f6d04a1..0d04207b4292 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -164,6 +164,92 @@ enum { #define MT_TXS4_TIMESTAMP GENMASK(31, 0) +/* RXD DW1 */ +#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) +#define MT_RXD1_NORMAL_GROUP_1 BIT(11) +#define MT_RXD1_NORMAL_GROUP_2 BIT(12) +#define MT_RXD1_NORMAL_GROUP_3 BIT(13) +#define MT_RXD1_NORMAL_GROUP_4 BIT(14) +#define MT_RXD1_NORMAL_GROUP_5 BIT(15) +#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) +#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) +#define MT_RXD1_NORMAL_CM BIT(23) +#define MT_RXD1_NORMAL_CLM BIT(24) +#define MT_RXD1_NORMAL_ICV_ERR BIT(25) +#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) +#define MT_RXD1_NORMAL_FCS_ERR BIT(27) +#define MT_RXD1_NORMAL_BAND_IDX BIT(28) +#define MT_RXD1_NORMAL_SPP_EN BIT(29) +#define MT_RXD1_NORMAL_ADD_OM BIT(30) +#define MT_RXD1_NORMAL_SEC_DONE BIT(31) + +/* RXD DW2 */ +#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) +#define MT_RXD2_NORMAL_CO_ANT BIT(6) +#define MT_RXD2_NORMAL_BF_CQI BIT(7) +#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) +#define MT_RXD2_NORMAL_HDR_TRANS BIT(13) +#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) +#define MT_RXD2_NORMAL_TID GENMASK(19, 16) +#define MT_RXD2_NORMAL_MU_BAR BIT(21) +#define MT_RXD2_NORMAL_SW_BIT BIT(22) +#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) +#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) +#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) +#define MT_RXD2_NORMAL_INT_FRAME BIT(26) +#define MT_RXD2_NORMAL_FRAG BIT(27) +#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) +#define MT_RXD2_NORMAL_NDATA BIT(29) +#define MT_RXD2_NORMAL_NON_AMPDU BIT(30) +#define MT_RXD2_NORMAL_BF_REPORT BIT(31) + +/* RXD DW4 */ +#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) +#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) +#define MT_RXD4_MID_AMSDU_FRAME BIT(1) +#define MT_RXD4_LAST_AMSDU_FRAME BIT(0) +#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) +#define MT_RXD4_NORMAL_CLS BIT(10) +#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) +#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) +#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) +#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) +#define MT_RXD3_NORMAL_PF_MODE BIT(29) +#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) + +#define MT_RXV_HDR_BAND_IDX BIT(24) + +/* RXD DW3 */ +#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) +#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) +#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) +#define MT_RXD3_NORMAL_U2M BIT(0) +#define MT_RXD3_NORMAL_HTC_VLD BIT(0) +#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) +#define MT_RXD3_NORMAL_BEACON_MC BIT(20) +#define MT_RXD3_NORMAL_BEACON_UC BIT(21) +#define MT_RXD3_NORMAL_AMSDU BIT(22) +#define MT_RXD3_NORMAL_MESH BIT(23) +#define MT_RXD3_NORMAL_MHCP BIT(24) +#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) +#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) +#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) +#define MT_RXD3_NORMAL_MORE BIT(28) +#define MT_RXD3_NORMAL_UNWANT BIT(29) +#define MT_RXD3_NORMAL_RX_DROP BIT(30) +#define MT_RXD3_NORMAL_VLAN2ETH BIT(31) + +/* RXD GROUP4 */ +#define MT_RXD6_FRAME_CONTROL GENMASK(15, 0) +#define MT_RXD6_TA_LO GENMASK(31, 16) + +#define MT_RXD7_TA_HI GENMASK(31, 0) + +#define MT_RXD8_SEQ_CTRL GENMASK(15, 0) +#define MT_RXD8_QOS_CTL GENMASK(31, 16) + +#define MT_RXD9_HT_CONTROL GENMASK(31, 0) + /* P-RXV DW0 */ #define MT_PRXV_TX_RATE GENMASK(6, 0) #define MT_PRXV_TX_DCM BIT(4) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 08cd2e1d8625..6ac1ac3f5480 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -708,3 +708,79 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, } } EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap); + +/* The HW does not translate the mac header to 802.3 for mesh point */ +int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, + struct sk_buff *skb, u16 hdr_offset) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_offset); + __le32 *rxd = (__le32 *)skb->data; + struct ieee80211_sta *sta; + struct ieee80211_hdr hdr; + u16 frame_control; + + if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != + MT_RXD3_NORMAL_U2M) + return -EINVAL; + + if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) + return -EINVAL; + + sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv); + + /* store the info from RXD and ethhdr to avoid being overridden */ + frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL); + hdr.frame_control = cpu_to_le16(frame_control); + hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL)); + hdr.duration_id = 0; + + ether_addr_copy(hdr.addr1, vif->addr); + ether_addr_copy(hdr.addr2, sta->addr); + switch (frame_control & (IEEE80211_FCTL_TODS | + IEEE80211_FCTL_FROMDS)) { + case 0: + ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); + break; + case IEEE80211_FCTL_FROMDS: + ether_addr_copy(hdr.addr3, eth_hdr->h_source); + break; + case IEEE80211_FCTL_TODS: + ether_addr_copy(hdr.addr3, eth_hdr->h_dest); + break; + case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: + ether_addr_copy(hdr.addr3, eth_hdr->h_dest); + ether_addr_copy(hdr.addr4, eth_hdr->h_source); + break; + default: + break; + } + + skb_pull(skb, hdr_offset + sizeof(struct ethhdr) - 2); + if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || + eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) + ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); + else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) + ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); + else + skb_pull(skb, 2); + + if (ieee80211_has_order(hdr.frame_control)) + memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9], + IEEE80211_HT_CTL_LEN); + if (ieee80211_is_data_qos(hdr.frame_control)) { + __le16 qos_ctrl; + + qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL)); + memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, + IEEE80211_QOS_CTL_LEN); + } + + if (ieee80211_has_a4(hdr.frame_control)) + memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); + else + memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac2_reverse_frag0_hdr_trans); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 27b2a9edb317..1d83f8790c44 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -176,7 +176,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) /* * We don't support reading GI info from txs packets. * For accurate tx status reporting and AQL improvement, - * we need to make sure that flags match so polling GI + we need to make sure that flags match so polling GI * from per-sta counters directly. */ rate = &msta->wcid.rate; @@ -214,86 +214,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } -/* The HW does not translate the mac header to 802.3 for mesh point */ -static int mt7915_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); - struct mt7915_sta *msta = (struct mt7915_sta *)status->wcid; - __le32 *rxd = (__le32 *)skb->data; - struct ieee80211_sta *sta; - struct ieee80211_vif *vif; - struct ieee80211_hdr hdr; - u16 frame_control; - - if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != - MT_RXD3_NORMAL_U2M) - return -EINVAL; - - if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) - return -EINVAL; - - if (!msta || !msta->vif) - return -EINVAL; - - sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); - vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); - - /* store the info from RXD and ethhdr to avoid being overridden */ - frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL); - hdr.frame_control = cpu_to_le16(frame_control); - hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL)); - hdr.duration_id = 0; - - ether_addr_copy(hdr.addr1, vif->addr); - ether_addr_copy(hdr.addr2, sta->addr); - switch (frame_control & (IEEE80211_FCTL_TODS | - IEEE80211_FCTL_FROMDS)) { - case 0: - ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); - break; - case IEEE80211_FCTL_FROMDS: - ether_addr_copy(hdr.addr3, eth_hdr->h_source); - break; - case IEEE80211_FCTL_TODS: - ether_addr_copy(hdr.addr3, eth_hdr->h_dest); - break; - case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: - ether_addr_copy(hdr.addr3, eth_hdr->h_dest); - ether_addr_copy(hdr.addr4, eth_hdr->h_source); - break; - default: - break; - } - - skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2); - if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || - eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) - ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); - else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) - ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); - else - skb_pull(skb, 2); - - if (ieee80211_has_order(hdr.frame_control)) - memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9], - IEEE80211_HT_CTL_LEN); - if (ieee80211_is_data_qos(hdr.frame_control)) { - __le16 qos_ctrl; - - qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL)); - memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, - IEEE80211_QOS_CTL_LEN); - } - - if (ieee80211_has_a4(hdr.frame_control)) - memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); - else - memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); - - return 0; -} - static int mt7915_mac_fill_rx_rate(struct mt7915_dev *dev, struct mt76_rx_status *status, @@ -414,6 +334,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) bool unicast, insert_ccmp_hdr = false; u8 remove_pad, amsdu_info; u8 mode = 0, qos_ctl = 0; + struct mt7915_sta *msta; bool hdr_trans; u16 hdr_gap; u16 seq_ctrl = 0; @@ -450,8 +371,6 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) status->wcid = mt7915_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - struct mt7915_sta *msta; - msta = container_of(status->wcid, struct mt7915_sta, wcid); spin_lock_bh(&dev->sta_poll_lock); if (list_empty(&msta->poll_list)) @@ -605,8 +524,18 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { - if (mt7915_reverse_frag0_hdr_trans(skb, hdr_gap)) + struct ieee80211_vif *vif; + int err; + + if (!msta || !msta->vif) return -EINVAL; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap); + if (err) + return err; + hdr_trans = false; } else { int pad_start = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 611bf23b2eb0..724feb2df4a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -29,93 +29,6 @@ enum rx_pkt_type { PKT_TYPE_TXRX_NOTIFY_V0 = 0x18, }; -/* RXD DW1 */ -#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) -#define MT_RXD1_NORMAL_GROUP_1 BIT(11) -#define MT_RXD1_NORMAL_GROUP_2 BIT(12) -#define MT_RXD1_NORMAL_GROUP_3 BIT(13) -#define MT_RXD1_NORMAL_GROUP_4 BIT(14) -#define MT_RXD1_NORMAL_GROUP_5 BIT(15) -#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) -#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) -#define MT_RXD1_NORMAL_CM BIT(23) -#define MT_RXD1_NORMAL_CLM BIT(24) -#define MT_RXD1_NORMAL_ICV_ERR BIT(25) -#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) -#define MT_RXD1_NORMAL_FCS_ERR BIT(27) -#define MT_RXD1_NORMAL_BAND_IDX BIT(28) -#define MT_RXD1_NORMAL_SPP_EN BIT(29) -#define MT_RXD1_NORMAL_ADD_OM BIT(30) -#define MT_RXD1_NORMAL_SEC_DONE BIT(31) - -/* RXD DW2 */ -#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) -#define MT_RXD2_NORMAL_CO_ANT BIT(6) -#define MT_RXD2_NORMAL_BF_CQI BIT(7) -#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) -#define MT_RXD2_NORMAL_HDR_TRANS BIT(13) -#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) -#define MT_RXD2_NORMAL_TID GENMASK(19, 16) -#define MT_RXD2_NORMAL_MU_BAR BIT(21) -#define MT_RXD2_NORMAL_SW_BIT BIT(22) -#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) -#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) -#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) -#define MT_RXD2_NORMAL_INT_FRAME BIT(26) -#define MT_RXD2_NORMAL_FRAG BIT(27) -#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) -#define MT_RXD2_NORMAL_NDATA BIT(29) -#define MT_RXD2_NORMAL_NON_AMPDU BIT(30) -#define MT_RXD2_NORMAL_BF_REPORT BIT(31) - -/* RXD DW3 */ -#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) -#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) -#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) -#define MT_RXD3_NORMAL_U2M BIT(0) -#define MT_RXD3_NORMAL_HTC_VLD BIT(0) -#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) -#define MT_RXD3_NORMAL_BEACON_MC BIT(20) -#define MT_RXD3_NORMAL_BEACON_UC BIT(21) -#define MT_RXD3_NORMAL_AMSDU BIT(22) -#define MT_RXD3_NORMAL_MESH BIT(23) -#define MT_RXD3_NORMAL_MHCP BIT(24) -#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) -#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) -#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) -#define MT_RXD3_NORMAL_MORE BIT(28) -#define MT_RXD3_NORMAL_UNWANT BIT(29) -#define MT_RXD3_NORMAL_RX_DROP BIT(30) -#define MT_RXD3_NORMAL_VLAN2ETH BIT(31) - -/* RXD DW4 */ -#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) -#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) -#define MT_RXD4_MID_AMSDU_FRAME BIT(1) -#define MT_RXD4_LAST_AMSDU_FRAME BIT(0) - -#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) -#define MT_RXD4_NORMAL_CLS BIT(10) -#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) -#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) -#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) -#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) -#define MT_RXD3_NORMAL_PF_MODE BIT(29) -#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) - -#define MT_RXV_HDR_BAND_IDX BIT(24) - -/* RXD GROUP4 */ -#define MT_RXD6_FRAME_CONTROL GENMASK(15, 0) -#define MT_RXD6_TA_LO GENMASK(31, 16) - -#define MT_RXD7_TA_HI GENMASK(31, 0) - -#define MT_RXD8_SEQ_CTRL GENMASK(15, 0) -#define MT_RXD8_QOS_CTL GENMASK(31, 16) - -#define MT_RXD9_HT_CONTROL GENMASK(31, 0) - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 4c2f62696b56..5b48a725e637 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -218,86 +218,6 @@ mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_mac_rssi_iter, skb); } -/* The HW does not translate the mac header to 802.3 for mesh point */ -static int mt7921_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); - struct mt7921_sta *msta = (struct mt7921_sta *)status->wcid; - __le32 *rxd = (__le32 *)skb->data; - struct ieee80211_sta *sta; - struct ieee80211_vif *vif; - struct ieee80211_hdr hdr; - u16 frame_control; - - if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != - MT_RXD3_NORMAL_U2M) - return -EINVAL; - - if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) - return -EINVAL; - - if (!msta || !msta->vif) - return -EINVAL; - - sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); - vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); - - /* store the info from RXD and ethhdr to avoid being overridden */ - frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL); - hdr.frame_control = cpu_to_le16(frame_control); - hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL)); - hdr.duration_id = 0; - - ether_addr_copy(hdr.addr1, vif->addr); - ether_addr_copy(hdr.addr2, sta->addr); - switch (frame_control & (IEEE80211_FCTL_TODS | - IEEE80211_FCTL_FROMDS)) { - case 0: - ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); - break; - case IEEE80211_FCTL_FROMDS: - ether_addr_copy(hdr.addr3, eth_hdr->h_source); - break; - case IEEE80211_FCTL_TODS: - ether_addr_copy(hdr.addr3, eth_hdr->h_dest); - break; - case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: - ether_addr_copy(hdr.addr3, eth_hdr->h_dest); - ether_addr_copy(hdr.addr4, eth_hdr->h_source); - break; - default: - break; - } - - skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2); - if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || - eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) - ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); - else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) - ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); - else - skb_pull(skb, 2); - - if (ieee80211_has_order(hdr.frame_control)) - memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9], - IEEE80211_HT_CTL_LEN); - if (ieee80211_is_data_qos(hdr.frame_control)) { - __le16 qos_ctrl; - - qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL)); - memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, - IEEE80211_QOS_CTL_LEN); - } - - if (ieee80211_has_a4(hdr.frame_control)) - memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); - else - memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); - - return 0; -} - static int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) { @@ -315,6 +235,7 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); + struct mt7921_sta *msta; u16 seq_ctrl = 0; __le16 fc = 0; u32 mode = 0; @@ -345,8 +266,6 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) status->wcid = mt7921_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - struct mt7921_sta *msta; - msta = container_of(status->wcid, struct mt7921_sta, wcid); spin_lock_bh(&dev->sta_poll_lock); if (list_empty(&msta->poll_list)) @@ -581,8 +500,18 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { - if (mt7921_reverse_frag0_hdr_trans(skb, hdr_gap)) + struct ieee80211_vif *vif; + int err; + + if (!msta || !msta->vif) return -EINVAL; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap); + if (err) + return err; + hdr_trans = false; } else { skb_pull(skb, hdr_gap); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 6e31ae7d39d3..ca2ec83bc831 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -29,90 +29,6 @@ enum rx_pkt_type { PKT_TYPE_NORMAL_MCU, }; -/* RXD DW1 */ -#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) -#define MT_RXD1_NORMAL_GROUP_1 BIT(11) -#define MT_RXD1_NORMAL_GROUP_2 BIT(12) -#define MT_RXD1_NORMAL_GROUP_3 BIT(13) -#define MT_RXD1_NORMAL_GROUP_4 BIT(14) -#define MT_RXD1_NORMAL_GROUP_5 BIT(15) -#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) -#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) -#define MT_RXD1_NORMAL_CM BIT(23) -#define MT_RXD1_NORMAL_CLM BIT(24) -#define MT_RXD1_NORMAL_ICV_ERR BIT(25) -#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) -#define MT_RXD1_NORMAL_FCS_ERR BIT(27) -#define MT_RXD1_NORMAL_BAND_IDX BIT(28) -#define MT_RXD1_NORMAL_SPP_EN BIT(29) -#define MT_RXD1_NORMAL_ADD_OM BIT(30) -#define MT_RXD1_NORMAL_SEC_DONE BIT(31) - -/* RXD DW2 */ -#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) -#define MT_RXD2_NORMAL_CO_ANT BIT(6) -#define MT_RXD2_NORMAL_BF_CQI BIT(7) -#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) -#define MT_RXD2_NORMAL_HDR_TRANS BIT(13) -#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) -#define MT_RXD2_NORMAL_TID GENMASK(19, 16) -#define MT_RXD2_NORMAL_MU_BAR BIT(21) -#define MT_RXD2_NORMAL_SW_BIT BIT(22) -#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) -#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) -#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) -#define MT_RXD2_NORMAL_INT_FRAME BIT(26) -#define MT_RXD2_NORMAL_FRAG BIT(27) -#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) -#define MT_RXD2_NORMAL_NDATA BIT(29) -#define MT_RXD2_NORMAL_NON_AMPDU BIT(30) -#define MT_RXD2_NORMAL_BF_REPORT BIT(31) - -/* RXD DW3 */ -#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) -#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) -#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) -#define MT_RXD3_NORMAL_U2M BIT(0) -#define MT_RXD3_NORMAL_HTC_VLD BIT(0) -#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) -#define MT_RXD3_NORMAL_BEACON_MC BIT(20) -#define MT_RXD3_NORMAL_BEACON_UC BIT(21) -#define MT_RXD3_NORMAL_AMSDU BIT(22) -#define MT_RXD3_NORMAL_MESH BIT(23) -#define MT_RXD3_NORMAL_MHCP BIT(24) -#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) -#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) -#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) -#define MT_RXD3_NORMAL_MORE BIT(28) -#define MT_RXD3_NORMAL_UNWANT BIT(29) -#define MT_RXD3_NORMAL_RX_DROP BIT(30) -#define MT_RXD3_NORMAL_VLAN2ETH BIT(31) - -/* RXD DW4 */ -#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) -#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) -#define MT_RXD4_MID_AMSDU_FRAME BIT(1) -#define MT_RXD4_LAST_AMSDU_FRAME BIT(0) -#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) -#define MT_RXD4_NORMAL_CLS BIT(10) -#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) -#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) -#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) -#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) -#define MT_RXD3_NORMAL_PF_MODE BIT(29) -#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) - -/* RXD GROUP4 */ -#define MT_RXD6_FRAME_CONTROL GENMASK(15, 0) -#define MT_RXD6_TA_LO GENMASK(31, 16) - -#define MT_RXD7_TA_HI GENMASK(31, 0) - -#define MT_RXD8_SEQ_CTRL GENMASK(15, 0) -#define MT_RXD8_QOS_CTL GENMASK(31, 16) - -#define MT_RXD9_HT_CONTROL GENMASK(31, 0) - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU -- cgit v1.2.3 From d832f5e73815c3043ede569fd3af07c33764e49e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Jun 2022 19:30:31 +0200 Subject: mt76: connac: move mt76_connac2_mac_fill_rx_rate in connac module Rely on mt76_connac2_mac_fill_rx_rate routine in mt7921 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 4 + .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 105 ++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 106 +-------------------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 82 ++-------------- 4 files changed, 117 insertions(+), 180 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 27ab1f2355ce..a9927dcf3d6c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -258,5 +258,9 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, __le32 *rxv, u32 mode); int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, struct sk_buff *skb, u16 hdr_offset); +int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, + struct mt76_rx_status *status, + struct ieee80211_supported_band *sband, + __le32 *rxv, u8 *mode); #endif /* __MT76_CONNAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 6ac1ac3f5480..6aa02ace365b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -784,3 +784,108 @@ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, return 0; } EXPORT_SYMBOL_GPL(mt76_connac2_reverse_frag0_hdr_trans); + +int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, + struct mt76_rx_status *status, + struct ieee80211_supported_band *sband, + __le32 *rxv, u8 *mode) +{ + u32 v0, v2; + u8 stbc, gi, bw, dcm, nss; + int i, idx; + bool cck = false; + + v0 = le32_to_cpu(rxv[0]); + v2 = le32_to_cpu(rxv[2]); + + idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); + nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1; + + if (!is_mt7915(dev)) { + stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); + gi = FIELD_GET(MT_PRXV_HT_SGI, v0); + *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); + if (is_mt7921(dev)) + dcm = !!(idx & MT_PRXV_TX_DCM); + else + dcm = FIELD_GET(MT_PRXV_DCM, v0); + bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0); + } else { + stbc = FIELD_GET(MT_CRXV_HT_STBC, v2); + gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2); + *mode = FIELD_GET(MT_CRXV_TX_MODE, v2); + dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM); + bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2); + } + + switch (*mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + i = mt76_get_rate(dev, sband, i, cck); + break; + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + if (gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + if (i > 31) + return -EINVAL; + break; + case MT_PHY_TYPE_VHT: + status->nss = nss; + status->encoding = RX_ENC_VHT; + if (gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + if (i > 11) + return -EINVAL; + break; + case MT_PHY_TYPE_HE_MU: + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + status->nss = nss; + status->encoding = RX_ENC_HE; + i &= GENMASK(3, 0); + + if (gi <= NL80211_RATE_INFO_HE_GI_3_2) + status->he_gi = gi; + + status->he_dcm = dcm; + break; + default: + return -EINVAL; + } + status->rate_idx = i; + + switch (bw) { + case IEEE80211_STA_RX_BW_20: + break; + case IEEE80211_STA_RX_BW_40: + if (*mode & MT_PHY_TYPE_HE_EXT_SU && + (idx & MT_PRXV_TX_ER_SU_106T)) { + status->bw = RATE_INFO_BW_HE_RU; + status->he_ru = + NL80211_RATE_INFO_HE_RU_ALLOC_106; + } else { + status->bw = RATE_INFO_BW_40; + } + break; + case IEEE80211_STA_RX_BW_80: + status->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_160: + status->bw = RATE_INFO_BW_160; + break; + default: + return -EINVAL; + } + + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; + if (*mode < MT_PHY_TYPE_HE_SU && gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 1d83f8790c44..a575a44685b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -214,108 +214,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } -static int -mt7915_mac_fill_rx_rate(struct mt7915_dev *dev, - struct mt76_rx_status *status, - struct ieee80211_supported_band *sband, - __le32 *rxv, u8 *mode) -{ - u32 v0, v2; - u8 stbc, gi, bw, dcm, nss; - int i, idx; - bool cck = false; - - v0 = le32_to_cpu(rxv[0]); - v2 = le32_to_cpu(rxv[2]); - - idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); - nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1; - - if (!is_mt7915(&dev->mt76)) { - stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); - gi = FIELD_GET(MT_PRXV_HT_SGI, v0); - *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); - dcm = FIELD_GET(MT_PRXV_DCM, v0); - bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0); - } else { - stbc = FIELD_GET(MT_CRXV_HT_STBC, v2); - gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2); - *mode = FIELD_GET(MT_CRXV_TX_MODE, v2); - dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM); - bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2); - } - - switch (*mode) { - case MT_PHY_TYPE_CCK: - cck = true; - fallthrough; - case MT_PHY_TYPE_OFDM: - i = mt76_get_rate(&dev->mt76, sband, i, cck); - break; - case MT_PHY_TYPE_HT_GF: - case MT_PHY_TYPE_HT: - status->encoding = RX_ENC_HT; - if (gi) - status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - if (i > 31) - return -EINVAL; - break; - case MT_PHY_TYPE_VHT: - status->nss = nss; - status->encoding = RX_ENC_VHT; - if (gi) - status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - if (i > 11) - return -EINVAL; - break; - case MT_PHY_TYPE_HE_MU: - case MT_PHY_TYPE_HE_SU: - case MT_PHY_TYPE_HE_EXT_SU: - case MT_PHY_TYPE_HE_TB: - status->nss = nss; - status->encoding = RX_ENC_HE; - i &= GENMASK(3, 0); - - if (gi <= NL80211_RATE_INFO_HE_GI_3_2) - status->he_gi = gi; - - status->he_dcm = dcm; - break; - default: - return -EINVAL; - } - status->rate_idx = i; - - switch (bw) { - case IEEE80211_STA_RX_BW_20: - break; - case IEEE80211_STA_RX_BW_40: - if (*mode & MT_PHY_TYPE_HE_EXT_SU && - (idx & MT_PRXV_TX_ER_SU_106T)) { - status->bw = RATE_INFO_BW_HE_RU; - status->he_ru = - NL80211_RATE_INFO_HE_RU_ALLOC_106; - } else { - status->bw = RATE_INFO_BW_40; - } - break; - case IEEE80211_STA_RX_BW_80: - status->bw = RATE_INFO_BW_80; - break; - case IEEE80211_STA_RX_BW_160: - status->bw = RATE_INFO_BW_160; - break; - default: - return -EINVAL; - } - - status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; - if (*mode < MT_PHY_TYPE_HE_SU && gi) - status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - - return 0; -} - static int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -508,8 +406,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } if (!is_mt7915(&dev->mt76) || (rxd1 & MT_RXD1_NORMAL_GROUP_5)) { - ret = mt7915_mac_fill_rx_rate(dev, status, sband, rxv, - &mode); + ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status, + sband, rxv, &mode); if (ret < 0) return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 5b48a725e637..b8fe61355cce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -238,7 +238,7 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) struct mt7921_sta *msta; u16 seq_ctrl = 0; __le16 fc = 0; - u32 mode = 0; + u8 mode = 0; int i, idx; memset(status, 0, sizeof(*status)); @@ -380,9 +380,8 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) /* RXD Group 3 - P-RXV */ if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { - u8 stbc, gi; u32 v0, v1; - bool cck; + int ret; rxv = rxd; rxd += 2; @@ -410,79 +409,10 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) status->chain_signal[i]); } - stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); - gi = FIELD_GET(MT_PRXV_HT_SGI, v0); - cck = false; - - idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); - mode = FIELD_GET(MT_PRXV_TX_MODE, v0); - - switch (mode) { - case MT_PHY_TYPE_CCK: - cck = true; - fallthrough; - case MT_PHY_TYPE_OFDM: - i = mt76_get_rate(&dev->mt76, sband, i, cck); - break; - case MT_PHY_TYPE_HT_GF: - case MT_PHY_TYPE_HT: - status->encoding = RX_ENC_HT; - if (i > 31) - return -EINVAL; - break; - case MT_PHY_TYPE_VHT: - status->nss = - FIELD_GET(MT_PRXV_NSTS, v0) + 1; - status->encoding = RX_ENC_VHT; - if (i > 11) - return -EINVAL; - break; - case MT_PHY_TYPE_HE_MU: - case MT_PHY_TYPE_HE_SU: - case MT_PHY_TYPE_HE_EXT_SU: - case MT_PHY_TYPE_HE_TB: - status->nss = - FIELD_GET(MT_PRXV_NSTS, v0) + 1; - status->encoding = RX_ENC_HE; - i &= GENMASK(3, 0); - - if (gi <= NL80211_RATE_INFO_HE_GI_3_2) - status->he_gi = gi; - - status->he_dcm = !!(idx & MT_PRXV_TX_DCM); - break; - default: - return -EINVAL; - } - - status->rate_idx = i; - - switch (FIELD_GET(MT_PRXV_FRAME_MODE, v0)) { - case IEEE80211_STA_RX_BW_20: - break; - case IEEE80211_STA_RX_BW_40: - if (mode & MT_PHY_TYPE_HE_EXT_SU && - (idx & MT_PRXV_TX_ER_SU_106T)) { - status->bw = RATE_INFO_BW_HE_RU; - status->he_ru = - NL80211_RATE_INFO_HE_RU_ALLOC_106; - } else { - status->bw = RATE_INFO_BW_40; - } - break; - case IEEE80211_STA_RX_BW_80: - status->bw = RATE_INFO_BW_80; - break; - case IEEE80211_STA_RX_BW_160: - status->bw = RATE_INFO_BW_160; - break; - default: - return -EINVAL; - } - - status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; - if (mode < MT_PHY_TYPE_HE_SU && gi) - status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status, sband, + rxv, &mode); + if (ret < 0) + return ret; if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { rxd += 18; -- cgit v1.2.3 From cfd6110998e33b8695ed8931f39b44d337aa2d50 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Jun 2022 14:00:44 +0200 Subject: mt76: mt7921s: remove unnecessary goto in mt7921s_mcu_drv_pmctrl Get rid of unnecessary goto in mt7921s_mcu_drv_pmctrl routine. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c index 54a5c712a3c3..04cdebaec521 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -99,8 +99,8 @@ int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; - int err = 0; u32 status; + int err; sdio_claim_host(func); @@ -118,8 +118,7 @@ int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) if (err < 0) { dev_err(dev->mt76.dev, "driver own failed\n"); - err = -EIO; - goto out; + return -EIO; } clear_bit(MT76_STATE_PM, &mphy->state); @@ -127,8 +126,8 @@ int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) pm->stats.last_wake_event = jiffies; pm->stats.doze_time += pm->stats.last_wake_event - pm->stats.last_doze_event; -out: - return err; + + return 0; } int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) -- cgit v1.2.3 From 79717c4eeeae9dec894794fbe8af72f08f03ebdd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Jun 2022 14:03:28 +0200 Subject: mt76: mt7615: do not update pm stats in case of error Do not update pm stats if mt7615_mcu_fw_pmctrl returns an error. Fixes: abe912ae3cd42 ("mt76: mt7663: add awake and doze time accounting") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index b89d21f77e5e..194e9ccd4a73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -338,10 +338,11 @@ static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev) } mt7622_trigger_hif_int(dev, false); - - pm->stats.last_doze_event = jiffies; - pm->stats.awake_time += pm->stats.last_doze_event - - pm->stats.last_wake_event; + if (!err) { + pm->stats.last_doze_event = jiffies; + pm->stats.awake_time += pm->stats.last_doze_event - + pm->stats.last_wake_event; + } out: mutex_unlock(&pm->mutex); -- cgit v1.2.3 From f4a92547fb9818ff272e1e2f0c79cd6b0bc99ce8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Jun 2022 14:07:08 +0200 Subject: mt76: mt7921: do not update pm states in case of error Do not update pm stats if mt7921e_mcu_fw_pmctrl routine returns an error. Fixes: 36873246f78a2 ("mt76: mt7921: add awake and doze time accounting") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c index 36669e5aeef3..a1ab5f878f81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -102,7 +102,7 @@ int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; - int i, err = 0; + int i; for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); @@ -114,12 +114,12 @@ int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev) if (i == MT7921_DRV_OWN_RETRY_COUNT) { dev_err(dev->mt76.dev, "firmware own failed\n"); clear_bit(MT76_STATE_PM, &mphy->state); - err = -EIO; + return -EIO; } pm->stats.last_doze_event = jiffies; pm->stats.awake_time += pm->stats.last_doze_event - pm->stats.last_wake_event; - return err; + return 0; } -- cgit v1.2.3 From 364718c94ac2ea4e51958ac0aa15c9092c785a3a Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Tue, 14 Jun 2022 15:50:24 +0800 Subject: mt76: mt7921s: fix possible sdio deadlock in command fail Move sdio_release_host() to final resource handing Fixes: b12deb5e86fa ("mt76: mt7921s: fix mt7921s_mcu_[fw|drv]_pmctrl") Reported-by: YN Chen Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c index 04cdebaec521..efcbe06964db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -135,8 +135,8 @@ int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; - int err = 0; u32 status; + int err; sdio_claim_host(func); @@ -147,7 +147,7 @@ int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) 2000, 1000000); if (err < 0) { dev_err(dev->mt76.dev, "mailbox ACK not cleared\n"); - goto err; + goto out; } } @@ -155,18 +155,18 @@ int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); +out: sdio_release_host(func); -err: if (err < 0) { dev_err(dev->mt76.dev, "firmware own failed\n"); clear_bit(MT76_STATE_PM, &mphy->state); - err = -EIO; + return -EIO; } pm->stats.last_doze_event = jiffies; pm->stats.awake_time += pm->stats.last_doze_event - pm->stats.last_wake_event; - return err; + return 0; } -- cgit v1.2.3 From d5a50e6bd1972c481f82befa846dce0b9866f025 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Thu, 16 Jun 2022 23:57:43 +0800 Subject: mt76: mt7921: fix aggregation subframes setting to HE max mt7921/mt7922 support HE max aggregation subframes 256 for both tx/rx. Get better throughput then before. Fixes: 94bb18b03d43 ("mt76: mt7921: fix max aggregation subframes setting") Tested-by: Ming Yen Hsieh Reviewed-by: Sean Wang Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 920fb3a42740..79023992715e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -52,8 +52,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) struct wiphy *wiphy = hw->wiphy; hw->queues = 4; - hw->max_rx_aggregation_subframes = 64; - hw->max_tx_aggregation_subframes = 128; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; + hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; hw->netdev_features = NETIF_F_RXCSUM; hw->radiotap_timestamp.units_pos = -- cgit v1.2.3 From 31f3248a75932b111bc90c66b1f6c7d89eedca8e Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Sat, 18 Jun 2022 18:56:44 +0800 Subject: mt76: mt7921: enlarge maximum VHT MPDU length to 11454 Enlarge maximum MPDU length to 11454 that both mt7921/mt7922 can support. After this fixing, we can get better performance. Fixes: 5c14a5f944b9 ("mt76: mt7921: introduce mt7921e support") Tested-by: Ming Yen Hsieh Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 79023992715e..af594b10f47f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -306,7 +306,7 @@ int mt7921_register_device(struct mt7921_dev *dev) IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; dev->mphy.sband_5g.sband.vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | -- cgit v1.2.3 From 6d6796db0bd93b09f424e76fd6dd21115378bb2d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 15:05:51 +0200 Subject: mt76: mt7915: get rid of unnecessary new line in mt7915_mac_write_txwi Remove unnecessary new line in mt7915_mac_write_txwi routine. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index a575a44685b2..3af4a6afb55b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -672,7 +672,6 @@ void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, changed); - if (mt76_testmode_enabled(mphy)) mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb); } -- cgit v1.2.3 From 5c0bed88c19d05b87aa4ca6ce6a2a93df4533a5e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 22:42:36 +0200 Subject: mt76: connac: move mt76_connac_fw_txp in common module Since mt76_connac_fw_txp struct is shared between mt7615e, mt7915e and mt7921e, move it in mt76_connac module. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 +-- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 33 +------------------- .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 7 +++-- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 35 ++++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac2_mac.h | 13 ++++---- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 14 ++++----- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 32 -------------------- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 32 -------------------- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 4 +-- 10 files changed, 59 insertions(+), 117 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f26213c4e64c..4beb7b1f7c7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -877,7 +877,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, EXPORT_SYMBOL_GPL(mt7615_mac_write_txwi); static void -mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt7615_fw_txp *txp) +mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt76_connac_fw_txp *txp) { int i; @@ -922,7 +922,7 @@ void mt7615_txp_skb_unmap(struct mt76_dev *dev, { struct mt7615_txp_common *txp; - txp = mt7615_txwi_to_txp(dev, t); + txp = mt76_connac_txwi_to_txp(dev, t); if (is_mt7615(dev)) mt7615_txp_skb_unmap_fw(dev, &txp->fw); else diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index e241c613091c..fefbc7153937 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -165,12 +165,6 @@ enum tx_phy_bandwidth { #define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) #define MT_CT_INFO_HSR2_TX BIT(4) -#define MT_TXD_SIZE (8 * 4) - -#define MT_USB_TXD_SIZE (MT_TXD_SIZE + 8 * 4) -#define MT_USB_HDR_SIZE 4 -#define MT_USB_TAIL_SIZE 4 - #define MT_TXD0_P_IDX BIT(31) #define MT_TXD0_Q_IDX GENMASK(30, 26) #define MT_TXD0_UDP_TCP_SUM BIT(24) @@ -250,7 +244,6 @@ enum tx_phy_bandwidth { #define MT_TX_RATE_MODE GENMASK(8, 6) #define MT_TX_RATE_IDX GENMASK(5, 0) -#define MT_TXP_MAX_BUF_NUM 6 #define MT_HW_TXP_MAX_MSDU_NUM 4 #define MT_HW_TXP_MAX_BUF_NUM 4 @@ -274,20 +267,9 @@ struct mt7615_hw_txp { struct mt7615_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; } __packed __aligned(4); -struct mt7615_fw_txp { - __le16 flags; - __le16 token; - u8 bss_idx; - u8 rept_wds_wcid; - u8 rsv; - u8 nbuf; - __le32 buf[MT_TXP_MAX_BUF_NUM]; - __le16 len[MT_TXP_MAX_BUF_NUM]; -} __packed __aligned(4); - struct mt7615_txp_common { union { - struct mt7615_fw_txp fw; + struct mt76_connac_fw_txp fw; struct mt7615_hw_txp hw; }; }; @@ -385,19 +367,6 @@ struct mt7615_dfs_radar_spec { struct mt7615_dfs_pattern radar_pattern[16]; }; -static inline struct mt7615_txp_common * -mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) -{ - u8 *txwi; - - if (!t) - return NULL; - - txwi = mt76_get_txwi_ptr(dev, t); - - return (struct mt7615_txp_common *)(txwi + MT_TXD_SIZE); -} - static inline u32 mt7615_mac_wtbl_addr(struct mt7615_dev *dev, int wcid) { return MT_WTBL_BASE(dev) + wcid * MT_WTBL_ENTRY_SIZE; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 73298dce35b7..2b8b70106a9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -29,7 +29,7 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) u16 token; dev = container_of(mdev, struct mt7615_dev, mt76); - txp = mt7615_txwi_to_txp(mdev, e->txwi); + txp = mt76_connac_txwi_to_txp(mdev, e->txwi); if (is_mt7615(&dev->mt76)) token = le16_to_cpu(txp->fw.token); @@ -91,7 +91,8 @@ mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; - struct mt7615_fw_txp *txp = txp_ptr; + struct mt76_connac_fw_txp *txp = txp_ptr; + u8 *rept_wds_wcid = (u8 *)&txp->rept_wds_wcid; int nbuf = tx_info->nbuf - 1; int i; @@ -122,7 +123,7 @@ mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, } txp->token = cpu_to_le16(id); - txp->rept_wds_wcid = 0xff; + *rept_wds_wcid = 0xff; } int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index a9927dcf3d6c..9981ceef7987 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -17,6 +17,16 @@ #define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) #define MT76_CONNAC_COREDUMP_SZ (1300 * 1024) +#define MT_TXD_SIZE (8 * 4) + +#define MT_USB_TXD_SIZE (MT_TXD_SIZE + 8 * 4) +#define MT_USB_HDR_SIZE 4 +#define MT_USB_TAIL_SIZE 4 + +#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4) +#define MT_SDIO_TAIL_SIZE 8 +#define MT_SDIO_HDR_SIZE 4 + enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, @@ -92,6 +102,18 @@ struct mt76_connac_sta_key_conf { u8 key[16]; }; +#define MT_TXP_MAX_BUF_NUM 6 + +struct mt76_connac_fw_txp { + __le16 flags; + __le16 token; + u8 bss_idx; + __le16 rept_wds_wcid; + u8 nbuf; + __le32 buf[MT_TXP_MAX_BUF_NUM]; + __le16 len[MT_TXP_MAX_BUF_NUM]; +} __packed __aligned(4); + extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; static inline bool is_mt7922(struct mt76_dev *dev) @@ -172,6 +194,19 @@ static inline u8 mt76_connac_lmac_mapping(u8 ac) return 3 - ac; } +static inline void * +mt76_connac_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + u8 *txwi; + + if (!t) + return NULL; + + txwi = mt76_get_txwi_ptr(dev, t); + + return (void *)(txwi + MT_TXD_SIZE); +} + int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm); void mt76_connac_power_save_sched(struct mt76_phy *phy, struct mt76_connac_pm *pm); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h index 0d04207b4292..a72ae9af9b38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -32,12 +32,6 @@ enum { MT_LMAC_PSMP0, }; -#define MT_TXD_SIZE (8 * 4) -#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4) -#define MT_SDIO_TAIL_SIZE 8 -#define MT_SDIO_HDR_SIZE 4 -#define MT_USB_TAIL_SIZE 4 - #define MT_TXD0_Q_IDX GENMASK(31, 25) #define MT_TXD0_PKT_FMT GENMASK(24, 23) #define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) @@ -306,4 +300,11 @@ enum { #define MT_CRXV_FOE_HI GENMASK(6, 0) #define MT_CRXV_FOE_SHIFT 13 +#define MT_CT_INFO_APPLY_TXD BIT(0) +#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) +#define MT_CT_INFO_MGMT_FRAME BIT(2) +#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) +#define MT_CT_INFO_HSR2_TX BIT(4) +#define MT_CT_INFO_FROM_HOST BIT(7) + #endif /* __MT76_CONNAC2_MAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 3af4a6afb55b..6e97c443f1c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -686,8 +686,8 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; + struct mt76_connac_fw_txp *txp; struct mt76_txwi_cache *t; - struct mt7915_txp *txp; int id, i, nbuf = tx_info->nbuf - 1; u8 *txwi = (u8 *)txwi_ptr; int pid; @@ -719,7 +719,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key, 0); - txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE); + txp = (struct mt76_connac_fw_txp *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); @@ -758,7 +758,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) { - struct mt7915_txp *txp = ptr + MT_TXD_SIZE; + struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; __le32 *txwi = ptr; u32 val; @@ -807,10 +807,10 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) static void mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { - struct mt7915_txp *txp; + struct mt76_connac_fw_txp *txp; int i; - txp = mt7915_txwi_to_txp(dev, t); + txp = mt76_connac_txwi_to_txp(dev, t); for (i = 0; i < txp->nbuf; i++) dma_unmap_single(dev->dma_dev, le32_to_cpu(txp->buf[i]), le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); @@ -1120,10 +1120,10 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) /* error path */ if (e->skb == DMA_DUMMY_DATA) { + struct mt76_connac_fw_txp *txp; struct mt76_txwi_cache *t; - struct mt7915_txp *txp; - txp = mt7915_txwi_to_txp(mdev, e->txwi); + txp = mt76_connac_txwi_to_txp(mdev, e->txwi); t = mt76_token_put(mdev, le16_to_cpu(txp->token)); e->skb = t ? t->skb : NULL; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 724feb2df4a0..ed71a7bc25eb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -42,25 +42,6 @@ enum tx_mcu_port_q_idx { MT_TX_MCU_PORT_RX_FWDL = 0x3e }; -#define MT_CT_INFO_APPLY_TXD BIT(0) -#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) -#define MT_CT_INFO_MGMT_FRAME BIT(2) -#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) -#define MT_CT_INFO_HSR2_TX BIT(4) -#define MT_CT_INFO_FROM_HOST BIT(7) - -#define MT_TXP_MAX_BUF_NUM 6 - -struct mt7915_txp { - __le16 flags; - __le16 token; - u8 bss_idx; - __le16 rept_wds_wcid; - u8 nbuf; - __le32 buf[MT_TXP_MAX_BUF_NUM]; - __le16 len[MT_TXP_MAX_BUF_NUM]; -} __packed __aligned(4); - struct mt7915_tx_free { __le16 rx_byte_cnt; __le16 ctrl; @@ -137,17 +118,4 @@ struct mt7915_dfs_radar_spec { struct mt7915_dfs_pattern radar_pattern[16]; }; -static inline struct mt7915_txp * -mt7915_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) -{ - u8 *txwi; - - if (!t) - return NULL; - - txwi = mt76_get_txwi_ptr(dev, t); - - return (struct mt7915_txp *)(txwi + MT_TXD_SIZE); -} - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 46ee8a7db7bc..6b889f454d1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -645,7 +645,7 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ - .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), + .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index ca2ec83bc831..ecb73e30ff08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -42,25 +42,6 @@ enum tx_mcu_port_q_idx { MT_TX_MCU_PORT_RX_FWDL = 0x3e }; -#define MT_CT_INFO_APPLY_TXD BIT(0) -#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) -#define MT_CT_INFO_MGMT_FRAME BIT(2) -#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) -#define MT_CT_INFO_HSR2_TX BIT(4) -#define MT_CT_INFO_FROM_HOST BIT(7) - -#define MT_TXP_MAX_BUF_NUM 6 - -struct mt7921_txp { - __le16 flags; - __le16 token; - u8 bss_idx; - __le16 rept_wds_wcid; - u8 nbuf; - __le32 buf[MT_TXP_MAX_BUF_NUM]; - __le16 len[MT_TXP_MAX_BUF_NUM]; -} __packed __aligned(4); - struct mt7921_tx_free { __le16 rx_byte_cnt; __le16 ctrl; @@ -79,19 +60,6 @@ struct mt7921_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -static inline struct mt7921_txp_common * -mt7921_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) -{ - u8 *txwi; - - if (!t) - return NULL; - - txwi = mt76_get_txwi_ptr(dev, t); - - return (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); -} - #define MT_HW_TXP_MAX_MSDU_NUM 4 #define MT_HW_TXP_MAX_BUF_NUM 4 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index b0f58bcf70cb..9608b5ae8820 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -90,7 +90,7 @@ mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) struct mt7921_txp_common *txp; int i; - txp = mt7921_txwi_to_txp(dev, t); + txp = mt76_connac_txwi_to_txp(dev, t); for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) { struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i]; @@ -275,7 +275,7 @@ void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) struct mt7921_txp_common *txp; u16 token; - txp = mt7921_txwi_to_txp(mdev, e->txwi); + txp = mt76_connac_txwi_to_txp(mdev, e->txwi); token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID; t = mt76_token_put(mdev, token); e->skb = t ? t->skb : NULL; -- cgit v1.2.3 From 4cb4da17fe2f3cc4e9ac9e0f1c6ac752b899571f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 22:42:37 +0200 Subject: mt76: move mt7615_txp_ptr in mt76_connac module Since mt7615_txp_ptr is shared between mt7615 and mt7921 move it in mt76_connac module. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 22 ---------------------- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 22 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 21 --------------------- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 3 +-- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 16 ++++++++-------- 8 files changed, 39 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 4beb7b1f7c7b..de809cbf0733 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -887,7 +887,7 @@ mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt76_connac_fw_txp *txp) } static void -mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) +mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt76_connac_hw_txp *txp) { u32 last_mask; int i; @@ -895,7 +895,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) last_mask = is_mt7663(dev) ? MT_TXD_LEN_LAST : MT_TXD_LEN_MSDU_LAST; for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) { - struct mt7615_txp_ptr *ptr = &txp->ptr[i]; + struct mt76_connac_txp_ptr *ptr = &txp->ptr[i]; bool last; u16 len; @@ -920,7 +920,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) void mt7615_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { - struct mt7615_txp_common *txp; + struct mt76_connac_txp_common *txp; txp = mt76_connac_txwi_to_txp(dev, t); if (is_mt7615(dev)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index fefbc7153937..310c187a1a29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -244,9 +244,6 @@ enum tx_phy_bandwidth { #define MT_TX_RATE_MODE GENMASK(8, 6) #define MT_TX_RATE_IDX GENMASK(5, 0) -#define MT_HW_TXP_MAX_MSDU_NUM 4 -#define MT_HW_TXP_MAX_BUF_NUM 4 - #define MT_MSDU_ID_VALID BIT(15) #define MT_TXD_LEN_MASK GENMASK(11, 0) @@ -255,25 +252,6 @@ enum tx_phy_bandwidth { /* mt7663 */ #define MT_TXD_LEN_LAST BIT(15) -struct mt7615_txp_ptr { - __le32 buf0; - __le16 len0; - __le16 len1; - __le32 buf1; -} __packed __aligned(4); - -struct mt7615_hw_txp { - __le16 msdu_id[MT_HW_TXP_MAX_MSDU_NUM]; - struct mt7615_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; -} __packed __aligned(4); - -struct mt7615_txp_common { - union { - struct mt76_connac_fw_txp fw; - struct mt7615_hw_txp hw; - }; -}; - struct mt7615_tx_free { __le16 rx_byte_cnt; __le16 ctrl; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index a208035e197a..3320a80b4171 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -186,7 +186,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ - .txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp_common), + .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_txp_common), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 2b8b70106a9e..4dd0f0803fda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -23,9 +23,9 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) /* error path */ if (e->skb == DMA_DUMMY_DATA) { + struct mt76_connac_txp_common *txp; struct mt76_txwi_cache *t; struct mt7615_dev *dev; - struct mt7615_txp_common *txp; u16 token; dev = container_of(mdev, struct mt7615_dev, mt76); @@ -49,8 +49,8 @@ static void mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id) { - struct mt7615_hw_txp *txp = txp_ptr; - struct mt7615_txp_ptr *ptr = &txp->ptr[0]; + struct mt76_connac_hw_txp *txp = txp_ptr; + struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; int i, nbuf = tx_info->nbuf - 1; u32 last_mask; @@ -168,7 +168,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, pid, key, false); txp = txwi + MT_TXD_SIZE; - memset(txp, 0, sizeof(struct mt7615_txp_common)); + memset(txp, 0, sizeof(struct mt76_connac_txp_common)); if (is_mt7615(&dev->mt76)) mt7615_write_fw_txp(dev, tx_info, txp, id); else diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 9981ceef7987..4357fea1d79b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -114,6 +114,28 @@ struct mt76_connac_fw_txp { __le16 len[MT_TXP_MAX_BUF_NUM]; } __packed __aligned(4); +#define MT_HW_TXP_MAX_MSDU_NUM 4 +#define MT_HW_TXP_MAX_BUF_NUM 4 + +struct mt76_connac_txp_ptr { + __le32 buf0; + __le16 len0; + __le16 len1; + __le32 buf1; +} __packed __aligned(4); + +struct mt76_connac_hw_txp { + __le16 msdu_id[MT_HW_TXP_MAX_MSDU_NUM]; + struct mt76_connac_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; +} __packed __aligned(4); + +struct mt76_connac_txp_common { + union { + struct mt76_connac_fw_txp fw; + struct mt76_connac_hw_txp hw; + }; +}; + extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; static inline bool is_mt7922(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index ecb73e30ff08..dc98d2c82988 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -60,9 +60,6 @@ struct mt7921_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -#define MT_HW_TXP_MAX_MSDU_NUM 4 -#define MT_HW_TXP_MAX_BUF_NUM 4 - #define MT_MSDU_ID_VALID BIT(15) #define MT_TXD_LEN_MASK GENMASK(11, 0) @@ -70,24 +67,6 @@ struct mt7921_tx_free { #define MT_TXD_LEN_AMSDU_LAST BIT(15) #define MT_TXD_LEN_LAST BIT(15) -struct mt7921_txp_ptr { - __le32 buf0; - __le16 len0; - __le16 len1; - __le32 buf1; -} __packed __aligned(4); - -struct mt7921_hw_txp { - __le16 msdu_id[MT_HW_TXP_MAX_MSDU_NUM]; - struct mt7921_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; -} __packed __aligned(4); - -struct mt7921_txp_common { - union { - struct mt7921_hw_txp hw; - }; -}; - #define MT_WTBL_TXRX_CAP_RATE_OFFSET 7 #define MT_WTBL_TXRX_RATE_G2_HE 24 #define MT_WTBL_TXRX_RATE_G2 12 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 624eb75c15cd..c61e646a1a94 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -230,7 +230,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ - .txwi_size = MT_TXD_SIZE + sizeof(struct mt7921_txp_common), + .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_hw_txp), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | @@ -247,7 +247,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt7921_update_channel, }; - static const struct mt7921_hif_ops mt7921_pcie_ops = { .init_reset = mt7921e_init_reset, .reset = mt7921e_mac_reset, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 9608b5ae8820..bf58dcf1b980 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -9,8 +9,8 @@ static void mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id) { - struct mt7921_hw_txp *txp = txp_ptr; - struct mt7921_txp_ptr *ptr = &txp->ptr[0]; + struct mt76_connac_hw_txp *txp = txp_ptr; + struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; int i, nbuf = tx_info->nbuf - 1; tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); @@ -44,8 +44,8 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; + struct mt76_connac_hw_txp *txp; struct mt76_txwi_cache *t; - struct mt7921_txp_common *txp; int id, pid; u8 *txwi = (u8 *)txwi_ptr; @@ -75,8 +75,8 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, mt76_connac2_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, pid, 0); - txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); - memset(txp, 0, sizeof(struct mt7921_txp_common)); + txp = (struct mt76_connac_hw_txp *)(txwi + MT_TXD_SIZE); + memset(txp, 0, sizeof(struct mt76_connac_hw_txp)); mt7921_write_hw_txp(dev, tx_info, txp, id); tx_info->skb = DMA_DUMMY_DATA; @@ -87,13 +87,13 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, static void mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { - struct mt7921_txp_common *txp; + struct mt76_connac_txp_common *txp; int i; txp = mt76_connac_txwi_to_txp(dev, t); for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) { - struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i]; + struct mt76_connac_txp_ptr *ptr = &txp->hw.ptr[i]; bool last; u16 len; @@ -271,8 +271,8 @@ void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) /* error path */ if (e->skb == DMA_DUMMY_DATA) { + struct mt76_connac_txp_common *txp; struct mt76_txwi_cache *t; - struct mt7921_txp_common *txp; u16 token; txp = mt76_connac_txwi_to_txp(mdev, e->txwi); -- cgit v1.2.3 From 4b3be9d8408ba1d6b38c5c477d59df0e5ad7e576 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 22:42:38 +0200 Subject: mt76: connac: move mt76_connac_tx_free in shared code Move mt76_connac_tx_free structure in mt76_connac module since it is shared by mt7615 and mt7921 drivers. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 8 -------- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 8 -------- drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c | 7 ++++--- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index de809cbf0733..06d17e07034d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1638,7 +1638,8 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token) static void mt7615_mac_tx_free(struct mt7615_dev *dev, void *data, int len) { - struct mt7615_tx_free *free = (struct mt7615_tx_free *)data; + struct mt76_connac_tx_free *free = data; + void *tx_token = data + sizeof(*free); void *end = data + len; u8 i, count; @@ -1652,7 +1653,7 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, void *data, int len) count = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_ID_CNT); if (is_mt7615(&dev->mt76)) { - __le16 *token = &free->token[0]; + __le16 *token = tx_token; if (WARN_ON_ONCE((void *)&token[count] > end)) return; @@ -1660,7 +1661,7 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, void *data, int len) for (i = 0; i < count; i++) mt7615_mac_tx_free_token(dev, le16_to_cpu(token[i])); } else { - __le32 *token = (__le32 *)&free->token[0]; + __le32 *token = tx_token; if (WARN_ON_ONCE((void *)&token[count] > end)) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 310c187a1a29..6af15f2e0f5a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -252,14 +252,6 @@ enum tx_phy_bandwidth { /* mt7663 */ #define MT_TXD_LEN_LAST BIT(15) -struct mt7615_tx_free { - __le16 rx_byte_cnt; - __le16 ctrl; - u8 txd_cnt; - u8 rsv[3]; - __le16 token[]; -} __packed __aligned(4); - #define MT_TX_FREE_MSDU_ID_CNT GENMASK(6, 0) #define MT_TXS0_PID GENMASK(31, 24) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 4357fea1d79b..0ef10895fbf8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -136,6 +136,13 @@ struct mt76_connac_txp_common { }; }; +struct mt76_connac_tx_free { + __le16 rx_byte_cnt; + __le16 ctrl; + u8 txd_cnt; + u8 rsv[3]; +} __packed __aligned(4); + extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; static inline bool is_mt7922(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index dc98d2c82988..26b1ec35cc2b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -42,14 +42,6 @@ enum tx_mcu_port_q_idx { MT_TX_MCU_PORT_RX_FWDL = 0x3e }; -struct mt7921_tx_free { - __le16 rx_byte_cnt; - __le16 ctrl; - u8 txd_cnt; - u8 rsv[3]; - __le32 info[]; -} __packed __aligned(4); - #define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) #define MT_TX_FREE_WLAN_ID GENMASK(23, 14) #define MT_TX_FREE_LATENCY GENMASK(12, 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index bf58dcf1b980..333390cb791b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -150,7 +150,8 @@ out: static void mt7921e_mac_tx_free(struct mt7921_dev *dev, void *data, int len) { - struct mt7921_tx_free *free = (struct mt7921_tx_free *)data; + struct mt76_connac_tx_free *free = data; + __le32 *tx_info = (__le32 *)(data + sizeof(*free)); struct mt76_dev *mdev = &dev->mt76; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; @@ -165,11 +166,11 @@ mt7921e_mac_tx_free(struct mt7921_dev *dev, void *data, int len) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); count = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT); - if (WARN_ON_ONCE((void *)&free->info[count] > end)) + if (WARN_ON_ONCE((void *)&tx_info[count] > end)) return; for (i = 0; i < count; i++) { - u32 msdu, info = le32_to_cpu(free->info[i]); + u32 msdu, info = le32_to_cpu(tx_info[i]); u8 stat; /* 1'b1: new wcid pair. -- cgit v1.2.3 From 0a178a6084d6b6a1cb782d01ae8f65d9f6ddc37c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 22:42:39 +0200 Subject: mt76: connac: move mt76_connac_tx_complete_skb in shared code Since now txp structures are in common code we can reuse mt76_connac_tx_complete_skb routine in mt7921e, mt7915e and mt7615e drivers. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 2 -- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 - .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 31 ---------------------- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 17 ++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 31 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 21 --------------- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 - drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 2 -- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 - drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 23 ---------------- 13 files changed, 51 insertions(+), 85 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 6af15f2e0f5a..4cc805f0fea9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -244,8 +244,6 @@ enum tx_phy_bandwidth { #define MT_TX_RATE_MODE GENMASK(8, 6) #define MT_TX_RATE_IDX GENMASK(5, 0) -#define MT_MSDU_ID_VALID BIT(15) - #define MT_TXD_LEN_MASK GENMASK(11, 0) #define MT_TXD_LEN_MSDU_LAST BIT(14) #define MT_TXD_LEN_AMSDU_LAST BIT(15) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 3320a80b4171..a784f9d9e935 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -193,7 +193,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, SURVEY_INFO_TIME_BSS_RX, .token_size = MT7615_TOKEN_SIZE, .tx_prepare_skb = mt7615_tx_prepare_skb, - .tx_complete_skb = mt7615_tx_complete_skb, + .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_check = mt7615_rx_check, .rx_skb = mt7615_queue_rx_skb, .rx_poll_complete = mt7615_rx_poll_complete, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 2e91f6a27d0f..288cc391b61e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -507,7 +507,6 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt76_tx_info *tx_info); void mt7615_tx_worker(struct mt76_worker *w); -void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt7615_tx_token_put(struct mt7615_dev *dev); bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 4dd0f0803fda..9117012b9b1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -14,37 +14,6 @@ #include "../dma.h" #include "mac.h" -void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) -{ - if (!e->txwi) { - dev_kfree_skb_any(e->skb); - return; - } - - /* error path */ - if (e->skb == DMA_DUMMY_DATA) { - struct mt76_connac_txp_common *txp; - struct mt76_txwi_cache *t; - struct mt7615_dev *dev; - u16 token; - - dev = container_of(mdev, struct mt7615_dev, mt76); - txp = mt76_connac_txwi_to_txp(mdev, e->txwi); - - if (is_mt7615(&dev->mt76)) - token = le16_to_cpu(txp->fw.token); - else - token = le16_to_cpu(txp->hw.msdu_id[0]) & - ~MT_MSDU_ID_VALID; - - t = mt76_token_put(mdev, token); - e->skb = t ? t->skb : NULL; - } - - if (e->skb) - mt76_tx_complete_skb(mdev, e->wcid, e->skb); -} - static void mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 0ef10895fbf8..da41ad6c87fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -27,6 +27,8 @@ #define MT_SDIO_TAIL_SIZE 8 #define MT_SDIO_HDR_SIZE 4 +#define MT_MSDU_ID_VALID BIT(15) + enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, @@ -198,6 +200,19 @@ static inline bool is_connac_v1(struct mt76_dev *dev) return is_mt7615(dev) || is_mt7663(dev) || is_mt7622(dev); } +static inline bool is_mt76_fw_txp(struct mt76_dev *dev) +{ + switch (mt76_chip(dev)) { + case 0x7961: + case 0x7922: + case 0x7663: + case 0x7622: + return false; + default: + return true; + } +} + static inline u8 mt76_connac_chan_bw(struct cfg80211_chan_def *chandef) { static const u8 width_to_bw[] = { @@ -304,6 +319,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) mutex_unlock(&dev->mutex); } +void mt76_connac_tx_complete_skb(struct mt76_dev *mdev, + struct mt76_queue_entry *e); void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, struct mt76_connac_pm *pm, struct mt76_wcid *wcid, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 6aa02ace365b..134daa9103a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -3,6 +3,7 @@ #include "mt76_connac.h" #include "mt76_connac2_mac.h" +#include "dma.h" #define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) #define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ @@ -121,6 +122,36 @@ void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, } EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); +void mt76_connac_tx_complete_skb(struct mt76_dev *mdev, + struct mt76_queue_entry *e) +{ + if (!e->txwi) { + dev_kfree_skb_any(e->skb); + return; + } + + /* error path */ + if (e->skb == DMA_DUMMY_DATA) { + struct mt76_connac_txp_common *txp; + struct mt76_txwi_cache *t; + u16 token; + + txp = mt76_connac_txwi_to_txp(mdev, e->txwi); + if (is_mt76_fw_txp(mdev)) + token = le16_to_cpu(txp->fw.token); + else + token = le16_to_cpu(txp->hw.msdu_id[0]) & + ~MT_MSDU_ID_VALID; + + t = mt76_token_put(mdev, token); + e->skb = t ? t->skb : NULL; + } + + if (e->skb) + mt76_tx_complete_skb(mdev, e->wcid, e->skb); +} +EXPORT_SYMBOL_GPL(mt76_connac_tx_complete_skb); + static u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, bool beacon, bool mcast) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 6e97c443f1c2..719b11e2e57c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1111,27 +1111,6 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } -void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) -{ - if (!e->txwi) { - dev_kfree_skb_any(e->skb); - return; - } - - /* error path */ - if (e->skb == DMA_DUMMY_DATA) { - struct mt76_connac_fw_txp *txp; - struct mt76_txwi_cache *t; - - txp = mt76_connac_txwi_to_txp(mdev, e->txwi); - t = mt76_token_put(mdev, le16_to_cpu(txp->token)); - e->skb = t ? t->skb : NULL; - } - - if (e->skb) - mt76_tx_complete_skb(mdev, e->wcid, e->skb); -} - void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 6b889f454d1a..c2646d24b574 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -652,7 +652,7 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, SURVEY_INFO_TIME_BSS_RX, .token_size = MT7915_TOKEN_SIZE, .tx_prepare_skb = mt7915_tx_prepare_skb, - .tx_complete_skb = mt7915_tx_complete_skb, + .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_skb = mt7915_queue_rx_skb, .rx_check = mt7915_rx_check, .rx_poll_complete = mt7915_rx_poll_complete, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 3db0758b75e3..b6a6aa7fcf43 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -571,7 +571,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info); -void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt7915_tx_token_put(struct mt7915_dev *dev); void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 26b1ec35cc2b..a2e9e1bae859 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -52,8 +52,6 @@ enum tx_mcu_port_q_idx { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -#define MT_MSDU_ID_VALID BIT(15) - #define MT_TXD_LEN_MASK GENMASK(11, 0) #define MT_TXD_LEN_MSDU_LAST BIT(14) #define MT_TXD_LEN_AMSDU_LAST BIT(15) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index f7609c8ac549..48fd14c67e44 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -386,7 +386,6 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt76_tx_info *tx_info); void mt7921_tx_worker(struct mt76_worker *w); -void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt7921_tx_token_put(struct mt7921_dev *dev); void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index c61e646a1a94..23361a505daf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -237,7 +237,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, SURVEY_INFO_TIME_BSS_RX, .token_size = MT7921_TOKEN_SIZE, .tx_prepare_skb = mt7921e_tx_prepare_skb, - .tx_complete_skb = mt7921e_tx_complete_skb, + .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_check = mt7921e_rx_check, .rx_skb = mt7921e_queue_rx_skb, .rx_poll_complete = mt7921_rx_poll_complete, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 333390cb791b..75e5dc4e6f84 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -263,29 +263,6 @@ void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } -void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) -{ - if (!e->txwi) { - dev_kfree_skb_any(e->skb); - return; - } - - /* error path */ - if (e->skb == DMA_DUMMY_DATA) { - struct mt76_connac_txp_common *txp; - struct mt76_txwi_cache *t; - u16 token; - - txp = mt76_connac_txwi_to_txp(mdev, e->txwi); - token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID; - t = mt76_token_put(mdev, token); - e->skb = t ? t->skb : NULL; - } - - if (e->skb) - mt76_tx_complete_skb(mdev, e->wcid, e->skb); -} - void mt7921_tx_token_put(struct mt7921_dev *dev) { struct mt76_txwi_cache *txwi; -- cgit v1.2.3 From 5e610f8e3115ca92a59d3721642185e15df1a065 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 22:42:40 +0200 Subject: mt76: connac: move mt76_connac_write_hw_txp in shared code Now we can move mt76_connac_write_hw_txp routine in mt76-connac module and reuse it in mt7921e and mt7615e driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 6 ---- .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 40 +--------------------- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 8 +++++ .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 39 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 5 --- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 33 +----------------- 6 files changed, 49 insertions(+), 82 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 4cc805f0fea9..880c9f74a7f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -244,12 +244,6 @@ enum tx_phy_bandwidth { #define MT_TX_RATE_MODE GENMASK(8, 6) #define MT_TX_RATE_IDX GENMASK(5, 0) -#define MT_TXD_LEN_MASK GENMASK(11, 0) -#define MT_TXD_LEN_MSDU_LAST BIT(14) -#define MT_TXD_LEN_AMSDU_LAST BIT(15) -/* mt7663 */ -#define MT_TXD_LEN_LAST BIT(15) - #define MT_TX_FREE_MSDU_ID_CNT GENMASK(6, 0) #define MT_TXS0_PID GENMASK(31, 24) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 9117012b9b1a..05b6669466ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -14,44 +14,6 @@ #include "../dma.h" #include "mac.h" -static void -mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, - void *txp_ptr, u32 id) -{ - struct mt76_connac_hw_txp *txp = txp_ptr; - struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; - int i, nbuf = tx_info->nbuf - 1; - u32 last_mask; - - tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); - tx_info->nbuf = 1; - - txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); - - if (is_mt7663(&dev->mt76)) - last_mask = MT_TXD_LEN_LAST; - else - last_mask = MT_TXD_LEN_AMSDU_LAST | - MT_TXD_LEN_MSDU_LAST; - - for (i = 0; i < nbuf; i++) { - u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; - u32 addr = tx_info->buf[i + 1].addr; - - if (i == nbuf - 1) - len |= last_mask; - - if (i & 1) { - ptr->buf1 = cpu_to_le32(addr); - ptr->len1 = cpu_to_le16(len); - ptr++; - } else { - ptr->buf0 = cpu_to_le32(addr); - ptr->len0 = cpu_to_le16(len); - } - } -} - static void mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id) @@ -141,7 +103,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (is_mt7615(&dev->mt76)) mt7615_write_fw_txp(dev, tx_info, txp, id); else - mt7615_write_hw_txp(dev, tx_info, txp, id); + mt76_connac_write_hw_txp(mdev, tx_info, txp, id); tx_info->skb = DMA_DUMMY_DATA; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index da41ad6c87fe..9f4323de3a8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -29,6 +29,11 @@ #define MT_MSDU_ID_VALID BIT(15) +#define MT_TXD_LEN_LAST BIT(15) +#define MT_TXD_LEN_MASK GENMASK(11, 0) +#define MT_TXD_LEN_MSDU_LAST BIT(14) +#define MT_TXD_LEN_AMSDU_LAST BIT(15) + enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, @@ -319,6 +324,9 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) mutex_unlock(&dev->mutex); } +void mt76_connac_write_hw_txp(struct mt76_dev *dev, + struct mt76_tx_info *tx_info, + void *txp_ptr, u32 id); void mt76_connac_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 134daa9103a2..9bba5dcbe0c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -152,6 +152,45 @@ void mt76_connac_tx_complete_skb(struct mt76_dev *mdev, } EXPORT_SYMBOL_GPL(mt76_connac_tx_complete_skb); +void mt76_connac_write_hw_txp(struct mt76_dev *dev, + struct mt76_tx_info *tx_info, + void *txp_ptr, u32 id) +{ + struct mt76_connac_hw_txp *txp = txp_ptr; + struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; + int i, nbuf = tx_info->nbuf - 1; + u32 last_mask; + + tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); + tx_info->nbuf = 1; + + txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); + + if (is_mt7663(dev) || is_mt7921(dev)) + last_mask = MT_TXD_LEN_LAST; + else + last_mask = MT_TXD_LEN_AMSDU_LAST | + MT_TXD_LEN_MSDU_LAST; + + for (i = 0; i < nbuf; i++) { + u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; + u32 addr = tx_info->buf[i + 1].addr; + + if (i == nbuf - 1) + len |= last_mask; + + if (i & 1) { + ptr->buf1 = cpu_to_le32(addr); + ptr->len1 = cpu_to_le16(len); + ptr++; + } else { + ptr->buf0 = cpu_to_le32(addr); + ptr->len0 = cpu_to_le16(len); + } + } +} +EXPORT_SYMBOL_GPL(mt76_connac_write_hw_txp); + static u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, bool beacon, bool mcast) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index a2e9e1bae859..b8cabeb796b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -52,11 +52,6 @@ enum tx_mcu_port_q_idx { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -#define MT_TXD_LEN_MASK GENMASK(11, 0) -#define MT_TXD_LEN_MSDU_LAST BIT(14) -#define MT_TXD_LEN_AMSDU_LAST BIT(15) -#define MT_TXD_LEN_LAST BIT(15) - #define MT_WTBL_TXRX_CAP_RATE_OFFSET 7 #define MT_WTBL_TXRX_RATE_G2_HE 24 #define MT_WTBL_TXRX_RATE_G2 12 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 75e5dc4e6f84..368f114dc60c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -5,37 +5,6 @@ #include "../dma.h" #include "mac.h" -static void -mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info, - void *txp_ptr, u32 id) -{ - struct mt76_connac_hw_txp *txp = txp_ptr; - struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; - int i, nbuf = tx_info->nbuf - 1; - - tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); - tx_info->nbuf = 1; - - txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); - - for (i = 0; i < nbuf; i++) { - u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; - u32 addr = tx_info->buf[i + 1].addr; - - if (i == nbuf - 1) - len |= MT_TXD_LEN_LAST; - - if (i & 1) { - ptr->buf1 = cpu_to_le32(addr); - ptr->len1 = cpu_to_le16(len); - ptr++; - } else { - ptr->buf0 = cpu_to_le32(addr); - ptr->len0 = cpu_to_le16(len); - } - } -} - int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, @@ -77,7 +46,7 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, txp = (struct mt76_connac_hw_txp *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt76_connac_hw_txp)); - mt7921_write_hw_txp(dev, tx_info, txp, id); + mt76_connac_write_hw_txp(mdev, tx_info, txp, id); tx_info->skb = DMA_DUMMY_DATA; -- cgit v1.2.3 From 2b25b8555d631c6d21d7d29f4f3d85a118f1e52d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Jun 2022 22:42:41 +0200 Subject: mt76: connac: move mt7615_txp_skb_unmap in common code Move mt7615_txp_skb_unmap in shared code and reuse it in mt7915e and mt7921e driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 56 +------------------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 - drivers/net/wireless/mediatek/mt76/mt76_connac.h | 2 + .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 60 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 14 +---- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 33 +----------- 6 files changed, 65 insertions(+), 102 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 06d17e07034d..d9dd3d404986 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -876,60 +876,6 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, } EXPORT_SYMBOL_GPL(mt7615_mac_write_txwi); -static void -mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt76_connac_fw_txp *txp) -{ - int i; - - for (i = 0; i < txp->nbuf; i++) - dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]), - le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); -} - -static void -mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt76_connac_hw_txp *txp) -{ - u32 last_mask; - int i; - - last_mask = is_mt7663(dev) ? MT_TXD_LEN_LAST : MT_TXD_LEN_MSDU_LAST; - - for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) { - struct mt76_connac_txp_ptr *ptr = &txp->ptr[i]; - bool last; - u16 len; - - len = le16_to_cpu(ptr->len0); - last = len & last_mask; - len &= MT_TXD_LEN_MASK; - dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, - DMA_TO_DEVICE); - if (last) - break; - - len = le16_to_cpu(ptr->len1); - last = len & last_mask; - len &= MT_TXD_LEN_MASK; - dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, - DMA_TO_DEVICE); - if (last) - break; - } -} - -void mt7615_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *t) -{ - struct mt76_connac_txp_common *txp; - - txp = mt76_connac_txwi_to_txp(dev, t); - if (is_mt7615(dev)) - mt7615_txp_skb_unmap_fw(dev, &txp->fw); - else - mt7615_txp_skb_unmap_hw(dev, &txp->hw); -} -EXPORT_SYMBOL_GPL(mt7615_txp_skb_unmap); - bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, @@ -1608,7 +1554,7 @@ mt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi) u32 val; u8 wcid; - mt7615_txp_skb_unmap(mdev, txwi); + mt76_connac_txp_skb_unmap(mdev, txwi); if (!txwi->skb) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 288cc391b61e..653181905d09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -517,8 +517,6 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7615_mac_work(struct work_struct *work); -void mt7615_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *txwi); int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev); int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val); int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 9f4323de3a8b..077239b0820a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -327,6 +327,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id); +void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *txwi); void mt76_connac_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 9bba5dcbe0c6..af2b33d738ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -191,6 +191,66 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76_connac_write_hw_txp); +static void +mt76_connac_txp_skb_unmap_fw(struct mt76_dev *mdev, + struct mt76_connac_fw_txp *txp) +{ + struct device *dev = is_connac_v1(mdev) ? mdev->dev : mdev->dma_dev; + int i; + + for (i = 0; i < txp->nbuf; i++) + dma_unmap_single(dev, le32_to_cpu(txp->buf[i]), + le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); +} + +static void +mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev, + struct mt76_connac_hw_txp *txp) +{ + u32 last_mask; + int i; + + if (is_mt7663(dev) || is_mt7921(dev)) + last_mask = MT_TXD_LEN_LAST; + else + last_mask = MT_TXD_LEN_MSDU_LAST; + + for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) { + struct mt76_connac_txp_ptr *ptr = &txp->ptr[i]; + bool last; + u16 len; + + len = le16_to_cpu(ptr->len0); + last = len & last_mask; + len &= MT_TXD_LEN_MASK; + dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, + DMA_TO_DEVICE); + if (last) + break; + + len = le16_to_cpu(ptr->len1); + last = len & last_mask; + len &= MT_TXD_LEN_MASK; + dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, + DMA_TO_DEVICE); + if (last) + break; + } +} + +void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *t) +{ + struct mt76_connac_txp_common *txp; + + txp = mt76_connac_txwi_to_txp(dev, t); + if (is_mt76_fw_txp(dev)) + mt76_connac_txp_skb_unmap_fw(dev, &txp->fw); + else + mt76_connac_txp_skb_unmap_hw(dev, &txp->hw); +} +EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); + static u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, bool beacon, bool mcast) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 719b11e2e57c..dabcd425cd34 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -804,18 +804,6 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) ieee80211_start_tx_ba_session(sta, tid, 0); } -static void -mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) -{ - struct mt76_connac_fw_txp *txp; - int i; - - txp = mt76_connac_txwi_to_txp(dev, t); - for (i = 0; i < txp->nbuf; i++) - dma_unmap_single(dev->dma_dev, le32_to_cpu(txp->buf[i]), - le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); -} - static void mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_sta *sta, struct list_head *free_list) @@ -826,7 +814,7 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t, __le32 *txwi; u16 wcid_idx; - mt7915_txp_skb_unmap(mdev, t); + mt76_connac_txp_skb_unmap(mdev, t); if (!t->skb) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 368f114dc60c..f6c605a59b81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -53,37 +53,6 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return 0; } -static void -mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) -{ - struct mt76_connac_txp_common *txp; - int i; - - txp = mt76_connac_txwi_to_txp(dev, t); - - for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) { - struct mt76_connac_txp_ptr *ptr = &txp->hw.ptr[i]; - bool last; - u16 len; - - len = le16_to_cpu(ptr->len0); - last = len & MT_TXD_LEN_LAST; - len &= MT_TXD_LEN_MASK; - dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, - DMA_TO_DEVICE); - if (last) - break; - - len = le16_to_cpu(ptr->len1); - last = len & MT_TXD_LEN_LAST; - len &= MT_TXD_LEN_MASK; - dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, - DMA_TO_DEVICE); - if (last) - break; - } -} - static void mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_sta *sta, bool clear_status, @@ -93,7 +62,7 @@ mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t, __le32 *txwi; u16 wcid_idx; - mt7921_txp_skb_unmap(mdev, t); + mt76_connac_txp_skb_unmap(mdev, t); if (!t->skb) goto out; -- cgit v1.2.3 From a8021cb9c1ef26536a766a0c3ecdd1f702516cb0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Jun 2022 14:37:34 +0200 Subject: mt76: mt7915: rely on mt76_connac_tx_free As for mt7921 and mt7615 drivers, rely on mt76_connac_tx_free data structure in mt7915e driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 3 +-- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 8 -------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 077239b0820a..1d32d55ba587 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -146,8 +146,7 @@ struct mt76_connac_txp_common { struct mt76_connac_tx_free { __le16 rx_byte_cnt; __le16 ctrl; - u8 txd_cnt; - u8 rsv[3]; + __le32 txd; } __packed __aligned(4); extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index dabcd425cd34..f696c20dc6e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -884,7 +884,8 @@ mt7915_mac_tx_free_done(struct mt7915_dev *dev, static void mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) { - struct mt7915_tx_free *free = (struct mt7915_tx_free *)data; + struct mt76_connac_tx_free *free = data; + __le32 *tx_info = (__le32 *)(data + sizeof(*free)); struct mt76_dev *mdev = &dev->mt76; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; @@ -899,10 +900,10 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT); v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4); - if (WARN_ON_ONCE((void *)&free->info[total >> v3] > end)) + if (WARN_ON_ONCE((void *)&tx_info[total >> v3] > end)) return; - for (cur_info = &free->info[0]; count < total; cur_info++) { + for (cur_info = tx_info; count < total; cur_info++) { u32 msdu, info = le32_to_cpu(*cur_info); u8 i; @@ -955,9 +956,9 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) static void mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len) { - struct mt7915_tx_free *free = (struct mt7915_tx_free *)data; + struct mt76_connac_tx_free *free = data; + __le16 *info = (__le16 *)(data + sizeof(*free)); struct mt76_dev *mdev = &dev->mt76; - __le16 *info = (__le16 *)free->info; void *end = data + len; LIST_HEAD(free_list); bool wake = false; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index ed71a7bc25eb..3876a7457cde 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -41,14 +41,6 @@ enum tx_mcu_port_q_idx { MT_TX_MCU_PORT_RX_Q3, MT_TX_MCU_PORT_RX_FWDL = 0x3e }; - -struct mt7915_tx_free { - __le16 rx_byte_cnt; - __le16 ctrl; - __le32 txd; - __le32 info[]; -} __packed __aligned(4); - #define MT_TX_FREE_VER GENMASK(18, 16) #define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) #define MT_TX_FREE_MSDU_CNT_V0 GENMASK(6, 0) -- cgit v1.2.3 From fc6ee71a2a8f2d183724e3f97762e93c5102425c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Jun 2022 14:59:17 +0200 Subject: mt76: move mcu_txd/mcu_rxd structures in shared code This is a preliminary patch to add mt7990 chipset support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 85 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 29 +++++--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 42 +---------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 33 +++++---- drivers/net/wireless/mediatek/mt76/mt7921/mcu.h | 85 ---------------------- .../net/wireless/mediatek/mt76/mt7921/pci_mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/sdio_mcu.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7921/usb.c | 3 +- 10 files changed, 131 insertions(+), 157 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index d65b3cba1ace..4d29345deae5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -33,6 +33,91 @@ #define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) #define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) +struct mt76_connac2_mcu_txd { + __le32 txd[8]; + + __le16 len; + __le16 pq_id; + + u8 cid; + u8 pkt_type; + u8 set_query; /* FW don't care */ + u8 seq; + + u8 uc_d2b0_rev; + u8 ext_cid; + u8 s2d_index; + u8 ext_cid_ack; + + u32 rsv[5]; +} __packed __aligned(4); + +/** + * struct mt76_connac2_mcu_uni_txd - mcu command descriptor for firmware v3 + * @txd: hardware descriptor + * @len: total length not including txd + * @cid: command identifier + * @pkt_type: must be 0xa0 (cmd packet by long format) + * @frag_n: fragment number + * @seq: sequence number + * @checksum: 0 mean there is no checksum + * @s2d_index: index for command source and destination + * Definition | value | note + * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM + * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM + * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA + * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM + * + * @option: command option + * BIT[0]: UNI_CMD_OPT_BIT_ACK + * set to 1 to request a fw reply + * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY + * is set, mcu firmware will send response event EID = 0x01 + * (UNI_EVENT_ID_CMD_RESULT) to the host. + * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD + * 0: original command + * 1: unified command + * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY + * 0: QUERY command + * 1: SET command + */ +struct mt76_connac2_mcu_uni_txd { + __le32 txd[8]; + + /* DW1 */ + __le16 len; + __le16 cid; + + /* DW2 */ + u8 rsv; + u8 pkt_type; + u8 frag_n; + u8 seq; + + /* DW3 */ + __le16 checksum; + u8 s2d_index; + u8 option; + + /* DW4 */ + u8 rsv1[4]; +} __packed __aligned(4); + +struct mt76_connac2_mcu_rxd { + __le32 rxd[6]; + + __le16 len; + __le16 pkt_type_id; + + u8 eid; + u8 seq; + u8 rsv[2]; + + u8 ext_eid; + u8 rsv1[2]; + u8 s2d_index; +}; + struct mt76_connac2_patch_hdr { char build_date[16]; char platform[4]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 3a7051858892..c8cc60cdcc56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -150,7 +150,7 @@ static int mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { - struct mt7915_mcu_rxd *rxd; + struct mt76_connac2_mcu_rxd *rxd; int ret = 0; if (!skb) { @@ -159,7 +159,7 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, return -ETIMEDOUT; } - rxd = (struct mt7915_mcu_rxd *)skb->data; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (seq != rxd->seq) return -EAGAIN; @@ -170,7 +170,7 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, skb_pull(skb, sizeof(*rxd) + 4); ret = le32_to_cpu(*(__le32 *)skb->data); } else { - skb_pull(skb, sizeof(struct mt7915_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); } return ret; @@ -181,7 +181,7 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - struct mt7915_mcu_txd *mcu_txd; + struct mt76_connac2_mcu_txd *mcu_txd; enum mt76_mcuq_id qid; __le32 *txd; u32 val; @@ -199,7 +199,7 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, goto exit; } - mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); + mcu_txd = (struct mt76_connac2_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) qid = MT_MCUQ_WA; else @@ -326,10 +326,12 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) static void mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) { - struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; - const char *data = (char *)&rxd[1]; - const char *type; + struct mt76_connac2_mcu_rxd *rxd; int len = skb->len - sizeof(*rxd); + const char *data, *type; + + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; + data = (char *)&rxd[1]; switch (rxd->s2d_index) { case 0: @@ -377,8 +379,9 @@ mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) static void mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) { - struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + struct mt76_connac2_mcu_rxd *rxd; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->ext_eid) { case MCU_EXT_EVENT_THERMAL_PROTECT: mt7915_mcu_rx_thermal_notify(dev, skb); @@ -403,8 +406,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) static void mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) { - struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + struct mt76_connac2_mcu_rxd *rxd; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_EXT: mt7915_mcu_rx_ext_event(dev, skb); @@ -417,8 +421,9 @@ mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) { - struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + struct mt76_connac2_mcu_rxd *rxd; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || @@ -2275,7 +2280,7 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) int mt7915_mcu_init(struct mt7915_dev *dev) { static const struct mt76_mcu_ops mt7915_mcu_ops = { - .headroom = sizeof(struct mt7915_mcu_txd), + .headroom = sizeof(struct mt76_connac2_mcu_txd), .mcu_skb_send_msg = mt7915_mcu_send_message, .mcu_parse_response = mt7915_mcu_parse_response, .mcu_restart = mt76_connac_mcu_restart, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 5abde482a97f..e1919e05de3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -6,25 +6,6 @@ #include "../mt76_connac_mcu.h" -struct mt7915_mcu_txd { - __le32 txd[8]; - - __le16 len; - __le16 pq_id; - - u8 cid; - u8 pkt_type; - u8 set_query; /* FW don't care */ - u8 seq; - - u8 uc_d2b0_rev; - u8 ext_cid; - u8 s2d_index; - u8 ext_cid_ack; - - u32 reserved[5]; -} __packed __aligned(4); - enum { MCU_ATE_SET_TRX = 0x1, MCU_ATE_SET_FREQ_OFFSET = 0xa, @@ -32,21 +13,6 @@ enum { MCU_ATE_CLEAN_TXQUEUE = 0x1c, }; -struct mt7915_mcu_rxd { - __le32 rxd[6]; - - __le16 len; - __le16 pkt_type_id; - - u8 eid; - u8 seq; - __le16 __rsv; - - u8 ext_eid; - u8 __rsv1[2]; - u8 s2d_index; -}; - struct mt7915_mcu_thermal_ctrl { u8 ctrl_id; u8 band_idx; @@ -63,7 +29,7 @@ struct mt7915_mcu_thermal_ctrl { } __packed; struct mt7915_mcu_thermal_notify { - struct mt7915_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd rxd; struct mt7915_mcu_thermal_ctrl ctrl; __le32 temperature; @@ -71,7 +37,7 @@ struct mt7915_mcu_thermal_notify { } __packed; struct mt7915_mcu_csa_notify { - struct mt7915_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd rxd; u8 omac_idx; u8 csa_count; @@ -80,7 +46,7 @@ struct mt7915_mcu_csa_notify { } __packed; struct mt7915_mcu_bcc_notify { - struct mt7915_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd rxd; u8 band_idx; u8 omac_idx; @@ -89,7 +55,7 @@ struct mt7915_mcu_bcc_notify { } __packed; struct mt7915_mcu_rdd_report { - struct mt7915_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd rxd; u8 band_idx; u8 long_detected; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index b8fe61355cce..eb1bfb682e02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -970,7 +970,7 @@ void mt7921_coredump_work(struct work_struct *work) if (!skb) break; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { dev_kfree_skb(skb); continue; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 4be488da0117..f2f29eca5d49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1168,7 +1168,7 @@ void mt7921_scan_work(struct work_struct *work) scan_work.work); while (true) { - struct mt7921_mcu_rxd *rxd; + struct mt76_connac2_mcu_rxd *rxd; struct sk_buff *skb; spin_lock_bh(&phy->dev->mt76.lock); @@ -1178,7 +1178,7 @@ void mt7921_scan_work(struct work_struct *work) if (!skb) break; - rxd = (struct mt7921_mcu_rxd *)skb->data; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) { ieee80211_sched_scan_results(phy->mt76->hw); } else if (test_and_clear_bit(MT76_HW_SCANNING, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index bc434e60dfc6..6eab03890e02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -19,7 +19,7 @@ mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) if (!skb) return -EINVAL; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); res = (struct mt7921_mcu_eeprom_info *)skb->data; buf = dev->eeprom.data + le32_to_cpu(res->addr); @@ -32,7 +32,7 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); - struct mt7921_mcu_rxd *rxd; + struct mt76_connac2_mcu_rxd *rxd; int ret = 0; if (!skb) { @@ -43,7 +43,7 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, return -ETIMEDOUT; } - rxd = (struct mt7921_mcu_rxd *)skb->data; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (seq != rxd->seq) return -EAGAIN; @@ -77,7 +77,7 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, event = (struct mt7921_mcu_reg_event *)skb->data; ret = (int)le32_to_cpu(event->val); } else { - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); } return ret; @@ -89,8 +89,8 @@ int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); - struct mt7921_uni_txd *uni_txd; - struct mt7921_mcu_txd *mcu_txd; + struct mt76_connac2_mcu_uni_txd *uni_txd; + struct mt76_connac2_mcu_txd *mcu_txd; __le32 *txd; u32 val; u8 seq; @@ -122,7 +122,7 @@ int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, txd[1] = cpu_to_le32(val); if (cmd & __MCU_CMD_FIELD_UNI) { - uni_txd = (struct mt7921_uni_txd *)txd; + uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); uni_txd->option = MCU_CMD_UNI_EXT_ACK; uni_txd->cid = cpu_to_le16(mcu_cmd); @@ -133,7 +133,7 @@ int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, goto exit; } - mcu_txd = (struct mt7921_mcu_txd *)txd; + mcu_txd = (struct mt76_connac2_mcu_txd *)txd; mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, MT_TX_MCU_PORT_RX_Q0)); @@ -241,7 +241,7 @@ mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) struct mt76_connac_beacon_loss_event *event; struct mt76_phy *mphy = &dev->mt76.phy; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt76_connac_beacon_loss_event *)skb->data; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -255,7 +255,7 @@ mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_mcu_bss_event *event; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt76_connac_mcu_bss_event *)skb->data; if (event->is_absent) ieee80211_stop_queues(mphy->hw); @@ -275,7 +275,7 @@ mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) u8 content[512]; } __packed * msg; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); msg = (struct mt7921_debug_msg *)skb->data; if (msg->type == 3) { /* fw log */ @@ -298,7 +298,7 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) u8 reserved[3]; } __packed * event; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt7921_mcu_lp_event *)skb->data; trace_lp_event(dev, event->state); @@ -309,7 +309,7 @@ mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt7921_mcu_tx_done_event *event; - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt7921_mcu_tx_done_event *)skb->data; mt7921_mac_add_txs(dev, event->txs); @@ -318,8 +318,9 @@ mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) static void mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) { - struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; + struct mt76_connac2_mcu_rxd *rxd; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_BSS_BEACON_LOSS: mt7921_mcu_connection_loss_event(dev, skb); @@ -353,12 +354,12 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) { - struct mt7921_mcu_rxd *rxd; + struct mt76_connac2_mcu_rxd *rxd; if (skb_linearize(skb)) return; - rxd = (struct mt7921_mcu_rxd *)skb->data; + rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (rxd->eid == 0x6) { mt76_mcu_rx_event(&dev->mt76, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index 77cc0cc5b436..a420821357e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -6,76 +6,6 @@ #include "../mt76_connac_mcu.h" -struct mt7921_mcu_txd { - __le32 txd[8]; - - __le16 len; - __le16 pq_id; - - u8 cid; - u8 pkt_type; - u8 set_query; /* FW don't care */ - u8 seq; - - u8 uc_d2b0_rev; - u8 ext_cid; - u8 s2d_index; - u8 ext_cid_ack; - - u32 reserved[5]; -} __packed __aligned(4); - -/** - * struct mt7921_uni_txd - mcu command descriptor for firmware v3 - * @txd: hardware descriptor - * @len: total length not including txd - * @cid: command identifier - * @pkt_type: must be 0xa0 (cmd packet by long format) - * @frag_n: fragment number - * @seq: sequence number - * @checksum: 0 mean there is no checksum - * @s2d_index: index for command source and destination - * Definition | value | note - * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM - * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM - * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA - * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM - * - * @option: command option - * BIT[0]: UNI_CMD_OPT_BIT_ACK - * set to 1 to request a fw reply - * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY - * is set, mcu firmware will send response event EID = 0x01 - * (UNI_EVENT_ID_CMD_RESULT) to the host. - * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD - * 0: original command - * 1: unified command - * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY - * 0: QUERY command - * 1: SET command - */ -struct mt7921_uni_txd { - __le32 txd[8]; - - /* DW1 */ - __le16 len; - __le16 cid; - - /* DW2 */ - u8 reserved; - u8 pkt_type; - u8 frag_n; - u8 seq; - - /* DW3 */ - __le16 checksum; - u8 s2d_index; - u8 option; - - /* DW4 */ - u8 reserved2[4]; -} __packed __aligned(4); - struct mt7921_mcu_tx_done_event { u8 pid; u8 status; @@ -108,21 +38,6 @@ enum { MCU_EXT_EVENT_RATE_REPORT = 0x87, }; -struct mt7921_mcu_rxd { - __le32 rxd[6]; - - __le16 len; - __le16 pkt_type_id; - - u8 eid; - u8 seq; - __le16 __rsv; - - u8 ext_eid; - u8 __rsv1[2]; - u8 s2d_index; -}; - struct mt7921_mcu_eeprom_info { __le32 addr; __le32 valid; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c index a1ab5f878f81..07d970ed6f87 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -39,7 +39,7 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int mt7921e_mcu_init(struct mt7921_dev *dev) { static const struct mt76_mcu_ops mt7921_mcu_ops = { - .headroom = sizeof(struct mt7921_mcu_txd), + .headroom = sizeof(struct mt76_connac2_mcu_txd), .mcu_skb_send_msg = mt7921_mcu_send_message, .mcu_parse_response = mt7921_mcu_parse_response, .mcu_restart = mt76_connac_mcu_restart, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c index efcbe06964db..ba4fdff0da56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -72,7 +72,8 @@ static u32 mt7921s_clear_rm3r_drv_own(struct mt7921_dev *dev) int mt7921s_mcu_init(struct mt7921_dev *dev) { static const struct mt76_mcu_ops mt7921s_mcu_ops = { - .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd), + .headroom = MT_SDIO_HDR_SIZE + + sizeof(struct mt76_connac2_mcu_txd), .tailroom = MT_SDIO_TAIL_SIZE, .mcu_skb_send_msg = mt7921s_mcu_send_message, .mcu_parse_response = mt7921_mcu_parse_response, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c index 4e4cd2dc2aeb..2966b2072d73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c @@ -125,7 +125,8 @@ mt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, static int mt7921u_mcu_init(struct mt7921_dev *dev) { static const struct mt76_mcu_ops mcu_ops = { - .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd), + .headroom = MT_SDIO_HDR_SIZE + + sizeof(struct mt76_connac2_mcu_txd), .tailroom = MT_USB_TAIL_SIZE, .mcu_skb_send_msg = mt7921u_mcu_send_message, .mcu_parse_response = mt7921_mcu_parse_response, -- cgit v1.2.3 From d2f5c8ed9fc436b53a59fdb8bdeb5f19f3a1b12c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Jun 2022 14:59:18 +0200 Subject: mt76: move mt76_connac2_mcu_fill_message in mt76_connac module Move mt76_connac2_mcu_fill_message routine in shared module in order to reuse it for mt7921 and mt7915e drivers. This is a preliminary patch to add mt7990 driver support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 3 - .../net/wireless/mediatek/mt76/mt76_connac2_mac.h | 13 ++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 77 ++++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 5 ++ drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 12 ---- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 61 ++--------------- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 3 - drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 13 ---- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 77 ---------------------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.h | 3 - drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 - .../net/wireless/mediatek/mt76/mt7921/pci_mcu.c | 9 ++- .../net/wireless/mediatek/mt76/mt7921/sdio_mcu.c | 9 ++- drivers/net/wireless/mediatek/mt76/mt7921/usb.c | 9 ++- 14 files changed, 125 insertions(+), 171 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 47863ae9f30b..615956acc6b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -201,9 +201,6 @@ struct mt7615_mcu_rdd_report { } hw_pulse[32]; }; -#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) -#define MCU_PKT_ID 0xa0 - enum { MCU_ATE_SET_FREQ_OFFSET = 0xa, MCU_ATE_SET_TX_POWER_CONTROL = 0x15, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h index a72ae9af9b38..67ce216fb564 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -307,4 +307,17 @@ enum { #define MT_CT_INFO_HSR2_TX BIT(4) #define MT_CT_INFO_FROM_HOST BIT(7) +enum tx_mcu_port_q_idx { + MT_TX_MCU_PORT_RX_Q0 = 0x20, + MT_TX_MCU_PORT_RX_Q1, + MT_TX_MCU_PORT_RX_Q2, + MT_TX_MCU_PORT_RX_Q3, + MT_TX_MCU_PORT_RX_FWDL = 0x3e +}; + +enum tx_port_idx { + MT_TX_PORT_IDX_LMAC, + MT_TX_PORT_IDX_MCU +}; + #endif /* __MT76_CONNAC2_MAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 8c9b0f0b5c39..3c84850ab9fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -2,6 +2,7 @@ /* Copyright (C) 2020 MediaTek Inc. */ #include +#include "mt76_connac2_mac.h" #include "mt76_connac_mcu.h" int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) @@ -3034,5 +3035,81 @@ out: } EXPORT_SYMBOL_GPL(mt76_connac2_load_patch); +int mt76_connac2_mcu_fill_message(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, int *wait_seq) +{ + int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); + struct mt76_connac2_mcu_uni_txd *uni_txd; + struct mt76_connac2_mcu_txd *mcu_txd; + __le32 *txd; + u32 val; + u8 seq; + + /* TODO: make dynamic based on msg type */ + dev->mcu.timeout = 20 * HZ; + + seq = ++dev->mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mcu.msg_seq & 0xf; + + if (cmd == MCU_CMD(FW_SCATTER)) + goto exit; + + txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); + txd = (__le32 *)skb_push(skb, txd_len); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | + FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); + txd[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); + txd[1] = cpu_to_le32(val); + + if (cmd & __MCU_CMD_FIELD_UNI) { + uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; + uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + uni_txd->cid = cpu_to_le16(mcu_cmd); + uni_txd->s2d_index = MCU_S2D_H2N; + uni_txd->pkt_type = MCU_PKT_ID; + uni_txd->seq = seq; + + goto exit; + } + + mcu_txd = (struct mt76_connac2_mcu_txd *)txd; + mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); + mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, + MT_TX_MCU_PORT_RX_Q0)); + mcu_txd->pkt_type = MCU_PKT_ID; + mcu_txd->seq = seq; + mcu_txd->cid = mcu_cmd; + mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); + + if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) { + if (cmd & __MCU_CMD_FIELD_QUERY) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; + } else { + mcu_txd->set_query = MCU_Q_NA; + } + + if (cmd & __MCU_CMD_FIELD_WA) + mcu_txd->s2d_index = MCU_S2D_H2C; + else + mcu_txd->s2d_index = MCU_S2D_H2N; + +exit: + if (wait_seq) + *wait_seq = seq; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 4d29345deae5..f1d7c05bd794 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -33,6 +33,9 @@ #define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) #define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) +#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) +#define MCU_PKT_ID 0xa0 + struct mt76_connac2_mcu_txd { __le32 txd[8]; @@ -1804,4 +1807,6 @@ int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa); int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name); +int mt76_connac2_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *wait_seq); #endif /* __MT76_CONNAC_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 3876a7457cde..6fa9c79f3e5f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -29,18 +29,6 @@ enum rx_pkt_type { PKT_TYPE_TXRX_NOTIFY_V0 = 0x18, }; -enum tx_port_idx { - MT_TX_PORT_IDX_LMAC, - MT_TX_PORT_IDX_MCU -}; - -enum tx_mcu_port_q_idx { - MT_TX_MCU_PORT_RX_Q0 = 0x20, - MT_TX_MCU_PORT_RX_Q1, - MT_TX_MCU_PORT_RX_Q2, - MT_TX_MCU_PORT_RX_Q3, - MT_TX_MCU_PORT_RX_FWDL = 0x3e -}; #define MT_TX_FREE_VER GENMASK(18, 16) #define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) #define MT_TX_FREE_MSDU_CNT_V0 GENMASK(6, 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c8cc60cdcc56..207fd0b83417 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -181,69 +181,20 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - struct mt76_connac2_mcu_txd *mcu_txd; enum mt76_mcuq_id qid; - __le32 *txd; - u32 val; - u8 seq; - - /* TODO: make dynamic based on msg type */ - mdev->mcu.timeout = 20 * HZ; + int ret; - seq = ++dev->mt76.mcu.msg_seq & 0xf; - if (!seq) - seq = ++dev->mt76.mcu.msg_seq & 0xf; + ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, wait_seq); + if (ret) + return ret; - if (cmd == MCU_CMD(FW_SCATTER)) { + if (cmd == MCU_CMD(FW_SCATTER)) qid = MT_MCUQ_FWDL; - goto exit; - } - - mcu_txd = (struct mt76_connac2_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) + else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) qid = MT_MCUQ_WA; else qid = MT_MCUQ_WM; - txd = mcu_txd->txd; - - val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | - FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | - FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); - txd[0] = cpu_to_le32(val); - - val = MT_TXD1_LONG_FORMAT | - FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); - txd[1] = cpu_to_le32(val); - - mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); - mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, - MT_TX_MCU_PORT_RX_Q0)); - mcu_txd->pkt_type = MCU_PKT_ID; - mcu_txd->seq = seq; - - mcu_txd->cid = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); - mcu_txd->set_query = MCU_Q_NA; - mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); - if (mcu_txd->ext_cid) { - mcu_txd->ext_cid_ack = 1; - - /* do not use Q_SET for efuse */ - if (cmd & __MCU_CMD_FIELD_QUERY) - mcu_txd->set_query = MCU_Q_QUERY; - else - mcu_txd->set_query = MCU_Q_SET; - } - - if (cmd & __MCU_CMD_FIELD_WA) - mcu_txd->s2d_index = MCU_S2D_H2C; - else - mcu_txd->s2d_index = MCU_S2D_H2N; - -exit: - if (wait_seq) - *wait_seq = seq; - return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index e1919e05de3a..da4ee0ac2618 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -233,9 +233,6 @@ struct mt7915_mcu_muru_stats { #define WMM_TXOP_SET BIT(3) #define WMM_PARAM_SET GENMASK(3, 0) -#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) -#define MCU_PKT_ID 0xa0 - enum { MCU_FW_LOG_WM, MCU_FW_LOG_WA, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index b8cabeb796b9..8afec600364f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -29,19 +29,6 @@ enum rx_pkt_type { PKT_TYPE_NORMAL_MCU, }; -enum tx_port_idx { - MT_TX_PORT_IDX_LMAC, - MT_TX_PORT_IDX_MCU -}; - -enum tx_mcu_port_q_idx { - MT_TX_MCU_PORT_RX_Q0 = 0x20, - MT_TX_MCU_PORT_RX_Q1, - MT_TX_MCU_PORT_RX_Q2, - MT_TX_MCU_PORT_RX_Q3, - MT_TX_MCU_PORT_RX_FWDL = 0x3e -}; - #define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) #define MT_TX_FREE_WLAN_ID GENMASK(23, 14) #define MT_TX_FREE_LATENCY GENMASK(12, 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 6eab03890e02..1b62135bdc8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -84,83 +84,6 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, } EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); -int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, - int cmd, int *wait_seq) -{ - struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); - int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); - struct mt76_connac2_mcu_uni_txd *uni_txd; - struct mt76_connac2_mcu_txd *mcu_txd; - __le32 *txd; - u32 val; - u8 seq; - - if (cmd == MCU_UNI_CMD(HIF_CTRL) || - cmd == MCU_UNI_CMD(SUSPEND) || - cmd == MCU_UNI_CMD(OFFLOAD)) - mdev->mcu.timeout = HZ; - else - mdev->mcu.timeout = 3 * HZ; - - seq = ++dev->mt76.mcu.msg_seq & 0xf; - if (!seq) - seq = ++dev->mt76.mcu.msg_seq & 0xf; - - if (cmd == MCU_CMD(FW_SCATTER)) - goto exit; - - txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); - txd = (__le32 *)skb_push(skb, txd_len); - - val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | - FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | - FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); - txd[0] = cpu_to_le32(val); - - val = MT_TXD1_LONG_FORMAT | - FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); - txd[1] = cpu_to_le32(val); - - if (cmd & __MCU_CMD_FIELD_UNI) { - uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; - uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); - uni_txd->option = MCU_CMD_UNI_EXT_ACK; - uni_txd->cid = cpu_to_le16(mcu_cmd); - uni_txd->s2d_index = MCU_S2D_H2N; - uni_txd->pkt_type = MCU_PKT_ID; - uni_txd->seq = seq; - - goto exit; - } - - mcu_txd = (struct mt76_connac2_mcu_txd *)txd; - mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); - mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, - MT_TX_MCU_PORT_RX_Q0)); - mcu_txd->pkt_type = MCU_PKT_ID; - mcu_txd->seq = seq; - mcu_txd->cid = mcu_cmd; - mcu_txd->s2d_index = MCU_S2D_H2N; - mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); - - if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) { - if (cmd & __MCU_CMD_FIELD_QUERY) - mcu_txd->set_query = MCU_Q_QUERY; - else - mcu_txd->set_query = MCU_Q_SET; - mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; - } else { - mcu_txd->set_query = MCU_Q_NA; - } - -exit: - if (wait_seq) - *wait_seq = seq; - - return 0; -} -EXPORT_SYMBOL_GPL(mt7921_mcu_fill_message); - #ifdef CONFIG_PM static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index a420821357e0..0d20f7d8d474 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -50,9 +50,6 @@ struct mt7921_mcu_eeprom_info { #define MT_RA_RATE_DCM_EN BIT(4) #define MT_RA_RATE_BW GENMASK(14, 13) -#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) -#define MCU_PKT_ID 0xa0 - struct mt7921_mcu_uni_event { u8 cid; u8 pad[3]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 48fd14c67e44..efeb82cbbe83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -419,8 +419,6 @@ int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, struct netlink_callback *cb, void *data, int len); void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi); void mt7921_mac_sta_poll(struct mt7921_dev *dev); -int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, - int cmd, int *wait_seq); int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c index 07d970ed6f87..5efda694fb9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -26,10 +26,17 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, enum mt76_mcuq_id txq = MT_MCUQ_WM; int ret; - ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); + ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); if (ret) return ret; + if (cmd == MCU_UNI_CMD(HIF_CTRL) || + cmd == MCU_UNI_CMD(SUSPEND) || + cmd == MCU_UNI_CMD(OFFLOAD)) + mdev->mcu.timeout = HZ; + else + mdev->mcu.timeout = 3 * HZ; + if (cmd == MCU_CMD(FW_SCATTER)) txq = MT_MCUQ_FWDL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c index ba4fdff0da56..e038d7404323 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -29,10 +29,17 @@ mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, if (dev->fw_assert) return -EBUSY; - ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); + ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); if (ret) return ret; + if (cmd == MCU_UNI_CMD(HIF_CTRL) || + cmd == MCU_UNI_CMD(SUSPEND) || + cmd == MCU_UNI_CMD(OFFLOAD)) + mdev->mcu.timeout = HZ; + else + mdev->mcu.timeout = 3 * HZ; + if (cmd == MCU_CMD(FW_SCATTER)) type = MT7921_SDIO_FWDL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c index 2966b2072d73..dd3b8884e162 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c @@ -102,10 +102,17 @@ mt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, u32 pad, ep; int ret; - ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); + ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); if (ret) return ret; + if (cmd == MCU_UNI_CMD(HIF_CTRL) || + cmd == MCU_UNI_CMD(SUSPEND) || + cmd == MCU_UNI_CMD(OFFLOAD)) + mdev->mcu.timeout = HZ; + else + mdev->mcu.timeout = 3 * HZ; + if (cmd != MCU_CMD(FW_SCATTER)) ep = MT_EP_OUT_INBAND_CMD; else -- cgit v1.2.3 From c3f2ed588867e14560b86e9db6bf5ac29f03dc5a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 21 Jun 2022 20:34:44 +0200 Subject: mt76: mt7915: disable UL MU-MIMO for mt7915 After initially establishing a connection, it can produce multi-second latency spikes and tx hangs when pushing traffic. It should work better for MT7916 and MT7986, so leave it enabled there Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 2764c22179fb..6bdbc59beada 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -753,9 +753,10 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_dev *dev, elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; - c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | - IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | - IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US; + if (!is_mt7915(&dev->mt76)) + c |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; elem->phy_cap_info[2] |= c; c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 207fd0b83417..6b0b9a86b9d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -826,8 +826,8 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } static void -mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, - struct ieee80211_vif *vif) +mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; @@ -845,7 +845,8 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer || mvif->cap.vht_mu_ebfer || mvif->cap.vht_mu_ebfee; - muru->cfg.mimo_ul_en = true; + if (!is_mt7915(&dev->mt76)) + muru->cfg.mimo_ul_en = true; muru->cfg.ofdma_dl_en = true; if (sta->deflink.vht_cap.vht_supported) @@ -1647,7 +1648,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, /* starec he */ mt7915_mcu_sta_he_tlv(skb, sta, vif); /* starec muru */ - mt7915_mcu_sta_muru_tlv(skb, sta, vif); + mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif); /* starec bfee */ mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta); } -- cgit v1.2.3 From 6e744cfeee02c2d8676eb55d5b3720808812f41f Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 20 Jun 2022 14:17:17 +0800 Subject: mt76: mt7915: fix incorrect testmode ipg on band 1 caused by wmm_idx Fix the issue that the measured inter packet gap didn't fit its setting value. Fixes: c2d3b1926f30 ("mt76: mt7915: add support for ipg in testmode") Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/testmode.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index 20f63644e929..0f5c1e5bffe1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -168,13 +168,14 @@ mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu) } static int -mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min, +mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min, u16 cw_max, u16 txop) { + struct mt7915_vif *mvif = (struct mt7915_vif *)phy->monitor_vif->drv_priv; struct mt7915_mcu_tx req = { .total = 1 }; struct edca *e = &req.edca[0]; - e->queue = qid; + e->queue = qid + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; e->set = WMM_PARAM_SET; e->aifs = aifs; @@ -182,7 +183,7 @@ mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min, e->cw_max = cpu_to_le16(cw_max); e->txop = cpu_to_le16(txop); - return mt7915_mcu_update_edca(dev, &req); + return mt7915_mcu_update_edca(phy->dev, &req); } static int @@ -244,7 +245,7 @@ done: mt7915_tm_set_slot_time(phy, slot_time, sifs); - return mt7915_tm_set_wmm_qid(dev, + return mt7915_tm_set_wmm_qid(phy, mt76_connac_lmac_mapping(IEEE80211_AC_BE), aifsn, cw, cw, 0); } -- cgit v1.2.3 From 8dae26a3bddf8bcd81f6f13de8c9ea085e64cdea Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 22 Jun 2022 00:51:24 +0200 Subject: mt76: mt7915: do not copy ieee80211_ops pointer in mt7915_mmio_probe We do not modify ieee80211_ops pointers so we do not need to copy them. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index c2646d24b574..930fae7a0bd5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -661,16 +661,11 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, .sta_remove = mt7915_mac_sta_remove, .update_survey = mt7915_update_channel, }; - struct ieee80211_ops *ops; struct mt7915_dev *dev; struct mt76_dev *mdev; int ret; - ops = devm_kmemdup(pdev, &mt7915_ops, sizeof(mt7915_ops), GFP_KERNEL); - if (!ops) - return ERR_PTR(-ENOMEM); - - mdev = mt76_alloc_device(pdev, sizeof(*dev), ops, &drv_ops); + mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt7915_ops, &drv_ops); if (!mdev) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From 754f9ae80e4fc3a42cfb7e2c680fdf7710ff8273 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 22 Jun 2022 09:24:48 +0800 Subject: mt76: mt7915: update mpdu density in 6g capability Set mpdu density to 2 usec in 6g capability to meet hardware capability and also enhance throughput. Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 6bdbc59beada..c0f4f2053738 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -980,7 +980,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; - cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_8, + cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | -- cgit v1.2.3 From 8e3e7567b8c1216c743a69a32e468f7c86b8643f Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Wed, 22 Jun 2022 09:24:49 +0800 Subject: mt76: mt7915: add sta_rec with EXTRA_INFO_NEW for the first time only Set EXTRA_INFO_NEW for the first time only to prevent adding the same starec entry, otherwise the entry might be removed in fw. Reviewed-by: Ryder Lee Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 8a114dae6110..b1a5aab7a984 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -235,7 +235,6 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; @@ -251,6 +250,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mt7915_mcu_add_bss_info(phy, vif, true); mt7915_mcu_add_sta(dev, vif, NULL, true); + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); out: mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 6b0b9a86b9d7..39024795b2b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1620,7 +1620,8 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable, true); + mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable, + !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx])); if (!enable) goto out; -- cgit v1.2.3 From 1858e4fc89b2301e9a9e056a331cbd0902e516b5 Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Wed, 22 Jun 2022 16:30:34 +0800 Subject: mt76: do not check the ccmp pn for ONLY_MONITOR frame if the received frame enables RX_FLAG_ONLY_MONITOR, driver doesn't need to check the ccmp pn of this frame. Reviewed-by: Ryder Lee Signed-off-by: MeiChia Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 60da9995357e..ecf5bd9605db 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1030,6 +1030,9 @@ mt76_check_ccmp_pn(struct sk_buff *skb) if (!(status->flag & RX_FLAG_DECRYPTED)) return 0; + if (status->flag & RX_FLAG_ONLY_MONITOR) + return 0; + if (!wcid || !wcid->rx_check_pn) return 0; -- cgit v1.2.3 From 18fced2017d8b8a21a484640f5880bd7ec0d62ec Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Wed, 22 Jun 2022 17:46:55 +0800 Subject: mt76: mt7915: update the maximum size of beacon offload Since an in-band discovery frame is offloaded by MCU, here we enlarge the command size to accommodate the additional content. Reviewed-by: Ryder Lee Signed-off-by: Money Wang Signed-off-by: MeiChia Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 11 ++++++++--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 39024795b2b9..18fb205e26fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1938,6 +1938,12 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi len = sizeof(*discov) + MT_TXD_SIZE + skb->len; len = (len & 0x3) ? ((len | 0x3) + 1) : len; + if (len > (MT7915_MAX_BSS_OFFLOAD_SIZE - rskb->len)) { + dev_err(dev->mt76.dev, "inband discovery size limit exceed\n"); + dev_kfree_skb(skb); + return; + } + tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV, len, &bcn->sub_ntlv, &bcn->len); discov = (struct bss_info_inband_discovery *)tlv; @@ -1960,7 +1966,6 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int en, u32 changed) { -#define MAX_BEACON_SIZE 512 struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; @@ -1969,7 +1974,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct sk_buff *skb, *rskb; struct tlv *tlv; struct bss_info_bcn *bcn; - int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE; + int len = MT7915_MAX_BSS_OFFLOAD_SIZE; bool ext_phy = phy != &dev->phy; if (vif->bss_conf.nontransmitted) @@ -1991,7 +1996,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!skb) return -EINVAL; - if (skb->len > MAX_BEACON_SIZE - MT_TXD_SIZE) { + if (skb->len > MT7915_MAX_BEACON_SIZE - MT_TXD_SIZE) { dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); dev_kfree_skb(skb); return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index da4ee0ac2618..cd1edf553fc1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -452,6 +452,12 @@ enum { SER_RECOVER }; +#define MT7915_MAX_BEACON_SIZE 512 +#define MT7915_MAX_INBAND_FRAME_SIZE 256 +#define MT7915_MAX_BSS_OFFLOAD_SIZE (MT7915_MAX_BEACON_SIZE + \ + MT7915_MAX_INBAND_FRAME_SIZE + \ + MT7915_BEACON_UPDATE_SIZE) + #define MT7915_BSS_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct bss_info_omac) + \ sizeof(struct bss_info_basic) +\ -- cgit v1.2.3 From df6b739fd7d15371357c32d4b1190e681434a096 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jun 2022 14:11:06 +0200 Subject: mt76: mt7615: add sta_rec with EXTRA_INFO_NEW for the first time only Set EXTRA_INFO_NEW for the first time only to prevent adding the same starec entry, otherwise the entry might be removed in fw. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 9 ++++++++- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 194e9ccd4a73..989b2a41b670 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -844,6 +844,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct mt7615_dev *dev = phy->dev; struct wtbl_req_hdr *wtbl_hdr; struct mt7615_sta *msta; + bool new_entry = true; int cmd, err; msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; @@ -853,7 +854,13 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (IS_ERR(sskb)) return PTR_ERR(sskb); - mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, true); + if (!sta) { + if (mvif->sta_added) + new_entry = false; + else + mvif->sta_added = true; + } + mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, new_entry); if (enable && sta) mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0, MT76_STA_INFO_STATE_ASSOC); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 653181905d09..8499cdc4bb0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -141,6 +141,7 @@ struct mt7615_sta { struct mt7615_vif { struct mt76_vif mt76; /* must be first */ struct mt7615_sta sta; + bool sta_added; }; struct mib_stats { -- cgit v1.2.3 From 8916e4e513a85ff6315d1e7fef999916b35023d7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 23 Jun 2022 11:39:58 +0200 Subject: mt76: mt76x02: improve reliability of the beacon hang check Increment the counter only when writing beacons to the hardware in order to avoid triggering restarts if beacons are disabled. Additionally, avoid resetting the MAC if stopping it failed Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c | 6 +++++- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index b72510949877..ad4dc8e17b58 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -57,8 +57,11 @@ void mt76x02_mac_set_beacon(struct mt76x02_dev *dev, int bcn_len = dev->beacon_ops->slot_size; int bcn_addr = MT_BEACON_BASE + (bcn_len * dev->beacon_data_count); - if (!mt76x02_write_beacon(dev, bcn_addr, skb)) + if (!mt76x02_write_beacon(dev, bcn_addr, skb)) { + if (!dev->beacon_data_count) + dev->beacon_hang_check++; dev->beacon_data_count++; + } dev_kfree_skb(skb); } EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon); @@ -74,6 +77,7 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, if (!dev->mt76.beacon_mask) dev->tbtt_count = 0; + dev->beacon_hang_check = 0; if (enable) { dev->mt76.beacon_mask |= BIT(mvif->idx); } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index cf4d4110cc99..de30cf5e2d2f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1044,10 +1044,9 @@ static void mt76x02_check_mac_err(struct mt76x02_dev *dev) return; } - if (++dev->beacon_hang_check < 10) + if (dev->beacon_hang_check < 10) return; - dev->beacon_hang_check = 0; } else { u32 val = mt76_rr(dev, 0x10f4); if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) @@ -1057,10 +1056,16 @@ static void mt76x02_check_mac_err(struct mt76x02_dev *dev) dev_err(dev->mt76.dev, "MAC error detected\n"); mt76_wr(dev, MT_MAC_SYS_CTRL, 0); - mt76x02_wait_for_txrx_idle(&dev->mt76); + if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) { + dev_err(dev->mt76.dev, "MAC stop failed\n"); + goto out; + } + dev->beacon_hang_check = 0; mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); udelay(10); + +out: mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); } -- cgit v1.2.3 From 3c1032e1221723777d59c116e805be5e3fcb319d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 23 Jun 2022 14:21:18 +0200 Subject: mt76: allow receiving frames with invalid CCMP PN via monitor interfaces This can be useful for debugging Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index ecf5bd9605db..cb41f54bdd1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1018,7 +1018,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, *hw = mt76_phy_hw(dev, mstat.ext_phy); } -static int +static void mt76_check_ccmp_pn(struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -1028,13 +1028,13 @@ mt76_check_ccmp_pn(struct sk_buff *skb) int ret; if (!(status->flag & RX_FLAG_DECRYPTED)) - return 0; + return; if (status->flag & RX_FLAG_ONLY_MONITOR) - return 0; + return; if (!wcid || !wcid->rx_check_pn) - return 0; + return; security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; if (status->flag & RX_FLAG_8023) @@ -1048,7 +1048,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) */ if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) - return 0; + return; } /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): @@ -1065,15 +1065,15 @@ skip_hdr_check: BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], sizeof(status->iv)); - if (ret <= 0) - return -EINVAL; /* replay */ + if (ret <= 0) { + status->flag |= RX_FLAG_ONLY_MONITOR; + return; + } memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); if (status->flag & RX_FLAG_IV_STRIPPED) status->flag |= RX_FLAG_PN_VALIDATED; - - return 0; } static void @@ -1246,11 +1246,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, while ((skb = __skb_dequeue(frames)) != NULL) { struct sk_buff *nskb = skb_shinfo(skb)->frag_list; - if (mt76_check_ccmp_pn(skb)) { - dev_kfree_skb(skb); - continue; - } - + mt76_check_ccmp_pn(skb); skb_shinfo(skb)->frag_list = NULL; mt76_rx_convert(dev, skb, &hw, &sta); ieee80211_rx_list(hw, sta, skb, &list); -- cgit v1.2.3 From aac86cebb4a09e3fa2c07589f79f7d0e07e8c9a4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 24 Jun 2022 20:57:47 +0200 Subject: mt76: mt7615: fix throughput regression on DFS channels For some reason, mt7615 reacts badly to repeatedly enabling/disabling the radar detector without also switching the channel. This results in very bad throughput on DFS channels, because hw->conf.radar_enabled can get toggled a few times after CAC ends. Fix this by always leaving the DFS detector enabled on DFS channels and instead suppress unwanted detection events. Fixes: 2c86f6752046 ("mt76: mt7615: fix/rewrite the dfs state handling logic") Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 21 --------------------- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 - 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d9dd3d404986..038774b3ced0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2231,6 +2231,7 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy) int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy) { + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; enum mt76_dfs_state dfs_state, prev_state; @@ -2241,13 +2242,13 @@ int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy) prev_state = phy->mt76->dfs_state; dfs_state = mt76_phy_dfs_state(phy->mt76); + if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && + dfs_state < MT_DFS_STATE_CAC) + dfs_state = MT_DFS_STATE_ACTIVE; if (prev_state == dfs_state) return 0; - if (prev_state == MT_DFS_STATE_UNKNOWN) - mt7615_dfs_stop_radar_detector(phy); - if (dfs_state == MT_DFS_STATE_DISABLED) goto stop; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 277c22a4d049..28bc76c8e8e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -282,26 +282,6 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid); } -static void mt7615_init_dfs_state(struct mt7615_phy *phy) -{ - struct mt76_phy *mphy = phy->mt76; - struct ieee80211_hw *hw = mphy->hw; - struct cfg80211_chan_def *chandef = &hw->conf.chandef; - - if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) - return; - - if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR) && - !(mphy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) - return; - - if (mphy->chandef.chan->center_freq == chandef->chan->center_freq && - mphy->chandef.width == chandef->width) - return; - - phy->dfs_state = -1; -} - int mt7615_set_channel(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; @@ -314,7 +294,6 @@ int mt7615_set_channel(struct mt7615_phy *phy) set_bit(MT76_RESET, &phy->mt76->state); - mt7615_init_dfs_state(phy); mt76_set_channel(phy->mt76); if (is_mt7615(&dev->mt76) && dev->flash_eeprom) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 989b2a41b670..3d35381013f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -391,6 +391,9 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb) if (r->band_idx && dev->mt76.phy2) mphy = dev->mt76.phy2; + if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC) + return; + ieee80211_radar_detected(mphy->hw); dev->hw_pattern++; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 8499cdc4bb0d..93a9e8f46193 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -178,7 +178,6 @@ struct mt7615_phy { u8 chfreq; u8 rdd_state; - int dfs_state; u32 rx_ampdu_ts; u32 ampdu_ref; -- cgit v1.2.3 From d08295f5be8e63e64f9e664572f1b582ede7958b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Jul 2022 17:52:24 +0200 Subject: mt76: pass original queue id from __mt76_tx_queue_skb to the driver MT7615 and newer map multiple software tx queues to the hardware id Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7603/beacon.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 3 ++- drivers/net/wireless/mediatek/mt76/sdio.c | 6 +++--- drivers/net/wireless/mediatek/mt76/testmode.c | 4 ++-- drivers/net/wireless/mediatek/mt76/tx.c | 2 +- drivers/net/wireless/mediatek/mt76/usb.c | 6 +++--- 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 30de8be4aac1..f22273cde1a8 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -349,8 +349,8 @@ error: static int mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta) + enum mt76_txq_id qid, struct sk_buff *skb, + struct mt76_wcid *wcid, struct ieee80211_sta *sta) { struct ieee80211_tx_status status = { .sta = sta, @@ -406,7 +406,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, dev->drv->txwi_size, DMA_TO_DEVICE); - ret = dev->drv->tx_prepare_skb(dev, txwi, q->qid, wcid, sta, &tx_info); + ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info); dma_sync_single_for_device(dev->dma_dev, t->dma_addr, dev->drv->txwi_size, DMA_TO_DEVICE); if (ret < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 4e8997c45c1b..cb712c0438c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -223,8 +223,8 @@ struct mt76_queue_ops { u32 ring_base); int (*tx_queue_skb)(struct mt76_dev *dev, struct mt76_queue *q, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta); + enum mt76_txq_id qid, struct sk_buff *skb, + struct mt76_wcid *wcid, struct ieee80211_sta *sta); int (*tx_queue_skb_raw)(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, u32 tx_info); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c index c67fc29bb7c3..b65b0a88c1de 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c @@ -24,8 +24,8 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!skb) return; - mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON], skb, - &mvif->sta.wcid, NULL); + mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON], + MT_TXQ_BEACON, skb, &mvif->sta.wcid, NULL); spin_lock_bh(&dev->ps_lock); mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY | @@ -123,7 +123,7 @@ void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t) struct ieee80211_vif *vif = info->control.vif; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; - mt76_tx_queue_skb(dev, q, skb, &mvif->sta.wcid, NULL); + mt76_tx_queue_skb(dev, q, MT_TXQ_CAB, skb, &mvif->sta.wcid, NULL); } mt76_queue_kick(dev, q); spin_unlock(&q->lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 96ec96df6a3c..e9c5e85ec07c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -59,7 +59,8 @@ static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t) struct ieee80211_vif *vif = info->control.vif; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; - mt76_tx_queue_skb(dev, q, skb, &mvif->group_wcid, NULL); + mt76_tx_queue_skb(dev, q, MT_TXQ_PSD, skb, &mvif->group_wcid, + NULL); } spin_unlock(&q->lock); } diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index def7f325f5c5..974fdbf0ffab 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -517,8 +517,8 @@ static void mt76s_tx_status_data(struct work_struct *work) static int mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta) + enum mt76_txq_id qid, struct sk_buff *skb, + struct mt76_wcid *wcid, struct ieee80211_sta *sta) { struct mt76_tx_info tx_info = { .skb = skb, @@ -530,7 +530,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, return -ENOSPC; skb->prev = skb->next = NULL; - err = dev->drv->tx_prepare_skb(dev, NULL, q->qid, wcid, sta, &tx_info); + err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index 382b45639f26..47ac0ca1af32 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -50,8 +50,8 @@ void mt76_testmode_tx_pending(struct mt76_phy *phy) q->queued < q->ndesc / 2) { int ret; - ret = dev->queue_ops->tx_queue_skb(dev, q, skb_get(skb), wcid, - NULL); + ret = dev->queue_ops->tx_queue_skb(dev, q, qid, skb_get(skb), + wcid, NULL); if (ret < 0) break; diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 1d08d99e298c..e1d5996c4675 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -284,7 +284,7 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, int idx; non_aql = !info->tx_time_est; - idx = dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta); + idx = dev->queue_ops->tx_queue_skb(dev, q, qid, skb, wcid, sta); if (idx < 0 || !sta) return idx; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 1bb92ca7451b..b030b567989b 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -845,8 +845,8 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb, static int mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta) + enum mt76_txq_id qid, struct sk_buff *skb, + struct mt76_wcid *wcid, struct ieee80211_sta *sta) { struct mt76_tx_info tx_info = { .skb = skb, @@ -858,7 +858,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, return -ENOSPC; skb->prev = skb->next = NULL; - err = dev->drv->tx_prepare_skb(dev, NULL, q->qid, wcid, sta, &tx_info); + err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); if (err < 0) return err; -- cgit v1.2.3 From 1d5af0acac6eee9cb2b6688ed5e7084494d8707b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 2 Jul 2022 15:56:23 +0200 Subject: mt76: do not use skb_set_queue_mapping for internal purposes Previously the code used skb_set_queue_mapping for management or non-bufferable powersave frames that need to be sent to a different hardware queue. This can confuse AQL, which expects the value to remain the same until the tx status report. The only place that currently uses the altered skb queue mapping is the txwi write function. Change the code to pass the hardware queue id as a function parameter instead. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/tx.c | 1 - 14 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 038774b3ced0..372862768bb4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -717,7 +717,8 @@ mt7615_mac_tx_rate_val(struct mt7615_dev *dev, int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, - struct ieee80211_key_conf *key, bool beacon) + struct ieee80211_key_conf *key, + enum mt76_txq_id qid, bool beacon) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; @@ -755,7 +756,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, if (beacon) { p_fmt = MT_TX_TYPE_FW; q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0; - } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + } else if (qid >= MT_TXQ_PSD) { p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 3d35381013f1..e8b1be818c30 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -714,7 +714,7 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, } mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL, - 0, NULL, true); + 0, NULL, 0, true); memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len); req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); @@ -1086,7 +1086,7 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, } mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb, - wcid, NULL, 0, NULL, true); + wcid, NULL, 0, NULL, 0, true); memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 93a9e8f46193..25880d1a50da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -477,7 +477,8 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, - struct ieee80211_key_conf *key, bool beacon); + struct ieee80211_key_conf *key, + enum mt76_txq_id qid, bool beacon); void mt7615_mac_set_timing(struct mt7615_phy *phy); int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 05b6669466ba..26211c63dac4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -96,7 +96,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta, - pid, key, false); + pid, key, qid, false); txp = txwi + MT_TXD_SIZE; memset(txp, 0, sizeof(struct mt76_connac_txp_common)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index 5a6d7829c6e0..0052d103e276 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -49,7 +49,7 @@ mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, __le32 *txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); memset(txwi, 0, MT_USB_TXD_SIZE); - mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); + mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, qid, false); skb_push(skb, MT_USB_TXD_SIZE); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 1d32d55ba587..9070162c6869 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -339,7 +339,7 @@ void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, - u32 changed); + enum mt76_txq_id qid, u32 changed); bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data, struct mt76_sta_stats *stats); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index af2b33d738ca..3ab0dcde7351 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -436,7 +436,7 @@ mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, - u32 changed) + enum mt76_txq_id qid, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; @@ -467,7 +467,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, } else if (beacon) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_BCN0; - } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + } else if (qid >= MT_TXQ_PSD) { p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = MT_LMAC_ALTX0; } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index f696c20dc6e3..757b4e1c3164 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -662,7 +662,8 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, - struct ieee80211_key_conf *key, u32 changed) + struct ieee80211_key_conf *key, + enum mt76_txq_id qid, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76_phy *mphy = &dev->phy; @@ -670,7 +671,7 @@ void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phy2) mphy = dev->phy2; - mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, changed); + mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, qid, changed); if (mt76_testmode_enabled(mphy)) mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb); @@ -717,7 +718,8 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return id; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key, 0); + mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key, + qid, 0); txp = (struct mt76_connac_fw_txp *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 18fb205e26fb..4a841bcead0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1812,7 +1812,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, buf = (u8 *)tlv + sizeof(*cont); mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, - BSS_CHANGED_BEACON); + 0, BSS_CHANGED_BEACON); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } @@ -1957,7 +1957,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi buf = (u8 *)tlv + sizeof(*discov); mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, - changed); + 0, changed); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); dev_kfree_skb(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b6a6aa7fcf43..db63012e8aa9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -551,7 +551,8 @@ void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy); void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, - struct ieee80211_key_conf *key, u32 changed); + struct ieee80211_key_conf *key, + enum mt76_txq_id qid, u32 changed); void mt7915_mac_set_timing(struct mt7915_phy *phy); int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index eb1bfb682e02..49b7f0debc78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -999,7 +999,7 @@ mt7921_usb_sdio_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid, __le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); memset(txwi, 0, MT_SDIO_TXD_SIZE); - mt76_connac2_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, 0); + mt76_connac2_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, qid, 0); skb_push(skb, MT_SDIO_TXD_SIZE); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 1b62135bdc8f..c232319d2071 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -919,7 +919,7 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, } mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt), - skb, wcid, NULL, 0, BSS_CHANGED_BEACON); + skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON); memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index f6c605a59b81..e1800674089a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -42,7 +42,7 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt76_connac2_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, - pid, 0); + pid, qid, 0); txp = (struct mt76_connac_hw_txp *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt76_connac_hw_txp)); diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index e1d5996c4675..13c5e78dd39d 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -327,7 +327,6 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, !ieee80211_is_data(hdr->frame_control) && !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { qid = MT_TXQ_PSD; - skb_set_queue_mapping(skb, qid); } if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET)) -- cgit v1.2.3 From bceb8b8ded9b2470c10a13e5446f2d5a8e178964 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Jul 2022 20:59:05 +0200 Subject: mt76: remove q->qid It is no longer used Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 --- drivers/net/wireless/mediatek/mt76/sdio.c | 2 -- drivers/net/wireless/mediatek/mt76/usb.c | 1 - 3 files changed, 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index cb712c0438c2..f25f2dad43d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -185,7 +185,6 @@ struct mt76_queue { u8 buf_offset; u8 hw_idx; - u8 qid; u8 flags; u32 wed_regs; @@ -977,7 +976,6 @@ static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, if (IS_ERR(q)) return PTR_ERR(q); - q->qid = qid; phy->q_tx[qid] = q; return 0; @@ -992,7 +990,6 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, if (IS_ERR(q)) return PTR_ERR(q); - q->qid = __MT_TXQ_MAX + qid; dev->q_mcu[qid] = q; return 0; diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 974fdbf0ffab..aba2a9865821 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -350,7 +350,6 @@ int mt76s_alloc_tx(struct mt76_dev *dev) if (IS_ERR(q)) return PTR_ERR(q); - q->qid = i; dev->phy.q_tx[i] = q; } @@ -358,7 +357,6 @@ int mt76s_alloc_tx(struct mt76_dev *dev) if (IS_ERR(q)) return PTR_ERR(q); - q->qid = MT_MCUQ_WM; dev->q_mcu[MT_MCUQ_WM] = q; return 0; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index b030b567989b..6b8964c19f50 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -937,7 +937,6 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) spin_lock_init(&q->lock); q->hw_idx = mt76u_ac_to_hwq(dev, i); - q->qid = i; dev->phy.q_tx[i] = q; -- cgit v1.2.3 From abdb2b524b32292b78cb3aa41e9e64659e8a3a2f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 22 Jun 2022 05:17:38 +0800 Subject: mt76: mt7921: enable HW beacon filter not depending on PM flag The hardware beacon filter works whether or not the PM flag is set, so we drop redundant dependency checks on PM flags. Additionally, the patch implicitly allow the MT7921[E, S, U] to have a consistent configuration of the hardware beacon filter. Tested-by: Deren Wu Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index f2f29eca5d49..2ea20e9306fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -668,8 +668,7 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_ASSOC); - if (dev->pm.enable) - mt7921_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); + mt7921_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); } if (changed & BSS_CHANGED_ARP_FILTER) { -- cgit v1.2.3 From 4aa8e0a475e7630aa5862f7e7eda9f020e836294 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 22 Jun 2022 05:17:39 +0800 Subject: mt76: mt7921: enable HW beacon filter in the initialization stage The current driver has worked with HW beacon filter and connection monitor all the way, here we move the enablement into the initialization stage like other HW features being done to get rid of others are confused why these configurations would be changed at runtime. We still leave a way to turn off these offload features in debugfs knobs but that is just for debugging purposes. Tested-by: Deren Wu Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 16 +++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 5 ----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index af594b10f47f..cd960e23770f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -97,6 +97,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + ieee80211_hw_set(hw, CONNECTION_MONITOR); if (dev->pm.enable) ieee80211_hw_set(hw, CONNECTION_MONITOR); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 2ea20e9306fd..6891d655ab93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -352,6 +352,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, mtxq->wcid = idx; } + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; out: mt7921_mutex_release(dev); @@ -495,8 +496,21 @@ static void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt7921_dev *dev = priv; + struct ieee80211_hw *hw = mt76_hw(dev); + bool pm_enable = dev->pm.enable; + int err; - mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable); + err = mt7921_mcu_set_beacon_filter(dev, vif, pm_enable); + if (err < 0) + return; + + if (pm_enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + ieee80211_hw_set(hw, CONNECTION_MONITOR); + } else { + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); + } } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index c232319d2071..6139ba63f609 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -779,7 +779,6 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable) { - struct ieee80211_hw *hw = mt76_hw(dev); int err; if (enable) { @@ -787,8 +786,6 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, if (err) return err; - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; - ieee80211_hw_set(hw, CONNECTION_MONITOR); mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); return 0; @@ -798,8 +795,6 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, if (err) return err; - vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; - __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); return 0; -- cgit v1.2.3 From 81f302fdef1a721ce94c8db0f18ec7686fbc09c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 24 Jun 2022 12:06:29 +0200 Subject: mt76: mt7921: make mt7921_pci_driver static mt7921_pci_driver struct is only referenced in mt7921/pci.c so make it static. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 - drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index efeb82cbbe83..d2d45f381232 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -272,7 +272,6 @@ mt7921_hw_dev(struct ieee80211_hw *hw) mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) extern const struct ieee80211_ops mt7921_ops; -extern struct pci_driver mt7921_pci_driver; u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 23361a505daf..06af35250b3b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -489,7 +489,7 @@ static int mt7921_pci_resume(struct pci_dev *pdev) } #endif /* CONFIG_PM */ -struct pci_driver mt7921_pci_driver = { +static struct pci_driver mt7921_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7921_pci_device_table, .probe = mt7921_pci_probe, -- cgit v1.2.3 From 9dfb28e9bcd48235b685979e176ed4366a96d95a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 24 Jun 2022 12:08:29 +0200 Subject: mt76: connac: move tx initialization/cleanup in mt76_connac module Move mt76_connac_init_tx_queues and mt76_connac_tx_cleanup routines in mt76_connac module. This is a preliminary patch to add mt7990 chipset support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 9 +++------ drivers/net/wireless/mediatek/mt76/mt76_connac.h | 8 ++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 16 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 22 +++------------------- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 21 ++++----------------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 6 ------ 7 files changed, 35 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index ce19f57de475..f1914431ff7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -44,7 +44,7 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev) static int mt7615_init_tx_queues(struct mt7615_dev *dev) { - int ret, i; + int ret; ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7615_TXQ_FWDL, MT7615_TX_FWDL_RING_SIZE, MT_TX_RING_BASE); @@ -54,14 +54,11 @@ mt7615_init_tx_queues(struct mt7615_dev *dev) if (!is_mt7615(&dev->mt76)) return mt7622_init_tx_queues_multi(dev); - ret = mt76_init_tx_queue(&dev->mphy, 0, 0, MT7615_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE, + MT_TX_RING_BASE, 0); if (ret) return ret; - for (i = 1; i <= MT_TXQ_PSD ; i++) - dev->mphy.q_tx[i] = dev->mphy.q_tx[0]; - return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7615_TXQ_MCU, MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 9070162c6869..75afcb469d3c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -261,6 +261,12 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy, void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, struct mt76_wcid *wcid); +static inline void mt76_connac_tx_cleanup(struct mt76_dev *dev) +{ + dev->queue_ops->tx_cleanup(dev, dev->q_mcu[MT_MCUQ_WM], false); + dev->queue_ops->tx_cleanup(dev, dev->q_mcu[MT_MCUQ_WA], false); +} + static inline bool mt76_connac_pm_ref(struct mt76_phy *phy, struct mt76_connac_pm *pm) { @@ -323,6 +329,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) mutex_unlock(&dev->mutex); } +int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, + int ring_base, u32 flags); void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 3ab0dcde7351..8695956c57e4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -251,6 +251,22 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); +int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, + int ring_base, u32 flags) +{ + int i, err; + + err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags); + if (err < 0) + return err; + + for (i = 1; i <= MT_TXQ_PSD; i++) + phy->q_tx[i] = phy->q_tx[0]; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues); + static u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, bool beacon, bool mcast) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index f3d608d2d3b2..1c662e89b870 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -9,29 +9,14 @@ static int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base) { struct mt7915_dev *dev = phy->dev; - int i, err; if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { ring_base = MT_WED_TX_RING_BASE; idx -= MT_TXQ_ID(0); } - err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, ring_base, - MT_WED_Q_TX(idx)); - if (err < 0) - return err; - - for (i = 0; i <= MT_TXQ_PSD; i++) - phy->mt76->q_tx[i] = phy->mt76->q_tx[0]; - - return 0; -} - -static void -mt7915_tx_cleanup(struct mt7915_dev *dev) -{ - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false); + return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base, + MT_WED_Q_TX(idx)); } static int mt7915_poll_tx(struct napi_struct *napi, int budget) @@ -40,8 +25,7 @@ static int mt7915_poll_tx(struct napi_struct *napi, int budget) dev = container_of(napi, struct mt7915_dev, mt76.tx_napi); - mt7915_tx_cleanup(dev); - + mt76_connac_tx_cleanup(&dev->mt76); if (napi_complete_done(napi, 0)) mt7915_irq_enable(dev, MT_INT_TX_DONE_MCU); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 3a6b158b779e..d1f10f6d9adc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -5,20 +5,6 @@ #include "../dma.h" #include "mac.h" -static int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc) -{ - int i, err; - - err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, MT_TX_RING_BASE, 0); - if (err < 0) - return err; - - for (i = 0; i <= MT_TXQ_PSD; i++) - phy->mt76->q_tx[i] = phy->mt76->q_tx[0]; - - return 0; -} - static int mt7921_poll_tx(struct napi_struct *napi, int budget) { struct mt7921_dev *dev; @@ -31,7 +17,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget) return 0; } - mt7921_mcu_tx_cleanup(dev); + mt76_connac_tx_cleanup(&dev->mt76); if (napi_complete(napi)) mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL); mt76_connac_pm_unref(&dev->mphy, &dev->pm); @@ -250,8 +236,9 @@ int mt7921_dma_init(struct mt7921_dev *dev) return ret; /* init tx queue */ - ret = mt7921_init_tx_queues(&dev->phy, MT7921_TXQ_BAND0, - MT7921_TX_RING_SIZE); + ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, + MT7921_TX_RING_SIZE, + MT_TX_RING_BASE, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 49b7f0debc78..26b16bd53de7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -894,7 +894,7 @@ void mt7921_pm_wake_work(struct work_struct *work) napi_schedule(&mdev->napi[i]); local_bh_enable(); mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); - mt7921_mcu_tx_cleanup(dev); + mt76_connac_tx_cleanup(mdev); } if (test_bit(MT76_STATE_RUNNING, &mphy->state)) ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index d2d45f381232..c161031ac62a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -345,12 +345,6 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev) return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } -static inline void mt7921_mcu_tx_cleanup(struct mt7921_dev *dev) -{ - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false); -} - static inline void mt7921_skb_add_usb_sdio_hdr(struct mt7921_dev *dev, struct sk_buff *skb, int type) -- cgit v1.2.3 From af1c9bb282861386dfa73e8f2d9bdb0dde5db481 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 27 Jun 2022 07:27:05 +0800 Subject: mt76: mt7921: reduce log severity levels for informative messages Use dev_dbg instead for the diagnostic messages. Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 26b16bd53de7..a07e9a4c2ea3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -740,7 +740,7 @@ void mt7921_mac_reset_work(struct work_struct *work) struct mt76_connac_pm *pm = &dev->pm; int i; - dev_err(dev->mt76.dev, "chip reset\n"); + dev_dbg(dev->mt76.dev, "chip reset\n"); dev->hw_full_reset = true; ieee80211_stop_queues(hw); -- cgit v1.2.3 From 5163150a47af58e32940e5b223b97928ecae2b89 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 27 Jun 2022 07:27:06 +0800 Subject: mt76: mt7921: reduce the mutex lock scope during reset Reduce the mutex lock scope for reset to get rid of possible task hung e.g wpa_supplicant and to allow the user-space process to keep running during we need more retries to complete the reset. Reviewed-by: AngeloGioacchino Del Regno Suggested-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index a07e9a4c2ea3..47f0aa81ab02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -738,7 +738,7 @@ void mt7921_mac_reset_work(struct work_struct *work) reset_work); struct ieee80211_hw *hw = mt76_hw(dev); struct mt76_connac_pm *pm = &dev->pm; - int i; + int i, ret; dev_dbg(dev->mt76.dev, "chip reset\n"); dev->hw_full_reset = true; @@ -748,11 +748,14 @@ void mt7921_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); - mutex_lock(&dev->mt76.mutex); - for (i = 0; i < 10; i++) - if (!mt7921_dev_reset(dev)) + for (i = 0; i < 10; i++) { + mutex_lock(&dev->mt76.mutex); + ret = mt7921_dev_reset(dev); + mutex_unlock(&dev->mt76.mutex); + + if (!ret) break; - mutex_unlock(&dev->mt76.mutex); + } if (i == 10) dev_err(dev->mt76.dev, "chip reset failed\n"); -- cgit v1.2.3 From 7e6ffd5d5da93ee3936402058e12826669849611 Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Tue, 28 Jun 2022 13:55:28 +0800 Subject: mt76: mt7915 add ht mpdu density set ht mpdu density to 4 usec. Reviewed-by: Ryder Lee Signed-off-by: MeiChia Chiu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index c0f4f2053738..8521f7b2cff8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -369,15 +369,20 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) hw->max_tx_fragments = 4; - if (phy->mt76->cap.has_2ghz) + if (phy->mt76->cap.has_2ghz) { phy->mt76->sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; + phy->mt76->sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_4; + } if (phy->mt76->cap.has_5ghz) { phy->mt76->sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; + phy->mt76->sband_5g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_4; if (is_mt7915(&dev->mt76)) { phy->mt76->sband_5g.sband.vht_cap.cap |= -- cgit v1.2.3 From b146f238d1200f975b5f6d833ef70dab4f4474d4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 30 Jun 2022 14:55:18 +0200 Subject: mt76: add len parameter to __mt76_mcu_msg_alloc signature Introduce len to __mt76_mcu_msg_alloc signature in order to add the capability to specify two different value for allocation and copy length. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mcu.c | 10 ++++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 11 +++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index 914ee278e6e2..a8cafa39a56d 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -7,17 +7,19 @@ struct sk_buff * __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, - int data_len, gfp_t gfp) + int len, int data_len, gfp_t gfp) { const struct mt76_mcu_ops *ops = dev->mcu_ops; - int length = ops->headroom + data_len + ops->tailroom; struct sk_buff *skb; - skb = alloc_skb(length, gfp); + len = max_t(int, len, data_len); + len = ops->headroom + len + ops->tailroom; + + skb = alloc_skb(len, gfp); if (!skb) return NULL; - memset(skb->head, 0, length); + memset(skb->head, 0, len); skb_reserve(skb, ops->headroom); if (data && data_len) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f25f2dad43d8..0a86afbe89db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1343,12 +1343,12 @@ int mt76s_rd_rp(struct mt76_dev *dev, u32 base, struct sk_buff * __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, - int data_len, gfp_t gfp); + int len, int data_len, gfp_t gfp); static inline struct sk_buff * mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, int data_len) { - return __mt76_mcu_msg_alloc(dev, data, data_len, GFP_KERNEL); + return __mt76_mcu_msg_alloc(dev, data, data_len, data_len, GFP_KERNEL); } void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 6891d655ab93..7628204a5d99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1454,15 +1454,14 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw, if (!idx) return; - skb = __mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + - idx * sizeof(struct in6_addr), GFP_ATOMIC); - if (!skb) - return; - req_hdr.arpns.ips_num = idx; req_hdr.arpns.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv) + idx * sizeof(struct in6_addr)); - skb_put_data(skb, &req_hdr, sizeof(req_hdr)); + skb = __mt76_mcu_msg_alloc(&dev->mt76, &req_hdr, + sizeof(req_hdr) + idx * sizeof(struct in6_addr), + sizeof(req_hdr), GFP_ATOMIC); + if (!skb) + return; for (i = 0; i < idx; i++) skb_put_data(skb, &ns_addrs[i].in6_u, sizeof(struct in6_addr)); -- cgit v1.2.3 From fc8f841bacfc092d0ca0f3022dc9bdf8e570797b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 30 Jun 2022 15:56:13 +0200 Subject: mt76: introduce MT_RXQ_BAND2 and MT_RXQ_BAND2_WA in mt76_rxq_id Rename MT_RXQ_EXT in MT_RXQ_BAND1. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++- drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 47 +++++++++++++--------- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 8 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 8 ++-- .../net/wireless/mediatek/mt76/mt7915/testmode.c | 2 +- 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 0a86afbe89db..5fd9e5d29463 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -99,9 +99,11 @@ enum mt76_rxq_id { MT_RXQ_MAIN, MT_RXQ_MCU, MT_RXQ_MCU_WA, - MT_RXQ_EXT, - MT_RXQ_EXT_WA, + MT_RXQ_BAND1, + MT_RXQ_BAND1_WA, MT_RXQ_MAIN_WA, + MT_RXQ_BAND2, + MT_RXQ_BAND2_WA, __MT_RXQ_MAX }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 1c662e89b870..00aafc2422f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -49,8 +49,8 @@ static void mt7915_dma_config(struct mt7915_dev *dev) RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7915_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MCU, WFDMA1, MT_INT_RX_DONE_WM, MT7915_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA1, MT_INT_RX_DONE_WA, MT7915_RXQ_MCU_WA); - RXQ_CONFIG(MT_RXQ_EXT, WFDMA0, MT_INT_RX_DONE_BAND1, MT7915_RXQ_BAND1); - RXQ_CONFIG(MT_RXQ_EXT_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, MT7915_RXQ_MCU_WA_EXT); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7915_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, MT7915_RXQ_MCU_WA_EXT); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA1, MT_INT_RX_DONE_WA_MAIN, MT7915_RXQ_MCU_WA); TXQ_CONFIG(0, WFDMA1, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA1, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); @@ -61,8 +61,8 @@ static void mt7915_dma_config(struct mt7915_dev *dev) RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0_MT7916, MT7916_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7916_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7916_RXQ_MCU_WA); - RXQ_CONFIG(MT_RXQ_EXT, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); - RXQ_CONFIG(MT_RXQ_EXT_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, MT7916_RXQ_MCU_WA_EXT); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, MT7916_RXQ_MCU_WA_EXT); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN_MT7916, MT7916_RXQ_MCU_WA_MAIN); TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); @@ -84,24 +84,33 @@ static void __mt7915_dma_prefetch(struct mt7915_dev *dev, u32 ofs) mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0xc0, 0x4)); mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x100, 0x4)); - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x140, 0x4)); - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x180, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, + PREFETCH(0x140, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, + PREFETCH(0x180, 0x4)); if (!is_mt7915(&dev->mt76)) { - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x1c0, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, + PREFETCH(0x1c0, 0x4)); base = 0x40; } - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_EXT_WA) + ofs, PREFETCH(0x1c0 + base, 0x4)); - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x200 + base, 0x4)); - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_EXT) + ofs, PREFETCH(0x240 + base, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1_WA) + ofs, + PREFETCH(0x1c0 + base, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, + PREFETCH(0x200 + base, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1) + ofs, + PREFETCH(0x240 + base, 0x4)); /* for mt7915, the ring which is next the last * used ring must be initialized. */ if (is_mt7915(&dev->mt76)) { ofs += 0x4; - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x140, 0x0)); - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_EXT_WA) + ofs, PREFETCH(0x200 + base, 0x0)); - mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_EXT) + ofs, PREFETCH(0x280 + base, 0x0)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, + PREFETCH(0x140, 0x0)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1_WA) + ofs, + PREFETCH(0x200 + base, 0x0)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1) + ofs, + PREFETCH(0x280 + base, 0x0)); } } @@ -439,20 +448,20 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (dev->dbdc_support || dev->phy.band_idx) { /* rx data queue for band1 */ - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT], - MT_RXQ_ID(MT_RXQ_EXT), + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], + MT_RXQ_ID(MT_RXQ_BAND1), MT7915_RX_RING_SIZE, MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_EXT) + hif1_ofs); + MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs); if (ret) return ret; /* tx free notify event from WA for band1 */ - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT_WA], - MT_RXQ_ID(MT_RXQ_EXT_WA), + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], + MT_RXQ_ID(MT_RXQ_BAND1_WA), MT7915_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_EXT_WA) + hif1_ofs); + MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs); if (ret) return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 930fae7a0bd5..4499a630e8f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -591,8 +591,8 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) if (intr & MT_INT_RX(MT_RXQ_MAIN)) napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]); - if (intr & MT_INT_RX(MT_RXQ_EXT)) - napi_schedule(&dev->mt76.napi[MT_RXQ_EXT]); + if (intr & MT_INT_RX(MT_RXQ_BAND1)) + napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1]); if (intr & MT_INT_RX(MT_RXQ_MCU)) napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]); @@ -604,8 +604,8 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) (intr & MT_INT_RX(MT_RXQ_MAIN_WA))) napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN_WA]); - if (intr & MT_INT_RX(MT_RXQ_EXT_WA)) - napi_schedule(&dev->mt76.napi[MT_RXQ_EXT_WA]); + if (intr & MT_INT_RX(MT_RXQ_BAND1_WA)) + napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1_WA]); if (intr & MT_INT_MCU_CMD) { u32 val = mt76_rr(dev, MT_MCU_CMD); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index db63012e8aa9..b51571dbad52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -66,7 +66,7 @@ #define MT7915_MAX_TWT_AGRT 16 #define MT7915_MAX_STA_TWT_AGRT 8 #define MT7915_MIN_TWT_DUR 64 -#define MT7915_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 2) +#define MT7915_MAX_QUEUE (MT_RXQ_BAND2 + __MT_MCUQ_MAX + 2) struct mt7915_vif; struct mt7915_sta; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 77fd448beed7..2493c3ad3c56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -623,7 +623,7 @@ enum offs_rev { /* WFDMA COMMON */ #define __RXQ(q) ((q) + __MT_MCUQ_MAX) -#define __TXQ(q) (__RXQ(q) + __MT_RXQ_MAX) +#define __TXQ(q) (__RXQ(q) + MT_RXQ_BAND2) #define MT_Q_ID(q) (dev->q_id[(q)]) #define MT_Q_BASE(q) ((dev->wfdma_mask >> (q)) & 0x1 ? \ @@ -639,7 +639,7 @@ enum offs_rev { #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q)* 0x4) -#define MT_RXQ_EXT_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ +#define MT_RXQ_BAND1_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ MT_RXQ_ID(q)* 0x4) #define MT_TXQ_EXT_CTRL(q) (MT_Q_BASE(__TXQ(q)) + 0x600 + \ MT_TXQ_ID(q)* 0x4) @@ -671,8 +671,8 @@ enum offs_rev { #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ MT_INT_RX(MT_RXQ_MAIN_WA)) -#define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_EXT) | \ - MT_INT_RX(MT_RXQ_EXT_WA) | \ +#define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ + MT_INT_RX(MT_RXQ_BAND1_WA) | \ MT_INT_RX(MT_RXQ_MAIN_WA)) #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index 0f5c1e5bffe1..efb9bb8231e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -775,7 +775,7 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) fcs_err = is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); - q = phy->band_idx ? MT_RXQ_EXT : MT_RXQ_MAIN; + q = phy->band_idx ? MT_RXQ_BAND1 : MT_RXQ_MAIN; mphy->test.rx_stats.packets[q] += fcs_err; mphy->test.rx_stats.fcs_error[q] += fcs_err; -- cgit v1.2.3 From 128c9b7d6235b960e367944cad352790f76862eb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Jul 2022 09:02:19 +0200 Subject: mt76: add phy_idx in mt76_rx_status Introduce phy_idx mt76_rx_status instead of ext_idx. This is a preliminary patch to add newer chipset support Co-developed-by: Bo Jiao Signed-off-by: Bo Jiao Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index cb41f54bdd1c..331e92e72672 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -739,7 +739,7 @@ static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy); + struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { dev_kfree_skb(skb); @@ -1015,7 +1015,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, sizeof(mstat.chain_signal)); *sta = wcid_to_sta(mstat.wcid); - *hw = mt76_phy_hw(dev, mstat.ext_phy); + *hw = mt76_phy_hw(dev, mstat.phy_idx); } static void @@ -1178,7 +1178,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; bool ps; - hw = mt76_phy_hw(dev, status->ext_phy); + hw = mt76_phy_hw(dev, status->phy_idx); if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && !(status->flag & RX_FLAG_8023)) { sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 5fd9e5d29463..72390707ee73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -574,7 +574,7 @@ struct mt76_rx_status { u8 iv[6]; - u8 ext_phy:1; + u8 phy_idx:2; u8 aggr:1; u8 qos_ctl; u16 seqno; @@ -998,17 +998,18 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, } static inline struct mt76_phy * -mt76_dev_phy(struct mt76_dev *dev, bool phy_ext) +mt76_dev_phy(struct mt76_dev *dev, u8 phy_idx) { - if (phy_ext && dev->phy2) + if (phy_idx && dev->phy2) return dev->phy2; + return &dev->phy; } static inline struct ieee80211_hw * -mt76_phy_hw(struct mt76_dev *dev, bool phy_ext) +mt76_phy_hw(struct mt76_dev *dev, u8 phy_idx) { - return mt76_dev_phy(dev, phy_ext)->hw; + return mt76_dev_phy(dev, phy_idx)->hw; } static inline u8 * diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 372862768bb4..1eb9d286091d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -500,7 +500,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) if (phy_idx == 1 && phy2) { mphy = dev->mt76.phy2; phy = phy2; - status->ext_phy = true; + status->phy_idx = phy_idx; } if (!mt7615_firmware_offload(dev) && chfreq != phy->chfreq) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 757b4e1c3164..718025518bab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -247,7 +247,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return -EINVAL; phy = mphy->priv; - status->ext_phy = true; + status->phy_idx = 1; } if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) -- cgit v1.2.3 From dc44c45c8cd062292c45626b5c941397a0ff5ead Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Jul 2022 09:02:20 +0200 Subject: mt76: introduce phys array in mt76_dev structure Introduce phys array in mt76_dev structure to reference mt76_phy supported by the chipset. This is a preliminary patch to introduce newer chipset support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 13 +++++-- drivers/net/wireless/mediatek/mt76/mac80211.c | 9 +++-- drivers/net/wireless/mediatek/mt76/mt76.h | 43 ++++++++++++++-------- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 36 ++++++++++-------- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 26 ++++++------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 +- .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 14 ++++--- .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 8 ++-- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 20 +++++----- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 16 ++++---- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- drivers/net/wireless/mediatek/mt76/tx.c | 42 ++++++++++++++------- 14 files changed, 142 insertions(+), 97 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f22273cde1a8..40cb91097b2e 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -791,10 +791,15 @@ void mt76_dma_cleanup(struct mt76_dev *dev) mt76_worker_disable(&dev->tx_worker); netif_napi_del(&dev->tx_napi); - for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) { - mt76_dma_tx_cleanup(dev, dev->phy.q_tx[i], true); - if (dev->phy2) - mt76_dma_tx_cleanup(dev, dev->phy2->q_tx[i], true); + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { + struct mt76_phy *phy = dev->phys[i]; + int j; + + if (!phy) + continue; + + for (j = 0; j < ARRAY_SIZE(phy->q_tx); j++) + mt76_dma_tx_cleanup(dev, phy->q_tx[j], true); } for (i = 0; i < ARRAY_SIZE(dev->q_mcu); i++) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 331e92e72672..4d97fa48996b 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -452,7 +452,7 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) struct mt76_phy * mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, - const struct ieee80211_ops *ops) + const struct ieee80211_ops *ops, u8 band_idx) { struct ieee80211_hw *hw; unsigned int phy_size; @@ -467,6 +467,7 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, phy->dev = dev; phy->hw = hw; phy->priv = hw->priv + phy_size; + phy->band_idx = band_idx; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->interface_modes = @@ -519,7 +520,7 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht, if (ret) return ret; - phy->dev->phy2 = phy; + phy->dev->phys[phy->band_idx] = phy; return 0; } @@ -531,7 +532,7 @@ void mt76_unregister_phy(struct mt76_phy *phy) mt76_tx_status_check(dev, true); ieee80211_unregister_hw(phy->hw); - dev->phy2 = NULL; + dev->phys[phy->band_idx] = NULL; } EXPORT_SYMBOL_GPL(mt76_unregister_phy); @@ -558,6 +559,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size, phy = &dev->phy; phy->dev = dev; phy->hw = hw; + phy->band_idx = MT_BAND0; + dev->phys[phy->band_idx] = phy; spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 72390707ee73..d3b793e1e8f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -107,6 +107,13 @@ enum mt76_rxq_id { __MT_RXQ_MAX }; +enum mt76_band_id { + MT_BAND0, + MT_BAND1, + MT_BAND2, + __MT_MAX_BAND +}; + enum mt76_cipher_type { MT_CIPHER_NONE, MT_CIPHER_WEP40, @@ -661,6 +668,7 @@ struct mt76_phy { void *priv; unsigned long state; + u8 band_idx; struct mt76_queue *q_tx[__MT_TXQ_MAX]; @@ -700,8 +708,7 @@ struct mt76_phy { struct mt76_dev { struct mt76_phy phy; /* must be first */ - - struct mt76_phy *phy2; + struct mt76_phy *phys[__MT_MAX_BAND]; struct ieee80211_hw *hw; @@ -891,7 +898,7 @@ mt76_wcid_hw(struct mt76_dev *dev, u16 wcid) { if (wcid <= MT76_N_WCIDS && mt76_wcid_mask_test(dev->wcid_phy_mask, wcid)) - return dev->phy2->hw; + return dev->phys[MT_BAND1]->hw; return dev->phy.hw; } @@ -946,7 +953,8 @@ void mt76_free_device(struct mt76_dev *dev); void mt76_unregister_phy(struct mt76_phy *phy); struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, - const struct ieee80211_ops *ops); + const struct ieee80211_ops *ops, + u8 band_idx); int mt76_register_phy(struct mt76_phy *phy, bool vht, struct ieee80211_rate *rates, int n_rates); @@ -1000,8 +1008,9 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, static inline struct mt76_phy * mt76_dev_phy(struct mt76_dev *dev, u8 phy_idx) { - if (phy_idx && dev->phy2) - return dev->phy2; + if ((phy_idx == MT_BAND1 && dev->phys[phy_idx]) || + (phy_idx == MT_BAND2 && dev->phys[phy_idx])) + return dev->phys[phy_idx]; return &dev->phy; } @@ -1120,13 +1129,17 @@ static inline bool mt76_is_testmode_skb(struct mt76_dev *dev, struct ieee80211_hw **hw) { #ifdef CONFIG_NL80211_TESTMODE - if (skb == dev->phy.test.tx_skb) - *hw = dev->phy.hw; - else if (dev->phy2 && skb == dev->phy2->test.tx_skb) - *hw = dev->phy2->hw; - else - return false; - return true; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { + struct mt76_phy *phy = dev->phys[i]; + + if (phy && skb == phy->test.tx_skb) { + *hw = dev->phys[i]->hw; + return true; + } + } + return false; #else return false; #endif @@ -1244,8 +1257,8 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hw *hw = dev->phy.hw; - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phy2) - hw = dev->phy2->hw; + if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phys[MT_BAND1]) + hw = dev->phys[MT_BAND1]->hw; info->hw_queue &= ~MT_TX_HW_QUEUE_EXT_PHY; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 3e076092714e..07a1fea94f66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -459,7 +459,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) return 0; mt7615_cap_dbdc_enable(dev); - mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops); + mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops, MT_BAND1); if (!mphy) return -ENOMEM; @@ -509,7 +509,7 @@ EXPORT_SYMBOL_GPL(mt7615_register_ext_phy); void mt7615_unregister_ext_phy(struct mt7615_dev *dev) { struct mt7615_phy *phy = mt7615_ext_phy(dev); - struct mt76_phy *mphy = dev->mt76.phy2; + struct mt76_phy *mphy = dev->mt76.phys[MT_BAND1]; if (!phy) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 1eb9d286091d..d0a13e78d7f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -109,6 +109,7 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, void mt7615_mac_reset_counters(struct mt7615_dev *dev) { + struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; int i; for (i = 0; i < 4; i++) { @@ -118,8 +119,8 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); dev->mt76.phy.survey_time = ktime_get_boottime(); - if (dev->mt76.phy2) - dev->mt76.phy2->survey_time = ktime_get_boottime(); + if (mphy_ext) + mphy_ext->survey_time = ktime_get_boottime(); /* reset airtime counters */ mt76_rr(dev, MT_MIB_SDR9(0)); @@ -336,9 +337,9 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7615_phy *phy = &dev->phy; - struct mt7615_phy *phy2 = dev->mt76.phy2 ? dev->mt76.phy2->priv : NULL; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; + struct mt7615_phy *phy2; __le32 *rxd = (__le32 *)skb->data; u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); @@ -355,6 +356,8 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) memset(status, 0, sizeof(*status)); chfreq = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1); + + phy2 = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; if (!phy2) phy_idx = 0; else if (phy2->chfreq == phy->chfreq) @@ -498,7 +501,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) } if (phy_idx == 1 && phy2) { - mphy = dev->mt76.phy2; + mphy = dev->mt76.phys[MT_BAND1]; phy = phy2; status->phy_idx = phy_idx; } @@ -747,8 +750,8 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, tx_count = msta->rate_count; } - if (ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (ext_phy && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; @@ -1386,8 +1389,8 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, if (sta->rate_probe) { struct mt7615_phy *phy = &dev->phy; - if (sta->wcid.ext_phy && dev->mt76.phy2) - phy = dev->mt76.phy2->priv; + if (sta->wcid.ext_phy && dev->mt76.phys[MT_BAND1]) + phy = dev->mt76.phys[MT_BAND1]->priv; mt7615_mac_set_rates(phy, sta, NULL, sta->rates); } @@ -1429,8 +1432,8 @@ out: fallthrough; case MT_PHY_TYPE_OFDM: mphy = &dev->mphy; - if (sta->wcid.ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (sta->wcid.ext_phy && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; @@ -1537,8 +1540,8 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) if (wcidx >= MT7615_WTBL_STA || !sta) goto out; - if (wcid->ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (wcid->ext_phy && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; if (mt7615_fill_txs(dev, msta, &info, txs_data)) ieee80211_tx_status_noskb(mphy->hw, sta, &info); @@ -1955,6 +1958,7 @@ mt7615_phy_update_channel(struct mt76_phy *mphy, int idx) static void mt7615_update_survey(struct mt7615_dev *dev) { struct mt76_dev *mdev = &dev->mt76; + struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1]; ktime_t cur_time; /* MT7615 can only update both phys simultaneously @@ -1962,14 +1966,14 @@ static void mt7615_update_survey(struct mt7615_dev *dev) */ mt7615_phy_update_channel(&mdev->phy, 0); - if (mdev->phy2) - mt7615_phy_update_channel(mdev->phy2, 1); + if (mphy_ext) + mt7615_phy_update_channel(mphy_ext, 1); cur_time = ktime_get_boottime(); mt76_update_survey_active_time(&mdev->phy, cur_time); - if (mdev->phy2) - mt76_update_survey_active_time(mdev->phy2, cur_time); + if (mphy_ext) + mt76_update_survey_active_time(mphy_ext, cur_time); /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index e8b1be818c30..9a1696da0cc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -369,7 +369,7 @@ mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb) return; if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx)) - mphy = dev->mt76.phy2; + mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, @@ -388,8 +388,8 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb) !r->constant_prf_detected && !r->staggered_prf_detected) return; - if (r->band_idx && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (r->band_idx && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC) return; @@ -448,8 +448,8 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) struct mt7615_phy *phy; struct mt76_phy *mphy; - if (*seq_num & BIT(7) && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (*seq_num & BIT(7) && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; @@ -474,8 +474,8 @@ mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); event = (struct mt7615_roc_tlv *)skb->data; - if (event->dbdc_band && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (event->dbdc_band && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; @@ -499,8 +499,8 @@ mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb) skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); event = (struct mt76_connac_beacon_loss_event *)skb->data; - if (band_idx && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (band_idx && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; @@ -520,8 +520,8 @@ mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); event = (struct mt76_connac_mcu_bss_event *)skb->data; - if (band_idx && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if (band_idx && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; @@ -2330,7 +2330,7 @@ int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy) .bw = mt7615_mcu_chan_bw(chandef), .band = chandef->center_freq1 > 4000, - .dbdc_en = !!dev->mt76.phy2, + .dbdc_en = !!dev->mt76.phys[MT_BAND1], }; u16 center_freq = chandef->center_freq1; int freq_idx; @@ -2451,7 +2451,7 @@ int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy) .bw = mt7615_mcu_chan_bw(chandef), .band = chandef->center_freq1 > 4000, - .dbdc_en = !!dev->mt76.phy2, + .dbdc_en = !!dev->mt76.phys[MT_BAND1], }; u16 center_freq = chandef->center_freq1; int freq_idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 25880d1a50da..060d52c81d9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -345,7 +345,7 @@ mt7615_hw_dev(struct ieee80211_hw *hw) static inline struct mt7615_phy * mt7615_ext_phy(struct mt7615_dev *dev) { - struct mt76_phy *phy = dev->mt76.phy2; + struct mt76_phy *phy = dev->mt76.phys[MT_BAND1]; if (!phy) return NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 26211c63dac4..2ec8f2beb373 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -78,8 +78,8 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) { struct mt7615_phy *phy = &dev->phy; - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2) - phy = mdev->phy2->priv; + if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phys[MT_BAND1]) + phy = mdev->phys[MT_BAND1]->priv; spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(phy, msta, &info->control.rates[0], @@ -182,16 +182,18 @@ mt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) static void mt7615_update_beacons(struct mt7615_dev *dev) { + struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; + ieee80211_iterate_active_interfaces(dev->mt76.hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_update_vif_beacon, dev->mt76.hw); - if (!dev->mt76.phy2) + if (!mphy_ext) return; - ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw, + ieee80211_iterate_active_interfaces(mphy_ext->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt7615_update_vif_beacon, dev->mt76.phy2->hw); + mt7615_update_vif_beacon, mphy_ext->hw); } void mt7615_mac_reset_work(struct work_struct *work) @@ -203,7 +205,7 @@ void mt7615_mac_reset_work(struct work_struct *work) int i; dev = container_of(work, struct mt7615_dev, reset_work); - ext_phy = dev->mt76.phy2; + ext_phy = dev->mt76.phys[MT_BAND1]; phy2 = ext_phy ? ext_phy->priv : NULL; if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_PDMA)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 8695956c57e4..fb22fffd721a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -474,8 +474,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, band_idx = mvif->band_idx; } - if (ext_phy && dev->phy2) - mphy = dev->phy2; + if (ext_phy && dev->phys[MT_BAND1]) + mphy = dev->phys[MT_BAND1]; if (inband_disc) { p_fmt = MT_TX_TYPE_FW; @@ -597,8 +597,8 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, fallthrough; case MT_PHY_TYPE_OFDM: mphy = &dev->phy; - if (wcid->ext_phy && dev->phy2) - mphy = dev->phy2; + if (wcid->ext_phy && dev->phys[MT_BAND1]) + mphy = dev->phys[MT_BAND1]; if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 8521f7b2cff8..cc2aac86bcfb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -504,7 +504,7 @@ mt7915_alloc_ext_phy(struct mt7915_dev *dev) if (!dev->dbdc_support) return NULL; - mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops); + mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops, MT_BAND1); if (!mphy) return ERR_PTR(-ENOMEM); @@ -1038,7 +1038,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy) static void mt7915_unregister_ext_phy(struct mt7915_dev *dev) { struct mt7915_phy *phy = mt7915_ext_phy(dev); - struct mt76_phy *mphy = dev->mt76.phy2; + struct mt76_phy *mphy = dev->mt76.phys[MT_BAND1]; if (!phy) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 718025518bab..a66236ba60fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -242,7 +242,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) memset(status, 0, sizeof(*status)); if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->band_idx) { - mphy = dev->mt76.phy2; + mphy = dev->mt76.phys[MT_BAND1]; if (!mphy) return -EINVAL; @@ -668,8 +668,8 @@ void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76_phy *mphy = &dev->phy; - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phy2) - mphy = dev->phy2; + if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phys[MT_BAND1]) + mphy = dev->phys[MT_BAND1]; mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, qid, changed); @@ -853,7 +853,7 @@ static void mt7915_mac_tx_free_prepare(struct mt7915_dev *dev) { struct mt76_dev *mdev = &dev->mt76; - struct mt76_phy *mphy_ext = mdev->phy2; + struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1]; /* clean DMA queues and unmap buffers first */ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); @@ -1275,22 +1275,24 @@ mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) static void mt7915_update_beacons(struct mt7915_dev *dev) { + struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; + ieee80211_iterate_active_interfaces(dev->mt76.hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7915_update_vif_beacon, dev->mt76.hw); - if (!dev->mt76.phy2) + if (!mphy_ext) return; - ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw, + ieee80211_iterate_active_interfaces(mphy_ext->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt7915_update_vif_beacon, dev->mt76.phy2->hw); + mt7915_update_vif_beacon, mphy_ext->hw); } static void mt7915_dma_reset(struct mt7915_dev *dev) { - struct mt76_phy *mphy_ext = dev->mt76.phy2; + struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); int i; @@ -1377,7 +1379,7 @@ void mt7915_mac_reset_work(struct work_struct *work) int i; dev = container_of(work, struct mt7915_dev, reset_work); - ext_phy = dev->mt76.phy2; + ext_phy = dev->mt76.phys[MT_BAND1]; phy2 = ext_phy ? ext_phy->priv : NULL; if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 4a841bcead0e..601b1a3709db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -228,8 +228,8 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) c = (struct mt7915_mcu_csa_notify *)skb->data; - if ((c->band_idx && !dev->phy.band_idx) && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if ((c->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, @@ -247,8 +247,8 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) return; - if ((t->ctrl.band_idx && !dev->phy.band_idx) && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if ((t->ctrl.band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; phy = (struct mt7915_phy *)mphy->priv; phy->throttle_state = t->ctrl.duty.duty_cycle; @@ -262,8 +262,8 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) r = (struct mt7915_mcu_rdd_report *)skb->data; - if ((r->band_idx && !dev->phy.band_idx) && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if ((r->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; if (r->band_idx == MT_RX_SEL2) cfg80211_background_radar_event(mphy->hw->wiphy, @@ -319,8 +319,8 @@ mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) b = (struct mt7915_mcu_bcc_notify *)skb->data; - if ((b->band_idx && !dev->phy.band_idx) && dev->mt76.phy2) - mphy = dev->mt76.phy2; + if ((b->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b51571dbad52..54ef2a12a443 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -388,7 +388,7 @@ mt7915_hw_dev(struct ieee80211_hw *hw) static inline struct mt7915_phy * mt7915_ext_phy(struct mt7915_dev *dev) { - struct mt76_phy *phy = dev->mt76.phy2; + struct mt76_phy *phy = dev->mt76.phys[MT_BAND1]; if (!phy) return NULL; diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 13c5e78dd39d..6d26e872d4ba 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -585,15 +585,25 @@ EXPORT_SYMBOL_GPL(mt76_txq_schedule_all); void mt76_tx_worker_run(struct mt76_dev *dev) { - mt76_txq_schedule_all(&dev->phy); - if (dev->phy2) - mt76_txq_schedule_all(dev->phy2); + struct mt76_phy *phy; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { + phy = dev->phys[i]; + if (!phy) + continue; + + mt76_txq_schedule_all(phy); + } #ifdef CONFIG_NL80211_TESTMODE - if (dev->phy.test.tx_pending) - mt76_testmode_tx_pending(&dev->phy); - if (dev->phy2 && dev->phy2->test.tx_pending) - mt76_testmode_tx_pending(dev->phy2); + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { + phy = dev->phys[i]; + if (!phy || !phy->test.tx_pending) + continue; + + mt76_testmode_tx_pending(phy); + } #endif } EXPORT_SYMBOL_GPL(mt76_tx_worker_run); @@ -696,17 +706,23 @@ EXPORT_SYMBOL_GPL(mt76_queue_tx_complete); void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked) { - struct mt76_phy *phy = &dev->phy, *phy2 = dev->phy2; - struct mt76_queue *q, *q2 = NULL; + struct mt76_phy *phy = &dev->phy; + struct mt76_queue *q = phy->q_tx[0]; - q = phy->q_tx[0]; if (blocked == q->blocked) return; q->blocked = blocked; - if (phy2) { - q2 = phy2->q_tx[0]; - q2->blocked = blocked; + + phy = dev->phys[MT_BAND1]; + if (phy) { + q = phy->q_tx[0]; + q->blocked = blocked; + } + phy = dev->phys[MT_BAND2]; + if (phy) { + q = phy->q_tx[0]; + q->blocked = blocked; } if (!blocked) -- cgit v1.2.3 From a1a99d7bddad6b8a5ae12d253b3c6a44bd7c7e7b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Jul 2022 09:02:21 +0200 Subject: mt76: add phy_idx to mt76_wcid Introduce phy_idx to mt76_wcid structure instead of ext_phy. This is a preliminary patch to add newer chipset support. Co-developed-by: Bo Jiao Signed-off-by: Bo Jiao Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 12 ++++++------ drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4d97fa48996b..0e7bd4a67ad4 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1295,10 +1295,11 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); static int -mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool ext_phy) +mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + struct mt76_dev *dev = phy->dev; int ret; int i; @@ -1319,9 +1320,9 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, } ewma_signal_init(&wcid->rssi); - if (ext_phy) + if (phy->band_idx == MT_BAND1) mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); - wcid->ext_phy = ext_phy; + wcid->phy_idx = phy->band_idx; rcu_assign_pointer(dev->wcid[wcid->idx], wcid); mt76_packet_id_init(wcid); @@ -1366,11 +1367,10 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) - return mt76_sta_add(dev, vif, sta, ext_phy); + return mt76_sta_add(phy, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d3b793e1e8f0..21eec8ce9bd9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -287,8 +287,8 @@ struct mt76_wcid { u8 hw_key_idx2; u8 sta:1; - u8 ext_phy:1; u8 amsdu:1; + u8 phy_idx:2; u8 rx_check_pn; u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d0a13e78d7f4..36b42dcac102 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1389,7 +1389,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, if (sta->rate_probe) { struct mt7615_phy *phy = &dev->phy; - if (sta->wcid.ext_phy && dev->mt76.phys[MT_BAND1]) + if (sta->wcid.phy_idx && dev->mt76.phys[MT_BAND1]) phy = dev->mt76.phys[MT_BAND1]->priv; mt7615_mac_set_rates(phy, sta, NULL, sta->rates); @@ -1432,7 +1432,7 @@ out: fallthrough; case MT_PHY_TYPE_OFDM: mphy = &dev->mphy; - if (sta->wcid.ext_phy && dev->mt76.phys[MT_BAND1]) + if (sta->wcid.phy_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) @@ -1540,7 +1540,7 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) if (wcidx >= MT7615_WTBL_STA || !sta) goto out; - if (wcid->ext_phy && dev->mt76.phys[MT_BAND1]) + if (wcid->phy_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (mt7615_fill_txs(dev, msta, &info, txs_data)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 28bc76c8e8e7..789271a8d65f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -224,7 +224,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; + mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mt76_packet_id_init(&mvif->sta.wcid); @@ -629,7 +629,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; - msta->wcid.ext_phy = mvif->mt76.band_idx; + msta->wcid.phy_idx = mvif->mt76.band_idx; phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy; err = mt76_connac_pm_wake(phy->mt76, &dev->pm); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index fb22fffd721a..f1d51b572da4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -597,7 +597,7 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, fallthrough; case MT_PHY_TYPE_OFDM: mphy = &dev->phy; - if (wcid->ext_phy && dev->phys[MT_BAND1]) + if (wcid->phy_idx == MT_BAND1 && dev->phys[MT_BAND1]) mphy = dev->phys[MT_BAND1]; if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index b1a5aab7a984..dbd5b29309d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -227,7 +227,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, INIT_LIST_HEAD(&mvif->sta.rc_list); INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.ext_phy = ext_phy; + mvif->sta.wcid.phy_idx = ext_phy; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; mt76_packet_id_init(&mvif->sta.wcid); @@ -660,7 +660,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; - msta->wcid.ext_phy = ext_phy; + msta->wcid.phy_idx = ext_phy; msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; msta->jiffies = jiffies; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 7628204a5d99..91671eab7b55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -336,7 +336,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; + mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; mt76_packet_id_init(&mvif->sta.wcid); @@ -711,7 +711,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; - msta->wcid.ext_phy = mvif->mt76.band_idx; + msta->wcid.phy_idx = mvif->mt76.band_idx; msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; msta->last_txs = jiffies; -- cgit v1.2.3 From a062f00173913ec244053a7fac35544e917bd6f9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Jul 2022 09:02:22 +0200 Subject: mt76: convert MT_TX_HW_QUEUE_EXT_PHY to MT_TX_HW_QUEUE_PHY Report phy_indx in tx_info->hw_queue. This is a preliminary patch to add newer chipset support Co-developed-by: Bo Jiao Signed-off-by: Bo Jiao Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 10 ++++------ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 9 +++------ drivers/net/wireless/mediatek/mt76/testmode.c | 5 +---- drivers/net/wireless/mediatek/mt76/tx.c | 9 ++------- 9 files changed, 23 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 21eec8ce9bd9..91685ac5a257 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -262,7 +262,7 @@ enum mt76_wcid_flags { #define MT76_N_WCIDS 544 /* stored in ieee80211_tx_info::hw_queue */ -#define MT_TX_HW_QUEUE_EXT_PHY BIT(3) +#define MT_TX_HW_QUEUE_PHY GENMASK(3, 2) DECLARE_EWMA(signal, 10, 8); @@ -1255,12 +1255,10 @@ static inline struct ieee80211_hw * mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = dev->phy.hw; + u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; + struct ieee80211_hw *hw = mt76_phy_hw(dev, phy_idx); - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phys[MT_BAND1]) - hw = dev->phys[MT_BAND1]->hw; - - info->hw_queue &= ~MT_TX_HW_QUEUE_EXT_PHY; + info->hw_queue &= ~MT_TX_HW_QUEUE_PHY; return hw; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 36b42dcac102..ad6c7d632eed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -727,7 +727,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; - bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; + u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; bool multicast = is_multicast_ether_addr(hdr->addr1); struct ieee80211_vif *vif = info->control.vif; bool is_mmio = mt76_is_mmio(&dev->mt76); @@ -750,7 +750,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, tx_count = msta->rate_count; } - if (ext_phy && dev->mt76.phys[MT_BAND1]) + if (phy_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; @@ -758,10 +758,10 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, if (beacon) { p_fmt = MT_TX_TYPE_FW; - q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0; + q_idx = phy_idx ? MT_LMAC_BCN1 : MT_LMAC_BCN0; } else if (qid >= MT_TXQ_PSD) { p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; - q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; + q_idx = phy_idx ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; } else { p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT7615_MAX_WMM_SETS + diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 9a1696da0cc9..3dac76e6df4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -708,10 +708,8 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, return -EINVAL; } - if (mvif->mt76.band_idx) { - info = IEEE80211_SKB_CB(skb); - info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; - } + info = IEEE80211_SKB_CB(skb); + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mvif->mt76.band_idx); mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL, 0, NULL, 0, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 2ec8f2beb373..0019890fdb78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -77,8 +77,9 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) { struct mt7615_phy *phy = &dev->phy; + u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phys[MT_BAND1]) + if (phy_idx && mdev->phys[MT_BAND1]) phy = mdev->phys[MT_BAND1]->priv; spin_lock_bh(&dev->mt76.lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index f1d51b572da4..18dea8e1fb20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -455,7 +455,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, enum mt76_txq_id qid, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; + u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->phy; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0; @@ -474,7 +474,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, band_idx = mvif->band_idx; } - if (ext_phy && dev->phys[MT_BAND1]) + if (phy_idx && dev->phys[MT_BAND1]) mphy = dev->phys[MT_BAND1]; if (inband_disc) { @@ -502,7 +502,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); if (!is_mt7921(dev)) val |= MT_TXD1_VTA; - if (ext_phy || band_idx) + if (phy_idx || band_idx) val |= MT_TXD1_TGID; txwi[1] = cpu_to_le32(val); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index a66236ba60fd..60ae834d95a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -666,9 +666,10 @@ void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, enum mt76_txq_id qid, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; struct mt76_phy *mphy = &dev->phy; - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phys[MT_BAND1]) + if (phy_idx && dev->phys[MT_BAND1]) mphy = dev->phys[MT_BAND1]; mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, qid, changed); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 601b1a3709db..f83067961945 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1932,8 +1932,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi info->control.vif = vif; info->band = band; - if (ext_phy) - info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy); len = sizeof(*discov) + MT_TXD_SIZE + skb->len; len = (len & 0x3) ? ((len | 0x3) + 1) : len; @@ -2002,10 +2001,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -EINVAL; } - if (ext_phy) { - info = IEEE80211_SKB_CB(skb); - info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; - } + info = IEEE80211_SKB_CB(skb); + info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy); mt7915_mcu_beacon_check_caps(phy, vif, skb); diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index 47ac0ca1af32..71fd3fbfa7d2 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -101,7 +101,6 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS; struct mt76_testmode_data *td = &phy->test; - bool ext_phy = phy != &phy->dev->phy; struct sk_buff **frag_tail, *head; struct ieee80211_tx_info *info; struct ieee80211_hdr *hdr; @@ -136,9 +135,7 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) IEEE80211_TX_CTL_NO_ACK | IEEE80211_TX_CTL_NO_PS_BUFFER; - if (ext_phy) - info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; - + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); frag_tail = &skb_shinfo(head)->frag_list; for (i = 0; i < nfrags; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 6d26e872d4ba..e67cc7909bce 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -310,7 +310,6 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct mt76_queue *q; int qid = skb_get_queue_mapping(skb); - bool ext_phy = phy != &dev->phy; if (mt76_testmode_enabled(phy)) { ieee80211_free_txskb(phy->hw, skb); @@ -333,9 +332,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, ieee80211_get_tx_rates(info->control.vif, sta, skb, info->control.rates, 1); - if (ext_phy) - info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; - + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); q = phy->q_tx[qid]; spin_lock_bh(&q->lock); @@ -350,7 +347,6 @@ mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); struct ieee80211_tx_info *info; - bool ext_phy = phy != &phy->dev->phy; struct sk_buff *skb; skb = ieee80211_tx_dequeue(phy->hw, txq); @@ -358,8 +354,7 @@ mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq) return NULL; info = IEEE80211_SKB_CB(skb); - if (ext_phy) - info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); return skb; } -- cgit v1.2.3 From 8950a62f19c9fe009a451aeea08ab740354549be Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Jul 2022 09:02:23 +0200 Subject: mt76: get rid of mt76_wcid_hw routine mt76_wcid_hw() is no longer used. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 91685ac5a257..4da77d47b0a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -893,16 +893,6 @@ extern struct ieee80211_rate mt76_rates[12]; #define mt76_hw(dev) (dev)->mphy.hw -static inline struct ieee80211_hw * -mt76_wcid_hw(struct mt76_dev *dev, u16 wcid) -{ - if (wcid <= MT76_N_WCIDS && - mt76_wcid_mask_test(dev->wcid_phy_mask, wcid)) - return dev->phys[MT_BAND1]->hw; - - return dev->phy.hw; -} - bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, int timeout); -- cgit v1.2.3 From 0a14c1d0113f121151edf34333cdf212dd209190 Mon Sep 17 00:00:00 2001 From: Liang He Date: Mon, 4 Jul 2022 16:34:20 +0800 Subject: mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init() We should use of_node_put() for the reference 'np' returned by of_get_child_by_name() which will increase the refcount. Fixes: 17f1de56df05 ("mt76: add common code shared between multiple chipsets") Signed-off-by: Liang He Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 0e7bd4a67ad4..253cbc1956d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -216,6 +216,7 @@ static int mt76_led_init(struct mt76_dev *dev) if (!of_property_read_u32(np, "led-sources", &led_pin)) dev->led_pin = led_pin; dev->led_al = of_property_read_bool(np, "led-active-low"); + of_node_put(np); } return led_classdev_register(dev->dev, &dev->led_cdev); -- cgit v1.2.3 From 3bd53ea02d77917c2314ec7be9e2d05be22f87d3 Mon Sep 17 00:00:00 2001 From: Liang He Date: Mon, 4 Jul 2022 16:34:21 +0800 Subject: mediatek: mt76: eeprom: fix missing of_node_put() in mt76_find_power_limits_node() We should use of_node_put() for the reference 'np' returned by of_get_child_by_name() which will increase the refcount. Fixes: 22b980badc0f ("mt76: add functions for parsing rate power limits from DT") Signed-off-by: Liang He Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index a499861918fa..9bc8758573fc 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -162,10 +162,13 @@ mt76_find_power_limits_node(struct mt76_dev *dev) } if (mt76_string_prop_find(country, dev->alpha2) || - mt76_string_prop_find(regd, region_name)) + mt76_string_prop_find(regd, region_name)) { + of_node_put(np); return cur; + } } + of_node_put(np); return fallback; } -- cgit v1.2.3 From 454b768f9ba653d65968c1ef29d2d4aa477147ea Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 5 Jul 2022 22:23:04 +0800 Subject: mt76: mt7921: Let PCI core handle power state and use pm_sleep_ptr() PCI power state and wakeup are already handled by PCI core, so it's not necessary to handle them in the driver. Also switch to use pm_sleep_ptr() to remove #ifdef guard. Signed-off-by: Kai-Heng Feng Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 06af35250b3b..ea3069d18c35 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -358,9 +358,9 @@ static void mt7921_pci_remove(struct pci_dev *pdev) pci_free_irq_vectors(pdev); } -#ifdef CONFIG_PM -static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int mt7921_pci_suspend(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); struct mt76_connac_pm *pm = &dev->pm; @@ -390,8 +390,6 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) napi_disable(&mdev->napi[i]); } - pci_enable_wake(pdev, pci_choose_state(pdev, state), true); - /* wait until dma is idle */ mt76_poll(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | @@ -411,8 +409,6 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (err) goto restore_napi; - pci_save_state(pdev); - err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); if (err) goto restore_napi; @@ -435,19 +431,14 @@ restore_suspend: return err; } -static int mt7921_pci_resume(struct pci_dev *pdev) +static int mt7921_pci_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); struct mt76_connac_pm *pm = &dev->pm; int i, err; - err = pci_set_power_state(pdev, PCI_D0); - if (err) - return err; - - pci_restore_state(pdev); - err = mt7921_mcu_drv_pmctrl(dev); if (err < 0) return err; @@ -487,17 +478,15 @@ static int mt7921_pci_resume(struct pci_dev *pdev) return err; } -#endif /* CONFIG_PM */ + +static DEFINE_SIMPLE_DEV_PM_OPS(mt7921_pm_ops, mt7921_pci_suspend, mt7921_pci_resume); static struct pci_driver mt7921_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7921_pci_device_table, .probe = mt7921_pci_probe, .remove = mt7921_pci_remove, -#ifdef CONFIG_PM - .suspend = mt7921_pci_suspend, - .resume = mt7921_pci_resume, -#endif /* CONFIG_PM */ + .driver.pm = pm_sleep_ptr(&mt7921_pm_ops), }; module_pci_driver(mt7921_pci_driver); -- cgit v1.2.3 From 9dd9495d560a39a3f6f43e77dc8cec3666efd7f7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jul 2022 21:16:37 +0200 Subject: wifi: rsi: remove unused variable Remove a variable here that was now set but never used. Fixes: f276e20b182d ("wifi: mac80211: move interface config to new struct") Signed-off-by: Johannes Berg --- drivers/net/wireless/rsi/rsi_91x_hal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 40f9a31f9ca7..c61f83a7333b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -334,7 +334,6 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; - struct ieee80211_bss_conf *bss; struct ieee80211_hdr *wh; struct ieee80211_tx_info *info; struct skb_info *tx_params; @@ -359,7 +358,6 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, return status; } - bss = &info->control.vif->bss_conf; wh = (struct ieee80211_hdr *)&skb->data[header_size]; mgmt_desc = (struct rsi_mgmt_desc *)skb->data; xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; -- cgit v1.2.3 From cc5250cdb43d444061412df7fae72d2b4acbdf97 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jul 2022 21:16:45 +0200 Subject: wifi: mac80211_hwsim: use 32-bit skb cookie We won't really have enough skbs to need a 64-bit cookie, and on 32-bit platforms storing the 64-bit cookie into the void *rate_driver_data doesn't work anyway. Switch back to using just a 32-bit cookie and uintptr_t for the type to avoid compiler warnings about all this. Fixes: 4ee186fa7e40 ("wifi: mac80211_hwsim: fix race condition in pending packet") Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d51a30f7e1c2..31c8a77932dc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -687,7 +687,7 @@ struct mac80211_hwsim_data { bool ps_poll_pending; struct dentry *debugfs; - atomic64_t pending_cookie; + atomic_t pending_cookie; struct sk_buff_head pending; /* packets pending */ /* * Only radios in the same group can communicate together (the @@ -1358,7 +1358,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, int i; struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; struct hwsim_tx_rate_flag tx_attempts_flags[IEEE80211_TX_MAX_RATES]; - u64 cookie; + uintptr_t cookie; if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); @@ -1427,7 +1427,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, goto nla_put_failure; /* We create a cookie to identify this skb */ - cookie = (u64)atomic64_inc_return(&data->pending_cookie); + cookie = atomic_inc_return(&data->pending_cookie); info->rate_driver_data[0] = (void *)cookie; if (nla_put_u64_64bit(skb, HWSIM_ATTR_COOKIE, cookie, HWSIM_ATTR_PAD)) goto nla_put_failure; @@ -4207,10 +4207,10 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, /* look for the skb matching the cookie passed back from user */ spin_lock_irqsave(&data2->pending.lock, flags); skb_queue_walk_safe(&data2->pending, skb, tmp) { - u64 skb_cookie; + uintptr_t skb_cookie; txi = IEEE80211_SKB_CB(skb); - skb_cookie = (u64)(uintptr_t)txi->rate_driver_data[0]; + skb_cookie = (uintptr_t)txi->rate_driver_data[0]; if (skb_cookie == ret_skb_cookie) { __skb_unlink(skb, &data2->pending); -- cgit v1.2.3 From 51d3cfaf992ff52c2e922dc935a78f415038a2da Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Jul 2022 10:34:44 +0200 Subject: wifi: mac80211: exclude multicast packets from AQL pending airtime In AP mode, multicast traffic is handled very differently from normal traffic, especially if at least one client is in powersave mode. This means that multicast packets can be buffered a lot longer than normal unicast packets, and can eat up the AQL budget very quickly because of the low data rate. Along with the recent change to maintain a global PHY AQL limit, this can lead to significant latency spikes for unicast traffic. Since queueing multicast to hardware is currently not constrained by AQL limits anyway, let's just exclude it from the AQL pending airtime calculation entirely. Fixes: 8e4bac067105 ("wifi: mac80211: add a per-PHY AQL limit to improve fairness") Signed-off-by: Felix Fietkau Link: https://lore.kernel.org/r/20220713083444.86129-1-nbd@nbd.name Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b58c85abcb1b..6cd3aeba870f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3760,7 +3760,7 @@ begin: encap_out: IEEE80211_SKB_CB(skb)->control.vif = vif; - if (vif && + if (tx.sta && wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { bool ampdu = txq->ac != IEEE80211_AC_VO; u32 airtime; -- cgit v1.2.3 From 59e8ef18f6a1b7712bfb6889fcd808b7b5951600 Mon Sep 17 00:00:00 2001 From: XueBing Chen Date: Mon, 11 Jul 2022 22:27:58 +0800 Subject: wifi: cfg80211: use strscpy to replace strlcpy The strlcpy should not be used because it doesn't limit the source length. Preferred is strscpy. Signed-off-by: XueBing Chen Link: https://lore.kernel.org/r/2d2fcbf7.e33.181eda8e70e.Coremail.chenxuebing@jari.cn Signed-off-by: Johannes Berg --- net/wireless/ethtool.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index 24e18405cdb4..2613d6ac0fda 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c @@ -10,20 +10,20 @@ void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) struct device *pdev = wiphy_dev(wdev->wiphy); if (pdev->driver) - strlcpy(info->driver, pdev->driver->name, + strscpy(info->driver, pdev->driver->name, sizeof(info->driver)); else - strlcpy(info->driver, "N/A", sizeof(info->driver)); + strscpy(info->driver, "N/A", sizeof(info->driver)); - strlcpy(info->version, init_utsname()->release, sizeof(info->version)); + strscpy(info->version, init_utsname()->release, sizeof(info->version)); if (wdev->wiphy->fw_version[0]) - strlcpy(info->fw_version, wdev->wiphy->fw_version, + strscpy(info->fw_version, wdev->wiphy->fw_version, sizeof(info->fw_version)); else - strlcpy(info->fw_version, "N/A", sizeof(info->fw_version)); + strscpy(info->fw_version, "N/A", sizeof(info->fw_version)); - strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), + strscpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), sizeof(info->bus_info)); } EXPORT_SYMBOL(cfg80211_get_drvinfo); -- cgit v1.2.3 From bf326cf53a38e3cebbbb929216718fa9c925e869 Mon Sep 17 00:00:00 2001 From: Lian Chen Date: Thu, 14 Jul 2022 17:16:36 +0800 Subject: wifi: mac80211: make 4addr null frames using min_rate for WDS WDS needs 4addr packets to trigger AP for wlan0.sta creation. However, the 4addr null frame is sent at a high rate so that sometimes the AP can't receive it. Switch to using min rate. Signed-off-by: Lian Chen Link: https://lore.kernel.org/r/20220714091636.59107-1-lian.chen@mediatek.com Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 01a72d1fcfcc..4175247c325e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1207,6 +1207,7 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; ieee80211_tx_skb(sdata, skb); } -- cgit v1.2.3 From 0bd509325508aad1bf01967d618ada7d8da14d4d Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 1 Jul 2022 19:06:11 +0530 Subject: wifi: mac80211: fix mesh airtime link metric estimating ieee80211s_update_metric function uses sta_set_rate_info_tx function to get struct rate_info data from ieee80211_tx_rate struct, present in ieee80211_sta->deflink.tx_stats. However, drivers can skip tx rate calculation by setting rate idx as -1. Such drivers provides rate_info directly and hence ieee80211s metric is updated incorrectly since ieee80211_tx_rate has inconsistent data. Add fix to use rate_info directly if present instead of sta_set_rate_info_tx for updating ieee80211s metric. Signed-off-by: Aditya Kumar Singh Link: https://lore.kernel.org/r/20220701133611.544-1-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 45e7c1b307bc..7fd269cbb01a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -310,7 +310,12 @@ void ieee80211s_update_metric(struct ieee80211_local *local, LINK_FAIL_THRESH) mesh_plink_broken(sta); - sta_set_rate_info_tx(sta, &sta->deflink.tx_stats.last_rate, &rinfo); + /* use rate info set by the driver directly if present */ + if (st->n_rates) + rinfo = sta->deflink.tx_stats.last_rate_info; + else + sta_set_rate_info_tx(sta, &sta->deflink.tx_stats.last_rate, &rinfo); + ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, cfg80211_calculate_bitrate(&rinfo)); } -- cgit v1.2.3 From 912fa56b27631ba4d9b6c59a9f6d7c53ae2795b2 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 14 Jun 2022 13:41:30 +0300 Subject: wifi: mac80211_hwsim: Support link channel matching on rx Accept frames from all the links' channels. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 31c8a77932dc..4f22f3df161c 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) -- cgit v1.2.3 From 6858ad75c228e8c47840afeda0f752b50f2e840c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Jun 2022 15:16:36 +0200 Subject: wifi: mac80211: consistently use sdata_dereference() Instead of open-coding it, use sdata_dereference(). Signed-off-by: Johannes Berg --- 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); -- cgit v1.2.3 From 892b3bceb0b5340fe8b3480e0ff507a9dfd75b27 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jun 2022 13:08:42 +0200 Subject: wifi: mac80211: rx: accept link-addressed frames 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 --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/rx.c | 69 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f08060a36ef2..84b6ae32ae50 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; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 304b9909f025..b7dff3ef9748 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -4029,6 +4029,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; @@ -4065,6 +4066,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; @@ -4141,6 +4143,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; @@ -4159,7 +4186,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; @@ -4213,9 +4240,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 @@ -4223,7 +4252,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; @@ -4741,6 +4771,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); @@ -4765,6 +4796,29 @@ drop: dev_kfree_skb(skb); } +static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, + struct sk_buff *skb, bool consume) +{ + struct link_sta_info *link_sta; + struct ieee80211_hdr *hdr = (void *)skb->data; + + /* + * 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(rx->sdata, hdr->addr2); + if (link_sta) { + rx->sta = link_sta->sta; + rx->link_id = link_sta->link_id; + } else { + rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2); + } + + return ieee80211_prepare_and_rx_handle(rx, skb, consume); +} + /* * This is the actual Rx frames handler. as it belongs to Rx path it must * be called with rcu_read_lock protection. @@ -4788,6 +4842,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); @@ -4873,18 +4928,16 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } - rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; - ieee80211_prepare_and_rx_handle(&rx, skb, false); + ieee80211_rx_for_interface(&rx, skb, false); prev = sdata; } if (prev) { - rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; - if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) + if (ieee80211_rx_for_interface(&rx, skb, true)) return; } -- cgit v1.2.3 From 54283409cd162fc60480df514924ed4cb313735e Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 14 Jun 2022 17:20:04 +0300 Subject: wifi: mac80211: Consider MLO links in offchannel logic Check all the MLO links to decide whether offchannel TX is needed. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 && -- cgit v1.2.3 From 6df2810ac9a9b11523bda4f2fd4442598787013d Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 14 Jun 2022 17:21:23 +0300 Subject: wifi: cfg80211: Allow MLO TX with link source address Management frames are transmitted from link address and not device address. Allow that. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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. -- cgit v1.2.3 From 0866f8e3efd097cbb56176b40bf58961814eed6b Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sun, 19 Jun 2022 14:38:03 +0300 Subject: wifi: mac80211: Remove AP SMPS leftovers AP SMPS was removed and not needed anymore. Remove the leftovers. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 84b6ae32ae50..484ae6355cb8 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; } } } -- cgit v1.2.3 From f91cb507e671ad4d9f00327b01a4bbe21c41fd4a Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Sun, 19 Jun 2022 15:08:02 +0300 Subject: wifi: mac80211: add an ieee80211_get_link_sband Similar to ieee80211_get_sband but get the sband of the link_conf. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- 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 484ae6355cb8..604825dde4fd 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; -- cgit v1.2.3 From 577e5b8c3924539c7a09e3e00477534f39e61829 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 8 Jun 2022 12:01:12 +0300 Subject: wifi: cfg80211: add API to add/modify/remove a link station Add an API for adding/modifying/removing a link of a station. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- 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 3bcdd20ace66..422764881269 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(¶ms, 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, ¶ms); + err = nl80211_parse_sta_txpower_setting(info, ¶ms.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, ¶ms); @@ -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(¶ms, 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, ¶ms); + err = nl80211_parse_sta_txpower_setting(info, ¶ms.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, ¶ms); 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, ¶ms.txpwr, + ¶ms.txpwr_set); + if (err) + return err; + + if (add) + return rdev_add_link_station(rdev, dev, ¶ms); + return rdev_mod_link_station(rdev, dev, ¶ms); +} + +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, ¶ms); +} + #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 -- cgit v1.2.3 From b95eb7f0eee479478eb1a7c0a42a80167708c1df Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 14 Jun 2022 13:49:16 +0300 Subject: wifi: cfg80211/mac80211: separate link params from station params 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 Signed-off-by: Johannes Berg --- drivers/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 422764881269..c904cbd1c4d6 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 64801ab545c1..3eacf72279c2 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 (!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, ¶ms->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(¶ms, 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, ¶ms.txpwr, &txpwr_set); + err = nl80211_parse_sta_txpower_setting(info, + ¶ms.link_sta_params.txpwr, + ¶ms.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, ¶ms); @@ -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(¶ms, 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, ¶ms.txpwr, &txpwr_set); + err = nl80211_parse_sta_txpower_setting(info, + ¶ms.link_sta_params.txpwr, + ¶ms.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, ¶ms); 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, " -- cgit v1.2.3 From 21476ad16d3ca3687a474556c67d4789ef85a5df Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 14 Jun 2022 17:27:03 +0300 Subject: wifi: mac80211: implement callbacks for _link_station Implement callbacks for cfg80211 add_link_station, mod_link_station, and del_link_station API. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/sta_info.c | 7 ++++ net/mac80211/sta_info.h | 1 + 3 files changed, 116 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3eacf72279c2..85032dcaa595 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4588,6 +4588,111 @@ 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; + + if (sta->sta.valid_links & BIT(params->link_id)) + return -EALREADY; + + 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 +4800,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); -- cgit v1.2.3 From 858fd1880ba5fffaacc9bac5c3cd9b0952819208 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jun 2022 15:25:56 +0200 Subject: wifi: nl80211: hold wdev mutex in add/mod/del link station 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 --- 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, ¶ms); - return rdev_mod_link_station(rdev, dev, ¶ms); + err = rdev_add_link_station(rdev, dev, ¶ms); + else + err = rdev_mod_link_station(rdev, dev, ¶ms); + 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, ¶ms); + wdev_lock(dev->ieee80211_ptr); + ret = rdev_del_link_station(rdev, dev, ¶ms); + wdev_unlock(dev->ieee80211_ptr); + + return ret; } #define NL80211_FLAG_NEED_WIPHY 0x01 -- cgit v1.2.3 From 4e2f3d67e3afef751e1ad81c6b156f2aafa25dcf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jun 2022 15:28:50 +0200 Subject: wifi: nl80211: hold wdev mutex for channel switch APIs Since we deal with links in an MLD here, hold the wdev mutex now. Signed-off-by: Johannes Berg --- 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; } -- cgit v1.2.3 From 3d1cc7cdf2e848181398837fe158bf0850d29ee6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jun 2022 15:29:28 +0200 Subject: wifi: nl80211: hold wdev mutex for station APIs 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 --- 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, ¶ms); + 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, ¶ms); + 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(¶ms, 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, ¶ms); + wdev_lock(dev->ieee80211_ptr); + ret = rdev_del_station(rdev, dev, ¶ms); + wdev_unlock(dev->ieee80211_ptr); + + return ret; } static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, -- cgit v1.2.3 From d8675a63518c6148827838058feb7f18403faed1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Jun 2022 22:36:37 +0200 Subject: wifi: mac80211: RCU-ify link/link_conf pointers 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 --- 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 4f22f3df161c..6bad95eeb709 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 1c005a30313f..044ed417b06f 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 85032dcaa595..3d66e40af7a9 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, ¶ms->beacon, NULL, NULL); + err = ieee80211_assign_beacon(sdata, link, ¶ms->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 (!link_sta) + if (!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, ¶ms->beacon_csa, &csa, NULL); + err = ieee80211_assign_beacon(sdata, &sdata->deflink, + ¶ms->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], ¶ms->chandef, + err = ieee80211_link_reserve_chanctx(&sdata->deflink, ¶ms->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, ¶ms->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, ¶ms->beacon_color_change, + err = ieee80211_assign_beacon(sdata, &sdata->deflink, + ¶ms->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 @@ err: 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 604825dde4fd..f6791b47f78f 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 d5e904bff624..55b0a1fa92ab 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); } @@ -480,7 +480,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, @@ -1031,11 +1031,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); @@ -1128,7 +1129,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) { @@ -1173,7 +1174,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); @@ -1279,7 +1280,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 { @@ -1351,7 +1352,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: @@ -1535,7 +1537,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); @@ -1689,7 +1692,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); } /* @@ -2364,6 +2367,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]; @@ -2394,15 +2398,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; @@ -2426,20 +2430,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 4175247c325e..52a41416b8bb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1836,7 +1836,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); } } @@ -2032,7 +2033,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) @@ -2338,7 +2340,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); @@ -2921,7 +2923,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); @@ -2950,7 +2953,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; @@ -4392,7 +4396,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); } @@ -5702,9 +5707,10 @@ skip_rates: * 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); @@ -5870,7 +5876,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); @@ -6217,7 +6224,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 b7dff3ef9748..c70156e49d0d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -4156,9 +4156,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 6cd3aeba870f..4a7a714de79e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4598,13 +4598,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. */ @@ -4664,8 +4665,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; @@ -4677,12 +4679,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); } @@ -4691,7 +4691,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; @@ -4716,20 +4716,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; } @@ -4739,7 +4736,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) @@ -4863,14 +4859,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; @@ -4890,12 +4886,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); @@ -4926,7 +4922,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]) @@ -4958,11 +4954,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); @@ -4975,7 +4971,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, @@ -4991,7 +4987,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; @@ -5010,11 +5006,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; } @@ -5030,12 +5026,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; @@ -5044,12 +5044,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; @@ -5062,7 +5062,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 + @@ -5076,8 +5076,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; @@ -5094,7 +5094,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) @@ -5109,8 +5109,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; @@ -5118,8 +5118,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; @@ -5616,11 +5616,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 645f75b0f89f..3e29ef1f81ad 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1702,7 +1702,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); } } @@ -2259,7 +2260,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; @@ -2268,11 +2269,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); } @@ -2478,7 +2479,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 */ @@ -2488,16 +2489,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: @@ -2807,7 +2815,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; @@ -2815,7 +2823,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)); /* @@ -3984,7 +3992,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, @@ -4430,13 +4438,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); -- cgit v1.2.3 From c0d6701261dbfa29902ca64c7b57b1cc5f0c2533 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 21 Jun 2022 12:18:31 +0300 Subject: wifi: nl80211: enable setting the link address at new station 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 Signed-off-by: Johannes Berg --- 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 = -- cgit v1.2.3 From 23cc6d8c37cdbe3b2b74a922f3311ecb2a5aea6c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2022 10:17:23 +0200 Subject: wifi: cfg80211: make cfg80211_auth_request::key_idx signed 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 --- 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 c904cbd1c4d6..a4e2cb2378b8 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; -- cgit v1.2.3 From 1d4c0f0405ee8cf8ecbf743d640133af58e56e21 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2022 11:02:00 +0200 Subject: wifi: cfg80211: drop BSS elements from assoc trace for now 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 Signed-off-by: Johannes Berg --- 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); -- cgit v1.2.3 From b8375cf15834721c4534c118c5a201b92c1c385b Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 22 Jun 2022 15:02:37 +0300 Subject: wifi: mac80211_hwsim: Ack link addressed frames Do address matching with link addresses as well. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 6bad95eeb709..737f8ed56d94 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, -- cgit v1.2.3 From c5c48a11dd86c7f9d86b8c4cc8eaed350ffd1ea7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2022 14:30:20 +0200 Subject: wifi: mac80211: debug: omit link if non-MLO connection 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 --- 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, \ -- cgit v1.2.3 From 28977e790b5d0e6d37db6e659cfbcde9d24ae718 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jun 2022 09:48:00 +0200 Subject: wifi: mac80211: skip powersave recalc if driver SUPPORTS_DYNAMIC_PS 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 --- 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 52a41416b8bb..e5c058db451d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1787,7 +1787,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; } -- cgit v1.2.3 From 1e0b3b0b6cb5e04bcb25fbe4164180d64e3ace07 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 27 Apr 2022 18:02:10 +0300 Subject: wifi: mac80211: Align with Draft P802.11be_D1.5 Align the mac80211 implementation with P802.11be_D1.5. Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 52 ++++++++++++++++++--------- net/mac80211/ieee80211_i.h | 4 +++ net/mac80211/mlme.c | 32 +++++++++++++++++ net/mac80211/util.c | 87 +++++++++++++++++++++++++++++----------------- 4 files changed, 128 insertions(+), 47 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 f6791b47f78f..aa1e438ee61e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2326,6 +2326,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 e5c058db451d..39f13f3c29bf 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/util.c b/net/mac80211/util.c index 3e29ef1f81ad..924192238042 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3459,6 +3459,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, @@ -3539,7 +3591,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: @@ -3583,36 +3636,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)) { -- cgit v1.2.3 From 062e8e02dfd43c94b0d601c071e8a5c50bed830e Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 1 Jun 2022 17:43:34 +0300 Subject: wifi: mac80211: Align with Draft P802.11be_D2.0 Align the mac80211 implementation with P802.11be_D2.0. Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 6 +++--- include/linux/ieee80211.h | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 737f8ed56d94..f437d8a65268 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3118,7 +3118,7 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_NSEP_PRIO_ACCESS | + IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | IEEE80211_EHT_MAC_CAP0_OM_CONTROL | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, .phy_cap_info[0] = @@ -3271,7 +3271,7 @@ static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_NSEP_PRIO_ACCESS | + IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | IEEE80211_EHT_MAC_CAP0_OM_CONTROL | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, .phy_cap_info[0] = @@ -3453,7 +3453,7 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_NSEP_PRIO_ACCESS | + IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | IEEE80211_EHT_MAC_CAP0_OM_CONTROL | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, .phy_cap_info[0] = diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e75c73ca11ec..cca564372d16 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2020,7 +2020,7 @@ struct ieee80211_eht_mcs_nss_supp_bw { * struct ieee80211_eht_cap_elem_fixed - EHT capabilities fixed data * * This structure is the "EHT Capabilities element" fixed fields as - * described in P802.11be_D1.4 section 9.4.2.313. + * described in P802.11be_D2.0 section 9.4.2.313. * * @mac_cap_info: MAC capabilities, see IEEE80211_EHT_MAC_CAP* * @phy_cap_info: PHY capabilities, see IEEE80211_EHT_PHY_CAP* @@ -2046,20 +2046,27 @@ struct ieee80211_eht_cap_elem { u8 optional[]; } __packed; -#define IEEE80211_EHT_OPER_INFO_PRESENT 0x1 -#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x2 +#define IEEE80211_EHT_OPER_INFO_PRESENT 0x01 +#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x02 +#define IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION 0x04 +#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT 0x08 +#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK 0x30 /** * struct ieee80211_eht_operation - eht operation element * * This structure is the "EHT Operation Element" fields as - * described in P802.11be_D1.5 section 9.4.2.311 + * described in P802.11be_D2.0 section 9.4.2.311 * * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_* + * @basic_mcs_nss: indicates the EHT-MCSs for each number of spatial streams in + * EHT PPDUs that are supported by all EHT STAs in the BSS in transmit and + * receive. * @optional: optional parts */ struct ieee80211_eht_operation { u8 params; + __le32 basic_mcs_nss; u8 optional[]; } __packed; @@ -2779,8 +2786,8 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) #define S1G_OPER_CH_WIDTH_PRIMARY_1MHZ BIT(0) #define S1G_OPER_CH_WIDTH_OPER GENMASK(4, 1) -/* EHT MAC capabilities as defined in P802.11be_D1.4 section 9.4.2.313.2 */ -#define IEEE80211_EHT_MAC_CAP0_NSEP_PRIO_ACCESS 0x01 +/* EHT MAC capabilities as defined in P802.11be_D2.0 section 9.4.2.313.2 */ +#define IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS 0x01 #define IEEE80211_EHT_MAC_CAP0_OM_CONTROL 0x02 #define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 0x04 #define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 0x08 @@ -2793,7 +2800,7 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) #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 */ +/* EHT PHY capabilities as defined in P802.11be_D2.0 section 9.4.2.313.3 */ #define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02 #define IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ 0x04 #define IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI 0x08 @@ -2858,7 +2865,7 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) #define IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA 0x02 /* - * EHT operation channel width as defined in P802.11be_D1.4 section 9.4.2.311 + * EHT operation channel width as defined in P802.11be_D2.0 section 9.4.2.311 */ #define IEEE80211_EHT_OPER_CHAN_WIDTH 0x7 #define IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ 0 -- cgit v1.2.3 From ba323e29859458fb180e8a99b4382d0cbf72d47f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jun 2022 12:04:55 +0200 Subject: wifi: mac80211: separate out connection downgrade flags 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 --- 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(¶ms, 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 39f13f3c29bf..3b00383dbdbd 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 @@ out: 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 @@ out: 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 @@ out: 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 @@ skip_rates: /* 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 @@ skip_rates: 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 @@ skip_rates: } 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 @@ skip_rates: * 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); } @@ -1431,7 +1433,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) { @@ -2518,6 +2520,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); @@ -2959,6 +2962,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); @@ -2989,6 +2993,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); @@ -3480,9 +3485,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; @@ -3518,25 +3523,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"); @@ -3549,7 +3554,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"); @@ -3557,7 +3562,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"); @@ -3565,7 +3570,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"); @@ -3592,7 +3597,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, @@ -3602,17 +3607,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, @@ -3632,7 +3637,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, @@ -5041,6 +5046,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; @@ -5071,7 +5077,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; @@ -5083,7 +5088,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); @@ -5096,7 +5101,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); @@ -5115,7 +5120,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); @@ -5340,7 +5345,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; @@ -5370,70 +5374,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) { @@ -5462,8 +5466,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; } /* @@ -5472,8 +5476,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; @@ -5500,7 +5506,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) { @@ -5510,13 +5516,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); @@ -5526,7 +5533,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; } @@ -5549,7 +5556,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); } @@ -6005,10 +6013,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"); } @@ -6018,10 +6026,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"); } @@ -6069,7 +6077,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, @@ -6077,9 +6085,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(); @@ -6131,7 +6139,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) @@ -6141,37 +6149,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 * Copyright 2007-2008, Intel Corporation * Copyright 2008, Johannes Berg - * Copyright (C) 2018, 2020 Intel Corporation + * Copyright (C) 2018, 2020, 2022 Intel Corporation */ #include @@ -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 924192238042..f06514087511 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2948,7 +2948,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) { @@ -2968,16 +2968,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; @@ -4066,21 +4066,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; @@ -4089,13 +4089,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 */ @@ -4104,8 +4104,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 */ @@ -4114,13 +4114,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: @@ -4131,7 +4131,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; } -- cgit v1.2.3 From e2722d278ee3dbc589e4fdf1e7970f4d2b62c7dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jun 2022 22:21:28 +0200 Subject: wifi: mac80211: fix key lookup 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 --- net/mac80211/cfg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3d66e40af7a9..aa3a1568c7fc 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; } -- cgit v1.2.3 From 284b38b6902a7154e3675482418a7b6df47808fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 12:49:03 +0200 Subject: wifi: nl80211: acquire wdev mutex for dump_survey 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 --- 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) -- cgit v1.2.3 From 94ddc3b5aa21c261be277eab8bc80f7520038a34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 11:15:52 +0200 Subject: wifi: mac80211: move ieee80211_request_smps_mgd_work This function can be static. Signed-off-by: Johannes Berg --- 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 3b00383dbdbd..d4d226436e8d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5018,6 +5018,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) { -- cgit v1.2.3 From b2e8434f1829bb500f79b1adb80ffed2316811cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 10:57:41 +0200 Subject: wifi: mac80211: set up/tear down client vif links properly 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 --- 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 55b0a1fa92ab..fbb9c9c291b9 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; @@ -729,6 +931,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) @@ -1021,50 +1226,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) { @@ -1787,6 +1948,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); } @@ -2355,97 +2519,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 d4d226436e8d..299381d19760 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5033,17 +5033,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); @@ -5057,20 +5054,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) { @@ -6383,6 +6388,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; @@ -6394,7 +6404,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); -- cgit v1.2.3 From 3fbddae46e5fc3f1630c7cf561d88e4ad21c7105 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 14:42:12 +0200 Subject: wifi: mac80211: provide link ID in link_conf 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 --- 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 044ed417b06f..877b3eca6db4 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 fbb9c9c291b9..312a812bec84 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); -- cgit v1.2.3 From a3b8008dc1421a6f1d0d92cfc1352d729f6756c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 15:02:16 +0200 Subject: wifi: mac80211: move ps setting to vif config 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 --- 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 877b3eca6db4..fba06d7bc7eb 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 299381d19760..f8be05804e59 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1869,10 +1869,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; -- cgit v1.2.3 From 8c7c6b581987dda035c73661cf83973a02a055d8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 15:14:26 +0200 Subject: wifi: mac80211: expect powersave handling in driver for MLO 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 --- 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 f8be05804e59..5400b3e567fa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1786,6 +1786,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; @@ -1802,7 +1803,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(); -- cgit v1.2.3 From b3e2130bf5f6c66831707cd51a8b13007137ac37 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 15:40:11 +0200 Subject: wifi: mac80211: change QoS settings API to take link into account Take the link into account in the QoS settings (EDCA parameters) APIs. Signed-off-by: Johannes Berg --- 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 +- drivers/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 +- drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 5 +- drivers/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 +- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 +- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 3 +- drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 5 +- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 5 +- drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 3 +- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 3 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 3 +- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 5 +- drivers/net/wireless/ralink/rt2x00/rt73usb.c | 5 +- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 3 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 3 +- .../net/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 @@ exit: } 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 @@ exit: } 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 f437d8a65268..5da7a097d518 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 @@ out: } 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 @@ exit: } 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 @@ out: } 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 fba06d7bc7eb..7cf8d58eb5f0 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 aa3a1568c7fc..fa3b6cc2cafa 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 #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 312a812bec84..f29764936c99 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1539,7 +1539,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 5400b3e567fa..44f76a8fa80b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2018,10 +2018,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; @@ -2047,11 +2048,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, @@ -2085,10 +2086,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; @@ -2117,11 +2119,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; @@ -2219,16 +2221,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, ¶ms[ac])) - sdata_err(sdata, - "failed to set TX queue parameters for AC %d\n", - ac); + drv_conf_tx(local, link, ac, ¶ms[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; } @@ -2508,7 +2510,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); @@ -3766,12 +3768,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 @@ -3938,7 +3941,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; @@ -4363,7 +4366,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 f06514087511..2b2c8e1472f3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1596,9 +1596,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; @@ -1616,7 +1617,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); @@ -1693,17 +1694,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); } } @@ -2520,8 +2520,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; } -- cgit v1.2.3 From 7ebe994fbd2da8160ebc178c883ad92dc5e57dcf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 15:54:38 +0200 Subject: wifi: mac80211: remove unused bssid variable This variable is only written to, remove it. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 44f76a8fa80b..7eab15920a70 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6365,7 +6365,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]; /* @@ -6381,7 +6380,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); -- cgit v1.2.3 From b65567b03c9502e67bed6707cb53a4c730c2bee2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 16:08:39 +0200 Subject: wifi: mac80211: mlme: track AP (MLD) address separately 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 --- 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 7cf8d58eb5f0..36eba96a1012 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 7eab15920a70..a2e8fe9b43ab 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1808,7 +1808,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(); @@ -2313,6 +2313,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); @@ -2463,6 +2464,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 */ @@ -2653,7 +2655,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; @@ -2882,13 +2884,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 { @@ -3042,7 +3044,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; @@ -3056,14 +3058,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; } @@ -4402,7 +4404,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); @@ -4885,7 +4887,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; @@ -4981,7 +4983,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); } @@ -5909,7 +5911,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); @@ -5986,7 +5988,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); @@ -6344,7 +6346,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, -- cgit v1.2.3 From 42ed6748afa45fb3f540a5fd83595eee050c48fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 16:28:33 +0200 Subject: wifi: mac80211: mlme: do IEEE80211_STA_RESET_SIGNAL_AVE per link 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 --- 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 a2e8fe9b43ab..8cd275c3be70 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2317,8 +2317,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; @@ -2523,6 +2521,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; @@ -4052,8 +4051,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; -- cgit v1.2.3 From 5bd5666d8ad88366789b344647529841f6dadd7f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 16:18:56 +0200 Subject: wifi: mac80211: mlme: first adjustments for MLO 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 --- 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 8cd275c3be70..35c62e940946 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 @@ out: * 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 @@ out: 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 @@ skip_rates: /* 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 @@ skip_rates: 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 @@ skip_rates: } 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 */ @@ -1248,8 +1254,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; @@ -1264,7 +1271,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; /* @@ -1274,16 +1281,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", @@ -1296,8 +1303,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, @@ -1305,7 +1312,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); @@ -1316,29 +1323,30 @@ out: 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) { @@ -1349,8 +1357,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) @@ -1358,6 +1365,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, @@ -1365,22 +1375,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) @@ -1389,15 +1402,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); @@ -1405,14 +1418,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; @@ -1433,8 +1447,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; @@ -1448,23 +1462,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); @@ -1477,7 +1491,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, @@ -1487,14 +1501,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; } @@ -1508,7 +1522,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, @@ -1531,7 +1545,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, @@ -1541,13 +1555,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); @@ -1563,9 +1577,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; @@ -1580,8 +1594,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); @@ -1674,13 +1688,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; @@ -1716,25 +1731,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; @@ -1973,14 +1988,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); @@ -2300,7 +2316,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; @@ -2311,8 +2328,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); @@ -2332,7 +2349,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; } @@ -2345,14 +2362,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 { @@ -2390,6 +2407,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, @@ -2406,7 +2424,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); /* @@ -2444,12 +2462,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); } @@ -2460,7 +2478,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; @@ -2475,9 +2493,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)); @@ -2486,14 +2504,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); @@ -2502,7 +2520,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 */ @@ -2515,26 +2533,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); @@ -2658,6 +2676,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 @@ -2703,6 +2724,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; @@ -2774,7 +2798,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); @@ -2878,9 +2903,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); @@ -2893,6 +2915,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); } } @@ -2962,11 +2986,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); @@ -2993,11 +3018,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); @@ -3386,14 +3412,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; @@ -3431,6 +3457,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; @@ -3489,9 +3516,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; @@ -3527,25 +3554,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"); @@ -3558,7 +3585,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"); @@ -3566,7 +3593,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"); @@ -3574,7 +3601,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"); @@ -3601,7 +3628,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, @@ -3611,17 +3638,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, @@ -3638,10 +3665,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, @@ -3765,17 +3792,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 @@ -3955,10 +3981,11 @@ notify_driver: 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; @@ -3972,15 +3999,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; @@ -4012,10 +4040,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); } @@ -4043,31 +4071,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, }; @@ -4078,36 +4108,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, @@ -4116,22 +4146,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, @@ -4150,10 +4180,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; @@ -4189,7 +4220,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; @@ -4211,18 +4242,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) @@ -4246,12 +4277,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) { @@ -4314,28 +4345,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 @@ -4347,27 +4378,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; @@ -4376,12 +4407,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); @@ -4405,9 +4436,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, @@ -4427,20 +4458,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); } @@ -4448,6 +4477,7 @@ free: 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; @@ -4459,7 +4489,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); @@ -4468,6 +4498,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; @@ -4481,11 +4512,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); @@ -4517,7 +4548,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); @@ -4545,7 +4576,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); @@ -4861,6 +4892,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; @@ -4882,6 +4916,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; @@ -5041,7 +5078,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, @@ -5051,7 +5087,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); @@ -5079,6 +5114,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 */ @@ -5095,7 +5133,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; @@ -5110,7 +5148,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); @@ -5123,7 +5161,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); @@ -5142,7 +5180,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); @@ -5364,6 +5402,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; @@ -5396,77 +5435,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; @@ -5488,8 +5527,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; } /* @@ -5498,7 +5537,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) { @@ -5528,7 +5567,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) { @@ -5538,8 +5577,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, @@ -5547,21 +5586,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); /* @@ -5569,7 +5608,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. */ @@ -5578,9 +5617,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: @@ -5631,6 +5670,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; @@ -5674,6 +5714,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) { @@ -5711,12 +5754,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 && @@ -5726,38 +5769,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); @@ -5770,7 +5813,7 @@ skip_rates: * 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); @@ -5787,7 +5830,7 @@ skip_rates: 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) @@ -5800,6 +5843,7 @@ skip_rates: 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; @@ -5938,7 +5982,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; @@ -5962,6 +6006,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; @@ -6019,7 +6064,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); @@ -6035,10 +6080,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"); } @@ -6048,10 +6093,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"); } @@ -6099,7 +6144,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, @@ -6107,7 +6152,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; } @@ -6157,11 +6202,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) @@ -6171,49 +6216,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(); @@ -6226,7 +6271,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; @@ -6235,33 +6280,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; @@ -6286,7 +6331,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; @@ -6394,6 +6439,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) @@ -6408,7 +6454,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); -- cgit v1.2.3 From 6359598df67fe7d4d335298f50a23cb55dd1547b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 13:13:04 +0200 Subject: wifi: mac80211: split IEEE80211_STA_DISABLE_WMM to link data 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 --- 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 35c62e940946..918f095950f0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2540,6 +2540,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; @@ -3795,21 +3796,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; @@ -4397,7 +4398,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)) -- cgit v1.2.3 From 1dd0f31c23aa15d201576ae0b2a478cad8d7458f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 14:10:18 +0200 Subject: wifi: mac80211: mlme: use ieee80211_get_link_sband() 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 --- 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 918f095950f0..360cb666097a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2265,17 +2265,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; @@ -2321,7 +2321,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( @@ -3622,7 +3622,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; @@ -4430,7 +4430,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); -- cgit v1.2.3 From d3853f700ce621f7f90f3a119a1b706f829fc55f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 14:15:09 +0200 Subject: wifi: mac80211: mlme: remove sta argument from ieee80211_config_bw 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 --- 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 360cb666097a..3c59cac9ab85 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -405,7 +405,6 @@ out: } 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 @@ -4439,7 +4435,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, -- cgit v1.2.3 From 98b0b467466c6afe8f2863158383444fbbc5f322 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 14:17:28 +0200 Subject: wifi: mac80211: mlme: use correct link_sta 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 --- net/mac80211/mlme.c | 50 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3c59cac9ab85..b71de89d9734 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3396,7 +3396,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) @@ -3405,15 +3405,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; @@ -3425,14 +3425,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] & @@ -3447,6 +3447,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; @@ -3618,6 +3619,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); @@ -3638,12 +3647,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) { @@ -3651,9 +3660,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, @@ -3662,7 +3671,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)) { @@ -3671,9 +3680,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, elems->he_cap_len, elems->eht_cap, elems->eht_cap_len, - &sta->deflink); + link_sta); - bss_conf->eht_support = sta->sta.deflink.eht_cap.has_eht; + bss_conf->eht_support = link_sta->pub->eht_cap.has_eht; } else { bss_conf->eht_support = false; } @@ -3685,7 +3694,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 = @@ -3750,7 +3759,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); @@ -4191,6 +4200,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; @@ -4432,8 +4442,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, @@ -4455,7 +4471,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); -- cgit v1.2.3 From 8f6e0dfc2245d8ca1a3335a06a1219c56df04bb8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 16:19:18 +0200 Subject: wifi: cfg80211: remove BSS pointer from cfg80211_disassoc_request 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 --- 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 a4e2cb2378b8..d0be08483fa6 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 b71de89d9734..a2b4536c3a24 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6426,18 +6426,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; ), -- cgit v1.2.3 From f662d2f4e22e5d5a9215e9c881875a4769494ef6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 22:09:50 +0200 Subject: wifi: cfg80211: prepare association failure APIs for MLO 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 --- 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 d0be08483fa6..fbbe1796b85f 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 a2b4536c3a24..e1c4a4dcfc70 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3027,8 +3027,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); @@ -3956,8 +3961,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; @@ -4833,9 +4842,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) @@ -6468,8 +6481,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, -- cgit v1.2.3 From afa2d65938fec74baf6307fd906b4f86e4a411ab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 22:23:42 +0200 Subject: wifi: mac80211: mlme: unify assoc data event sending 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 --- 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 e1c4a4dcfc70..ac37cf74ab74 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2999,14 +2999,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 @@ -3027,9 +3034,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); @@ -3310,7 +3318,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; @@ -3954,19 +3962,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; @@ -3978,7 +3981,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; @@ -4836,19 +4839,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) @@ -5013,7 +5010,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, @@ -6408,7 +6405,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); @@ -6479,16 +6476,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); -- cgit v1.2.3 From e69dac88a155bd626170bb0bb43f83fb564392f7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 11:25:38 +0200 Subject: wifi: cfg80211: adjust assoc comeback for MLO 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 --- 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 fbbe1796b85f..1d8cecf035d1 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 ac37cf74ab74..91f07b67f2f0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3944,7 +3944,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, -- cgit v1.2.3 From cd47c0f57ae6607cfa3d161e341cbdd283bc444f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 16:25:37 +0200 Subject: wifi: cfg80211: put cfg80211_rx_assoc_resp() arguments into a struct 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 --- 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 1d8cecf035d1..2628e8f98a13 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 91f07b67f2f0..ecbd70a1fbb7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3878,7 +3878,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; @@ -3887,6 +3887,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); @@ -3984,16 +3987,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, -- cgit v1.2.3 From 5cd212cb6415aa604ada17d5150847fd65d27337 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 17:17:05 +0200 Subject: wifi: cfg80211: extend cfg80211_rx_assoc_resp() for MLO 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 --- 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 2628e8f98a13..2fe3eff11a8b 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 ecbd70a1fbb7..29c1fe8b9f4a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3995,7 +3995,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, -- cgit v1.2.3 From fd17bf041b40e3dac705c4313854becbe07b7557 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 17:49:12 +0200 Subject: wifi: mac80211: refactor elements parsing with parameter struct 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 --- 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(¶ms); +} + 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 2b2c8e1472f3..0ff09c639c50 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1026,19 +1026,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; @@ -1101,7 +1101,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; @@ -1282,7 +1282,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; @@ -1290,7 +1290,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; } @@ -1417,7 +1417,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; @@ -1491,11 +1491,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; @@ -1505,15 +1502,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, @@ -1521,14 +1519,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; @@ -1550,8 +1552,6 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, kfree(nontransmitted_profile); - elems->crc = crc; - return elems; } -- cgit v1.2.3 From b327c84c328ed2be4dbad4f5ed7c17476fe1b3bf Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 29 Jun 2022 12:22:24 +0300 Subject: wifi: mac80211: replace link_id with link_conf in start/stop_ap() 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 Signed-off-by: Johannes Berg --- drivers/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 @@ out_unlock: 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 36eba96a1012..dcb8b6dac2e1 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 fa3b6cc2cafa..9214883eb0a8 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 0ff09c639c50..cb0dd874c5df 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2579,7 +2579,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: -- cgit v1.2.3 From 635495e9c43da6280ec05e10a5fc6b9b62cbafe3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jun 2022 11:52:49 +0200 Subject: wifi: mac80211: don't re-parse elems in ieee80211_assoc_success() 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 --- 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 29c1fe8b9f4a..6f25ac2055d5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3470,27 +3470,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 @@ -3865,7 +3855,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ret = true; out: - kfree(elems); kfree(bss_ies); return ret; } -- cgit v1.2.3 From ab3a830d96644522eec0cd379cec46d854548b11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jun 2022 12:01:41 +0200 Subject: wifi: mac80211: move tdls_chan_switch_prohibited to link data This value should be per link, since a TDLS connection is only established on a given link. Signed-off-by: Johannes Berg --- 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 9214883eb0a8..e0ddecbb50aa 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 6f25ac2055d5..267229462973 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3504,7 +3504,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); -- cgit v1.2.3 From 38c6aa29d4558c55a1d2b4010cc588716e212f89 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jun 2022 13:29:05 +0200 Subject: wifi: mac80211: fix multi-BSSID element parsing 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 --- 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(¶ms); @@ -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 7fd269cbb01a..9b1ce7c3925a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -932,7 +932,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 267229462973..0409dcf5a6cb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3536,8 +3536,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; @@ -3927,7 +3926,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; @@ -4252,8 +4251,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; @@ -4321,7 +4319,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; @@ -4566,7 +4564,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, @@ -4590,7 +4588,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 */ @@ -5445,8 +5443,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 cb0dd874c5df..9394aef30ba4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1425,15 +1425,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) { @@ -1475,11 +1474,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]; @@ -1509,9 +1508,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, -- cgit v1.2.3 From 483456590adee7b97b201c6c5880095be14e1fd9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jun 2022 14:20:54 +0200 Subject: wifi: mac80211: don't set link address for station 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 --- net/mac80211/iface.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f29764936c99..f4341f378d4e 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); -- cgit v1.2.3 From c57d2e6a6554df407ef63cc9b65290de2344d51e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 13:40:19 +0200 Subject: wifi: mac80211: remove redundant condition 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 --- 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 0409dcf5a6cb..e2472c0927ac 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -981,7 +981,7 @@ skip_rates: /* 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; -- cgit v1.2.3 From 19654a61bfd66539087119fbceed46e48f084d89 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 14:01:29 +0200 Subject: wifi: cfg80211: add ieee80211_chanwidth_rate_flags() To simplify things when we don't have a full chandef, add ieee80211_chanwidth_rate_flags(). Signed-off-by: Johannes Berg --- 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 2fe3eff11a8b..f9ea49e67164 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 * -- cgit v1.2.3 From 3dc05935ead81ffafa6d937552cfae1f1463b4a8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 14:01:59 +0200 Subject: wifi: mac80211: use only channel width in ieee80211_parse_bitrates() 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 --- 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 e0ddecbb50aa..a9f8042be36d 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 e2472c0927ac..e0b290730baf 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 9394aef30ba4..6d6ba23aa074 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3689,12 +3689,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; -- cgit v1.2.3 From c1690b66ba7016a5c25dc1fb77133cbf64622fcc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 14:08:25 +0200 Subject: wifi: mac80211: refactor adding rates to assoc request 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 --- 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 e0b290730baf..c1904acf7c4e 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); -- cgit v1.2.3 From 3c68cb81bf611f6c80ccb164556808d7e04cca89 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 15:38:57 +0200 Subject: wifi: mac80211: refactor adding custom elements 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 --- 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 c1904acf7c4e..0a6ed925aa47 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); -- cgit v1.2.3 From df9a9c44e91ba4305249a7e61284b15d54f70b19 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 16:14:33 +0200 Subject: wifi: mac80211: mlme: simplify adding ht/vht/he/eht elements 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 --- 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 0a6ed925aa47..152d011c84f0 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 */ -- cgit v1.2.3 From a95fe067825526b10c8a165df2d77db1ddce42fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 16:22:29 +0200 Subject: wifi: mac80211: consider EHT element size in assoc request 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 --- net/mac80211/mlme.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 152d011c84f0..3cb1f091f17e 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 */ -- cgit v1.2.3 From cdf0a0a80c841cfede6926d417a8756ea4c52d26 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Jul 2022 09:57:42 +0200 Subject: wifi: cfg80211: clean up links appropriately 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 --- 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); +} -- cgit v1.2.3 From 939c4c7e823b161701637720016999ef1f4ae4db Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Jul 2022 10:09:57 +0200 Subject: wifi: mac80211: tighten locking check 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 --- 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); } -- cgit v1.2.3 From d3e2439b0f339de319d27118f6de365753081179 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Jul 2022 14:03:07 +0200 Subject: wifi: mac80211: fix link manipulation 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 --- 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 f4341f378d4e..7410370c291b 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 */ -- cgit v1.2.3 From efbfe5165e5dd353343af47199e0ee0dba139aed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Jul 2022 15:31:55 +0200 Subject: wifi: nl80211: better validate link ID for stations 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 --- 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, ¶ms); +out: wdev_unlock(dev->ieee80211_ptr); - dev_put(params.vlan); return err; } -- cgit v1.2.3 From 4e9c3af398207d95957ae6c25290891574f2d7e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Jul 2022 15:02:33 +0200 Subject: wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities 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 --- 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 f9ea49e67164..bc960646973b 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; -- cgit v1.2.3 From 9b6bf4d6120adfe8c631830dbe1c7c6c64e07ce5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Jul 2022 15:03:51 +0200 Subject: wifi: nl80211: set BSS to NULL if IS_ERR() 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 --- 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; } -- cgit v1.2.3 From 8a263dcb585f5d4193e33e22ae245e90dd0b0786 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Jul 2022 15:11:54 +0200 Subject: wifi: mac80211: skip rate statistics for MLD STAs 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 --- 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); } -- cgit v1.2.3 From e434254946c64bb27d7b202c0eeac03e49c166aa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Jul 2022 15:28:14 +0200 Subject: wifi: mac80211: add a helper to fragment an element 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 --- 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 6d6ba23aa074..2ff8d1ec564c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -4780,3 +4780,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; +} -- cgit v1.2.3 From 45aaf17c0c3471efa3100dadfc65e3d459821443 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Jul 2022 18:19:27 +0200 Subject: wifi: nl80211: check MLO support in authenticate 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 --- 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]); -- cgit v1.2.3 From d2bc52498b6bafb7c2d80347b9f8fea9e3c7fc66 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sun, 26 Jun 2022 10:35:48 +0300 Subject: wifi: nl80211: Support MLD parameters in nl80211_set_station() Set the MLD parameters in NL80211_CMD_SET_STATION handling to be able to change an MLD station. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 = -- cgit v1.2.3 From 67207bab9341418698ae1029b28a44b58c39257e Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 30 Jun 2022 15:27:59 +0300 Subject: wifi: cfg80211/mac80211: Support control port TX from specific link In case of authentication with a legacy station, link addressed EAPOL frames should be sent. Support it. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 bc960646973b..8dbc64286d91 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 4a7a714de79e..8f25cfe0d543 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5674,7 +5674,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; @@ -5714,7 +5714,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, -- cgit v1.2.3 From d06faef148837e39c320ed0b20a325165c6ba8d4 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 30 Jun 2022 15:37:37 +0300 Subject: wifi: mac80211: Allow EAPOL frames from link addresses 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 Signed-off-by: Johannes Berg --- 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 c70156e49d0d..1c798c11648e 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) || @@ -4143,35 +4172,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; -- cgit v1.2.3 From 0d5891e347a4924a6e6fd8e2799e3d3c762983eb Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 30 Jun 2022 16:43:44 +0300 Subject: wifi: mac80211: Allow EAPOL tx from specific link Allow link source address on TX. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- 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 1c798c11648e..9f1ea8c840e9 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 8f25cfe0d543..9d91a5f28044 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); -- cgit v1.2.3 From 69c3f2d30c357613f9059809bc95170301056aee Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 12 Jun 2022 16:49:45 +0300 Subject: wifi: nl80211: allow link ID in set_wiphy with frequency This simplifies hostapd implementation, since it didn't switch to NL80211_CMD_SET_CHANNEL. Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- 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; } -- cgit v1.2.3 From e10b680118774cf43e02f9e1fc84989636d1b5e5 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 14 Jun 2022 10:16:26 +0300 Subject: wifi: mac80211: don't check carrier in chanctx code 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 Signed-off-by: Johannes Berg --- 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); -- cgit v1.2.3 From 0cbf348a9a790d5dfbfa1b5b463f09507e7594fc Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 22 Jun 2022 16:15:56 +0300 Subject: wifi: mac80211: Support multi link in ieee80211_recalc_min_chandef() 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 Signed-off-by: Johannes Berg --- 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 2ff8d1ec564c..739c05fdb9bb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2839,22 +2839,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); } -- cgit v1.2.3 From fa2ca639c4e6f8d9bf11687a7e5e348c4c15b8c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Jul 2022 10:08:11 +0200 Subject: wifi: nl80211: advertise MLO support 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 --- 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; -- cgit v1.2.3 From 727eff4dd198d79f9e81d3aafbab741a8374b5d0 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Sun, 3 Jul 2022 18:04:15 +0300 Subject: wifi: mac80211: replace link_id with link_conf in switch/(un)assign_vif_chanctx() 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 Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++-- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/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 @@ unlock: 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 @@ err: 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 @@ out: 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 @@ out: } 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 @@ out: 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 5da7a097d518..7d573e90ad81 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 @@ out: 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 @@ out: 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 dcb8b6dac2e1..e4ead73c5c43 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 739c05fdb9bb..8cb93d65b80e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2270,7 +2270,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); } -- cgit v1.2.3 From 7840bd468a99edac26492afa828b8fcbbbb2384e Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 4 Jul 2022 00:38:22 +0300 Subject: wifi: mac80211: remove link_id parameter from link_info_changed() Since struct ieee80211_bss_conf already contains link_id, passing link_id is not necessary. Signed-off-by: Gregory Greenman Signed-off-by: Johannes Berg --- 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 7d573e90ad81..5418c4973501 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 e4ead73c5c43..6fc4253b5644 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; -- cgit v1.2.3 From e3d331c9b6205d21ace0f5285d21a5ba553c1068 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jul 2022 10:24:23 +0200 Subject: wifi: cfg80211: set country_elem to NULL 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 --- 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 22996d63c15f..62c773cf1b8d 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 -- cgit v1.2.3 From 34d76a14f8f75df1b37557247a973b9093c74a24 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Jul 2022 11:53:20 +0200 Subject: wifi: nl80211: reject link specific elements on assoc link When we associate, we'll include all the elements for the link we're sending the association request on in the frame and the specific ones for other links in the multi-link element container. Prohibit adding link-specific elements for the association link. Fixes: d648c23024bd ("wifi: nl80211: support MLO in auth/assoc") Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ead9bd111280..be969f64b5c3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10813,6 +10813,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto free; } + if (req.links[req.link_id].elems_len) { + GENL_SET_ERR_MSG(info, + "cannot have per-link elems on assoc link"); + err = -EINVAL; + goto free; + } + kfree(attrs); attrs = NULL; } else { -- cgit v1.2.3 From df35f3164ec1150249bcf559e7837edde2a0c66a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Jul 2022 14:18:18 +0200 Subject: wifi: nl80211: reject fragmented and non-inheritance elements The underlying mac80211 code cannot deal with fragmented elements for purposes of sorting the elements into the association frame, so reject those inside the link. We might want to reject them inside the assoc frame, but they're used today for FILS, so cannot do that. The non-inheritance element inside the links similarly cannot be handled by mac80211, and outside the links it makes no sense. Reject both since using them could lead to an incorrect implementation. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index be969f64b5c3..e2d1efe0174e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10661,6 +10661,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_IE]) { req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + + if (cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, + req.ie, req.ie_len)) { + GENL_SET_ERR_MSG(info, + "non-inheritance makes no sense"); + return -EINVAL; + } } if (info->attrs[NL80211_ATTR_USE_MFP]) { @@ -10805,6 +10812,24 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) nla_data(attrs[NL80211_ATTR_IE]); req.links[link_id].elems_len = nla_len(attrs[NL80211_ATTR_IE]); + + if (cfg80211_find_elem(WLAN_EID_FRAGMENT, + req.links[link_id].elems, + req.links[link_id].elems_len)) { + GENL_SET_ERR_MSG(info, + "cannot deal with fragmentation"); + err = -EINVAL; + goto free; + } + + if (cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, + req.links[link_id].elems, + req.links[link_id].elems_len)) { + GENL_SET_ERR_MSG(info, + "cannot deal with non-inheritance"); + err = -EINVAL; + goto free; + } } } -- cgit v1.2.3 From ff5c4dc4cd78ae88e52f0eaa757c0d8fd222ccfd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 17:33:13 +0200 Subject: wifi: nl80211: fix some attribute policy entries The new NL80211_CMD_ADD_LINK_STA and NL80211_CMD_MODIFY_LINK_STA commands have strict policy validation, so fix the policy so it can be validated correctly. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e2d1efe0174e..b6e640437568 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -456,6 +456,12 @@ nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = { [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG }, }; +static const struct nla_policy +nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = { + [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, + [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, +}; + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, @@ -560,9 +566,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_USE_MFP] = NLA_POLICY_RANGE(NLA_U32, NL80211_MFP_NO, NL80211_MFP_OPTIONAL), - [NL80211_ATTR_STA_FLAGS2] = { - .len = sizeof(struct nl80211_sta_flag_update), - }, + [NL80211_ATTR_STA_FLAGS2] = + NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_sta_flag_update)), [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 }, [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG }, @@ -615,6 +620,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr, IEEE80211_MAX_DATA_LEN), [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_STA_WME] = NLA_POLICY_NESTED(nl80211_sta_wme_policy), [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 }, @@ -6722,12 +6728,6 @@ static struct net_device *get_vlan(struct genl_info *info, return ERR_PTR(ret); } -static const struct nla_policy -nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = { - [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, - [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, -}; - static int nl80211_parse_sta_wme(struct genl_info *info, struct station_parameters *params) { -- cgit v1.2.3 From 19343659c82e8a8d2208773446f3f83fe0c43de0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 13:35:54 +0200 Subject: wifi: mac80211: prohibit DEAUTH_NEED_MGD_TX_PREP in MLO For now, prohibit DEAUTH_NEED_MGD_TX_PREP since we can't really transmit this on a specific link yet as we don't know which links are active. Signed-off-by: Johannes Berg --- net/mac80211/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 26bb30606282..5b1c47ed0cc0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1001,6 +1001,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (WARN_ON(!ieee80211_hw_check(hw, AP_LINK_PS))) return -EINVAL; + + if (WARN_ON(ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP))) + return -EINVAL; } #ifdef CONFIG_PM -- cgit v1.2.3 From b048c98447fde83de9f9a2b0974aa1ffd931d012 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 13:36:37 +0200 Subject: wifi: mac80211: release channel context on link stop When a link is stopped for removal, release the channel context it may have. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7410370c291b..3d485835dec2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -420,6 +420,8 @@ static void ieee80211_link_stop(struct ieee80211_link_data *link) { if (link->sdata->vif.type == NL80211_IFTYPE_STATION) ieee80211_mgd_stop_link(link); + + ieee80211_link_release_channel(link); } struct link_container { -- cgit v1.2.3 From 64f4b93afaf18f471724268bbb2d43262a9e0334 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 13:40:02 +0200 Subject: wifi: mac80211: mlme: clean up supported channels element code Clean up the code building the supported channels element a little bit by using a local variable instead of the long line. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3cb1f091f17e..b55d10464b7d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1078,8 +1078,9 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) *pos++ = WLAN_EID_SUPPORTED_CHANNELS; *pos++ = 2 * sband->n_channels; for (i = 0; i < sband->n_channels; i++) { - *pos++ = ieee80211_frequency_to_channel( - sband->channels[i].center_freq); + int cf = sband->channels[i].center_freq; + + *pos++ = ieee80211_frequency_to_channel(cf); *pos++ = 1; /* one channel in the subband*/ } } -- cgit v1.2.3 From 8ec9a96b83bd69a8735f2a532105a62eb2e05309 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 13:38:07 +0200 Subject: wifi: mac80211: add multi-link element to AUTH frames When sending an authentication frame from an MLD, include the multi-link element with the MLD address and use the link address for transmission. Signed-off-by: Johannes Berg --- net/mac80211/util.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8cb93d65b80e..18e1ba8ffee6 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1714,11 +1714,28 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; + bool multi_link = sdata->vif.valid_links; + struct { + u8 id; + u8 len; + u8 ext_id; + struct ieee80211_multi_link_elem ml; + struct ieee80211_mle_basic_common_info basic; + } __packed mle = { + .id = WLAN_EID_EXTENSION, + .len = sizeof(mle) - 2, + .ext_id = WLAN_EID_EXT_EHT_MULTI_LINK, + .ml.control = cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC), + .basic.len = sizeof(mle.basic), + }; int err; + memcpy(mle.basic.mld_mac_addr, sdata->vif.addr, ETH_ALEN); + /* 24 + 6 = header + auth_algo + auth_transaction + status_code */ skb = dev_alloc_skb(local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN + - 24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN); + 24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN + + multi_link * sizeof(mle)); if (!skb) return; @@ -1735,6 +1752,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, mgmt->u.auth.status_code = cpu_to_le16(status); if (extra) skb_put_data(skb, extra, extra_len); + if (multi_link) + skb_put_data(skb, &mle, sizeof(mle)); if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); -- cgit v1.2.3 From de03f8ac5c5225a675c754c1b2b69771b77dfa84 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Jul 2022 15:13:20 +0200 Subject: wifi: mac80211: make ieee80211_check_rate_mask() link-aware Change ieee80211_check_rate_mask() to use a link rather than the sdata and deflink/bss_conf. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/rate.c | 9 +++++---- net/mac80211/rate.h | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9f8042be36d..bdc3d74eecc1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2524,7 +2524,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, params->basic_rates_len, &sdata->vif.bss_conf.basic_rates); changed |= BSS_CHANGED_BASIC_RATES; - ieee80211_check_rate_mask(sdata); + ieee80211_check_rate_mask(&sdata->deflink); } if (params->ap_isolate >= 0) { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b55d10464b7d..5c08b256bbc9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2361,7 +2361,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN); memcpy(sdata->vif.cfg.ap_addr, cbss->bssid, ETH_ALEN); - ieee80211_check_rate_mask(sdata); + ieee80211_check_rate_mask(link); if (sdata->vif.p2p || sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) { diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 7947e9a162a9..d5ea5f5bcf3a 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -270,17 +270,18 @@ static void rate_control_free(struct ieee80211_local *local, kfree(ctrl_ref); } -void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata) +void ieee80211_check_rate_mask(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - u32 user_mask, basic_rates = sdata->vif.bss_conf.basic_rates; + u32 user_mask, basic_rates = link->conf->basic_rates; enum nl80211_band band; - if (WARN_ON(!sdata->vif.bss_conf.chandef.chan)) + if (WARN_ON(!link->conf->chandef.chan)) return; - band = sdata->vif.bss_conf.chandef.chan->band; + band = link->conf->chandef.chan->band; if (band == NL80211_BAND_S1GHZ) { /* TODO */ return; diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index d89c13584dc8..d6190f10fe7c 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -85,7 +85,7 @@ static inline void rate_control_add_debugfs(struct ieee80211_local *local) #endif } -void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata); +void ieee80211_check_rate_mask(struct ieee80211_link_data *link); /* Get a reference to the rate control algorithm. If `name' is NULL, get the * first available algorithm. */ -- cgit v1.2.3 From 39eac2de0098c3ac3e9c35cfdc924543f1f67acc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 10:49:23 +0200 Subject: wifi: mac80211: move IEEE80211_SDATA_OPERATING_GMODE to link The flag here is currently per interface, but the way we set and clear it means it should be per link, so change it. Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 6 ++---- net/mac80211/ieee80211_i.h | 6 ++++-- net/mac80211/mlme.c | 7 ++----- net/mac80211/ocb.c | 2 +- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 8 ++++---- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index e8df4ce33984..60b5230778a3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -351,10 +351,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, bss_change |= BSS_CHANGED_ERP_SLOT; /* cf. IEEE 802.11 9.2.12 */ - if (chan->band == NL80211_BAND_2GHZ && have_higher_than_11mbit) - sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; - else - sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + sdata->deflink.operating_11g_mode = + chan->band == NL80211_BAND_2GHZ && have_higher_than_11mbit; ieee80211_set_wmm_default(&sdata->deflink, true, false); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 877f2441b74b..baaff4c7a79c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -726,7 +726,6 @@ struct ieee80211_if_mesh { * enum ieee80211_sub_if_data_flags - virtual interface flags * * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets - * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between * associated stations and deliver multicast frames both * back to wireless media and to the local net stack. @@ -737,7 +736,6 @@ struct ieee80211_if_mesh { */ enum ieee80211_sub_if_data_flags { IEEE80211_SDATA_ALLMULTI = BIT(0), - IEEE80211_SDATA_OPERATING_GMODE = BIT(2), IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), IEEE80211_SDATA_IN_DRIVER = BIT(5), @@ -884,6 +882,7 @@ struct ieee80211_link_data_managed { bool have_beacon; bool tracking_signal_avg; bool disable_wmm_tracking; + bool operating_11g_mode; bool csa_waiting_bcn; bool csa_ignored_same_chan; @@ -946,6 +945,9 @@ struct ieee80211_link_data { struct work_struct csa_finalize_work; bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + + bool operating_11g_mode; + struct cfg80211_chan_def csa_chandef; struct work_struct color_change_finalize_work; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5c08b256bbc9..babe4986207a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5811,11 +5811,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, link->conf->basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ - if (cbss->channel->band == NL80211_BAND_2GHZ && - have_higher_than_11mbit) - sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; - else - sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + link->operating_11g_mode = sband->band == NL80211_BAND_2GHZ && + have_higher_than_11mbit; skip_rates: memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN); diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 2ca2164a3098..8664fee699e9 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -181,7 +181,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, if (ifocb->joined == true) return -EINVAL; - sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + sdata->deflink.operating_11g_mode = true; sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = sdata->local->rx_chains; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9d91a5f28044..5dd29288c009 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -148,7 +148,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, case NL80211_BAND_2GHZ: case NL80211_BAND_LC: { u32 flag; - if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + if (tx->sdata->deflink.operating_11g_mode) flag = IEEE80211_RATE_MANDATORY_G; else flag = IEEE80211_RATE_MANDATORY_B; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 18e1ba8ffee6..fc66b292b1c0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -191,7 +191,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, if (vif) { sdata = vif_to_sdata(vif); short_preamble = sdata->vif.bss_conf.use_short_preamble; - if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + if (sdata->deflink.operating_11g_mode) erp = rate->flags & IEEE80211_RATE_ERP_G; shift = ieee80211_vif_get_shift(vif); } @@ -225,7 +225,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, if (vif) { sdata = vif_to_sdata(vif); short_preamble = sdata->vif.bss_conf.use_short_preamble; - if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + if (sdata->deflink.operating_11g_mode) erp = rate->flags & IEEE80211_RATE_ERP_G; shift = ieee80211_vif_get_shift(vif); } @@ -268,7 +268,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, if (vif) { sdata = vif_to_sdata(vif); short_preamble = sdata->vif.bss_conf.use_short_preamble; - if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + if (sdata->deflink.operating_11g_mode) erp = rate->flags & IEEE80211_RATE_ERP_G; shift = ieee80211_vif_get_shift(vif); } @@ -1617,7 +1617,7 @@ void ieee80211_set_wmm_default(struct ieee80211_link_data *link, 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); + !link->operating_11g_mode; rcu_read_unlock(); is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB); -- cgit v1.2.3 From bbe90107e1d9e1bb5fac0e36c63d4c1649a9a77d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 11:06:33 +0200 Subject: wifi: mac80211: mlme: refactor link station setup Refactor the code here since we need to have it also for each link station after association in MLO later. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 119 ++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index babe4986207a..0d43b20d6e6f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3485,6 +3485,67 @@ static bool ieee80211_twt_bcast_support(struct ieee80211_sub_if_data *sdata, IEEE80211_HE_MAC_CAP2_BCAST_TWT); } +static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link, + struct sta_info *sta, + struct ieee80211_link_sta *link_sta, + struct cfg80211_bss *cbss) +{ + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_local *local = sdata->local; + struct ieee80211_bss *bss = (void *)cbss->priv; + u32 rates = 0, basic_rates = 0; + bool have_higher_than_11mbit = false; + int min_rate = INT_MAX, min_rate_index = -1; + /* this is clearly wrong for MLO but we'll just remove it later */ + int shift = ieee80211_vif_get_shift(&sdata->vif); + struct ieee80211_supported_band *sband; + + memcpy(link_sta->addr, cbss->bssid, ETH_ALEN); + + /* TODO: S1G Basic Rate Set is expressed elsewhere */ + if (cbss->channel->band == NL80211_BAND_S1GHZ) { + ieee80211_s1g_sta_rate_init(sta); + return 0; + } + + sband = local->hw.wiphy->bands[cbss->channel->band]; + + ieee80211_get_rates(sband, bss->supp_rates, bss->supp_rates_len, + &rates, &basic_rates, &have_higher_than_11mbit, + &min_rate, &min_rate_index, shift); + + /* + * This used to be a workaround for basic rates missing + * in the association response frame. Now that we no + * longer use the basic rates from there, it probably + * doesn't happen any more, but keep the workaround so + * in case some *other* APs are buggy in different ways + * we can connect -- with a warning. + * Allow this workaround only in case the AP provided at least + * one rate. + */ + if (min_rate_index < 0) { + link_info(link, "No legacy rates in association response\n"); + return -EINVAL; + } else if (!basic_rates) { + link_info(link, "No basic rates, using min rate instead\n"); + basic_rates = BIT(min_rate_index); + } + + if (rates) + link_sta->supp_rates[cbss->channel->band] = rates; + else + link_info(link, "No rates found, keeping mandatory only\n"); + + link->conf->basic_rates = basic_rates; + + /* cf. IEEE 802.11 9.2.12 */ + link->operating_11g_mode = sband->band == NL80211_BAND_2GHZ && + have_higher_than_11mbit; + + return 0; +} + static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, struct cfg80211_bss *cbss, struct ieee80211_mgmt *mgmt, size_t len, @@ -5718,13 +5779,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 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; - sband = local->hw.wiphy->bands[cbss->channel->band]; - if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) return -EINVAL; @@ -5758,63 +5816,16 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, * it might need the new channel for that. */ if (new_sta) { - u32 rates = 0, basic_rates = 0; - bool have_higher_than_11mbit = false; - 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) { - ieee80211_s1g_sta_rate_init(new_sta); - goto skip_rates; - } - - ieee80211_get_rates(sband, bss->supp_rates, - bss->supp_rates_len, - &rates, &basic_rates, - &have_higher_than_11mbit, - &min_rate, &min_rate_index, - shift); - - /* - * This used to be a workaround for basic rates missing - * in the association response frame. Now that we no - * longer use the basic rates from there, it probably - * doesn't happen any more, but keep the workaround so - * in case some *other* APs are buggy in different ways - * we can connect -- with a warning. - * Allow this workaround only in case the AP provided at least - * one rate. - */ - if (min_rate_index < 0) { - sdata_info(sdata, - "No legacy rates in association response\n"); - + err = ieee80211_mgd_setup_link_sta(link, new_sta, + link_sta, cbss); + if (err) { sta_info_free(local, new_sta); - return -EINVAL; - } else if (!basic_rates) { - sdata_info(sdata, - "No basic rates, using min rate instead\n"); - basic_rates = BIT(min_rate_index); + return err; } - if (rates) - link_sta->supp_rates[cbss->channel->band] = rates; - else - sdata_info(sdata, - "No rates found, keeping mandatory only\n"); - - link->conf->basic_rates = basic_rates; - - /* cf. IEEE 802.11 9.2.12 */ - link->operating_11g_mode = sband->band == NL80211_BAND_2GHZ && - have_higher_than_11mbit; - -skip_rates: memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN); /* set timing information */ -- cgit v1.2.3 From 61513162aa2d6c17c37d25de2d0e5020cd9b37ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 11:13:56 +0200 Subject: wifi: mac80211: mlme: shift some code around We'll need ieee80211_prep_channel() in other code for MLO later, so move the code up - unchanged for now - to avoid forward declarations in the future. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 3634 ++++++++++++++++++++++++++------------------------- 1 file changed, 1825 insertions(+), 1809 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0d43b20d6e6f..43b64ec6e9df 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3546,2195 +3546,2211 @@ static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link, return 0; } -static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee802_11_elems *elems) +static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, + struct cfg80211_bss *cbss) { - 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; - const struct cfg80211_bss_ies *bss_ies = NULL; - 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; - int err; - bool ret; + struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; + const struct element *ht_cap_elem, *vht_cap_elem; + const struct cfg80211_bss_ies *ies; + const struct ieee80211_ht_cap *ht_cap; + const struct ieee80211_vht_cap *vht_cap; + const struct ieee80211_he_cap_elem *he_cap; + const struct element *he_cap_elem; + u16 mcs_80_map, mcs_160_map; + int i, mcs_nss_size; + bool support_160; + u8 chains = 1; - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) + return chains; - 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); + ht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_CAPABILITY); + if (ht_cap_elem && ht_cap_elem->datalen >= sizeof(*ht_cap)) { + ht_cap = (void *)ht_cap_elem->data; + chains = ieee80211_mcs_to_chains(&ht_cap->mcs); + /* + * TODO: use "Tx Maximum Number Spatial Streams Supported" and + * "Tx Unequal Modulation Supported" fields. + */ + } - /* - * The 5 MSB of the AID field are reserved - * (802.11-2016 9.4.1.8 AID field) - */ - aid &= 0x7ff; + if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) + return chains; - ifmgd->broken_ap = false; + vht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); + if (vht_cap_elem && vht_cap_elem->datalen >= sizeof(*vht_cap)) { + u8 nss; + u16 tx_mcs_map; - if (aid == 0 || aid > IEEE80211_MAX_AID) { - sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n", - aid); - aid = 0; - ifmgd->broken_ap = true; + vht_cap = (void *)vht_cap_elem->data; + tx_mcs_map = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map); + for (nss = 8; nss > 0; nss--) { + if (((tx_mcs_map >> (2 * (nss - 1))) & 3) != + IEEE80211_VHT_MCS_NOT_SUPPORTED) + break; + } + /* TODO: use "Tx Highest Supported Long GI Data Rate" field? */ + chains = max(chains, nss); } - if (!is_s1g && !elems->supp_rates) { - sdata_info(sdata, "no SuppRates element in AssocResp\n"); - ret = false; - goto out; - } + if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) + return chains; - sdata->vif.cfg.aid = aid; - 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); + ies = rcu_dereference(cbss->ies); + he_cap_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, + ies->data, ies->len); - /* - * Some APs are erroneously not including some information in their - * (re)association response frames. Try to recover by using the data - * from the beacon or probe response. This seems to afflict mobile - * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", - * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. - */ - if (!is_6ghz && - ((assoc_data->wmm && !elems->wmm_param) || - (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && - (!elems->ht_cap_elem || !elems->ht_operation)) || - (!(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; + if (!he_cap_elem || he_cap_elem->datalen < sizeof(*he_cap)) + return chains; - rcu_read_lock(); - ies = rcu_dereference(cbss->ies); - if (ies) - bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, - GFP_ATOMIC); - rcu_read_unlock(); - if (!bss_ies) { - ret = false; - goto out; - } + /* skip one byte ext_tag_id */ + he_cap = (void *)(he_cap_elem->data + 1); + mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap); - bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, - false, assoc_data->bss); - if (!bss_elems) { - ret = false; - goto out; - } + /* invalid HE IE */ + if (he_cap_elem->datalen < 1 + mcs_nss_size + sizeof(*he_cap)) + return chains; - if (assoc_data->wmm && - !elems->wmm_param && bss_elems->wmm_param) { - elems->wmm_param = bss_elems->wmm_param; - sdata_info(sdata, - "AP bug: WMM param missing from AssocResp\n"); - } + /* mcs_nss is right after he_cap info */ + he_mcs_nss_supp = (void *)(he_cap + 1); - /* - * Also check if we requested HT/VHT, otherwise the AP doesn't - * have to include the IEs in the (re)association response. - */ - if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && - !(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 && - !(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 && - !(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 && - !(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"); - } + mcs_80_map = le16_to_cpu(he_mcs_nss_supp->tx_mcs_80); - kfree(bss_elems); + for (i = 7; i >= 0; i--) { + u8 mcs_80 = mcs_80_map >> (2 * i) & 3; + + if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { + chains = max_t(u8, chains, i + 1); + break; + } } - /* - * We previously checked these in the beacon/probe response, so - * they should be present here. This is just a safety net. - */ - 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"); - ret = false; - goto out; + support_160 = he_cap->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + if (!support_160) + return chains; + + mcs_160_map = le16_to_cpu(he_mcs_nss_supp->tx_mcs_160); + for (i = 7; i >= 0; i--) { + u8 mcs_160 = mcs_160_map >> (2 * i) & 3; + + if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { + chains = max_t(u8, chains, i + 1); + break; + } } - if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && - (!elems->vht_cap_elem || !elems->vht_operation)) { + return chains; +} + +static bool +ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bss_ies *ies, + const struct ieee80211_he_operation *he_op) +{ + const struct element *he_cap_elem; + const struct ieee80211_he_cap_elem *he_cap; + struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; + u16 mcs_80_map_tx, mcs_80_map_rx; + u16 ap_min_req_set; + int mcs_nss_size; + int nss; + + he_cap_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, + ies->data, ies->len); + + /* invalid HE IE */ + if (!he_cap_elem || he_cap_elem->datalen < 1 + sizeof(*he_cap)) { sdata_info(sdata, - "VHT AP is missing VHT capability/operation\n"); - ret = false; - goto out; + "Invalid HE elem, Disable HE\n"); + return false; } - if (is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && - !elems->he_6ghz_capa) { + /* skip one byte ext_tag_id */ + he_cap = (void *)(he_cap_elem->data + 1); + mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap); + + /* invalid HE IE */ + if (he_cap_elem->datalen < 1 + sizeof(*he_cap) + mcs_nss_size) { sdata_info(sdata, - "HE 6 GHz AP is missing HE 6 GHz band capability\n"); - ret = false; - goto out; + "Invalid HE elem with nss size, Disable HE\n"); + return false; } - mutex_lock(&sdata->local->sta_mtx); - /* - * station info was already allocated and inserted before - * the association and should be available to us - */ - sta = sta_info_get(sdata, cbss->bssid); - if (WARN_ON(!sta)) { - mutex_unlock(&sdata->local->sta_mtx); - ret = false; - goto out; - } + /* mcs_nss is right after he_cap info */ + he_mcs_nss_supp = (void *)(he_cap + 1); - 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); - ret = false; - goto out; - } + mcs_80_map_tx = le16_to_cpu(he_mcs_nss_supp->tx_mcs_80); + mcs_80_map_rx = le16_to_cpu(he_mcs_nss_supp->rx_mcs_80); - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && - (!elems->he_cap || !elems->he_operation)) { - mutex_unlock(&sdata->local->sta_mtx); + /* P802.11-REVme/D0.3 + * 27.1.1 Introduction to the HE PHY + * ... + * An HE STA shall support the following features: + * ... + * Single spatial stream HE-MCSs 0 to 7 (transmit and receive) in all + * supported channel widths for HE SU PPDUs + */ + if ((mcs_80_map_tx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED || + (mcs_80_map_rx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED) { sdata_info(sdata, - "HE AP is missing HE capability/operation\n"); - ret = false; - goto out; + "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n", + mcs_80_map_tx, mcs_80_map_rx); + return false; } - /* Set up internal HT/VHT capabilities */ - 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, - link_sta); + if (!he_op) + return true; - 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, - link_sta); + ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); - 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, - elems->he_cap_len, - elems->he_6ghz_capa, - link_sta); + /* + * Apparently iPhone 13 (at least iOS version 15.3.1) sets this to all + * zeroes, which is nonsense, and completely inconsistent with itself + * (it doesn't have 8 streams). Accept the settings in this case anyway. + */ + if (!ap_min_req_set) + return true; - 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, - NL80211_EXT_FEATURE_PROTECTED_TWT)) - bss_conf->twt_protected = true; - else - bss_conf->twt_protected = false; + /* make sure the AP is consistent with itself + * + * P802.11-REVme/D0.3 + * 26.17.1 Basic HE BSS operation + * + * A STA that is operating in an HE BSS shall be able to receive and + * transmit at each of the tuple values indicated by the + * Basic HE-MCS And NSS Set field of the HE Operation parameter of the + * MLME-START.request primitive and shall be able to receive at each of + * the tuple values indicated by the Supported HE-MCS and + * NSS Set field in the HE Capabilities parameter of the MLMESTART.request + * primitive + */ + for (nss = 8; nss > 0; nss--) { + u8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; + u8 ap_rx_val; + u8 ap_tx_val; - changed |= ieee80211_recalc_twt_req(link, link_sta, elems); + if (ap_op_val == IEEE80211_HE_MCS_NOT_SUPPORTED) + continue; - if (elems->eht_operation && elems->eht_cap && - !(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, - elems->eht_cap, - elems->eht_cap_len, - link_sta); + ap_rx_val = (mcs_80_map_rx >> (2 * (nss - 1))) & 3; + ap_tx_val = (mcs_80_map_tx >> (2 * (nss - 1))) & 3; - bss_conf->eht_support = link_sta->pub->eht_cap.has_eht; - } else { - bss_conf->eht_support = false; + if (ap_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + ap_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) { + sdata_info(sdata, + "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n", + nss, ap_rx_val, ap_rx_val, ap_op_val); + return false; } - } else { - bss_conf->he_support = false; - bss_conf->twt_requester = false; - bss_conf->twt_protected = false; - bss_conf->eht_support = false; } - bss_conf->twt_broadcast = - ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta); - - if (bss_conf->he_support) { - bss_conf->he_bss_color.color = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_BSS_COLOR_MASK); - bss_conf->he_bss_color.partial = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR); - bss_conf->he_bss_color.enabled = - !le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED); - - if (bss_conf->he_bss_color.enabled) - changed |= BSS_CHANGED_HE_BSS_COLOR; - - bss_conf->htc_trig_based_pkt_ext = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK); - bss_conf->frame_time_rts_th = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); + return true; +} - bss_conf->uora_exists = !!elems->uora_element; - if (elems->uora_element) - bss_conf->uora_ocw_range = elems->uora_element[0]; +static bool +ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + const struct ieee80211_he_operation *he_op) +{ + const struct ieee80211_sta_he_cap *sta_he_cap = + ieee80211_get_he_iftype_cap(sband, + ieee80211_vif_type_p2p(&sdata->vif)); + u16 ap_min_req_set; + int i; - ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation); - ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr); - /* TODO: OPEN: what happens if BSS color disable is set? */ - } + if (!sta_he_cap || !he_op) + return false; - if (cbss->transmitted_bss) { - bss_conf->nontransmitted = true; - ether_addr_copy(bss_conf->transmitter_bssid, - cbss->transmitted_bss->bssid); - bss_conf->bssid_indicator = cbss->max_bssid_indicator; - bss_conf->bssid_index = cbss->bssid_index; - } else { - bss_conf->nontransmitted = false; - memset(bss_conf->transmitter_bssid, 0, - sizeof(bss_conf->transmitter_bssid)); - bss_conf->bssid_indicator = 0; - bss_conf->bssid_index = 0; - } + ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); /* - * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data - * in their association response, so ignore that data for our own - * configuration. If it changed since the last beacon, we'll get the - * next beacon and update then. + * Apparently iPhone 13 (at least iOS version 15.3.1) sets this to all + * zeroes, which is nonsense, and completely inconsistent with itself + * (it doesn't have 8 streams). Accept the settings in this case anyway. */ + if (!ap_min_req_set) + return true; - /* - * If an operating mode notification IE is present, override the - * NSS calculation (that would be done in rate_control_rate_init()) - * and use the # of streams from that element. - */ - if (elems->opmode_notif && - !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { + /* Need to go over for 80MHz, 160MHz and for 80+80 */ + for (i = 0; i < 3; i++) { + const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp = + &sta_he_cap->he_mcs_nss_supp; + u16 sta_mcs_map_rx = + le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]); + u16 sta_mcs_map_tx = + le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]); u8 nss; + bool verified = true; - nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; - nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; - nss += 1; - link_sta->pub->rx_nss = nss; - } - - rate_control_rate_init(sta); + /* + * For each band there is a maximum of 8 spatial streams + * possible. Each of the sta_mcs_map_* is a 16-bit struct built + * of 2 bits per NSS (1-8), with the values defined in enum + * ieee80211_he_mcs_support. Need to make sure STA TX and RX + * capabilities aren't less than the AP's minimum requirements + * for this HE BSS per SS. + * It is enough to find one such band that meets the reqs. + */ + for (nss = 8; nss > 0; nss--) { + u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3; + u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3; + u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; - if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) { - set_sta_flag(sta, WLAN_STA_MFP); - sta->sta.mfp = true; - } else { - sta->sta.mfp = false; - } + if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED) + continue; - sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && - local->hw.queues >= IEEE80211_NUM_ACS; + /* + * Make sure the HE AP doesn't require MCSs that aren't + * supported by the client as required by spec + * + * P802.11-REVme/D0.3 + * 26.17.1 Basic HE BSS operation + * + * An HE STA shall not attempt to join * (MLME-JOIN.request primitive) + * a BSS, unless it supports (i.e., is able to both transmit and + * receive using) all of the tuples in the basic + * HE-MCS and NSS set. + */ + if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || + (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) { + verified = false; + break; + } + } - err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); - if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); - if (err) { - sdata_info(sdata, - "failed to move station %pM to desired state\n", - sta->sta.addr); - WARN_ON(__sta_info_destroy(sta)); - mutex_unlock(&sdata->local->sta_mtx); - ret = false; - goto out; + if (verified) + return true; } - if (sdata->wdev.use_4addr) - drv_sta_set_4addr(local, sdata, &sta->sta, true); - - mutex_unlock(&sdata->local->sta_mtx); + /* If here, STA doesn't meet AP's HE min requirements */ + return false; +} - /* - * Always handle WMM once after association regardless - * of the first value the AP uses. Setting -1 here has - * that effect because the AP values is an unsigned - * 4-bit value. - */ - link->u.mgd.wmm_last_param_set = -1; - link->u.mgd.mu_edca_last_param_set = -1; +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; + const struct ieee80211_ht_cap *ht_cap = NULL; + const struct ieee80211_ht_operation *ht_oper = NULL; + const struct ieee80211_vht_operation *vht_oper = NULL; + const struct ieee80211_he_operation *he_oper = NULL; + const struct ieee80211_eht_operation *eht_oper = NULL; + const struct ieee80211_s1g_oper_ie *s1g_oper = NULL; + struct ieee80211_supported_band *sband; + struct cfg80211_chan_def chandef; + bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; + bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; + struct ieee80211_bss *bss = (void *)cbss->priv; + struct ieee802_11_elems *elems; + const struct cfg80211_bss_ies *ies; + int ret; + u32 i; + bool have_80mhz; - 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); - /* 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. - */ - link->u.mgd.disable_wmm_tracking = true; + rcu_read_lock(); + + ies = rcu_dereference(cbss->ies); + elems = ieee802_11_parse_elems(ies->data, ies->len, false, cbss); + if (!elems) { + rcu_read_unlock(); + return -ENOMEM; } - changed |= BSS_CHANGED_QOS; - if (elems->max_idle_period_ie) { - bss_conf->max_idle_period = - le16_to_cpu(elems->max_idle_period_ie->max_idle_period); - bss_conf->protected_keep_alive = - !!(elems->max_idle_period_ie->idle_options & - WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE); - changed |= BSS_CHANGED_KEEP_ALIVE; - } else { - bss_conf->max_idle_period = 0; - bss_conf->protected_keep_alive = false; + sband = local->hw.wiphy->bands[cbss->channel->band]; + + 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"); + 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; } - /* set assoc capability (AID was already set earlier), - * ieee80211_set_associated() will tell the driver */ - bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, cbss, changed); + if (!sband->vht_cap.vht_supported && is_5ghz) { + mlme_dbg(sdata, "VHT not supported, disabling VHT/HE/EHT\n"); + 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 we're using 4-addr mode, let the AP know that we're - * doing so, so that it can create the STA VLAN on its side - */ - if (ifmgd->use_4addr) - ieee80211_send_4addr_nullfunc(local, sdata); + if (!ieee80211_get_he_iftype_cap(sband, + ieee80211_vif_type_p2p(&sdata->vif))) { + mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n"); + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + } - /* - * Start timer to probe the connection to the AP now. - * Also start the timer that will detect beacon loss. - */ - ieee80211_sta_reset_beacon_monitor(sdata); - ieee80211_sta_reset_conn_monitor(sdata); + if (!ieee80211_get_eht_iftype_cap(sband, + ieee80211_vif_type_p2p(&sdata->vif))) { + mlme_dbg(sdata, "EHT not supported, disabling EHT\n"); + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + } - ret = true; - out: - kfree(bss_ies); - return ret; -} + if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) { + ht_oper = elems->ht_operation; + ht_cap = elems->ht_cap_elem; -static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; - u16 capab_info, status_code, aid; - struct ieee802_11_elems *elems; - int ac; - u8 *pos; - bool reassoc; - struct cfg80211_bss *cbss; - struct ieee80211_event event = { - .type = MLME_EVENT, - .u.mlme.data = ASSOC_EVENT, - }; - struct ieee80211_prep_tx_info info = {}; - struct cfg80211_rx_assoc_resp resp = { - .uapsd_queues = -1, - }; + if (!ht_cap) { + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; + ht_oper = NULL; + } + } - sdata_assert_lock(sdata); + 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"); + 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 (!assoc_data) - return; + if (!elems->vht_cap_elem) { + sdata_info(sdata, + "bad VHT capabilities, disabling VHT\n"); + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; + vht_oper = NULL; + } + } - if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid)) - return; + if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) { + he_oper = elems->he_operation; - cbss = assoc_data->bss; + if (is_6ghz) { + struct ieee80211_bss_conf *bss_conf; + u8 j = 0; - /* - * AssocResp and ReassocResp have identical structure, so process both - * of them in this function. - */ + bss_conf = link->conf; - if (len < 24 + 6) - return; + if (elems->pwr_constr_elem) + bss_conf->pwr_reduction = *elems->pwr_constr_elem; - reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control); - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - pos = mgmt->u.assoc_resp.variable; - aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - if (cbss->channel->band == NL80211_BAND_S1GHZ) { - pos = (u8 *) mgmt->u.s1g_assoc_resp.variable; - aid = 0; /* TODO */ + BUILD_BUG_ON(ARRAY_SIZE(bss_conf->tx_pwr_env) != + ARRAY_SIZE(elems->tx_pwr_env)); + + for (i = 0; i < elems->tx_pwr_env_num; i++) { + if (elems->tx_pwr_env_len[i] > + sizeof(bss_conf->tx_pwr_env[j])) + continue; + + bss_conf->tx_pwr_env_num++; + memcpy(&bss_conf->tx_pwr_env[j], elems->tx_pwr_env[i], + elems->tx_pwr_env_len[i]); + j++; + } + } + + if (!ieee80211_verify_peer_he_mcs_support(sdata, ies, he_oper) || + !ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper)) + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE | + IEEE80211_CONN_DISABLE_EHT; } /* - * Note: this may not be perfect, AP might misbehave - if - * anyone needs to rely on perfect complete notification - * with the exact right subtype, then we need to track what - * we actually transmitted. + * EHT requires HE to be supported as well. Specifically for 6 GHz + * channels, the operation channel information can only be deduced from + * both the 6 GHz operation information (from the HE operation IE) and + * EHT operation. */ - info.subtype = reassoc ? IEEE80211_STYPE_REASSOC_REQ : - IEEE80211_STYPE_ASSOC_REQ; - - sdata_info(sdata, - "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", - reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + if (!(link->u.mgd.conn_flags & + (IEEE80211_CONN_DISABLE_HE | + IEEE80211_CONN_DISABLE_EHT)) && + he_oper) { + const struct cfg80211_bss_ies *cbss_ies; + const u8 *eht_oper_ie; - if (assoc_data->fils_kek_len && - fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) - return; + cbss_ies = rcu_dereference(cbss->ies); + eht_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_EHT_OPERATION, + cbss_ies->data, cbss_ies->len); + if (eht_oper_ie && eht_oper_ie[1] >= + 1 + sizeof(struct ieee80211_eht_operation)) + eht_oper = (void *)(eht_oper_ie + 3); + else + eht_oper = NULL; + } - elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, - assoc_data->bss); - if (!elems) - goto notify_driver; + /* Allow VHT if at least one channel on the sband supports 80 MHz */ + have_80mhz = false; + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_80MHZ)) + continue; - if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && - elems->timeout_int && - elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { - u32 tu, ms; + have_80mhz = true; + break; + } - cfg80211_assoc_comeback(sdata->dev, assoc_data->bss->bssid, - le32_to_cpu(elems->timeout_int->value)); + if (!have_80mhz) { + sdata_info(sdata, "80 MHz not supported, disabling VHT\n"); + link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; + } - tu = le32_to_cpu(elems->timeout_int->value); - ms = tu * 1024 / 1000; - sdata_info(sdata, - "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", - mgmt->sa, tu, ms); - assoc_data->timeout = jiffies + msecs_to_jiffies(ms); - assoc_data->timeout_started = true; - if (ms > IEEE80211_ASSOC_TIMEOUT) - run_again(sdata, assoc_data->timeout); - goto notify_driver; + if (sband->band == NL80211_BAND_S1GHZ) { + s1g_oper = elems->s1g_oper; + if (!s1g_oper) + sdata_info(sdata, + "AP missing S1G operation element?\n"); } - if (status_code != WLAN_STATUS_SUCCESS) { - sdata_info(sdata, "%pM denied association (code=%d)\n", - mgmt->sa, status_code); - 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 */ - ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); - goto notify_driver; - } - event.u.mlme.status = MLME_SUCCESS; - drv_event_callback(sdata->local, sdata, &event); - sdata_info(sdata, "associated\n"); + link->u.mgd.conn_flags |= + ieee80211_determine_chantype(link, sband, + cbss->channel, + bss->vht_cap_info, + ht_oper, vht_oper, + he_oper, eht_oper, + s1g_oper, + &chandef, false); - /* - * destroy assoc_data afterwards, as otherwise an idle - * recalc after assoc_data is NULL but before associated - * is set can cause the interface to go idle - */ - ieee80211_destroy_assoc_data(sdata, ASSOC_SUCCESS); + link->needed_rx_chains = + min(ieee80211_max_rx_chains(link, cbss), local->rx_chains); - /* get uapsd queues configuration */ - resp.uapsd_queues = 0; - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (sdata->deflink.tx_conf[ac].uapsd) - resp.uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; + rcu_read_unlock(); + /* the element data was RCU protected so no longer valid anyway */ + kfree(elems); + elems = NULL; - info.success = 1; + if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { + sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); + return -EINVAL; } - resp.links[0].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); -} - -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; + /* will change later if needed */ + link->smps_mode = IEEE80211_SMPS_OFF; - sdata_assert_lock(sdata); + mutex_lock(&local->mtx); + /* + * If this fails (possibly due to channel context sharing + * 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(link, &chandef, + IEEE80211_CHANCTX_SHARED); - channel = ieee80211_get_channel_khz(local->hw.wiphy, - ieee80211_rx_status_to_khz(rx_status)); - if (!channel) - return; + /* don't downgrade for 5 and 10 MHz channels, though. */ + if (chandef.width == NL80211_CHAN_WIDTH_5 || + chandef.width == NL80211_CHAN_WIDTH_10) + goto out; - bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel); - if (bss) { - link->conf->beacon_rate = bss->beacon_rate; - ieee80211_rx_bss_put(local, bss); + while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { + link->u.mgd.conn_flags |= + ieee80211_chandef_downgrade(&chandef); + ret = ieee80211_link_use_channel(link, &chandef, + IEEE80211_CHANCTX_SHARED); } + out: + mutex_unlock(&local->mtx); + return ret; } - -static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_link_data *link, - struct sk_buff *skb) +static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss, + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee802_11_elems *elems) { - 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; - struct ieee80211_channel *channel; - size_t baselen, len = skb->len; + 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; + const struct cfg80211_bss_ies *bss_ies = NULL; + 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; + int err; + bool ret; - ifmgd = &sdata->u.mgd; + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - sdata_assert_lock(sdata); + 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); /* - * According to Draft P802.11ax D6.0 clause 26.17.2.3.2: - * "If a 6 GHz AP receives a Probe Request frame and responds with - * a Probe Response frame [..], the Address 1 field of the Probe - * Response frame shall be set to the broadcast address [..]" - * So, on 6GHz band we should also accept broadcast responses. + * The 5 MSB of the AID field are reserved + * (802.11-2016 9.4.1.8 AID field) */ - channel = ieee80211_get_channel(sdata->local->hw.wiphy, - rx_status->freq); - if (!channel) - return; + aid &= 0x7ff; - if (!ether_addr_equal(mgmt->da, sdata->vif.addr) && - (channel->band != NL80211_BAND_6GHZ || - !is_broadcast_ether_addr(mgmt->da))) - return; /* ignore ProbeResp to foreign address */ + ifmgd->broken_ap = false; - baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; - if (baselen > len) - return; + if (aid == 0 || aid > IEEE80211_MAX_AID) { + sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n", + aid); + aid = 0; + ifmgd->broken_ap = true; + } - ieee80211_rx_bss_info(link, mgmt, len, rx_status); + if (!is_s1g && !elems->supp_rates) { + sdata_info(sdata, "no SuppRates element in AssocResp\n"); + ret = false; + goto out; + } - if (ifmgd->associated && - ether_addr_equal(mgmt->bssid, link->u.mgd.bssid)) - ieee80211_reset_ap_probe(sdata); -} + sdata->vif.cfg.aid = aid; + 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); -/* - * This is the canonical list of information elements we care about, - * the filter code also gives us all changes to the Microsoft OUI - * (00:50:F2) vendor IE which is used for WMM which we need to track, - * as well as the DTPC IE (part of the Cisco OUI) used for signaling - * changes to requested client power. - * - * We implement beacon filtering in software since that means we can - * avoid processing the frame here and in cfg80211, and userspace - * will not be able to tell whether the hardware supports it or not. - * - * XXX: This list needs to be dynamic -- userspace needs to be able to - * add items it requires. It also needs to be able to tell us to - * look out for other vendor IEs. - */ -static const u64 care_about_ies = - (1ULL << WLAN_EID_COUNTRY) | - (1ULL << WLAN_EID_ERP_INFO) | - (1ULL << WLAN_EID_CHANNEL_SWITCH) | - (1ULL << WLAN_EID_PWR_CONSTRAINT) | - (1ULL << WLAN_EID_HT_CAPABILITY) | - (1ULL << WLAN_EID_HT_OPERATION) | - (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN); + /* + * Some APs are erroneously not including some information in their + * (re)association response frames. Try to recover by using the data + * from the beacon or probe response. This seems to afflict mobile + * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", + * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. + */ + if (!is_6ghz && + ((assoc_data->wmm && !elems->wmm_param) || + (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && + (!elems->ht_cap_elem || !elems->ht_operation)) || + (!(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; -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; + rcu_read_lock(); + ies = rcu_dereference(cbss->ies); + if (ies) + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, + GFP_ATOMIC); + rcu_read_unlock(); + if (!bss_ies) { + ret = false; + goto out; + } - /* Track average RSSI from the Beacon frames of the current AP */ + bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, + false, assoc_data->bss); + if (!bss_elems) { + ret = false; + goto out; + } - 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 { - link->u.mgd.count_beacon_signal++; - } - - ewma_beacon_signal_add(&link->u.mgd.ave_beacon_signal, - -rx_status->signal); - - if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && - 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, - }; + if (assoc_data->wmm && + !elems->wmm_param && bss_elems->wmm_param) { + elems->wmm_param = bss_elems->wmm_param; + sdata_info(sdata, + "AP bug: WMM param missing from AssocResp\n"); + } /* - * if signal crosses either of the boundaries, invoke callback - * with appropriate parameters + * Also check if we requested HT/VHT, otherwise the AP doesn't + * have to include the IEs in the (re)association response. */ - if (sig > ifmgd->rssi_max_thold && - (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { - 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)) { - link->u.mgd.last_ave_beacon_signal = sig; - event.u.rssi.data = RSSI_EVENT_LOW; - drv_event_callback(local, sdata, &event); + if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && + !(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 (bss_conf->cqm_rssi_thold && - 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(&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)) { - 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)) { - link->u.mgd.last_cqm_event_signal = sig; - ieee80211_cqm_rssi_notify( - &sdata->vif, - NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, - sig, GFP_KERNEL); + if (!elems->ht_operation && bss_elems->ht_operation && + !(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 (bss_conf->cqm_rssi_low && - 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)) { - 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)) { - link->u.mgd.last_cqm_event_signal = sig; - ieee80211_cqm_rssi_notify( - &sdata->vif, - NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, - sig, GFP_KERNEL); + if (!elems->vht_cap_elem && bss_elems->vht_cap_elem && + !(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 && + !(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"); } - } -} - -static bool ieee80211_rx_our_beacon(const u8 *tx_bssid, - struct cfg80211_bss *bss) -{ - if (ether_addr_equal(tx_bssid, bss->bssid)) - return true; - if (!bss->transmitted_bss) - return false; - return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid); -} - -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; - struct ieee80211_mgmt *mgmt = (void *) hdr; - size_t baselen; - struct ieee802_11_elems *elems; - 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; - u8 erp_value = 0; - u32 ncrc = 0; - u8 *bssid, *variable = mgmt->u.beacon.variable; - u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; - - sdata_assert_lock(sdata); - - /* Process beacon from the current BSS */ - bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type); - if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { - struct ieee80211_ext *ext = (void *) mgmt; - if (ieee80211_is_s1g_short_beacon(ext->frame_control)) - variable = ext->u.s1g_short_beacon.variable; - else - variable = ext->u.s1g_beacon.variable; + kfree(bss_elems); } - baselen = (u8 *) variable - (u8 *) mgmt; - if (baselen > len) - return; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(link->conf->chanctx_conf); - if (!chanctx_conf) { - rcu_read_unlock(); - return; + /* + * We previously checked these in the beacon/probe response, so + * they should be present here. This is just a safety net. + */ + 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"); + ret = false; + goto out; } - if (ieee80211_rx_status_to_khz(rx_status) != - ieee80211_channel_to_khz(chanctx_conf->def.chan)) { - rcu_read_unlock(); - return; + 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"); + ret = false; + goto out; } - chan = chanctx_conf->def.chan; - rcu_read_unlock(); - - 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, - ifmgd->assoc_data->bss); - if (!elems) - return; - ieee80211_rx_bss_info(link, mgmt, len, rx_status); + 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"); + ret = false; + goto out; + } - if (elems->dtim_period) - 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)) { - link->conf->sync_tsf = - le64_to_cpu(mgmt->u.beacon.timestamp); - link->conf->sync_device_ts = - rx_status->device_timestamp; - link->conf->sync_dtim_count = elems->dtim_count; - } + mutex_lock(&sdata->local->sta_mtx); + /* + * station info was already allocated and inserted before + * the association and should be available to us + */ + sta = sta_info_get(sdata, cbss->bssid); + if (WARN_ON(!sta)) { + mutex_unlock(&sdata->local->sta_mtx); + ret = false; + goto out; + } - if (elems->mbssid_config_ie) - bss_conf->profile_periodicity = - elems->mbssid_config_ie->profile_periodicity; - else - bss_conf->profile_periodicity = 0; + 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; + } - if (elems->ext_capab_len >= 11 && - (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) - bss_conf->ema_ap = true; - else - bss_conf->ema_ap = false; + sband = ieee80211_get_link_sband(link); + if (!sband) { + mutex_unlock(&sdata->local->sta_mtx); + ret = false; + goto out; + } - /* continue assoc process */ - ifmgd->assoc_data->timeout = jiffies; - ifmgd->assoc_data->timeout_started = true; - run_again(sdata, ifmgd->assoc_data->timeout); - kfree(elems); - return; + 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, + "HE AP is missing HE capability/operation\n"); + ret = false; + goto out; } - if (!ifmgd->associated || - !ieee80211_rx_our_beacon(bssid, link->u.mgd.bss)) - return; - bssid = link->u.mgd.bssid; + /* Set up internal HT/VHT capabilities */ + 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, + link_sta); - if (!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)) - ieee80211_handle_beacon_sig(link, ifmgd, bss_conf, - local, rx_status); + 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, + link_sta); - if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { - mlme_dbg_ratelimited(sdata, - "cancelling AP probe due to a received beacon\n"); - ieee80211_reset_ap_probe(sdata); - } + 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, + elems->he_cap_len, + elems->he_6ghz_capa, + link_sta); - /* - * Push the beacon loss detection into the future since - * we are processing a beacon from the AP just now. - */ - ieee80211_sta_reset_beacon_monitor(sdata); + 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, + NL80211_EXT_FEATURE_PROTECTED_TWT)) + bss_conf->twt_protected = true; + else + bss_conf->twt_protected = false; - /* TODO: CRC urrently not calculated on S1G Beacon Compatibility - * element (which carries the beacon interval). Don't forget to add a - * bit to care_about_ies[] above if mac80211 is interested in a - * changing S1G element. - */ - if (!ieee80211_is_s1g_beacon(hdr->frame_control)) - 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, - link->u.mgd.bss); - if (!elems) - return; - ncrc = elems->crc; + changed |= ieee80211_recalc_twt_req(link, link_sta, elems); - if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && - ieee80211_check_tim(elems->tim, elems->tim_len, vif_cfg->aid)) { - if (local->hw.conf.dynamic_ps_timeout > 0) { - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_PS); - } - ieee80211_send_nullfunc(local, sdata, false); - } else if (!local->pspolling && sdata->u.mgd.powersave) { - local->pspolling = true; + if (elems->eht_operation && elems->eht_cap && + !(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, + elems->eht_cap, + elems->eht_cap_len, + link_sta); - /* - * Here is assumed that the driver will be - * able to send ps-poll frame and receive a - * response even though power save mode is - * enabled, but some drivers might require - * to disable power save here. This needs - * to be investigated. - */ - ieee80211_send_pspoll(local, sdata); + bss_conf->eht_support = link_sta->pub->eht_cap.has_eht; + } else { + bss_conf->eht_support = false; } + } else { + bss_conf->he_support = false; + bss_conf->twt_requester = false; + bss_conf->twt_protected = false; + bss_conf->eht_support = false; } - if (sdata->vif.p2p || - sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) { - struct ieee80211_p2p_noa_attr noa = {}; - int ret; + bss_conf->twt_broadcast = + ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta); - ret = cfg80211_get_p2p_attr(variable, - len - baselen, - IEEE80211_P2P_ATTR_ABSENCE_NOTICE, - (u8 *) &noa, sizeof(noa)); - if (ret >= 2) { - if (link->u.mgd.p2p_noa_index != noa.index) { - /* valid noa_attr and index changed */ - 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. - */ - link->u.mgd.beacon_crc_valid = false; - } - } else if (link->u.mgd.p2p_noa_index != -1) { - /* noa_attr not found and we had valid noa_attr before */ - 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; - link->u.mgd.beacon_crc_valid = false; - } - } + if (bss_conf->he_support) { + bss_conf->he_bss_color.color = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_BSS_COLOR_MASK); + bss_conf->he_bss_color.partial = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR); + bss_conf->he_bss_color.enabled = + !le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED); - if (link->u.mgd.csa_waiting_bcn) - ieee80211_chswitch_post_beacon(link); + if (bss_conf->he_bss_color.enabled) + changed |= BSS_CHANGED_HE_BSS_COLOR; - /* - * Update beacon timing and dtim count on every beacon appearance. This - * will allow the driver to use the most updated values. Do it before - * comparing this one with last received beacon. - * IMPORTANT: These parameters would possibly be out of sync by the time - * the driver will use them. The synchronized view is currently - * guaranteed only in certain callbacks. - */ - if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && - !ieee80211_is_s1g_beacon(hdr->frame_control)) { - link->conf->sync_tsf = - le64_to_cpu(mgmt->u.beacon.timestamp); - link->conf->sync_device_ts = - rx_status->device_timestamp; - link->conf->sync_dtim_count = elems->dtim_count; - } + bss_conf->htc_trig_based_pkt_ext = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK); + bss_conf->frame_time_rts_th = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); - if ((ncrc == link->u.mgd.beacon_crc && link->u.mgd.beacon_crc_valid) || - ieee80211_is_s1g_short_beacon(mgmt->frame_control)) - goto free; - link->u.mgd.beacon_crc = ncrc; - link->u.mgd.beacon_crc_valid = true; + bss_conf->uora_exists = !!elems->uora_element; + if (elems->uora_element) + bss_conf->uora_ocw_range = elems->uora_element[0]; - ieee80211_rx_bss_info(link, mgmt, len, rx_status); + ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation); + ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr); + /* TODO: OPEN: what happens if BSS color disable is set? */ + } - ieee80211_sta_process_chanswitch(link, rx_status->mactime, - rx_status->device_timestamp, - elems, true); + if (cbss->transmitted_bss) { + bss_conf->nontransmitted = true; + ether_addr_copy(bss_conf->transmitter_bssid, + cbss->transmitted_bss->bssid); + bss_conf->bssid_indicator = cbss->max_bssid_indicator; + bss_conf->bssid_index = cbss->bssid_index; + } else { + bss_conf->nontransmitted = false; + memset(bss_conf->transmitter_bssid, 0, + sizeof(bss_conf->transmitter_bssid)); + bss_conf->bssid_indicator = 0; + bss_conf->bssid_index = 0; + } - 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)) - changed |= BSS_CHANGED_QOS; + /* + * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data + * in their association response, so ignore that data for our own + * configuration. If it changed since the last beacon, we'll get the + * next beacon and update then. + */ /* - * If we haven't had a beacon before, tell the driver about the - * DTIM period (and beacon timing if desired) now. + * If an operating mode notification IE is present, override the + * NSS calculation (that would be done in rate_control_rate_init()) + * and use the # of streams from that element. */ - 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; + if (elems->opmode_notif && + !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { + u8 nss; - changed |= BSS_CHANGED_BEACON_INFO; - link->u.mgd.have_beacon = true; + nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; + nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; + nss += 1; + link_sta->pub->rx_nss = nss; + } - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local); - mutex_unlock(&local->iflist_mtx); + rate_control_rate_init(sta); - ieee80211_recalc_ps_vif(sdata); + if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) { + set_sta_flag(sta, WLAN_STA_MFP); + sta->sta.mfp = true; + } else { + sta->sta.mfp = false; } - if (elems->erp_info) { - erp_valid = true; - erp_value = elems->erp_info[0]; - } else { - erp_valid = false; + sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && + local->hw.queues >= IEEE80211_NUM_ACS; + + err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); + if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + if (err) { + sdata_info(sdata, + "failed to move station %pM to desired state\n", + sta->sta.addr); + WARN_ON(__sta_info_destroy(sta)); + mutex_unlock(&sdata->local->sta_mtx); + ret = false; + goto out; } - if (!ieee80211_is_s1g_beacon(hdr->frame_control)) - changed |= ieee80211_handle_bss_capability(link, - le16_to_cpu(mgmt->u.beacon.capab_info), - erp_valid, erp_value); + if (sdata->wdev.use_4addr) + drv_sta_set_4addr(local, sdata, &sta->sta, true); - 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; + mutex_unlock(&sdata->local->sta_mtx); - changed |= ieee80211_recalc_twt_req(link, link_sta, elems); + /* + * Always handle WMM once after association regardless + * of the first value the AP uses. Setting -1 here has + * that effect because the AP values is an unsigned + * 4-bit value. + */ + link->u.mgd.wmm_last_param_set = -1; + link->u.mgd.mu_edca_last_param_set = -1; - 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, - elems->s1g_oper, bssid, &changed)) { - mutex_unlock(&local->sta_mtx); - sdata_info(sdata, - "failed to follow AP %pM bandwidth change, disconnect\n", - bssid); - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, - WLAN_REASON_DEAUTH_LEAVING, - true, deauth_buf); - ieee80211_report_disconnect(sdata, deauth_buf, - sizeof(deauth_buf), true, - WLAN_REASON_DEAUTH_LEAVING, - false); - goto free; + 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); + /* 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. + */ + link->u.mgd.disable_wmm_tracking = true; } + changed |= BSS_CHANGED_QOS; - if (sta && elems->opmode_notif) - ieee80211_vht_handle_opmode(sdata, link_sta, - *elems->opmode_notif, - rx_status->band); - mutex_unlock(&local->sta_mtx); - - changed |= ieee80211_handle_pwr_constr(link, chan, mgmt, - elems->country_elem, - elems->country_elem_len, - elems->pwr_constr_elem, - elems->cisco_dtpc_elem); + if (elems->max_idle_period_ie) { + bss_conf->max_idle_period = + le16_to_cpu(elems->max_idle_period_ie->max_idle_period); + bss_conf->protected_keep_alive = + !!(elems->max_idle_period_ie->idle_options & + WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE); + changed |= BSS_CHANGED_KEEP_ALIVE; + } else { + bss_conf->max_idle_period = 0; + bss_conf->protected_keep_alive = false; + } - ieee80211_link_info_change_notify(sdata, link, changed); -free: - kfree(elems); -} + /* set assoc capability (AID was already set earlier), + * ieee80211_set_associated() will tell the driver */ + bss_conf->assoc_capability = capab_info; + ieee80211_set_associated(sdata, cbss, changed); -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; + /* + * If we're using 4-addr mode, let the AP know that we're + * doing so, so that it can create the STA VLAN on its side + */ + if (ifmgd->use_4addr) + ieee80211_send_4addr_nullfunc(local, sdata); - rx_status = (struct ieee80211_rx_status *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); + /* + * Start timer to probe the connection to the AP now. + * Also start the timer that will detect beacon loss. + */ + ieee80211_sta_reset_beacon_monitor(sdata); + ieee80211_sta_reset_conn_monitor(sdata); - sdata_lock(sdata); - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_S1G_BEACON: - ieee80211_rx_mgmt_beacon(link, hdr, skb->len, rx_status); - break; - } - sdata_unlock(sdata); + ret = true; + out: + kfree(bss_ies); + return ret; } -void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) +static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, + size_t len) { - struct ieee80211_link_data *link = &sdata->deflink; - struct ieee80211_rx_status *rx_status; - struct ieee80211_mgmt *mgmt; - u16 fc; - int ies_len; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + u16 capab_info, status_code, aid; + struct ieee802_11_elems *elems; + int ac; + u8 *pos; + bool reassoc; + struct cfg80211_bss *cbss; + struct ieee80211_event event = { + .type = MLME_EVENT, + .u.mlme.data = ASSOC_EVENT, + }; + struct ieee80211_prep_tx_info info = {}; + struct cfg80211_rx_assoc_resp resp = { + .uapsd_queues = -1, + }; - rx_status = (struct ieee80211_rx_status *) skb->cb; - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); + sdata_assert_lock(sdata); - sdata_lock(sdata); + if (!assoc_data) + return; - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(link, (void *)mgmt, - skb->len, rx_status); - break; - case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(link, skb); - break; - case IEEE80211_STYPE_AUTH: - ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_DEAUTH: - ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_DISASSOC: - ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_ACTION: - if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { - struct ieee802_11_elems *elems; + if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid)) + return; - ies_len = skb->len - - offsetof(struct ieee80211_mgmt, - u.action.u.chan_switch.variable); + cbss = assoc_data->bss; - if (ies_len < 0) - break; + /* + * AssocResp and ReassocResp have identical structure, so process both + * of them in this function. + */ - /* CSA IE cannot be overridden, no need for BSSID */ - elems = ieee802_11_parse_elems( - mgmt->u.action.u.chan_switch.variable, - ies_len, true, NULL); + if (len < 24 + 6) + return; - if (elems && !elems->parse_error) - ieee80211_sta_process_chanswitch(link, - rx_status->mactime, - rx_status->device_timestamp, - elems, false); - kfree(elems); - } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { - struct ieee802_11_elems *elems; + reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control); + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + pos = mgmt->u.assoc_resp.variable; + aid = le16_to_cpu(mgmt->u.assoc_resp.aid); + if (cbss->channel->band == NL80211_BAND_S1GHZ) { + pos = (u8 *) mgmt->u.s1g_assoc_resp.variable; + aid = 0; /* TODO */ + } - ies_len = skb->len - - offsetof(struct ieee80211_mgmt, - u.action.u.ext_chan_switch.variable); + /* + * Note: this may not be perfect, AP might misbehave - if + * anyone needs to rely on perfect complete notification + * with the exact right subtype, then we need to track what + * we actually transmitted. + */ + info.subtype = reassoc ? IEEE80211_STYPE_REASSOC_REQ : + IEEE80211_STYPE_ASSOC_REQ; - if (ies_len < 0) - break; + sdata_info(sdata, + "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", + reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); - /* - * extended CSA IE can't be overridden, no need for - * BSSID - */ - elems = ieee802_11_parse_elems( - mgmt->u.action.u.ext_chan_switch.variable, - ies_len, true, NULL); + if (assoc_data->fils_kek_len && + fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) + return; - if (elems && !elems->parse_error) { - /* for the handling code pretend it was an IE */ - elems->ext_chansw_ie = - &mgmt->u.action.u.ext_chan_switch.data; + elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, + assoc_data->bss); + if (!elems) + goto notify_driver; - ieee80211_sta_process_chanswitch(link, - rx_status->mactime, - rx_status->device_timestamp, - elems, false); - } + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && + elems->timeout_int && + elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; - kfree(elems); - } - break; - } - sdata_unlock(sdata); -} + cfg80211_assoc_comeback(sdata->dev, assoc_data->bss->bssid, + le32_to_cpu(elems->timeout_int->value)); -static void ieee80211_sta_timer(struct timer_list *t) -{ - struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mgd.timer); + tu = le32_to_cpu(elems->timeout_int->value); + ms = tu * 1024 / 1000; + sdata_info(sdata, + "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", + mgmt->sa, tu, ms); + assoc_data->timeout = jiffies + msecs_to_jiffies(ms); + assoc_data->timeout_started = true; + if (ms > IEEE80211_ASSOC_TIMEOUT) + run_again(sdata, assoc_data->timeout); + goto notify_driver; + } - ieee80211_queue_work(&sdata->local->hw, &sdata->work); -} + if (status_code != WLAN_STATUS_SUCCESS) { + sdata_info(sdata, "%pM denied association (code=%d)\n", + mgmt->sa, status_code); + 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 */ + ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); + goto notify_driver; + } + event.u.mlme.status = MLME_SUCCESS; + drv_event_callback(sdata->local, sdata, &event); + sdata_info(sdata, "associated\n"); -void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, - u8 reason, bool tx) -{ - u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; + /* + * destroy assoc_data afterwards, as otherwise an idle + * recalc after assoc_data is NULL but before associated + * is set can cause the interface to go idle + */ + ieee80211_destroy_assoc_data(sdata, ASSOC_SUCCESS); - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, - tx, frame_buf); + /* get uapsd queues configuration */ + resp.uapsd_queues = 0; + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + if (sdata->deflink.tx_conf[ac].uapsd) + resp.uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; - ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, - reason, false); + info.success = 1; + } + + resp.links[0].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); } -static int ieee80211_auth(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_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; - u32 tx_flags = 0; - u16 trans = 1; - u16 status = 0; - struct ieee80211_prep_tx_info info = { - .subtype = IEEE80211_STYPE_AUTH, - }; + struct ieee80211_bss *bss; + struct ieee80211_channel *channel; sdata_assert_lock(sdata); - if (WARN_ON_ONCE(!auth_data)) - return -EINVAL; - - auth_data->tries++; - - if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { - sdata_info(sdata, "authentication with %pM timed out\n", - auth_data->bss->bssid); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss); + channel = ieee80211_get_channel_khz(local->hw.wiphy, + ieee80211_rx_status_to_khz(rx_status)); + if (!channel) + return; - return -ETIMEDOUT; + bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel); + if (bss) { + link->conf->beacon_rate = bss->beacon_rate; + ieee80211_rx_bss_put(local, bss); } +} - if (auth_data->algorithm == WLAN_AUTH_SAE) - info.duration = jiffies_to_msecs(IEEE80211_AUTH_TIMEOUT_SAE); - - drv_mgd_prepare_tx(local, sdata, &info); - sdata_info(sdata, "send auth to %pM (try %d/%d)\n", - auth_data->bss->bssid, auth_data->tries, - IEEE80211_AUTH_MAX_TRIES); +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; + struct ieee80211_channel *channel; + size_t baselen, len = skb->len; - auth_data->expected_transaction = 2; + ifmgd = &sdata->u.mgd; - if (auth_data->algorithm == WLAN_AUTH_SAE) { - trans = auth_data->sae_trans; - status = auth_data->sae_status; - auth_data->expected_transaction = trans; - } + sdata_assert_lock(sdata); - if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) - tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | - IEEE80211_TX_INTFL_MLME_CONN_TX; + /* + * According to Draft P802.11ax D6.0 clause 26.17.2.3.2: + * "If a 6 GHz AP receives a Probe Request frame and responds with + * a Probe Response frame [..], the Address 1 field of the Probe + * Response frame shall be set to the broadcast address [..]" + * So, on 6GHz band we should also accept broadcast responses. + */ + channel = ieee80211_get_channel(sdata->local->hw.wiphy, + rx_status->freq); + if (!channel) + return; - ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, - auth_data->data, auth_data->data_len, - auth_data->bss->bssid, - auth_data->bss->bssid, NULL, 0, 0, - tx_flags); + if (!ether_addr_equal(mgmt->da, sdata->vif.addr) && + (channel->band != NL80211_BAND_6GHZ || + !is_broadcast_ether_addr(mgmt->da))) + return; /* ignore ProbeResp to foreign address */ - if (tx_flags == 0) { - if (auth_data->algorithm == WLAN_AUTH_SAE) - auth_data->timeout = jiffies + - IEEE80211_AUTH_TIMEOUT_SAE; - else - auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - } else { - auth_data->timeout = - round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG); - } + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; + if (baselen > len) + return; - auth_data->timeout_started = true; - run_again(sdata, auth_data->timeout); + ieee80211_rx_bss_info(link, mgmt, len, rx_status); - return 0; + if (ifmgd->associated && + ether_addr_equal(mgmt->bssid, link->u.mgd.bssid)) + ieee80211_reset_ap_probe(sdata); } -static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) +/* + * This is the canonical list of information elements we care about, + * the filter code also gives us all changes to the Microsoft OUI + * (00:50:F2) vendor IE which is used for WMM which we need to track, + * as well as the DTPC IE (part of the Cisco OUI) used for signaling + * changes to requested client power. + * + * We implement beacon filtering in software since that means we can + * avoid processing the frame here and in cfg80211, and userspace + * will not be able to tell whether the hardware supports it or not. + * + * XXX: This list needs to be dynamic -- userspace needs to be able to + * add items it requires. It also needs to be able to tell us to + * look out for other vendor IEs. + */ +static const u64 care_about_ies = + (1ULL << WLAN_EID_COUNTRY) | + (1ULL << WLAN_EID_ERP_INFO) | + (1ULL << WLAN_EID_CHANNEL_SWITCH) | + (1ULL << WLAN_EID_PWR_CONSTRAINT) | + (1ULL << WLAN_EID_HT_CAPABILITY) | + (1ULL << WLAN_EID_HT_OPERATION) | + (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN); + +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_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; - struct ieee80211_local *local = sdata->local; - int ret; + struct ieee80211_sub_if_data *sdata = link->sdata; - sdata_assert_lock(sdata); + /* Track average RSSI from the Beacon frames of the current AP */ - assoc_data->tries++; - if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { - sdata_info(sdata, "association with %pM timed out\n", - assoc_data->bss->bssid); + 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 { + link->u.mgd.count_beacon_signal++; + } + + ewma_beacon_signal_add(&link->u.mgd.ave_beacon_signal, + -rx_status->signal); + + if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && + 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, + }; /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. + * if signal crosses either of the boundaries, invoke callback + * with appropriate parameters */ - cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss); + if (sig > ifmgd->rssi_max_thold && + (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { + 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)) { + link->u.mgd.last_ave_beacon_signal = sig; + event.u.rssi.data = RSSI_EVENT_LOW; + drv_event_callback(local, sdata, &event); + } + } - return -ETIMEDOUT; + if (bss_conf->cqm_rssi_thold && + 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(&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)) { + 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)) { + link->u.mgd.last_cqm_event_signal = sig; + ieee80211_cqm_rssi_notify( + &sdata->vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + sig, GFP_KERNEL); + } } - sdata_info(sdata, "associate with %pM (try %d/%d)\n", - assoc_data->bss->bssid, assoc_data->tries, - IEEE80211_ASSOC_MAX_TRIES); - ret = ieee80211_send_assoc(sdata); - if (ret) - return ret; + if (bss_conf->cqm_rssi_low && + 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 (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { - assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - assoc_data->timeout_started = true; - run_again(sdata, assoc_data->timeout); - } else { - assoc_data->timeout = - round_jiffies_up(jiffies + - IEEE80211_ASSOC_TIMEOUT_LONG); - assoc_data->timeout_started = true; - run_again(sdata, assoc_data->timeout); + if (sig < low && + (last_event == 0 || last_event >= low)) { + 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)) { + link->u.mgd.last_cqm_event_signal = sig; + ieee80211_cqm_rssi_notify( + &sdata->vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + sig, GFP_KERNEL); + } } - - return 0; } -void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, - __le16 fc, bool acked) +static bool ieee80211_rx_our_beacon(const u8 *tx_bssid, + struct cfg80211_bss *bss) { - struct ieee80211_local *local = sdata->local; - - sdata->u.mgd.status_fc = fc; - sdata->u.mgd.status_acked = acked; - sdata->u.mgd.status_received = true; - - ieee80211_queue_work(&local->hw, &sdata->work); + if (ether_addr_equal(tx_bssid, bss->bssid)) + return true; + if (!bss->transmitted_bss) + return false; + return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid); } -void ieee80211_sta_work(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_local *local = sdata->local; + 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; + struct ieee80211_mgmt *mgmt = (void *) hdr; + size_t baselen; + struct ieee802_11_elems *elems; + 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; + u8 erp_value = 0; + u32 ncrc = 0; + u8 *bssid, *variable = mgmt->u.beacon.variable; + u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; - sdata_lock(sdata); + sdata_assert_lock(sdata); - if (ifmgd->status_received) { - __le16 fc = ifmgd->status_fc; - bool status_acked = ifmgd->status_acked; + /* Process beacon from the current BSS */ + bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type); + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { + struct ieee80211_ext *ext = (void *) mgmt; - ifmgd->status_received = false; - if (ifmgd->auth_data && ieee80211_is_auth(fc)) { - if (status_acked) { - if (ifmgd->auth_data->algorithm == - WLAN_AUTH_SAE) - ifmgd->auth_data->timeout = - jiffies + - IEEE80211_AUTH_TIMEOUT_SAE; - else - ifmgd->auth_data->timeout = - jiffies + - IEEE80211_AUTH_TIMEOUT_SHORT; - run_again(sdata, ifmgd->auth_data->timeout); - } else { - ifmgd->auth_data->timeout = jiffies - 1; - } - ifmgd->auth_data->timeout_started = true; - } else if (ifmgd->assoc_data && - (ieee80211_is_assoc_req(fc) || - ieee80211_is_reassoc_req(fc))) { - if (status_acked) { - ifmgd->assoc_data->timeout = - jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT; - run_again(sdata, ifmgd->assoc_data->timeout); - } else { - ifmgd->assoc_data->timeout = jiffies - 1; - } - ifmgd->assoc_data->timeout_started = true; - } + if (ieee80211_is_s1g_short_beacon(ext->frame_control)) + variable = ext->u.s1g_short_beacon.variable; + else + variable = ext->u.s1g_beacon.variable; } - if (ifmgd->auth_data && ifmgd->auth_data->timeout_started && - time_after(jiffies, ifmgd->auth_data->timeout)) { - if (ifmgd->auth_data->done || ifmgd->auth_data->waiting) { - /* - * ok ... we waited for assoc or continuation but - * userspace didn't do it, so kill the auth data - */ - ieee80211_destroy_auth_data(sdata, false); - } else if (ieee80211_auth(sdata)) { - u8 bssid[ETH_ALEN]; - struct ieee80211_event event = { - .type = MLME_EVENT, - .u.mlme.data = AUTH_EVENT, - .u.mlme.status = MLME_TIMEOUT, - }; + baselen = (u8 *) variable - (u8 *) mgmt; + if (baselen > len) + return; - memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); + rcu_read_lock(); + chanctx_conf = rcu_dereference(link->conf->chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + return; + } - ieee80211_destroy_auth_data(sdata, false); + if (ieee80211_rx_status_to_khz(rx_status) != + ieee80211_channel_to_khz(chanctx_conf->def.chan)) { + rcu_read_unlock(); + return; + } + chan = chanctx_conf->def.chan; + rcu_read_unlock(); - cfg80211_auth_timeout(sdata->dev, bssid); - drv_event_callback(sdata->local, sdata, &event); - } - } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) - run_again(sdata, ifmgd->auth_data->timeout); + 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, + ifmgd->assoc_data->bss); + if (!elems) + return; - if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && - time_after(jiffies, ifmgd->assoc_data->timeout)) { - if ((ifmgd->assoc_data->need_beacon && - !sdata->deflink.u.mgd.have_beacon) || - ieee80211_do_assoc(sdata)) { - struct ieee80211_event event = { - .type = MLME_EVENT, - .u.mlme.data = ASSOC_EVENT, - .u.mlme.status = MLME_TIMEOUT, - }; + ieee80211_rx_bss_info(link, mgmt, len, rx_status); - ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); - drv_event_callback(sdata->local, sdata, &event); + if (elems->dtim_period) + 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)) { + link->conf->sync_tsf = + le64_to_cpu(mgmt->u.beacon.timestamp); + link->conf->sync_device_ts = + rx_status->device_timestamp; + link->conf->sync_dtim_count = elems->dtim_count; } - } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) - run_again(sdata, ifmgd->assoc_data->timeout); - if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL && - ifmgd->associated) { - u8 *bssid = sdata->deflink.u.mgd.bssid; - int max_tries; + if (elems->mbssid_config_ie) + bss_conf->profile_periodicity = + elems->mbssid_config_ie->profile_periodicity; + else + bss_conf->profile_periodicity = 0; - if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) - max_tries = max_nullfunc_tries; + if (elems->ext_capab_len >= 11 && + (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) + bss_conf->ema_ap = true; else - max_tries = max_probe_tries; + bss_conf->ema_ap = false; + + /* continue assoc process */ + ifmgd->assoc_data->timeout = jiffies; + ifmgd->assoc_data->timeout_started = true; + run_again(sdata, ifmgd->assoc_data->timeout); + kfree(elems); + return; + } + + if (!ifmgd->associated || + !ieee80211_rx_our_beacon(bssid, link->u.mgd.bss)) + return; + bssid = link->u.mgd.bssid; + + if (!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)) + ieee80211_handle_beacon_sig(link, ifmgd, bss_conf, + local, rx_status); + + if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { + mlme_dbg_ratelimited(sdata, + "cancelling AP probe due to a received beacon\n"); + ieee80211_reset_ap_probe(sdata); + } + + /* + * Push the beacon loss detection into the future since + * we are processing a beacon from the AP just now. + */ + ieee80211_sta_reset_beacon_monitor(sdata); + + /* TODO: CRC urrently not calculated on S1G Beacon Compatibility + * element (which carries the beacon interval). Don't forget to add a + * bit to care_about_ies[] above if mac80211 is interested in a + * changing S1G element. + */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + 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, + link->u.mgd.bss); + if (!elems) + return; + ncrc = elems->crc; + + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && + ieee80211_check_tim(elems->tim, elems->tim_len, vif_cfg->aid)) { + if (local->hw.conf.dynamic_ps_timeout > 0) { + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_PS); + } + ieee80211_send_nullfunc(local, sdata, false); + } else if (!local->pspolling && sdata->u.mgd.powersave) { + local->pspolling = true; - /* ACK received for nullfunc probing frame */ - if (!ifmgd->probe_send_count) - ieee80211_reset_ap_probe(sdata); - else if (ifmgd->nullfunc_failed) { - if (ifmgd->probe_send_count < max_tries) { - mlme_dbg(sdata, - "No ack for nullfunc frame to AP %pM, try %d/%i\n", - bssid, ifmgd->probe_send_count, - max_tries); - ieee80211_mgd_probe_ap_send(sdata); - } else { - mlme_dbg(sdata, - "No ack for nullfunc frame to AP %pM, disconnecting.\n", - bssid); - ieee80211_sta_connection_lost(sdata, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - false); - } - } else if (time_is_after_jiffies(ifmgd->probe_timeout)) - run_again(sdata, ifmgd->probe_timeout); - else if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { - mlme_dbg(sdata, - "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", - bssid, probe_wait_ms); - ieee80211_sta_connection_lost(sdata, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); - } else if (ifmgd->probe_send_count < max_tries) { - mlme_dbg(sdata, - "No probe response from AP %pM after %dms, try %d/%i\n", - bssid, probe_wait_ms, - ifmgd->probe_send_count, max_tries); - ieee80211_mgd_probe_ap_send(sdata); - } else { /* - * We actually lost the connection ... or did we? - * Let's make sure! + * Here is assumed that the driver will be + * able to send ps-poll frame and receive a + * response even though power save mode is + * enabled, but some drivers might require + * to disable power save here. This needs + * to be investigated. */ - mlme_dbg(sdata, - "No probe response from AP %pM after %dms, disconnecting.\n", - bssid, probe_wait_ms); - - ieee80211_sta_connection_lost(sdata, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); + ieee80211_send_pspoll(local, sdata); } } - sdata_unlock(sdata); -} - -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; + if (sdata->vif.p2p || + sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) { + struct ieee80211_p2p_noa_attr noa = {}; + int ret; - if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) - return; + ret = cfg80211_get_p2p_attr(variable, + len - baselen, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + (u8 *) &noa, sizeof(noa)); + if (ret >= 2) { + if (link->u.mgd.p2p_noa_index != noa.index) { + /* valid noa_attr and index changed */ + 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. + */ + link->u.mgd.beacon_crc_valid = false; + } + } else if (link->u.mgd.p2p_noa_index != -1) { + /* noa_attr not found and we had valid noa_attr before */ + 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; + link->u.mgd.beacon_crc_valid = false; + } + } - sdata->u.mgd.connection_loss = false; - ieee80211_queue_work(&sdata->local->hw, - &sdata->u.mgd.beacon_connection_loss_work); -} + if (link->u.mgd.csa_waiting_bcn) + ieee80211_chswitch_post_beacon(link); -static void ieee80211_sta_conn_mon_timer(struct timer_list *t) -{ - struct ieee80211_sub_if_data *sdata = - from_timer(sdata, t, u.mgd.conn_mon_timer); - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - unsigned long timeout; + /* + * Update beacon timing and dtim count on every beacon appearance. This + * will allow the driver to use the most updated values. Do it before + * comparing this one with last received beacon. + * IMPORTANT: These parameters would possibly be out of sync by the time + * the driver will use them. The synchronized view is currently + * guaranteed only in certain callbacks. + */ + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && + !ieee80211_is_s1g_beacon(hdr->frame_control)) { + link->conf->sync_tsf = + le64_to_cpu(mgmt->u.beacon.timestamp); + link->conf->sync_device_ts = + rx_status->device_timestamp; + link->conf->sync_dtim_count = elems->dtim_count; + } - if (WARN_ON(sdata->vif.valid_links)) - return; + if ((ncrc == link->u.mgd.beacon_crc && link->u.mgd.beacon_crc_valid) || + ieee80211_is_s1g_short_beacon(mgmt->frame_control)) + goto free; + link->u.mgd.beacon_crc = ncrc; + link->u.mgd.beacon_crc_valid = true; - if (sdata->vif.bss_conf.csa_active && - !sdata->deflink.u.mgd.csa_waiting_bcn) - return; + ieee80211_rx_bss_info(link, mgmt, len, rx_status); - sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); - if (!sta) - return; + ieee80211_sta_process_chanswitch(link, rx_status->mactime, + rx_status->device_timestamp, + elems, true); - timeout = sta->deflink.status_stats.last_ack; - if (time_before(sta->deflink.status_stats.last_ack, sta->deflink.rx_stats.last_rx)) - timeout = sta->deflink.rx_stats.last_rx; - timeout += IEEE80211_CONNECTION_IDLE_TIME; + 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)) + changed |= BSS_CHANGED_QOS; - /* If timeout is after now, then update timer to fire at - * the later date, but do not actually probe at this time. + /* + * If we haven't had a beacon before, tell the driver about the + * DTIM period (and beacon timing if desired) now. */ - if (time_is_after_jiffies(timeout)) { - mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout)); - return; - } - - ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); -} + 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; -static void ieee80211_sta_monitor_work(struct work_struct *work) -{ - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, - u.mgd.monitor_work); + changed |= BSS_CHANGED_BEACON_INFO; + link->u.mgd.have_beacon = true; - ieee80211_mgd_probe_ap(sdata, false); -} + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local); + mutex_unlock(&local->iflist_mtx); -static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) -{ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - __ieee80211_stop_poll(sdata); + ieee80211_recalc_ps_vif(sdata); + } - /* let's probe the connection once */ - if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR)) - ieee80211_queue_work(&sdata->local->hw, - &sdata->u.mgd.monitor_work); + if (elems->erp_info) { + erp_valid = true; + erp_value = elems->erp_info[0]; + } else { + erp_valid = false; } -} -#ifdef CONFIG_PM -void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + changed |= ieee80211_handle_bss_capability(link, + le16_to_cpu(mgmt->u.beacon.capab_info), + erp_valid, erp_value); - sdata_lock(sdata); + 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; - if (ifmgd->auth_data || ifmgd->assoc_data) { - const u8 *bssid = ifmgd->auth_data ? - ifmgd->auth_data->bss->bssid : - ifmgd->assoc_data->bss->bssid; + changed |= ieee80211_recalc_twt_req(link, link_sta, elems); - /* - * If we are trying to authenticate / associate while suspending, - * cfg80211 won't know and won't actually abort those attempts, - * thus we need to do that ourselves. - */ - ieee80211_send_deauth_disassoc(sdata, bssid, bssid, - IEEE80211_STYPE_DEAUTH, - WLAN_REASON_DEAUTH_LEAVING, - false, frame_buf); - if (ifmgd->assoc_data) - 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, - IEEE80211_DEAUTH_FRAME_LEN, - false); + 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, + elems->s1g_oper, bssid, &changed)) { + mutex_unlock(&local->sta_mtx); + sdata_info(sdata, + "failed to follow AP %pM bandwidth change, disconnect\n", + bssid); + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DEAUTH_LEAVING, + true, deauth_buf); + ieee80211_report_disconnect(sdata, deauth_buf, + sizeof(deauth_buf), true, + WLAN_REASON_DEAUTH_LEAVING, + false); + goto free; } - /* This is a bit of a hack - we should find a better and more generic - * solution to this. Normally when suspending, cfg80211 will in fact - * deauthenticate. However, it doesn't (and cannot) stop an ongoing - * auth (not so important) or assoc (this is the problem) process. - * - * As a consequence, it can happen that we are in the process of both - * associating and suspending, and receive an association response - * after cfg80211 has checked if it needs to disconnect, but before - * we actually set the flag to drop incoming frames. This will then - * cause the workqueue flush to process the association response in - * the suspend, resulting in a successful association just before it - * tries to remove the interface from the driver, which now though - * has a channel context assigned ... this results in issues. - * - * To work around this (for now) simply deauth here again if we're - * now connected. - */ - if (ifmgd->associated && !sdata->local->wowlan) { - u8 bssid[ETH_ALEN]; - struct cfg80211_deauth_request req = { - .reason_code = WLAN_REASON_DEAUTH_LEAVING, - .bssid = bssid, - }; + if (sta && elems->opmode_notif) + ieee80211_vht_handle_opmode(sdata, link_sta, + *elems->opmode_notif, + rx_status->band); + mutex_unlock(&local->sta_mtx); - memcpy(bssid, sdata->vif.cfg.ap_addr, ETH_ALEN); - ieee80211_mgd_deauth(sdata, &req); - } + changed |= ieee80211_handle_pwr_constr(link, chan, mgmt, + elems->country_elem, + elems->country_elem_len, + elems->pwr_constr_elem, + elems->cisco_dtpc_elem); - sdata_unlock(sdata); + ieee80211_link_info_change_notify(sdata, link, changed); +free: + kfree(elems); } -#endif -void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) +void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - sdata_lock(sdata); - if (!ifmgd->associated) { - sdata_unlock(sdata); - return; - } + struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_rx_status *rx_status; + struct ieee80211_hdr *hdr; + u16 fc; - if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { - sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; - mlme_dbg(sdata, "driver requested disconnect after resume\n"); - ieee80211_sta_connection_lost(sdata, - WLAN_REASON_UNSPECIFIED, - true); - sdata_unlock(sdata); - return; - } + rx_status = (struct ieee80211_rx_status *) skb->cb; + hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); - if (sdata->flags & IEEE80211_SDATA_DISCONNECT_HW_RESTART) { - sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_HW_RESTART; - mlme_dbg(sdata, "driver requested disconnect after hardware restart\n"); - ieee80211_sta_connection_lost(sdata, - WLAN_REASON_UNSPECIFIED, - true); - sdata_unlock(sdata); - return; + sdata_lock(sdata); + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_S1G_BEACON: + ieee80211_rx_mgmt_beacon(link, hdr, skb->len, rx_status); + break; } - sdata_unlock(sdata); } -static void ieee80211_request_smps_mgd_work(struct work_struct *work) +void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) { - struct ieee80211_link_data *link = - container_of(work, struct ieee80211_link_data, - u.mgd.request_smps_work); + struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_rx_status *rx_status; + struct ieee80211_mgmt *mgmt; + u16 fc; + int ies_len; - sdata_lock(link->sdata); - __ieee80211_request_smps_mgd(link->sdata, link, - link->u.mgd.driver_smps_mode); - sdata_unlock(link->sdata); -} + rx_status = (struct ieee80211_rx_status *) skb->cb; + mgmt = (struct ieee80211_mgmt *) skb->data; + fc = le16_to_cpu(mgmt->frame_control); -/* interface setup */ -void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + sdata_lock(sdata); - INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_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_DELAYED_WORK(&ifmgd->tdls_peer_del_work, - ieee80211_tdls_peer_del_work); - 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); - INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk, - ieee80211_sta_handle_tspec_ac_params_wk); + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BEACON: + ieee80211_rx_mgmt_beacon(link, (void *)mgmt, + skb->len, rx_status); + break; + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(link, skb); + break; + case IEEE80211_STYPE_AUTH: + ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_DEAUTH: + ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_DISASSOC: + ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_ACTION: + if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { + struct ieee802_11_elems *elems; - ifmgd->flags = 0; - 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; - /* Setup TDLS data */ - spin_lock_init(&ifmgd->teardown_lock); - ifmgd->teardown_skb = NULL; - ifmgd->orig_teardown_skb = NULL; -} + ies_len = skb->len - + offsetof(struct ieee80211_mgmt, + u.action.u.chan_switch.variable); -void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) -{ - struct ieee80211_local *local = link->sdata->local; + if (ies_len < 0) + break; - link->u.mgd.p2p_noa_index = -1; - link->u.mgd.conn_flags = 0; - link->conf->bssid = link->u.mgd.bssid; + /* CSA IE cannot be overridden, no need for BSSID */ + elems = ieee802_11_parse_elems( + mgmt->u.action.u.chan_switch.variable, + ies_len, true, NULL); - 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; + if (elems && !elems->parse_error) + ieee80211_sta_process_chanswitch(link, + rx_status->mactime, + rx_status->device_timestamp, + elems, false); + kfree(elems); + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { + struct ieee802_11_elems *elems; - INIT_WORK(&link->u.mgd.chswitch_work, ieee80211_chswitch_work); - timer_setup(&link->u.mgd.chswitch_timer, ieee80211_chswitch_timer, 0); -} + ies_len = skb->len - + offsetof(struct ieee80211_mgmt, + u.action.u.ext_chan_switch.variable); -/* scan finished notification */ -void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; + if (ies_len < 0) + break; - /* Restart STA timers */ - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (ieee80211_sdata_running(sdata)) - ieee80211_restart_sta_timer(sdata); + /* + * extended CSA IE can't be overridden, no need for + * BSSID + */ + elems = ieee802_11_parse_elems( + mgmt->u.action.u.ext_chan_switch.variable, + ies_len, true, NULL); + + if (elems && !elems->parse_error) { + /* for the handling code pretend it was an IE */ + elems->ext_chansw_ie = + &mgmt->u.action.u.ext_chan_switch.data; + + ieee80211_sta_process_chanswitch(link, + rx_status->mactime, + rx_status->device_timestamp, + elems, false); + } + + kfree(elems); + } + break; } - rcu_read_unlock(); + sdata_unlock(sdata); } -static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, - struct cfg80211_bss *cbss) +static void ieee80211_sta_timer(struct timer_list *t) { - struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; - const struct element *ht_cap_elem, *vht_cap_elem; - const struct cfg80211_bss_ies *ies; - const struct ieee80211_ht_cap *ht_cap; - const struct ieee80211_vht_cap *vht_cap; - const struct ieee80211_he_cap_elem *he_cap; - const struct element *he_cap_elem; - u16 mcs_80_map, mcs_160_map; - int i, mcs_nss_size; - bool support_160; - u8 chains = 1; + struct ieee80211_sub_if_data *sdata = + from_timer(sdata, t, u.mgd.timer); - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) - return chains; + ieee80211_queue_work(&sdata->local->hw, &sdata->work); +} - ht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_CAPABILITY); - if (ht_cap_elem && ht_cap_elem->datalen >= sizeof(*ht_cap)) { - ht_cap = (void *)ht_cap_elem->data; - chains = ieee80211_mcs_to_chains(&ht_cap->mcs); - /* - * TODO: use "Tx Maximum Number Spatial Streams Supported" and - * "Tx Unequal Modulation Supported" fields. - */ - } +void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, + u8 reason, bool tx) +{ + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) - return chains; + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, + tx, frame_buf); - vht_cap_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); - if (vht_cap_elem && vht_cap_elem->datalen >= sizeof(*vht_cap)) { - u8 nss; - u16 tx_mcs_map; + ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, + reason, false); +} - vht_cap = (void *)vht_cap_elem->data; - tx_mcs_map = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map); - for (nss = 8; nss > 0; nss--) { - if (((tx_mcs_map >> (2 * (nss - 1))) & 3) != - IEEE80211_VHT_MCS_NOT_SUPPORTED) - break; - } - /* TODO: use "Tx Highest Supported Long GI Data Rate" field? */ - chains = max(chains, nss); - } +static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; + u32 tx_flags = 0; + u16 trans = 1; + u16 status = 0; + struct ieee80211_prep_tx_info info = { + .subtype = IEEE80211_STYPE_AUTH, + }; + + sdata_assert_lock(sdata); - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) - return chains; + if (WARN_ON_ONCE(!auth_data)) + return -EINVAL; - ies = rcu_dereference(cbss->ies); - he_cap_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, - ies->data, ies->len); + auth_data->tries++; - if (!he_cap_elem || he_cap_elem->datalen < sizeof(*he_cap)) - return chains; + if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { + sdata_info(sdata, "authentication with %pM timed out\n", + auth_data->bss->bssid); - /* skip one byte ext_tag_id */ - he_cap = (void *)(he_cap_elem->data + 1); - mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap); + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss); - /* invalid HE IE */ - if (he_cap_elem->datalen < 1 + mcs_nss_size + sizeof(*he_cap)) - return chains; + return -ETIMEDOUT; + } - /* mcs_nss is right after he_cap info */ - he_mcs_nss_supp = (void *)(he_cap + 1); + if (auth_data->algorithm == WLAN_AUTH_SAE) + info.duration = jiffies_to_msecs(IEEE80211_AUTH_TIMEOUT_SAE); - mcs_80_map = le16_to_cpu(he_mcs_nss_supp->tx_mcs_80); + drv_mgd_prepare_tx(local, sdata, &info); - for (i = 7; i >= 0; i--) { - u8 mcs_80 = mcs_80_map >> (2 * i) & 3; + sdata_info(sdata, "send auth to %pM (try %d/%d)\n", + auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); - if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { - chains = max_t(u8, chains, i + 1); - break; - } - } + auth_data->expected_transaction = 2; - support_160 = he_cap->phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + if (auth_data->algorithm == WLAN_AUTH_SAE) { + trans = auth_data->sae_trans; + status = auth_data->sae_status; + auth_data->expected_transaction = trans; + } - if (!support_160) - return chains; + if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) + tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_INTFL_MLME_CONN_TX; - mcs_160_map = le16_to_cpu(he_mcs_nss_supp->tx_mcs_160); - for (i = 7; i >= 0; i--) { - u8 mcs_160 = mcs_160_map >> (2 * i) & 3; + ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, + auth_data->data, auth_data->data_len, + auth_data->bss->bssid, + auth_data->bss->bssid, NULL, 0, 0, + tx_flags); - if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { - chains = max_t(u8, chains, i + 1); - break; - } + if (tx_flags == 0) { + if (auth_data->algorithm == WLAN_AUTH_SAE) + auth_data->timeout = jiffies + + IEEE80211_AUTH_TIMEOUT_SAE; + else + auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + } else { + auth_data->timeout = + round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG); } - return chains; + auth_data->timeout_started = true; + run_again(sdata, auth_data->timeout); + + return 0; } -static bool -ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_bss_ies *ies, - const struct ieee80211_he_operation *he_op) +static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) { - const struct element *he_cap_elem; - const struct ieee80211_he_cap_elem *he_cap; - struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp; - u16 mcs_80_map_tx, mcs_80_map_rx; - u16 ap_min_req_set; - int mcs_nss_size; - int nss; + struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; + struct ieee80211_local *local = sdata->local; + int ret; - he_cap_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, - ies->data, ies->len); + sdata_assert_lock(sdata); - /* invalid HE IE */ - if (!he_cap_elem || he_cap_elem->datalen < 1 + sizeof(*he_cap)) { - sdata_info(sdata, - "Invalid HE elem, Disable HE\n"); - return false; - } + assoc_data->tries++; + if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { + sdata_info(sdata, "association with %pM timed out\n", + assoc_data->bss->bssid); - /* skip one byte ext_tag_id */ - he_cap = (void *)(he_cap_elem->data + 1); - mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap); + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss); - /* invalid HE IE */ - if (he_cap_elem->datalen < 1 + sizeof(*he_cap) + mcs_nss_size) { - sdata_info(sdata, - "Invalid HE elem with nss size, Disable HE\n"); - return false; + return -ETIMEDOUT; } - /* mcs_nss is right after he_cap info */ - he_mcs_nss_supp = (void *)(he_cap + 1); - - mcs_80_map_tx = le16_to_cpu(he_mcs_nss_supp->tx_mcs_80); - mcs_80_map_rx = le16_to_cpu(he_mcs_nss_supp->rx_mcs_80); + sdata_info(sdata, "associate with %pM (try %d/%d)\n", + assoc_data->bss->bssid, assoc_data->tries, + IEEE80211_ASSOC_MAX_TRIES); + ret = ieee80211_send_assoc(sdata); + if (ret) + return ret; - /* P802.11-REVme/D0.3 - * 27.1.1 Introduction to the HE PHY - * ... - * An HE STA shall support the following features: - * ... - * Single spatial stream HE-MCSs 0 to 7 (transmit and receive) in all - * supported channel widths for HE SU PPDUs - */ - if ((mcs_80_map_tx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED || - (mcs_80_map_rx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED) { - sdata_info(sdata, - "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n", - mcs_80_map_tx, mcs_80_map_rx); - return false; + if (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { + assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; + assoc_data->timeout_started = true; + run_again(sdata, assoc_data->timeout); + } else { + assoc_data->timeout = + round_jiffies_up(jiffies + + IEEE80211_ASSOC_TIMEOUT_LONG); + assoc_data->timeout_started = true; + run_again(sdata, assoc_data->timeout); } - if (!he_op) - return true; + return 0; +} - ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); +void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, + __le16 fc, bool acked) +{ + struct ieee80211_local *local = sdata->local; - /* make sure the AP is consistent with itself - * - * P802.11-REVme/D0.3 - * 26.17.1 Basic HE BSS operation - * - * A STA that is operating in an HE BSS shall be able to receive and - * transmit at each of the tuple values indicated by the - * Basic HE-MCS And NSS Set field of the HE Operation parameter of the - * MLME-START.request primitive and shall be able to receive at each of - * the tuple values indicated by the Supported HE-MCS and - * NSS Set field in the HE Capabilities parameter of the MLMESTART.request - * primitive - */ - for (nss = 8; nss > 0; nss--) { - u8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; - u8 ap_rx_val; - u8 ap_tx_val; + sdata->u.mgd.status_fc = fc; + sdata->u.mgd.status_acked = acked; + sdata->u.mgd.status_received = true; - if (ap_op_val == IEEE80211_HE_MCS_NOT_SUPPORTED) - continue; + ieee80211_queue_work(&local->hw, &sdata->work); +} - ap_rx_val = (mcs_80_map_rx >> (2 * (nss - 1))) & 3; - ap_tx_val = (mcs_80_map_tx >> (2 * (nss - 1))) & 3; +void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - if (ap_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - ap_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) { - sdata_info(sdata, - "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n", - nss, ap_rx_val, ap_rx_val, ap_op_val); - return false; + sdata_lock(sdata); + + if (ifmgd->status_received) { + __le16 fc = ifmgd->status_fc; + bool status_acked = ifmgd->status_acked; + + ifmgd->status_received = false; + if (ifmgd->auth_data && ieee80211_is_auth(fc)) { + if (status_acked) { + if (ifmgd->auth_data->algorithm == + WLAN_AUTH_SAE) + ifmgd->auth_data->timeout = + jiffies + + IEEE80211_AUTH_TIMEOUT_SAE; + else + ifmgd->auth_data->timeout = + jiffies + + IEEE80211_AUTH_TIMEOUT_SHORT; + run_again(sdata, ifmgd->auth_data->timeout); + } else { + ifmgd->auth_data->timeout = jiffies - 1; + } + ifmgd->auth_data->timeout_started = true; + } else if (ifmgd->assoc_data && + (ieee80211_is_assoc_req(fc) || + ieee80211_is_reassoc_req(fc))) { + if (status_acked) { + ifmgd->assoc_data->timeout = + jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT; + run_again(sdata, ifmgd->assoc_data->timeout); + } else { + ifmgd->assoc_data->timeout = jiffies - 1; + } + ifmgd->assoc_data->timeout_started = true; } } - return true; -} + if (ifmgd->auth_data && ifmgd->auth_data->timeout_started && + time_after(jiffies, ifmgd->auth_data->timeout)) { + if (ifmgd->auth_data->done || ifmgd->auth_data->waiting) { + /* + * ok ... we waited for assoc or continuation but + * userspace didn't do it, so kill the auth data + */ + ieee80211_destroy_auth_data(sdata, false); + } else if (ieee80211_auth(sdata)) { + u8 bssid[ETH_ALEN]; + struct ieee80211_event event = { + .type = MLME_EVENT, + .u.mlme.data = AUTH_EVENT, + .u.mlme.status = MLME_TIMEOUT, + }; + + memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); -static bool -ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - const struct ieee80211_he_operation *he_op) -{ - const struct ieee80211_sta_he_cap *sta_he_cap = - ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); - u16 ap_min_req_set; - int i; + ieee80211_destroy_auth_data(sdata, false); - if (!sta_he_cap || !he_op) - return false; + cfg80211_auth_timeout(sdata->dev, bssid); + drv_event_callback(sdata->local, sdata, &event); + } + } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) + run_again(sdata, ifmgd->auth_data->timeout); - ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set); + if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && + time_after(jiffies, ifmgd->assoc_data->timeout)) { + if ((ifmgd->assoc_data->need_beacon && + !sdata->deflink.u.mgd.have_beacon) || + ieee80211_do_assoc(sdata)) { + struct ieee80211_event event = { + .type = MLME_EVENT, + .u.mlme.data = ASSOC_EVENT, + .u.mlme.status = MLME_TIMEOUT, + }; - /* Need to go over for 80MHz, 160MHz and for 80+80 */ - for (i = 0; i < 3; i++) { - const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp = - &sta_he_cap->he_mcs_nss_supp; - u16 sta_mcs_map_rx = - le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]); - u16 sta_mcs_map_tx = - le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]); - u8 nss; - bool verified = true; + ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); + drv_event_callback(sdata->local, sdata, &event); + } + } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) + run_again(sdata, ifmgd->assoc_data->timeout); - /* - * For each band there is a maximum of 8 spatial streams - * possible. Each of the sta_mcs_map_* is a 16-bit struct built - * of 2 bits per NSS (1-8), with the values defined in enum - * ieee80211_he_mcs_support. Need to make sure STA TX and RX - * capabilities aren't less than the AP's minimum requirements - * for this HE BSS per SS. - * It is enough to find one such band that meets the reqs. - */ - for (nss = 8; nss > 0; nss--) { - u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3; - u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3; - u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3; + if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL && + ifmgd->associated) { + u8 *bssid = sdata->deflink.u.mgd.bssid; + int max_tries; - if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED) - continue; + if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) + max_tries = max_nullfunc_tries; + else + max_tries = max_probe_tries; + /* ACK received for nullfunc probing frame */ + if (!ifmgd->probe_send_count) + ieee80211_reset_ap_probe(sdata); + else if (ifmgd->nullfunc_failed) { + if (ifmgd->probe_send_count < max_tries) { + mlme_dbg(sdata, + "No ack for nullfunc frame to AP %pM, try %d/%i\n", + bssid, ifmgd->probe_send_count, + max_tries); + ieee80211_mgd_probe_ap_send(sdata); + } else { + mlme_dbg(sdata, + "No ack for nullfunc frame to AP %pM, disconnecting.\n", + bssid); + ieee80211_sta_connection_lost(sdata, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + false); + } + } else if (time_is_after_jiffies(ifmgd->probe_timeout)) + run_again(sdata, ifmgd->probe_timeout); + else if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { + mlme_dbg(sdata, + "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", + bssid, probe_wait_ms); + ieee80211_sta_connection_lost(sdata, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); + } else if (ifmgd->probe_send_count < max_tries) { + mlme_dbg(sdata, + "No probe response from AP %pM after %dms, try %d/%i\n", + bssid, probe_wait_ms, + ifmgd->probe_send_count, max_tries); + ieee80211_mgd_probe_ap_send(sdata); + } else { /* - * Make sure the HE AP doesn't require MCSs that aren't - * supported by the client as required by spec - * - * P802.11-REVme/D0.3 - * 26.17.1 Basic HE BSS operation - * - * An HE STA shall not attempt to join * (MLME-JOIN.request primitive) - * a BSS, unless it supports (i.e., is able to both transmit and - * receive using) all of the tuples in the basic - * HE-MCS and NSS set. + * We actually lost the connection ... or did we? + * Let's make sure! */ - if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED || - (ap_val > sta_rx_val) || (ap_val > sta_tx_val)) { - verified = false; - break; - } - } + mlme_dbg(sdata, + "No probe response from AP %pM after %dms, disconnecting.\n", + bssid, probe_wait_ms); - if (verified) - return true; + ieee80211_sta_connection_lost(sdata, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); + } } - /* If here, STA doesn't meet AP's HE min requirements */ - return false; + sdata_unlock(sdata); } -static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_link_data *link, - struct cfg80211_bss *cbss) +static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) { - struct ieee80211_local *local = sdata->local; - const struct ieee80211_ht_cap *ht_cap = NULL; - const struct ieee80211_ht_operation *ht_oper = NULL; - const struct ieee80211_vht_operation *vht_oper = NULL; - const struct ieee80211_he_operation *he_oper = NULL; - const struct ieee80211_eht_operation *eht_oper = NULL; - const struct ieee80211_s1g_oper_ie *s1g_oper = NULL; - struct ieee80211_supported_band *sband; - struct cfg80211_chan_def chandef; - bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; - bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; - struct ieee80211_bss *bss = (void *)cbss->priv; - struct ieee802_11_elems *elems; - const struct cfg80211_bss_ies *ies; - int ret; - u32 i; - bool have_80mhz; - - rcu_read_lock(); - - ies = rcu_dereference(cbss->ies); - elems = ieee802_11_parse_elems(ies->data, ies->len, false, cbss); - if (!elems) { - rcu_read_unlock(); - return -ENOMEM; - } + struct ieee80211_sub_if_data *sdata = + from_timer(sdata, t, u.mgd.bcn_mon_timer); - sband = local->hw.wiphy->bands[cbss->channel->band]; + if (WARN_ON(sdata->vif.valid_links)) + return; - link->u.mgd.conn_flags &= ~(IEEE80211_CONN_DISABLE_40MHZ | - IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ); + if (sdata->vif.bss_conf.csa_active && + !sdata->deflink.u.mgd.csa_waiting_bcn) + return; - /* 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"); - 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 (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) + return; - if (!sband->vht_cap.vht_supported && is_5ghz) { - mlme_dbg(sdata, "VHT not supported, disabling VHT/HE/EHT\n"); - 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; - } + sdata->u.mgd.connection_loss = false; + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.beacon_connection_loss_work); +} - if (!ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) { - mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } +static void ieee80211_sta_conn_mon_timer(struct timer_list *t) +{ + struct ieee80211_sub_if_data *sdata = + from_timer(sdata, t, u.mgd.conn_mon_timer); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + unsigned long timeout; - if (!ieee80211_get_eht_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) { - mlme_dbg(sdata, "EHT not supported, disabling EHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } + if (WARN_ON(sdata->vif.valid_links)) + return; - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) { - ht_oper = elems->ht_operation; - ht_cap = elems->ht_cap_elem; + if (sdata->vif.bss_conf.csa_active && + !sdata->deflink.u.mgd.csa_waiting_bcn) + return; - if (!ht_cap) { - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; - ht_oper = NULL; - } - } + sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); + if (!sta) + return; - 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"); - 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; - } + timeout = sta->deflink.status_stats.last_ack; + if (time_before(sta->deflink.status_stats.last_ack, sta->deflink.rx_stats.last_rx)) + timeout = sta->deflink.rx_stats.last_rx; + timeout += IEEE80211_CONNECTION_IDLE_TIME; - if (!elems->vht_cap_elem) { - sdata_info(sdata, - "bad VHT capabilities, disabling VHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; - vht_oper = NULL; - } + /* If timeout is after now, then update timer to fire at + * the later date, but do not actually probe at this time. + */ + if (time_is_after_jiffies(timeout)) { + mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout)); + return; } - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) { - he_oper = elems->he_operation; + ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); +} - if (is_6ghz) { - struct ieee80211_bss_conf *bss_conf; - u8 i, j = 0; +static void ieee80211_sta_monitor_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.monitor_work); - bss_conf = link->conf; + ieee80211_mgd_probe_ap(sdata, false); +} - if (elems->pwr_constr_elem) - bss_conf->pwr_reduction = *elems->pwr_constr_elem; +static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + __ieee80211_stop_poll(sdata); - BUILD_BUG_ON(ARRAY_SIZE(bss_conf->tx_pwr_env) != - ARRAY_SIZE(elems->tx_pwr_env)); + /* let's probe the connection once */ + if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR)) + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.monitor_work); + } +} - for (i = 0; i < elems->tx_pwr_env_num; i++) { - if (elems->tx_pwr_env_len[i] > - sizeof(bss_conf->tx_pwr_env[j])) - continue; +#ifdef CONFIG_PM +void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; - bss_conf->tx_pwr_env_num++; - memcpy(&bss_conf->tx_pwr_env[j], elems->tx_pwr_env[i], - elems->tx_pwr_env_len[i]); - j++; - } - } + sdata_lock(sdata); - if (!ieee80211_verify_peer_he_mcs_support(sdata, ies, he_oper) || - !ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper)) - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; + if (ifmgd->auth_data || ifmgd->assoc_data) { + const u8 *bssid = ifmgd->auth_data ? + ifmgd->auth_data->bss->bssid : + ifmgd->assoc_data->bss->bssid; + + /* + * If we are trying to authenticate / associate while suspending, + * cfg80211 won't know and won't actually abort those attempts, + * thus we need to do that ourselves. + */ + ieee80211_send_deauth_disassoc(sdata, bssid, bssid, + IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DEAUTH_LEAVING, + false, frame_buf); + if (ifmgd->assoc_data) + 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, + IEEE80211_DEAUTH_FRAME_LEN, + false); } - /* - * EHT requires HE to be supported as well. Specifically for 6 GHz - * channels, the operation channel information can only be deduced from - * both the 6 GHz operation information (from the HE operation IE) and - * EHT operation. + /* This is a bit of a hack - we should find a better and more generic + * solution to this. Normally when suspending, cfg80211 will in fact + * deauthenticate. However, it doesn't (and cannot) stop an ongoing + * auth (not so important) or assoc (this is the problem) process. + * + * As a consequence, it can happen that we are in the process of both + * associating and suspending, and receive an association response + * after cfg80211 has checked if it needs to disconnect, but before + * we actually set the flag to drop incoming frames. This will then + * cause the workqueue flush to process the association response in + * the suspend, resulting in a successful association just before it + * tries to remove the interface from the driver, which now though + * has a channel context assigned ... this results in issues. + * + * To work around this (for now) simply deauth here again if we're + * now connected. */ - if (!(link->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; + if (ifmgd->associated && !sdata->local->wowlan) { + u8 bssid[ETH_ALEN]; + struct cfg80211_deauth_request req = { + .reason_code = WLAN_REASON_DEAUTH_LEAVING, + .bssid = bssid, + }; - ies = rcu_dereference(cbss->ies); - eht_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_EHT_OPERATION, - ies->data, ies->len); - if (eht_oper_ie && eht_oper_ie[1] >= - 1 + sizeof(struct ieee80211_eht_operation)) - eht_oper = (void *)(eht_oper_ie + 3); - else - eht_oper = NULL; + memcpy(bssid, sdata->vif.cfg.ap_addr, ETH_ALEN); + ieee80211_mgd_deauth(sdata, &req); } - /* Allow VHT if at least one channel on the sband supports 80 MHz */ - have_80mhz = false; - for (i = 0; i < sband->n_channels; i++) { - if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_NO_80MHZ)) - continue; + sdata_unlock(sdata); +} +#endif - have_80mhz = true; - break; +void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + sdata_lock(sdata); + if (!ifmgd->associated) { + sdata_unlock(sdata); + return; } - if (!have_80mhz) { - sdata_info(sdata, "80 MHz not supported, disabling VHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; + if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { + sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; + mlme_dbg(sdata, "driver requested disconnect after resume\n"); + ieee80211_sta_connection_lost(sdata, + WLAN_REASON_UNSPECIFIED, + true); + sdata_unlock(sdata); + return; } - if (sband->band == NL80211_BAND_S1GHZ) { - s1g_oper = elems->s1g_oper; - if (!s1g_oper) - sdata_info(sdata, - "AP missing S1G operation element?\n"); + if (sdata->flags & IEEE80211_SDATA_DISCONNECT_HW_RESTART) { + sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_HW_RESTART; + mlme_dbg(sdata, "driver requested disconnect after hardware restart\n"); + ieee80211_sta_connection_lost(sdata, + WLAN_REASON_UNSPECIFIED, + true); + sdata_unlock(sdata); + return; } - link->u.mgd.conn_flags |= - ieee80211_determine_chantype(link, sband, - cbss->channel, - bss->vht_cap_info, - ht_oper, vht_oper, - he_oper, eht_oper, - s1g_oper, - &chandef, false); + sdata_unlock(sdata); +} - link->needed_rx_chains = - min(ieee80211_max_rx_chains(link, cbss), local->rx_chains); +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); - rcu_read_unlock(); - /* the element data was RCU protected so no longer valid anyway */ - kfree(elems); - elems = NULL; + sdata_lock(link->sdata); + __ieee80211_request_smps_mgd(link->sdata, link, + link->u.mgd.driver_smps_mode); + sdata_unlock(link->sdata); +} - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { - sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); - return -EINVAL; - } +/* interface setup */ +void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - /* will change later if needed */ - link->smps_mode = IEEE80211_SMPS_OFF; + INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_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_DELAYED_WORK(&ifmgd->tdls_peer_del_work, + ieee80211_tdls_peer_del_work); + 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); + INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk, + ieee80211_sta_handle_tspec_ac_params_wk); - mutex_lock(&local->mtx); - /* - * If this fails (possibly due to channel context sharing - * 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(link, &chandef, - IEEE80211_CHANCTX_SHARED); + ifmgd->flags = 0; + 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; + /* Setup TDLS data */ + spin_lock_init(&ifmgd->teardown_lock); + ifmgd->teardown_skb = NULL; + ifmgd->orig_teardown_skb = NULL; +} - /* don't downgrade for 5 and 10 MHz channels, though. */ - if (chandef.width == NL80211_CHAN_WIDTH_5 || - chandef.width == NL80211_CHAN_WIDTH_10) - goto out; +void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) +{ + struct ieee80211_local *local = link->sdata->local; - while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { - link->u.mgd.conn_flags |= - ieee80211_chandef_downgrade(&chandef); - ret = ieee80211_link_use_channel(link, &chandef, - IEEE80211_CHANCTX_SHARED); + 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; + + INIT_WORK(&link->u.mgd.chswitch_work, ieee80211_chswitch_work); + timer_setup(&link->u.mgd.chswitch_timer, ieee80211_chswitch_timer, 0); +} + +/* scan finished notification */ +void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + + /* Restart STA timers */ + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (ieee80211_sdata_running(sdata)) + ieee80211_restart_sta_timer(sdata); } - out: - mutex_unlock(&local->mtx); - return ret; + rcu_read_unlock(); } static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies, -- cgit v1.2.3 From 4a21a8ae7964278f6ed8168a4391eaa88c4ab452 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 11:33:57 +0200 Subject: wifi: mac80211: mlme: change flags in ieee80211_determine_chantype() For MLO we'll need to read flags not directly from the link as it may not even exist yet if we're just setting up flags for a secondary link before sending the association request, so pass the incoming conn_flags separately. Also, while at it, pass the sdata/link separately as for non-tracking now the link may be NULL. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 43b64ec6e9df..5d8813fec850 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -143,7 +143,9 @@ static int ecw2cw(int ecw) } static ieee80211_conn_flags_t -ieee80211_determine_chantype(struct ieee80211_link_data *link, +ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, + ieee80211_conn_flags_t conn_flags, struct ieee80211_supported_band *sband, struct ieee80211_channel *channel, u32 vht_cap_info, @@ -154,7 +156,6 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, 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; @@ -249,7 +250,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, } vht_chandef = *chandef; - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) && + if (!(conn_flags & IEEE80211_CONN_DISABLE_HE) && he_oper && (le32_to_cpu(he_oper->he_oper_params) & IEEE80211_HE_OPERATION_VHT_OPER_INFO)) { @@ -265,7 +266,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, &he_oper_vht_cap, ht_oper, &vht_chandef)) { - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) + if (!(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; @@ -275,7 +276,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, vht_cap_info, vht_oper, ht_oper, &vht_chandef)) { - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) + if (!(conn_flags & IEEE80211_CONN_DISABLE_VHT)) sdata_info(sdata, "AP VHT information is invalid, disabling VHT\n"); ret = IEEE80211_CONN_DISABLE_VHT; @@ -283,7 +284,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, } if (!cfg80211_chandef_valid(&vht_chandef)) { - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) + if (!(conn_flags & IEEE80211_CONN_DISABLE_VHT)) sdata_info(sdata, "AP VHT information is invalid, disabling VHT\n"); ret = IEEE80211_CONN_DISABLE_VHT; @@ -296,7 +297,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, } if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) + if (!(conn_flags & IEEE80211_CONN_DISABLE_VHT)) sdata_info(sdata, "AP VHT information doesn't match HT, disabling VHT\n"); ret = IEEE80211_CONN_DISABLE_VHT; @@ -319,7 +320,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, false, &eht_chandef); if (!cfg80211_chandef_valid(&eht_chandef)) { - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) + if (!(conn_flags & IEEE80211_CONN_DISABLE_EHT)) sdata_info(sdata, "AP EHT information is invalid, disabling EHT\n"); ret = IEEE80211_CONN_DISABLE_EHT; @@ -327,7 +328,7 @@ ieee80211_determine_chantype(struct ieee80211_link_data *link, } if (!cfg80211_chandef_compatible(chandef, &eht_chandef)) { - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) + if (!(conn_flags & IEEE80211_CONN_DISABLE_EHT)) sdata_info(sdata, "AP EHT information is incompatible, disabling EHT\n"); ret = IEEE80211_CONN_DISABLE_EHT; @@ -462,7 +463,9 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, 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(link, sband, chan, vht_cap_info, + flags = ieee80211_determine_chantype(sdata, link, + link->u.mgd.conn_flags, + sband, chan, vht_cap_info, ht_oper, vht_oper, he_oper, eht_oper, s1g_oper, &chandef, true); @@ -4006,8 +4009,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, } link->u.mgd.conn_flags |= - ieee80211_determine_chantype(link, sband, - cbss->channel, + ieee80211_determine_chantype(sdata, link, + link->u.mgd.conn_flags, + sband, cbss->channel, bss->vht_cap_info, ht_oper, vht_oper, he_oper, eht_oper, -- cgit v1.2.3 From 39d805998c590429f6665f72e7b54a36c3035fa0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 13:46:19 +0200 Subject: wifi: mac80211: mlme: switch some things back to deflink With MLO, when we'll disconnect from an AP MLD, we'll just destroy all the links. Therefore, the only thing we (may) need to reset is the deflink data, so switch back to that and adjust the comments accordingly. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 71 +++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5d8813fec850..8a078d27c518 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2438,7 +2438,6 @@ 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 = { @@ -2456,7 +2455,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_stop_poll(sdata); ifmgd->associated = false; - link->u.mgd.bss = NULL; + + /* other links will be destroyed */ + sdata->deflink.u.mgd.bss = NULL; + netif_carrier_off(sdata->dev); /* @@ -2494,7 +2496,7 @@ 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) && - !link->u.mgd.have_beacon) { + !sdata->deflink.u.mgd.have_beacon) { drv_mgd_prepare_tx(sdata->local, sdata, &info); } @@ -2525,9 +2527,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ASSOC; sdata->vif.cfg.assoc = false; - link->u.mgd.p2p_noa_index = -1; - memset(&link->conf->p2p_noa_attr, 0, - sizeof(link->conf->p2p_noa_attr)); + 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)); /* on the next assoc, re-program HT/VHT parameters */ memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); @@ -2535,15 +2537,19 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); - /* reset MU-MIMO ownership and group data */ - 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; - link->conf->mu_mimo_owner = false; + /* + * reset MU-MIMO ownership and group data in default link, + * if used, other links are destroyed + */ + 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)); + if (!sdata->vif.valid_links) + changed |= BSS_CHANGED_MU_GROUPS; + sdata->vif.bss_conf.mu_mimo_owner = false; - link->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; + sdata->deflink.ap_power_level = IEEE80211_UNSET_POWER_LEVEL; del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -2552,7 +2558,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, if (sdata->vif.cfg.arp_addr_cnt) changed |= BSS_CHANGED_ARP_FILTER; - link->conf->qos = false; + sdata->vif.bss_conf.qos = false; changed |= BSS_CHANGED_QOS; /* The BSSID (not really interesting) and HT changed */ @@ -2565,27 +2571,27 @@ 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(&link->u.mgd.chswitch_timer); + del_timer_sync(&sdata->deflink.u.mgd.chswitch_timer); - link->conf->dtim_period = 0; - link->conf->beacon_rate = NULL; + sdata->vif.bss_conf.dtim_period = 0; + sdata->vif.bss_conf.beacon_rate = NULL; - link->u.mgd.have_beacon = false; - link->u.mgd.tracking_signal_avg = false; - link->u.mgd.disable_wmm_tracking = false; + sdata->deflink.u.mgd.have_beacon = false; + sdata->deflink.u.mgd.tracking_signal_avg = false; + sdata->deflink.u.mgd.disable_wmm_tracking = false; ifmgd->flags = 0; - link->u.mgd.conn_flags = 0; + sdata->deflink.u.mgd.conn_flags = 0; mutex_lock(&local->mtx); ieee80211_link_release_channel(link); - 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) { + 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) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - link->csa_block_tx = false; + sdata->deflink.csa_block_tx = false; } mutex_unlock(&local->mtx); @@ -2593,9 +2599,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); - bss_conf->pwr_reduction = 0; - bss_conf->tx_pwr_env_num = 0; - memset(bss_conf->tx_pwr_env, 0, sizeof(bss_conf->tx_pwr_env)); + sdata->vif.bss_conf.pwr_reduction = 0; + sdata->vif.bss_conf.tx_pwr_env_num = 0; + memset(sdata->vif.bss_conf.tx_pwr_env, 0, + sizeof(sdata->vif.bss_conf.tx_pwr_env)); } static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) @@ -2912,6 +2919,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, tx, frame_buf); mutex_lock(&local->mtx); + /* the other links will be destroyed */ sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; if (sdata->deflink.csa_block_tx) { @@ -3058,7 +3066,6 @@ 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, @@ -6408,7 +6415,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, return 0; err_clear: - eth_zero_addr(link->u.mgd.bssid); + eth_zero_addr(sdata->deflink.u.mgd.bssid); ieee80211_link_info_change_notify(sdata, &sdata->deflink, BSS_CHANGED_BSSID); ifmgd->assoc_data = NULL; -- cgit v1.2.3 From 978420c2105ca903f8eb563106ea0f676a170ab6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 14:38:02 +0200 Subject: wifi: mac80211: mlme: refactor assoc req element building For MLO, we will need to build these elements per link, so factor out the code that does this, returning the capability, to simplify building the multi-link element in the future. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 276 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 161 insertions(+), 115 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8a078d27c518..150dd211466e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -936,17 +936,158 @@ static size_t ieee80211_add_before_he_elems(struct sk_buff *skb, return noffset; } +static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, u16 *capab, + const struct element *ext_capa, + const u8 *extra_elems, + size_t extra_elems_len, + struct ieee80211_link_data *link) +{ + enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + struct cfg80211_bss *cbss = assoc_data->bss; + struct ieee80211_channel *chan = cbss->channel; + const struct ieee80211_sband_iftype_data *iftd; + struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband; + enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20; + struct ieee80211_chanctx_conf *chanctx_conf; + size_t offset = 0; + u8 *pos; + int i; + + /* + * 5/10 MHz scenarios are only viable without MLO, in which + * case this pointer should be used ... All of this is a bit + * unclear though, not sure this even works at all. + */ + rcu_read_lock(); + chanctx_conf = rcu_dereference(link->conf->chanctx_conf); + if (chanctx_conf) + width = chanctx_conf->def.width; + rcu_read_unlock(); + + sband = local->hw.wiphy->bands[chan->band]; + iftd = ieee80211_get_sband_iftype_data(sband, iftype); + + if (sband->band == NL80211_BAND_2GHZ) { + *capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + *capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; + } + + if ((cbss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + ieee80211_hw_check(&local->hw, SPECTRUM_MGMT)) + *capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + + if (sband->band != NL80211_BAND_S1GHZ) + ieee80211_assoc_add_rates(skb, width, sband, assoc_data); + + if (*capab & WLAN_CAPABILITY_SPECTRUM_MGMT || + *capab & WLAN_CAPABILITY_RADIO_MEASURE) { + struct cfg80211_chan_def chandef = { + .width = width, + .chan = chan, + }; + + pos = skb_put(skb, 4); + *pos++ = WLAN_EID_PWR_CAPABILITY; + *pos++ = 2; + *pos++ = 0; /* min tx power */ + /* max tx power */ + *pos++ = ieee80211_chandef_max_power(&chandef); + } + + /* + * Per spec, we shouldn't include the list of channels if we advertise + * support for extended channel switching, but we've always done that; + * (for now?) apply this restriction only on the (new) 6 GHz band. + */ + if (*capab & WLAN_CAPABILITY_SPECTRUM_MGMT && + (sband->band != NL80211_BAND_6GHZ || + !ext_capa || ext_capa->datalen < 1 || + !(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) { + /* TODO: get this in reg domain format */ + pos = skb_put(skb, 2 * sband->n_channels + 2); + *pos++ = WLAN_EID_SUPPORTED_CHANNELS; + *pos++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + int cf = sband->channels[i].center_freq; + + *pos++ = ieee80211_frequency_to_channel(cf); + *pos++ = 1; /* one channel in the subband*/ + } + } + + /* if present, add any custom IEs that go before HT */ + offset = ieee80211_add_before_ht_elems(skb, extra_elems, + extra_elems_len, + offset); + + if (sband->band != NL80211_BAND_6GHZ && + !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) + 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, extra_elems, + extra_elems_len, + offset); + + if (sband->band != NL80211_BAND_6GHZ && + !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) + 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. + * If on the 5GHz band, make sure it supports VHT. + */ + if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || + (sband->band == NL80211_BAND_5GHZ && + link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) + 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, extra_elems, + extra_elems_len, + offset); + + if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) + 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(sdata, skb, sband); + + if (sband->band == NL80211_BAND_S1GHZ) { + ieee80211_add_aid_request_ie(sdata, skb); + ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap, skb); + } + + if (iftd && iftd->vendor_elems.data && iftd->vendor_elems.len) + skb_put_data(skb, iftd->vendor_elems.data, iftd->vendor_elems.len); + + return offset; +} + static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + struct ieee80211_link_data *link = &sdata->deflink; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, qos_info, *ie_start; - size_t offset = 0, noffset; - int i; - u16 capab; + size_t offset, noffset; + u16 capab = WLAN_CAPABILITY_ESS; struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *chan; @@ -955,7 +1096,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; + void *capab_pos; int ret; /* we know it's writable, cast away the const */ @@ -1003,23 +1144,18 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) skb_reserve(skb, local->hw.extra_tx_headroom); - capab = WLAN_CAPABILITY_ESS; - - if (sband->band == NL80211_BAND_2GHZ) { - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; - capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; - } - if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; - if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - ieee80211_hw_check(&local->hw, SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - if (ifmgd->flags & IEEE80211_STA_ENABLE_RRM) capab |= WLAN_CAPABILITY_RADIO_MEASURE; + /* 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) && + ext_capa && ext_capa->datalen >= 3) + ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; + mgmt = skb_put_zero(skb, 24); memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); @@ -1032,7 +1168,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) skb_put(skb, 10); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); - mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); + capab_pos = &mgmt->u.reassoc_req.capab_info; mgmt->u.reassoc_req.listen_interval = listen_int; memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid, ETH_ALEN); @@ -1041,7 +1177,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) skb_put(skb, 4); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ); - mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); + capab_pos = &mgmt->u.assoc_req.capab_info; mgmt->u.assoc_req.listen_interval = listen_int; info.subtype = IEEE80211_STYPE_ASSOC_REQ; } @@ -1053,97 +1189,15 @@ 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) - ieee80211_assoc_add_rates(skb, chanctx_conf->def.width, - sband, assoc_data); - - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT || - capab & WLAN_CAPABILITY_RADIO_MEASURE) { - pos = skb_put(skb, 4); - *pos++ = WLAN_EID_PWR_CAPABILITY; - *pos++ = 2; - *pos++ = 0; /* min tx power */ - /* max tx power */ - *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def); - } - - /* - * Per spec, we shouldn't include the list of channels if we advertise - * support for extended channel switching, but we've always done that; - * (for now?) apply this restriction only on the (new) 6 GHz band. - */ - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT && - (sband->band != NL80211_BAND_6GHZ || - !ext_capa || ext_capa->datalen < 1 || - !(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) { - /* TODO: get this in reg domain format */ - pos = skb_put(skb, 2 * sband->n_channels + 2); - *pos++ = WLAN_EID_SUPPORTED_CHANNELS; - *pos++ = 2 * sband->n_channels; - for (i = 0; i < sband->n_channels; i++) { - int cf = sband->channels[i].center_freq; - - *pos++ = ieee80211_frequency_to_channel(cf); - *pos++ = 1; /* one channel in the subband*/ - } - } + /* add the elements for the assoc (main) link */ + offset = ieee80211_assoc_link_elems(sdata, skb, &capab, + ext_capa, + assoc_data->ie, + assoc_data->ie_len, + link); + put_unaligned_le16(capab, capab_pos); - /* 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) && - ext_capa && ext_capa->datalen >= 3) - ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; - - /* if present, add any custom IEs that go before HT */ - 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))) - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; - - if (sband->band != NL80211_BAND_6GHZ && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) - 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, - assoc_data->ie_len, - offset); - - if (sband->band != NL80211_BAND_6GHZ && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) - 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. - * If on the 5GHz band, make sure it supports VHT. - */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || - (sband->band == NL80211_BAND_5GHZ && - link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) - 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(sdata, skb, sband, link->u.mgd.conn_flags); - - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) - ieee80211_add_eht_ie(sdata, skb, sband); - } - - /* if present, add any custom non-vendor IEs that go after HE */ + /* if present, add any custom non-vendor IEs */ if (assoc_data->ie_len) { noffset = ieee80211_ie_split_vendor(assoc_data->ie, assoc_data->ie_len, @@ -1164,14 +1218,6 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); } - if (sband->band == NL80211_BAND_S1GHZ) { - ieee80211_add_aid_request_ie(sdata, skb); - ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap, skb); - } - - if (iftd && iftd->vendor_elems.data && iftd->vendor_elems.len) - skb_put_data(skb, iftd->vendor_elems.data, iftd->vendor_elems.len); - /* add any remaining custom (i.e. vendor specific here) IEs */ if (assoc_data->ie_len) { noffset = assoc_data->ie_len; -- cgit v1.2.3 From 7781f0d81c7a7e6dc37aa2902a634b7dc08be54d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 14:48:55 +0200 Subject: wifi: mac80211: mlme: refactor ieee80211_prep_channel() a bit Refactor ieee80211_prep_channel() to make the link argument optional and add a conn_flags pointer argument instead, so that we can later use this for links that don't exist yet to build the right information for MLO. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 81 +++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 150dd211466e..f3d4507a477c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3888,7 +3888,8 @@ 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 cfg80211_bss *cbss, + ieee80211_conn_flags_t *conn_flags) { struct ieee80211_local *local = sdata->local; const struct ieee80211_ht_cap *ht_cap = NULL; @@ -3919,73 +3920,73 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, sband = local->hw.wiphy->bands[cbss->channel->band]; - link->u.mgd.conn_flags &= ~(IEEE80211_CONN_DISABLE_40MHZ | - IEEE80211_CONN_DISABLE_80P80MHZ | - IEEE80211_CONN_DISABLE_160MHZ); + *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"); - 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; + *conn_flags |= IEEE80211_CONN_DISABLE_HT; + *conn_flags |= IEEE80211_CONN_DISABLE_VHT; + *conn_flags |= IEEE80211_CONN_DISABLE_HE; + *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"); - 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; + *conn_flags |= IEEE80211_CONN_DISABLE_VHT; + *conn_flags |= IEEE80211_CONN_DISABLE_HE; + *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"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + *conn_flags |= IEEE80211_CONN_DISABLE_HE; + *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"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + *conn_flags |= IEEE80211_CONN_DISABLE_EHT; } - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) { + if (!(*conn_flags & IEEE80211_CONN_DISABLE_HT) && !is_6ghz) { ht_oper = elems->ht_operation; ht_cap = elems->ht_cap_elem; if (!ht_cap) { - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; + *conn_flags |= IEEE80211_CONN_DISABLE_HT; ht_oper = NULL; } } - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && !is_6ghz) { + if (!(*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"); - 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; + *conn_flags |= IEEE80211_CONN_DISABLE_HT; + *conn_flags |= IEEE80211_CONN_DISABLE_VHT; + *conn_flags |= IEEE80211_CONN_DISABLE_HE; + *conn_flags |= IEEE80211_CONN_DISABLE_EHT; } if (!elems->vht_cap_elem) { sdata_info(sdata, "bad VHT capabilities, disabling VHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; + *conn_flags |= IEEE80211_CONN_DISABLE_VHT; vht_oper = NULL; } } - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) { + if (!(*conn_flags & IEEE80211_CONN_DISABLE_HE)) { he_oper = elems->he_operation; - if (is_6ghz) { + if (link && is_6ghz) { struct ieee80211_bss_conf *bss_conf; u8 j = 0; @@ -4011,8 +4012,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)) - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; + *conn_flags |= IEEE80211_CONN_DISABLE_HE | + IEEE80211_CONN_DISABLE_EHT; } /* @@ -4021,7 +4022,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 (!(link->u.mgd.conn_flags & + if (!(*conn_flags & (IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT)) && he_oper) { @@ -4051,7 +4052,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"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; + *conn_flags |= IEEE80211_CONN_DISABLE_VHT; } if (sband->band == NL80211_BAND_S1GHZ) { @@ -4061,29 +4062,34 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, "AP missing S1G operation element?\n"); } - link->u.mgd.conn_flags |= - ieee80211_determine_chantype(sdata, link, - link->u.mgd.conn_flags, - sband, cbss->channel, + *conn_flags |= + ieee80211_determine_chantype(sdata, link, *conn_flags, + sband, + cbss->channel, bss->vht_cap_info, ht_oper, vht_oper, he_oper, eht_oper, s1g_oper, &chandef, false); - link->needed_rx_chains = - min(ieee80211_max_rx_chains(link, cbss), local->rx_chains); + if (link) + 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 (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { + if (*conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); return -EINVAL; } + if (!link) + return 0; + /* will change later if needed */ link->smps_mode = IEEE80211_SMPS_OFF; @@ -4102,7 +4108,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, goto out; while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { - link->u.mgd.conn_flags |= + *conn_flags |= ieee80211_chandef_downgrade(&chandef); ret = ieee80211_link_use_channel(link, &chandef, IEEE80211_CHANCTX_SHARED); @@ -5930,7 +5936,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (new_sta || override) { - err = ieee80211_prep_channel(sdata, link, cbss); + err = ieee80211_prep_channel(sdata, link, cbss, + &link->u.mgd.conn_flags); if (err) { if (new_sta) sta_info_free(local, new_sta); -- cgit v1.2.3 From 6911458dc4283a790194d54d6e854a6ed63e42e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 14:59:22 +0200 Subject: wifi: mac80211: mlme: refactor assoc success handling Refactor the per-link setup out of ieee80211_assoc_success() into a new function ieee80211_assoc_config_link(). It looks useless for now to parse the elements again inside ieee80211_assoc_config_link(), but that will be done with the link ID in the future. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 865 ++++++++++++++++++++++++++-------------------------- 1 file changed, 440 insertions(+), 425 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f3d4507a477c..1829a0b6c9d4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3541,6 +3541,326 @@ static bool ieee80211_twt_bcast_support(struct ieee80211_sub_if_data *sdata, IEEE80211_HE_MAC_CAP2_BCAST_TWT); } +static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, + struct link_sta_info *link_sta, + struct cfg80211_bss *cbss, + struct ieee80211_mgmt *mgmt, + const u8 *elem_start, + unsigned int elem_len, + u64 *changed) +{ + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; + struct ieee80211_bss_conf *bss_conf = link->conf; + struct ieee80211_local *local = sdata->local; + struct ieee80211_elems_parse_params parse_params = { + .start = elem_start, + .len = elem_len, + .bss = cbss, + }; + bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; + bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ; + const struct cfg80211_bss_ies *bss_ies = NULL; + struct ieee80211_supported_band *sband; + struct ieee802_11_elems *elems; + u16 capab_info; + bool ret; + + elems = ieee802_11_parse_elems_full(&parse_params); + if (!elems) + return false; + + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + + if (!is_s1g && !elems->supp_rates) { + sdata_info(sdata, "no SuppRates element in AssocResp\n"); + ret = false; + goto out; + } + + link->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); + + /* + * Some APs are erroneously not including some information in their + * (re)association response frames. Try to recover by using the data + * from the beacon or probe response. This seems to afflict mobile + * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", + * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. + */ + if (!is_6ghz && + ((assoc_data->wmm && !elems->wmm_param) || + (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && + (!elems->ht_cap_elem || !elems->ht_operation)) || + (!(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; + + rcu_read_lock(); + ies = rcu_dereference(cbss->ies); + if (ies) + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, + GFP_ATOMIC); + rcu_read_unlock(); + if (!bss_ies) { + ret = false; + goto out; + } + + parse_params.start = bss_ies->data; + parse_params.len = bss_ies->len; + bss_elems = ieee802_11_parse_elems_full(&parse_params); + if (!bss_elems) { + ret = false; + goto out; + } + + if (assoc_data->wmm && + !elems->wmm_param && bss_elems->wmm_param) { + elems->wmm_param = bss_elems->wmm_param; + sdata_info(sdata, + "AP bug: WMM param missing from AssocResp\n"); + } + + /* + * Also check if we requested HT/VHT, otherwise the AP doesn't + * have to include the IEs in the (re)association response. + */ + if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && + !(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 && + !(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 && + !(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 && + !(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"); + } + + kfree(bss_elems); + } + + /* + * We previously checked these in the beacon/probe response, so + * they should be present here. This is just a safety net. + */ + 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"); + ret = false; + goto out; + } + + 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"); + ret = false; + goto out; + } + + 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"); + ret = false; + goto out; + } + + sband = ieee80211_get_link_sband(link); + if (!sband) { + ret = false; + goto out; + } + + 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, + "HE AP is missing HE capability/operation\n"); + ret = false; + goto out; + } + + /* Set up internal HT/VHT capabilities */ + 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, + 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, + link_sta); + + 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, + elems->he_cap_len, + elems->he_6ghz_capa, + link_sta); + + 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, + NL80211_EXT_FEATURE_PROTECTED_TWT)) + bss_conf->twt_protected = true; + else + bss_conf->twt_protected = false; + + *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)) { + ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, + elems->he_cap, + elems->he_cap_len, + elems->eht_cap, + elems->eht_cap_len, + link_sta); + + bss_conf->eht_support = link_sta->pub->eht_cap.has_eht; + } else { + bss_conf->eht_support = false; + } + } else { + bss_conf->he_support = false; + bss_conf->twt_requester = false; + bss_conf->twt_protected = false; + bss_conf->eht_support = false; + } + + bss_conf->twt_broadcast = + ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta); + + if (bss_conf->he_support) { + bss_conf->he_bss_color.color = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_BSS_COLOR_MASK); + bss_conf->he_bss_color.partial = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR); + bss_conf->he_bss_color.enabled = + !le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED); + + if (bss_conf->he_bss_color.enabled) + *changed |= BSS_CHANGED_HE_BSS_COLOR; + + bss_conf->htc_trig_based_pkt_ext = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK); + bss_conf->frame_time_rts_th = + le32_get_bits(elems->he_operation->he_oper_params, + IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); + + bss_conf->uora_exists = !!elems->uora_element; + if (elems->uora_element) + bss_conf->uora_ocw_range = elems->uora_element[0]; + + ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation); + ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr); + /* TODO: OPEN: what happens if BSS color disable is set? */ + } + + if (cbss->transmitted_bss) { + bss_conf->nontransmitted = true; + ether_addr_copy(bss_conf->transmitter_bssid, + cbss->transmitted_bss->bssid); + bss_conf->bssid_indicator = cbss->max_bssid_indicator; + bss_conf->bssid_index = cbss->bssid_index; + } + + /* + * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data + * in their association response, so ignore that data for our own + * configuration. If it changed since the last beacon, we'll get the + * next beacon and update then. + */ + + /* + * If an operating mode notification IE is present, override the + * NSS calculation (that would be done in rate_control_rate_init()) + * and use the # of streams from that element. + */ + if (elems->opmode_notif && + !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { + u8 nss; + + nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; + nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; + nss += 1; + link_sta->pub->rx_nss = nss; + } + + /* + * Always handle WMM once after association regardless + * of the first value the AP uses. Setting -1 here has + * that effect because the AP values is an unsigned + * 4-bit value. + */ + link->u.mgd.wmm_last_param_set = -1; + link->u.mgd.mu_edca_last_param_set = -1; + + 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); + /* 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. + */ + link->u.mgd.disable_wmm_tracking = true; + } + + if (elems->max_idle_period_ie) { + bss_conf->max_idle_period = + le16_to_cpu(elems->max_idle_period_ie->max_idle_period); + bss_conf->protected_keep_alive = + !!(elems->max_idle_period_ie->idle_options & + WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE); + *changed |= BSS_CHANGED_KEEP_ALIVE; + } else { + bss_conf->max_idle_period = 0; + bss_conf->protected_keep_alive = false; + } + + /* set assoc capability (AID was already set earlier), + * ieee80211_set_associated() will tell the driver */ + bss_conf->assoc_capability = capab_info; + + ret = true; +out: + kfree(elems); + kfree(bss_ies); + return ret; +} + static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link, struct sta_info *sta, struct ieee80211_link_sta *link_sta, @@ -4047,388 +4367,102 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, continue; have_80mhz = true; - break; - } - - if (!have_80mhz) { - sdata_info(sdata, "80 MHz not supported, disabling VHT\n"); - *conn_flags |= IEEE80211_CONN_DISABLE_VHT; - } - - if (sband->band == NL80211_BAND_S1GHZ) { - s1g_oper = elems->s1g_oper; - if (!s1g_oper) - sdata_info(sdata, - "AP missing S1G operation element?\n"); - } - - *conn_flags |= - ieee80211_determine_chantype(sdata, link, *conn_flags, - sband, - cbss->channel, - bss->vht_cap_info, - ht_oper, vht_oper, - he_oper, eht_oper, - s1g_oper, - &chandef, false); - - if (link) - 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 (*conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { - sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); - return -EINVAL; - } - - if (!link) - return 0; - - /* will change later if needed */ - link->smps_mode = IEEE80211_SMPS_OFF; - - mutex_lock(&local->mtx); - /* - * If this fails (possibly due to channel context sharing - * 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(link, &chandef, - IEEE80211_CHANCTX_SHARED); - - /* don't downgrade for 5 and 10 MHz channels, though. */ - if (chandef.width == NL80211_CHAN_WIDTH_5 || - chandef.width == NL80211_CHAN_WIDTH_10) - goto out; - - while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { - *conn_flags |= - ieee80211_chandef_downgrade(&chandef); - ret = ieee80211_link_use_channel(link, &chandef, - IEEE80211_CHANCTX_SHARED); - } - out: - mutex_unlock(&local->mtx); - return ret; -} - -static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee802_11_elems *elems) -{ - 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; - const struct cfg80211_bss_ies *bss_ies = NULL; - 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; - int err; - bool ret; - - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - - 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 - * (802.11-2016 9.4.1.8 AID field) - */ - aid &= 0x7ff; - - ifmgd->broken_ap = false; - - if (aid == 0 || aid > IEEE80211_MAX_AID) { - sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n", - aid); - aid = 0; - ifmgd->broken_ap = true; - } - - if (!is_s1g && !elems->supp_rates) { - sdata_info(sdata, "no SuppRates element in AssocResp\n"); - ret = false; - goto out; - } - - sdata->vif.cfg.aid = aid; - 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); - - /* - * Some APs are erroneously not including some information in their - * (re)association response frames. Try to recover by using the data - * from the beacon or probe response. This seems to afflict mobile - * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", - * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. - */ - if (!is_6ghz && - ((assoc_data->wmm && !elems->wmm_param) || - (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) && - (!elems->ht_cap_elem || !elems->ht_operation)) || - (!(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; - - rcu_read_lock(); - ies = rcu_dereference(cbss->ies); - if (ies) - bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, - GFP_ATOMIC); - rcu_read_unlock(); - if (!bss_ies) { - ret = false; - goto out; - } - - bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, - false, assoc_data->bss); - if (!bss_elems) { - ret = false; - goto out; - } - - if (assoc_data->wmm && - !elems->wmm_param && bss_elems->wmm_param) { - elems->wmm_param = bss_elems->wmm_param; - sdata_info(sdata, - "AP bug: WMM param missing from AssocResp\n"); - } - - /* - * Also check if we requested HT/VHT, otherwise the AP doesn't - * have to include the IEs in the (re)association response. - */ - if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && - !(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 && - !(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 && - !(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 && - !(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"); - } - - kfree(bss_elems); - } - - /* - * We previously checked these in the beacon/probe response, so - * they should be present here. This is just a safety net. - */ - 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"); - ret = false; - goto out; - } - - 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"); - ret = false; - goto out; - } - - 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"); - ret = false; - goto out; - } - - mutex_lock(&sdata->local->sta_mtx); - /* - * station info was already allocated and inserted before - * the association and should be available to us - */ - sta = sta_info_get(sdata, cbss->bssid); - if (WARN_ON(!sta)) { - mutex_unlock(&sdata->local->sta_mtx); - ret = false; - 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; + break; } - sband = ieee80211_get_link_sband(link); - if (!sband) { - mutex_unlock(&sdata->local->sta_mtx); - ret = false; - goto out; + if (!have_80mhz) { + sdata_info(sdata, "80 MHz not supported, disabling VHT\n"); + *conn_flags |= IEEE80211_CONN_DISABLE_VHT; } - 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, - "HE AP is missing HE capability/operation\n"); - ret = false; - goto out; + if (sband->band == NL80211_BAND_S1GHZ) { + s1g_oper = elems->s1g_oper; + if (!s1g_oper) + sdata_info(sdata, + "AP missing S1G operation element?\n"); } - /* Set up internal HT/VHT capabilities */ - 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, - 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, - link_sta); - - 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, - elems->he_cap_len, - elems->he_6ghz_capa, - link_sta); - - 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, - NL80211_EXT_FEATURE_PROTECTED_TWT)) - bss_conf->twt_protected = true; - else - bss_conf->twt_protected = false; + *conn_flags |= + ieee80211_determine_chantype(sdata, link, *conn_flags, + sband, + cbss->channel, + bss->vht_cap_info, + ht_oper, vht_oper, + he_oper, eht_oper, + s1g_oper, + &chandef, false); - changed |= ieee80211_recalc_twt_req(link, link_sta, elems); + if (link) + link->needed_rx_chains = + min(ieee80211_max_rx_chains(link, cbss), + local->rx_chains); - if (elems->eht_operation && elems->eht_cap && - !(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, - elems->eht_cap, - elems->eht_cap_len, - link_sta); + rcu_read_unlock(); + /* the element data was RCU protected so no longer valid anyway */ + kfree(elems); + elems = NULL; - bss_conf->eht_support = link_sta->pub->eht_cap.has_eht; - } else { - bss_conf->eht_support = false; - } - } else { - bss_conf->he_support = false; - bss_conf->twt_requester = false; - bss_conf->twt_protected = false; - bss_conf->eht_support = false; + if (*conn_flags & IEEE80211_CONN_DISABLE_HE && is_6ghz) { + sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection"); + return -EINVAL; } - bss_conf->twt_broadcast = - ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta); - - if (bss_conf->he_support) { - bss_conf->he_bss_color.color = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_BSS_COLOR_MASK); - bss_conf->he_bss_color.partial = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR); - bss_conf->he_bss_color.enabled = - !le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED); - - if (bss_conf->he_bss_color.enabled) - changed |= BSS_CHANGED_HE_BSS_COLOR; + if (!link) + return 0; - bss_conf->htc_trig_based_pkt_ext = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK); - bss_conf->frame_time_rts_th = - le32_get_bits(elems->he_operation->he_oper_params, - IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); + /* will change later if needed */ + link->smps_mode = IEEE80211_SMPS_OFF; - bss_conf->uora_exists = !!elems->uora_element; - if (elems->uora_element) - bss_conf->uora_ocw_range = elems->uora_element[0]; + mutex_lock(&local->mtx); + /* + * If this fails (possibly due to channel context sharing + * 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(link, &chandef, + IEEE80211_CHANCTX_SHARED); - ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation); - ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr); - /* TODO: OPEN: what happens if BSS color disable is set? */ - } + /* don't downgrade for 5 and 10 MHz channels, though. */ + if (chandef.width == NL80211_CHAN_WIDTH_5 || + chandef.width == NL80211_CHAN_WIDTH_10) + goto out; - if (cbss->transmitted_bss) { - bss_conf->nontransmitted = true; - ether_addr_copy(bss_conf->transmitter_bssid, - cbss->transmitted_bss->bssid); - bss_conf->bssid_indicator = cbss->max_bssid_indicator; - bss_conf->bssid_index = cbss->bssid_index; - } else { - bss_conf->nontransmitted = false; - memset(bss_conf->transmitter_bssid, 0, - sizeof(bss_conf->transmitter_bssid)); - bss_conf->bssid_indicator = 0; - bss_conf->bssid_index = 0; + while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { + *conn_flags |= + ieee80211_chandef_downgrade(&chandef); + ret = ieee80211_link_use_channel(link, &chandef, + IEEE80211_CHANCTX_SHARED); } + out: + mutex_unlock(&local->mtx); + return ret; +} - /* - * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data - * in their association response, so ignore that data for our own - * configuration. If it changed since the last beacon, we'll get the - * next beacon and update then. - */ +static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss, + struct ieee80211_mgmt *mgmt, + struct ieee802_11_elems *elems, + const u8 *elem_start, unsigned int elem_len) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + u64 changed = 0; + int err; + mutex_lock(&sdata->local->sta_mtx); /* - * If an operating mode notification IE is present, override the - * NSS calculation (that would be done in rate_control_rate_init()) - * and use the # of streams from that element. + * station info was already allocated and inserted before + * the association and should be available to us */ - if (elems->opmode_notif && - !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { - u8 nss; + sta = sta_info_get(sdata, cbss->bssid); + if (WARN_ON(!sta)) + goto out_err; - nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; - nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; - nss += 1; - link_sta->pub->rx_nss = nss; - } + if (!ieee80211_assoc_config_link(&sdata->deflink, &sta->deflink, + cbss, mgmt, elem_start, elem_len, + &changed)) + goto out_err; rate_control_rate_init(sta); @@ -4450,9 +4484,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, "failed to move station %pM to desired state\n", sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); - mutex_unlock(&sdata->local->sta_mtx); - ret = false; - goto out; + goto out_err; } if (sdata->wdev.use_4addr) @@ -4460,48 +4492,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, mutex_unlock(&sdata->local->sta_mtx); - /* - * Always handle WMM once after association regardless - * of the first value the AP uses. Setting -1 here has - * that effect because the AP values is an unsigned - * 4-bit value. - */ - link->u.mgd.wmm_last_param_set = -1; - link->u.mgd.mu_edca_last_param_set = -1; - - 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); - /* 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. - */ - link->u.mgd.disable_wmm_tracking = true; - } - changed |= BSS_CHANGED_QOS; - - if (elems->max_idle_period_ie) { - bss_conf->max_idle_period = - le16_to_cpu(elems->max_idle_period_ie->max_idle_period); - bss_conf->protected_keep_alive = - !!(elems->max_idle_period_ie->idle_options & - WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE); - changed |= BSS_CHANGED_KEEP_ALIVE; - } else { - bss_conf->max_idle_period = 0; - bss_conf->protected_keep_alive = false; - } - - /* set assoc capability (AID was already set earlier), - * ieee80211_set_associated() will tell the driver */ - bss_conf->assoc_capability = capab_info; ieee80211_set_associated(sdata, cbss, changed); /* @@ -4518,10 +4508,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_conn_monitor(sdata); - ret = true; - out: - kfree(bss_ies); - return ret; + return true; +out_err: + mutex_unlock(&sdata->local->sta_mtx); + return false; } static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, @@ -4533,7 +4523,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, u16 capab_info, status_code, aid; struct ieee802_11_elems *elems; int ac; - u8 *pos; + const u8 *elem_start; + unsigned int elem_len; bool reassoc; struct cfg80211_bss *cbss; struct ieee80211_event event = { @@ -4566,12 +4557,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control); capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - pos = mgmt->u.assoc_resp.variable; - aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - if (cbss->channel->band == NL80211_BAND_S1GHZ) { - pos = (u8 *) mgmt->u.s1g_assoc_resp.variable; - aid = 0; /* TODO */ - } + if (cbss->channel->band == NL80211_BAND_S1GHZ) + elem_start = mgmt->u.s1g_assoc_resp.variable; + else + elem_start = mgmt->u.assoc_resp.variable; /* * Note: this may not be perfect, AP might misbehave - if @@ -4582,20 +4571,35 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, info.subtype = reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ; - sdata_info(sdata, - "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", - reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); - if (assoc_data->fils_kek_len && fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) return; - elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, - assoc_data->bss); + elem_len = len - (elem_start - (u8 *)mgmt); + elems = ieee802_11_parse_elems(elem_start, elem_len, false, NULL); if (!elems) goto notify_driver; + if (elems->aid_resp) + aid = le16_to_cpu(elems->aid_resp->aid); + else if (cbss->channel->band == NL80211_BAND_S1GHZ) + aid = 0; /* TODO */ + else + aid = le16_to_cpu(mgmt->u.assoc_resp.aid); + + /* + * The 5 MSB of the AID field are reserved + * (802.11-2016 9.4.1.8 AID field) + */ + aid &= 0x7ff; + + sdata_info(sdata, + "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", + reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + + ifmgd->broken_ap = false; + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && elems->timeout_int && elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { @@ -4624,7 +4628,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, event.u.mlme.reason = status_code; drv_event_callback(sdata->local, sdata, &event); } else { - if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) { + if (aid == 0 || aid > IEEE80211_MAX_AID) { + sdata_info(sdata, + "invalid AID value %d (out of range), turn off PS\n", + aid); + aid = 0; + ifmgd->broken_ap = true; + } + + sdata->vif.cfg.aid = aid; + + if (!ieee80211_assoc_success(sdata, cbss, mgmt, elems, + elem_start, elem_len)) { /* oops -- internal error -- send timeout for now */ ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); goto notify_driver; -- cgit v1.2.3 From a857c21eaf398875dce41814761353e807054636 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 15:13:23 +0200 Subject: wifi: mac80211: mlme: remove address arg to ieee80211_mark_sta_auth() There's no need to pass the address, we can look at the auth_data inside the function rather than outside. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1829a0b6c9d4..326572b80ed8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3167,10 +3167,10 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, auth_data->key_idx, tx_flags); } -static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata, - const u8 *ap_addr) +static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ap_addr = ifmgd->auth_data->bss->bssid; struct sta_info *sta; bool result = true; @@ -3297,7 +3297,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, if (ifmgd->auth_data->algorithm != WLAN_AUTH_SAE || (auth_transaction == 2 && ifmgd->auth_data->expected_transaction == 2)) { - if (!ieee80211_mark_sta_auth(sdata, bssid)) + if (!ieee80211_mark_sta_auth(sdata)) return; /* ignore frame -- wait for timeout */ } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && auth_transaction == 2) { @@ -6099,7 +6099,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, */ if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE && auth_data->peer_confirmed && auth_data->sae_trans == 2) - ieee80211_mark_sta_auth(sdata, req->bss->bssid); + ieee80211_mark_sta_auth(sdata); if (ifmgd->associated) { u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; -- cgit v1.2.3 From 1845c1d4a455e000dbf66dc4126c98837ac3e528 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 15:21:23 +0200 Subject: wifi: mac80211: mlme: refactor assoc link setup Factor out the code to set up the assoc link into a new function ieee80211_setup_assoc_link(). While at it, also modify the 'override' handling to just take into account whether or not the conn_flags were changed, which is what we need to setup again the channel later. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 286 ++++++++++++++++++++++++++++------------------------ 1 file changed, 156 insertions(+), 130 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 326572b80ed8..292ad46daa9d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6145,22 +6145,138 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return err; } +static ieee80211_conn_flags_t +ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_assoc_data *assoc_data, + struct cfg80211_assoc_request *req, + ieee80211_conn_flags_t conn_flags) +{ + struct ieee80211_local *local = sdata->local; + const struct cfg80211_bss_ies *beacon_ies; + struct ieee80211_supported_band *sband; + const struct element *ht_elem, *vht_elem; + struct ieee80211_link_data *link = &sdata->deflink; + struct cfg80211_bss *cbss = req->bss; + struct ieee80211_bss *bss = (void *)cbss->priv; + bool is_5ghz, is_6ghz; + + sband = local->hw.wiphy->bands[cbss->channel->band]; + if (WARN_ON(!sband)) + return false; + + is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; + is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; + + assoc_data->supp_rates = bss->supp_rates; + assoc_data->supp_rates_len = bss->supp_rates_len; + + rcu_read_lock(); + ht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_OPERATION); + if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation)) + assoc_data->ap_ht_param = + ((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param; + else if (!is_6ghz) + conn_flags |= IEEE80211_CONN_DISABLE_HT; + vht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); + if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) { + memcpy(&assoc_data->ap_vht_cap, vht_elem->data, + sizeof(struct ieee80211_vht_cap)); + } else if (is_5ghz) { + link_info(link, + "VHT capa missing/short, disabling VHT/HE/EHT\n"); + conn_flags |= IEEE80211_CONN_DISABLE_VHT | + IEEE80211_CONN_DISABLE_HE | + IEEE80211_CONN_DISABLE_EHT; + } + rcu_read_unlock(); + + link->u.mgd.beacon_crc_valid = 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 (!(conn_flags & IEEE80211_CONN_DISABLE_HT)) { + struct ieee80211_sta_ht_cap sta_ht_cap; + + memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); + ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); + } + + rcu_read_lock(); + beacon_ies = rcu_dereference(cbss->beacon_ies); + if (beacon_ies) { + const struct element *elem; + u8 dtim_count = 0; + + ieee80211_get_dtim(beacon_ies, &dtim_count, + &link->u.mgd.dtim_period); + + sdata->deflink.u.mgd.have_beacon = true; + + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { + link->conf->sync_tsf = beacon_ies->tsf; + link->conf->sync_device_ts = bss->device_ts_beacon; + 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) + link->conf->profile_periodicity = elem->data[2]; + else + 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)) + link->conf->ema_ap = true; + else + link->conf->ema_ap = false; + } + rcu_read_unlock(); + + if (bss->corrupt_data) { + char *corrupt_type = "data"; + + if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) { + if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) + corrupt_type = "beacon and probe response"; + else + corrupt_type = "beacon"; + } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) { + corrupt_type = "probe response"; + } + sdata_info(sdata, "associating to AP %pM with corrupt %s\n", + cbss->bssid, corrupt_type); + } + + if (link->u.mgd.req_smps == IEEE80211_SMPS_AUTOMATIC) { + if (sdata->u.mgd.powersave) + link->smps_mode = IEEE80211_SMPS_DYNAMIC; + else + link->smps_mode = IEEE80211_SMPS_OFF; + } else { + link->smps_mode = link->u.mgd.req_smps; + } + + return conn_flags; +} + int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { - bool is_6ghz = req->bss->channel->band == NL80211_BAND_6GHZ; - bool is_5ghz = req->bss->channel->band == NL80211_BAND_5GHZ; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; const struct cfg80211_bss_ies *beacon_ies; - struct ieee80211_supported_band *sband; struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; - const struct element *ssid_elem, *ht_elem, *vht_elem; + const struct element *ssid_elem; struct ieee80211_link_data *link = &sdata->deflink; + ieee80211_conn_flags_t conn_flags = 0; int i, err; - bool override = false; + bool override; assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); if (!assoc_data) @@ -6216,8 +6332,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, /* prepare assoc data */ - link->u.mgd.beacon_crc_valid = false; - assoc_data->wmm = bss->wmm_used && (local->hw.queues >= IEEE80211_NUM_ACS); @@ -6232,27 +6346,44 @@ 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) { - 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; + conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; netdev_info(sdata->dev, "disabling HT/VHT/HE due to WEP/TKIP use\n"); } } - sband = local->hw.wiphy->bands[req->bss->channel->band]; - /* also disable HT/VHT/HE/EHT if the AP doesn't use WMM */ if (!bss->wmm_used) { - 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; + conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; netdev_info(sdata->dev, "disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n"); } + if (req->flags & ASSOC_REQ_DISABLE_HT) { + mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n"); + conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; + } + + if (req->flags & ASSOC_REQ_DISABLE_VHT) { + mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n"); + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + } + + if (req->flags & ASSOC_REQ_DISABLE_HE) { + mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n"); + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; + } + memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, sizeof(ifmgd->ht_capa_mask)); @@ -6287,28 +6418,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->bss = req->bss; assoc_data->capability = req->bss->capability; - assoc_data->supp_rates = bss->supp_rates; - assoc_data->supp_rates_len = bss->supp_rates_len; - rcu_read_lock(); - ht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_HT_OPERATION); - if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation)) - assoc_data->ap_ht_param = - ((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param; - else if (!is_6ghz) - 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, - sizeof(struct ieee80211_vht_cap)); - } else if (is_5ghz) { - sdata_info(sdata, - "VHT capa missing/short, disabling VHT/HE/EHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - } - rcu_read_unlock(); + /* default timeout */ + assoc_data->timeout = jiffies; + assoc_data->timeout_started = true; + + conn_flags |= ieee80211_setup_assoc_link(sdata, assoc_data, req, + conn_flags); + override = link->u.mgd.conn_flags != conn_flags; + link->u.mgd.conn_flags |= conn_flags; if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) && ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK), @@ -6352,50 +6470,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_no_preauth = req->crypto.control_port_no_preauth; /* kick off associate process */ - ifmgd->assoc_data = assoc_data; - 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 (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) { - struct ieee80211_sta_ht_cap sta_ht_cap; - - if (req->flags & ASSOC_REQ_DISABLE_HT) - override = true; - - memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); - ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); - - /* check for 40 MHz disable override */ - 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 (!(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"); - 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"); - 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"); - 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) link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; @@ -6427,60 +6502,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); assoc_data->timeout_started = true; assoc_data->need_beacon = true; - } else if (beacon_ies) { - const struct element *elem; - u8 dtim_count = 0; - - ieee80211_get_dtim(beacon_ies, &dtim_count, - &link->u.mgd.dtim_period); - - link->u.mgd.have_beacon = true; - assoc_data->timeout = jiffies; - assoc_data->timeout_started = true; - - if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { - link->conf->sync_tsf = beacon_ies->tsf; - link->conf->sync_device_ts = - bss->device_ts_beacon; - 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) - link->conf->profile_periodicity = elem->data[2]; - else - 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)) - link->conf->ema_ap = true; - else - link->conf->ema_ap = false; - } else { - assoc_data->timeout = jiffies; - assoc_data->timeout_started = true; } rcu_read_unlock(); run_again(sdata, assoc_data->timeout); - if (bss->corrupt_data) { - char *corrupt_type = "data"; - if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) { - if (bss->corrupt_data & - IEEE80211_BSS_CORRUPT_PROBE_RESP) - corrupt_type = "beacon and probe response"; - else - corrupt_type = "beacon"; - } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) - corrupt_type = "probe response"; - sdata_info(sdata, "associating with AP with corrupt %s\n", - corrupt_type); - } - return 0; err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); -- cgit v1.2.3 From 74e1309acedc1f091722f33e752aeb87d4ed4c33 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 17:21:22 +0200 Subject: wifi: mac80211: mlme: look up beacon elems only if needed If NEED_DTIM_BEFORE_ASSOC isn't set, then we don't need to enter an RCU critical section and look up the beacon elements. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 292ad46daa9d..059b66d158ff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6270,7 +6270,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; - const struct cfg80211_bss_ies *beacon_ies; struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; const struct element *ssid_elem; struct ieee80211_link_data *link = &sdata->deflink; @@ -6488,22 +6487,25 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, link->smps_mode = link->u.mgd.req_smps; } - rcu_read_lock(); - beacon_ies = rcu_dereference(req->bss->beacon_ies); + if (ieee80211_hw_check(&sdata->local->hw, NEED_DTIM_BEFORE_ASSOC)) { + const struct cfg80211_bss_ies *beacon_ies; - if (ieee80211_hw_check(&sdata->local->hw, NEED_DTIM_BEFORE_ASSOC) && - !beacon_ies) { - /* - * Wait up to one beacon interval ... - * should this be more if we miss one? - */ - sdata_info(sdata, "waiting for beacon from %pM\n", - 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; + rcu_read_lock(); + beacon_ies = rcu_dereference(req->bss->beacon_ies); + + if (beacon_ies) { + /* + * Wait up to one beacon interval ... + * should this be more if we miss one? + */ + sdata_info(sdata, "waiting for beacon from %pM\n", + 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; + } + rcu_read_unlock(); } - rcu_read_unlock(); run_again(sdata, assoc_data->timeout); -- cgit v1.2.3 From 7464f665158e09f3f29116d8d0676824c1f1eeda Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 18:32:49 +0200 Subject: wifi: cfg80211: add cfg80211_get_iftype_ext_capa() Add a helper function cfg80211_get_iftype_ext_capa() to look up interface type-specific (extended) capabilities. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 ++++++++ net/wireless/util.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8dbc64286d91..d5af3a7fc2b4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5005,6 +5005,14 @@ struct wiphy_iftype_ext_capab { u16 mld_capa_and_ops; }; +/** + * cfg80211_get_iftype_ext_capa - lookup interface type extended capability + * @wiphy: the wiphy to look up from + * @type: the interface type to look up + */ +const struct wiphy_iftype_ext_capab * +cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type); + /** * struct cfg80211_pmsr_capabilities - cfg80211 peer measurement capabilities * @max_peers: maximum number of peers in a single measurement diff --git a/net/wireless/util.c b/net/wireless/util.c index fe7956c8c6da..2c127951764a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2490,3 +2490,17 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, return rdev_del_virtual_intf(rdev, wdev); } + +const struct wiphy_iftype_ext_capab * +cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type) +{ + int i; + + for (i = 0; i < wiphy->num_iftype_ext_capab; i++) { + if (wiphy->iftype_ext_capab[i].iftype == type) + return &wiphy->iftype_ext_capab[i]; + } + + return NULL; +} +EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa); -- cgit v1.2.3 From 5d3a341c0dd21f14eb97cea3754621d8aa1637de Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 22:18:24 +0200 Subject: wifi: mac80211: mlme: refactor ieee80211_set_associated() Split out much of the code in ieee80211_set_associated() into a new ieee80211_link_set_associated() which can be called per link later for MLO. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 67 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 059b66d158ff..308a8fe50212 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2388,29 +2388,27 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_link_data *link, return changed; } -static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, - u32 bss_info_changed) +static u32 ieee80211_link_set_associated(struct ieee80211_link_data *link, + struct cfg80211_bss *cbss) { - struct ieee80211_bss *bss = (void *)cbss->priv; - struct ieee80211_local *local = sdata->local; - struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_bss_conf *bss_conf = link->conf; - struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; + struct ieee80211_bss *bss = (void *)cbss->priv; + u32 changed = 0; - bss_info_changed |= BSS_CHANGED_ASSOC; - 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(beacon_loss_count * + bss_conf->beacon_int)); - sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( - beacon_loss_count * bss_conf->beacon_int)); + changed |= ieee80211_handle_bss_capability(link, + bss_conf->assoc_capability, + bss->has_erp_value, + bss->erp_value); + + ieee80211_check_rate_mask(link); - sdata->u.mgd.associated = true; 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(link); if (sdata->vif.p2p || sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) { @@ -2429,17 +2427,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, if (ret >= 2) { link->u.mgd.p2p_noa_index = bss_conf->p2p_noa_attr.index; - bss_info_changed |= BSS_CHANGED_P2P_PS; + changed |= BSS_CHANGED_P2P_PS; } } rcu_read_unlock(); } - /* just to be sure */ - ieee80211_stop_poll(sdata); - - ieee80211_led_assoc(local, 1); - if (link->u.mgd.have_beacon) { /* * If the AP is buggy we may get here with no DTIM period @@ -2449,18 +2442,40 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, */ bss_conf->dtim_period = link->u.mgd.dtim_period ?: 1; bss_conf->beacon_rate = bss->beacon_rate; - bss_info_changed |= BSS_CHANGED_BEACON_INFO; + changed |= BSS_CHANGED_BEACON_INFO; } else { bss_conf->beacon_rate = NULL; bss_conf->dtim_period = 0; } - vif_cfg->assoc = 1; - /* Tell the driver to monitor connection quality (if supported) */ if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI && bss_conf->cqm_rssi_thold) - bss_info_changed |= BSS_CHANGED_CQM; + changed |= BSS_CHANGED_CQM; + + return changed; +} + +static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss, + u32 bss_info_changed) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; + + bss_info_changed |= BSS_CHANGED_ASSOC; + bss_info_changed |= ieee80211_link_set_associated(link, cbss); + + sdata->u.mgd.associated = true; + memcpy(sdata->vif.cfg.ap_addr, cbss->bssid, ETH_ALEN); + + /* just to be sure */ + ieee80211_stop_poll(sdata); + + ieee80211_led_assoc(local, 1); + + vif_cfg->assoc = 1; /* Enable ARP filtering */ if (vif_cfg->arp_addr_cnt) -- cgit v1.2.3 From 175ad2ec89feb8c01f87be64882af67481b1b1f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jul 2022 18:08:03 +0200 Subject: wifi: mac80211: limit A-MSDU subframes for client too In AP/mesh where the stations are added by userspace, we limit the number of A-MSDU subframes according to the extended capabilities. Refactor the code and extend that also to client-side. Fixes: 506bcfa8abeb ("mac80211: limit the A-MSDU Tx based on peer's capabilities") Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 29 ++--------------------------- net/mac80211/mlme.c | 3 +++ net/mac80211/sta_info.c | 23 +++++++++++++++++++++++ net/mac80211/sta_info.h | 4 ++++ 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bdc3d74eecc1..1545648e2031 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1776,33 +1776,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, sta->sta.max_sp = params->max_sp; } - /* The sender might not have sent the last bit, consider it to be 0 */ - if (params->ext_capab_len >= 8) { - u8 val = (params->ext_capab[7] & - WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7; - - /* we did get all the bits, take the MSB as well */ - if (params->ext_capab_len >= 9) { - u8 val_msb = params->ext_capab[8] & - WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB; - val_msb <<= 1; - val |= val_msb; - } - - switch (val) { - case 1: - sta->sta.max_amsdu_subframes = 32; - break; - case 2: - sta->sta.max_amsdu_subframes = 16; - break; - case 3: - sta->sta.max_amsdu_subframes = 8; - break; - default: - sta->sta.max_amsdu_subframes = 0; - } - } + ieee80211_sta_set_max_amsdu_subframes(sta, params->ext_capab, + params->ext_capab_len); /* * cfg80211 validates this (1-2007) and allows setting the AID diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 308a8fe50212..3263bb188284 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4488,6 +4488,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta->sta.mfp = false; } + ieee80211_sta_set_max_amsdu_subframes(sta, elems->ext_capab, + elems->ext_capab_len); + sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && local->hw.queues >= IEEE80211_NUM_ACS; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f52a7fa6dde5..eed88630594f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2761,3 +2761,26 @@ void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) sta_remove_link(sta, link_id, true); } + +void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta, + const u8 *ext_capab, + unsigned int ext_capab_len) +{ + u8 val; + + sta->sta.max_amsdu_subframes = 0; + + if (ext_capab_len < 8) + return; + + /* The sender might not have sent the last bit, consider it to be 0 */ + val = u8_get_bits(ext_capab[7], WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB); + + /* we did get all the bits, take the MSB as well */ + if (ext_capab_len >= 9) + val |= u8_get_bits(ext_capab[8], + WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB) << 1; + + if (val) + sta->sta.max_amsdu_subframes = 4 << val; +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ea0eeee808a5..6bc26a2c4607 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -910,6 +910,10 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); unsigned long ieee80211_sta_last_active(struct sta_info *sta); +void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta, + const u8 *ext_capab, + unsigned int ext_capab_len); + enum sta_stats_type { STA_STATS_RATE_TYPE_INVALID = 0, STA_STATS_RATE_TYPE_LEGACY, -- cgit v1.2.3 From d46ffecf82dea931c11a188e2cd618e0bfe083b1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jul 2022 22:23:02 +0200 Subject: wifi: mac80211_hwsim: implement sta_state for MLO In MLO, we need to transmit to another MLD and select the link to it, which requires knowing the station. But in TX, mac80211 will not give us a station that's not added to the driver, which in the older add/remove API is only done later. Implement the new API in MLO so we know about the STA at all times and get a pointer during TX as well. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5418c4973501..d0d19648d6a9 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2315,6 +2315,21 @@ static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, return 0; } +static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + if (new_state == IEEE80211_STA_NOTEXIST) + return mac80211_hwsim_sta_remove(hw, vif, sta); + + if (old_state == IEEE80211_STA_NOTEXIST) + return mac80211_hwsim_sta_add(hw, vif, sta); + + return 0; +} + static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, @@ -2900,8 +2915,6 @@ static int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw, .vif_cfg_changed = mac80211_hwsim_vif_info_changed, \ .link_info_changed = mac80211_hwsim_link_info_changed, \ .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ - .sta_add = mac80211_hwsim_sta_add, \ - .sta_remove = mac80211_hwsim_sta_remove, \ .sta_notify = mac80211_hwsim_sta_notify, \ .sta_rc_update = mac80211_hwsim_sta_rc_update, \ .conf_tx = mac80211_hwsim_conf_tx, \ @@ -2914,6 +2927,8 @@ static int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw, .get_et_strings = mac80211_hwsim_get_et_strings, #define HWSIM_NON_MLO_OPS \ + .sta_add = mac80211_hwsim_sta_add, \ + .sta_remove = mac80211_hwsim_sta_remove, \ .set_tim = mac80211_hwsim_set_tim, \ .get_tsf = mac80211_hwsim_get_tsf, \ .set_tsf = mac80211_hwsim_set_tsf, @@ -2948,6 +2963,7 @@ static const struct ieee80211_ops mac80211_hwsim_mlo_ops = { .set_rts_threshold = mac80211_hwsim_set_rts_threshold, .change_vif_links = mac80211_hwsim_change_vif_links, .change_sta_links = mac80211_hwsim_change_sta_links, + .sta_state = mac80211_hwsim_sta_state, }; struct hwsim_new_radio_params { -- cgit v1.2.3 From f36fe0a2df03209f4d681fa954f20bfa4eefec45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jul 2022 23:40:47 +0200 Subject: wifi: mac80211: fix up link station creation/insertion When we create a station with a non-default link, then we should have a link address, and we definitely need to insert it into the link hash table on insertion. Split the API into with and without link creation and if it has a link, insert the link into the link hash table on sta_info_insert(). Fixes: ba6ddab94fc6 ("wifi: mac80211: maintain link-sta hash table") Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 10 ++++++++-- net/mac80211/ibss.c | 4 ++-- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/ocb.c | 2 +- net/mac80211/sta_info.c | 49 +++++++++++++++++++++++++++++++++++------------ net/mac80211/sta_info.h | 7 ++++++- 7 files changed, 56 insertions(+), 20 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1545648e2031..1cacd1e0fc85 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1850,8 +1850,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; - sta = sta_info_alloc(sdata, mac, params->link_sta_params.link_id, - GFP_KERNEL); + if (params->link_sta_params.link_id >= 0) + sta = sta_info_alloc_with_link(sdata, mac, + params->link_sta_params.link_id, + params->link_sta_params.link_mac, + GFP_KERNEL); + else + sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + if (!sta) return -ENOMEM; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 60b5230778a3..d56890e3fabb 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -625,7 +625,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, -1, GFP_KERNEL); + sta = sta_info_alloc(sdata, addr, GFP_KERNEL); if (!sta) { rcu_read_lock(); return NULL; @@ -1226,7 +1226,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC); + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 84e3f43fd5c6..ddfe5102b9a4 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -511,7 +511,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) if (aid < 0) return NULL; - sta = sta_info_alloc(sdata, hw_addr, -1, GFP_KERNEL); + sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); if (!sta) return NULL; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3263bb188284..c7fb12d6fb17 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5909,7 +5909,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (!have_sta) { - new_sta = sta_info_alloc(sdata, cbss->bssid, -1, GFP_KERNEL); + new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); if (!new_sta) return -ENOMEM; } diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 8664fee699e9..a57dcbe99a0d 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -69,7 +69,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC); + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index eed88630594f..75122eced104 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -96,6 +96,14 @@ static int sta_info_hash_del(struct ieee80211_local *local, sta_rht_params); } +static int link_sta_info_hash_add(struct ieee80211_local *local, + struct link_sta_info *link_sta) +{ + return rhltable_insert(&local->link_sta_hash, + &link_sta->link_hash_node, + link_sta_rht_params); +} + static int link_sta_info_hash_del(struct ieee80211_local *local, struct link_sta_info *link_sta) { @@ -466,8 +474,10 @@ static void sta_info_add_link(struct sta_info *sta, rcu_assign_pointer(sta->sta.link[link_id], link_sta); } -struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - const u8 *addr, int link_id, gfp_t gfp) +static struct sta_info * +__sta_info_alloc(struct ieee80211_sub_if_data *sdata, + const u8 *addr, int link_id, const u8 *link_addr, + gfp_t gfp) { struct ieee80211_local *local = sdata->local; struct ieee80211_hw *hw = &local->hw; @@ -513,8 +523,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, memcpy(sta->addr, addr, ETH_ALEN); memcpy(sta->sta.addr, addr, ETH_ALEN); - memcpy(sta->deflink.addr, addr, ETH_ALEN); - memcpy(sta->sta.deflink.addr, addr, ETH_ALEN); + memcpy(sta->deflink.addr, link_addr, ETH_ALEN); + memcpy(sta->sta.deflink.addr, link_addr, ETH_ALEN); sta->sta.max_rx_aggregation_subframes = local->hw.max_rx_aggregation_subframes; @@ -641,6 +651,21 @@ free: return NULL; } +struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + const u8 *addr, gfp_t gfp) +{ + return __sta_info_alloc(sdata, addr, -1, addr, gfp); +} + +struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata, + const u8 *mld_addr, + unsigned int link_id, + const u8 *link_addr, + gfp_t gfp) +{ + return __sta_info_alloc(sdata, mld_addr, link_id, link_addr, gfp); +} + static int sta_info_insert_check(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; @@ -774,6 +799,14 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) if (err) goto out_drop_sta; + if (sta->sta.valid_links) { + err = link_sta_info_hash_add(local, &sta->deflink); + if (err) { + sta_info_hash_del(local, sta); + goto out_drop_sta; + } + } + list_add_tail_rcu(&sta->list, &local->sta_list); /* update channel context before notifying the driver about state @@ -2697,14 +2730,6 @@ int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) return 0; } -static int link_sta_info_hash_add(struct ieee80211_local *local, - struct link_sta_info *link_sta) -{ - return rhltable_insert(&local->link_sta_hash, - &link_sta->link_hash_node, - 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); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6bc26a2c4607..2eb3a9452e07 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -840,7 +840,12 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, * until sta_info_insert(). */ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - const u8 *addr, int link_id, gfp_t gfp); + const u8 *addr, gfp_t gfp); +struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata, + const u8 *mld_addr, + unsigned int link_id, + const u8 *link_addr, + gfp_t gfp); void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); -- cgit v1.2.3 From 3e0278b717b077f9ccf0280580ce6c5eb9c4dbac Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 13 Jul 2022 12:05:27 +0300 Subject: wifi: mac80211: select link when transmitting to non-MLO stations When an MLO AP is transmitting to a non-MLO station, addr2 should be set to a link address. This should be done before the frame is encrypted as otherwise aad verification would fail. In case of software encryption this can't be left for the device to handle, and should be done by mac80211 when building the frame hdr. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ net/mac80211/cfg.c | 4 ++++ net/mac80211/tx.c | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6fc4253b5644..6f856da28d71 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2147,6 +2147,7 @@ struct ieee80211_link_sta { * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only * valid if the STA is a TDLS peer in the first place. * @mfp: indicates whether the STA uses management frame protection or not. + * @mlo: indicates whether the STA is MLO station. * @max_amsdu_subframes: indicates the maximal number of MSDUs in a single * A-MSDU. Taken from the Extended Capabilities element. 0 means * unlimited. @@ -2180,6 +2181,7 @@ struct ieee80211_sta { bool tdls; bool tdls_initiator; bool mfp; + bool mlo; u8 max_amsdu_subframes; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1cacd1e0fc85..fe6500b36953 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1818,6 +1818,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, return ret; } + /* Mark the STA as MLO if MLD MAC address is available */ + if (params->link_sta_params.mld_mac) + sta->sta.mlo = true; + return 0; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5dd29288c009..1d60eab8308a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2570,6 +2570,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx_conf *chanctx_conf = NULL; enum nl80211_band band; int ret; + u8 link_id = IEEE80211_LINK_UNSPECIFIED; if (IS_ERR(sta)) sta = NULL; @@ -2618,7 +2619,21 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + + if (sdata->vif.valid_links && sta && !sta->sta.mlo) { + struct ieee80211_link_data *link; + + link_id = sta->deflink.link_id; + link = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link)) { + ret = -ENOLINK; + goto free; + } + memcpy(hdr.addr2, link->conf->addr, ETH_ALEN); + } else { + memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + } + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 24; break; @@ -2882,7 +2897,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, info->ack_frame_id = info_id; info->band = band; info->control.flags = ctrl_flags | - u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); return skb; -- cgit v1.2.3 From 42fb9148c078004d07b4c39bd7b1086b6165780c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jul 2022 23:47:32 +0200 Subject: wifi: mac80211: do link->MLD address translation on RX In some cases, e.g. with Qualcomm devices and management frames, or in hwsim, frames may be reported from the driver with link addresses, but for decryption and matching needs we really want to have them with MLD addresses. Support the translation on RX. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9f1ea8c840e9..cad4b2378218 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -4724,6 +4724,9 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, { struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = rx->sdata; + struct ieee80211_hdr *hdr = (void *)skb->data; + struct link_sta_info *link_sta = NULL; + struct ieee80211_link_data *link; rx->skb = skb; @@ -4745,6 +4748,15 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, if (!ieee80211_accept_frame(rx)) return false; + if (unlikely(!is_multicast_ether_addr(hdr->addr1) && + rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) { + link_sta = rcu_dereference(rx->sta->link[rx->link_id]); + link = rcu_dereference(rx->sdata->link[rx->link_id]); + + if (WARN_ON_ONCE(!link_sta || !link)) + return true; + } + if (!consume) { skb = skb_copy(skb, GFP_ATOMIC); if (!skb) { @@ -4758,6 +4770,19 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, rx->skb = skb; } + if (unlikely(link_sta)) { + /* translate to MLD addresses */ + if (ether_addr_equal(link->conf->addr, hdr->addr1)) + ether_addr_copy(hdr->addr1, rx->sdata->vif.addr); + if (ether_addr_equal(link_sta->addr, hdr->addr2)) + ether_addr_copy(hdr->addr2, rx->sta->addr); + if (ether_addr_equal(link_sta->addr, hdr->addr3)) + ether_addr_copy(hdr->addr3, rx->sta->addr); + else if (ether_addr_equal(link->conf->addr, hdr->addr3)) + ether_addr_copy(hdr->addr3, rx->sdata->vif.addr); + /* not needed for A4 since it can only carry the SA */ + } + ieee80211_invoke_rx_handlers(rx); return true; } -- cgit v1.2.3 From aea9a6088ae46e77527716496ab259ddfa320148 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 22 Jun 2022 16:11:43 +0300 Subject: wifi: mac80211_hwsim: do rc update per link Make mac80211_hwsim_sta_rc_update() iterate over all the STA links. This is somewhat temporary, we really should add the link to the API, but then hwsim still calls it internally and would need this. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 63 +++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d0d19648d6a9..4a3d42b3099f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2263,35 +2263,56 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, { struct mac80211_hwsim_data *data = hw->priv; u32 bw = U32_MAX; - enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; + int link_id; + + rcu_read_lock(); + for (link_id = 0; + link_id < ARRAY_SIZE(vif->link_conf); + link_id++) { + enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; + struct ieee80211_bss_conf *vif_conf; + struct ieee80211_link_sta *link_sta; + + link_sta = rcu_dereference(sta->link[link_id]); + + if (!link_sta) + continue; - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { #define C(_bw) case IEEE80211_STA_RX_BW_##_bw: bw = _bw; break - C(20); - C(40); - C(80); - C(160); - C(320); + C(20); + C(40); + C(80); + C(160); + C(320); #undef C - } + } - if (!data->use_chanctx) { - confbw = data->bw; - } else { - struct ieee80211_chanctx_conf *chanctx_conf; + if (!data->use_chanctx) { + confbw = data->bw; + } else { + struct ieee80211_chanctx_conf *chanctx_conf; + + vif_conf = rcu_dereference(vif->link_conf[link_id]); + if (WARN_ON(!vif_conf)) + continue; + + chanctx_conf = rcu_dereference(vif_conf->chanctx_conf); + + if (!WARN_ON(!chanctx_conf)) + confbw = chanctx_conf->def.width; + } + + WARN(bw > hwsim_get_chanwidth(confbw), + "intf %pM [link=%d]: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n", + vif->addr, link_id, sta->addr, bw, sta->deflink.bandwidth, + hwsim_get_chanwidth(data->bw), data->bw); - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); - if (!WARN_ON(!chanctx_conf)) - confbw = chanctx_conf->def.width; - rcu_read_unlock(); } + rcu_read_unlock(); + - WARN(bw > hwsim_get_chanwidth(confbw), - "intf %pM: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n", - vif->addr, sta->addr, bw, sta->deflink.bandwidth, - hwsim_get_chanwidth(data->bw), data->bw); } static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, -- cgit v1.2.3 From 2ab60f49eb4d87998be602ca09c0e88b0808142b Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 14 Jun 2022 17:17:20 +0300 Subject: wifi: mac80211_hwsim: use MLO link ID for TX Use the link ID provided in TX frame metadata to select the correct channel. For now, always select the link with the lowest link ID and do some address translation. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4a3d42b3099f..36b8c95150ae 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1700,6 +1700,42 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, return ack; } +static struct ieee80211_bss_conf * +mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_hdr *hdr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { + struct ieee80211_link_sta *link_sta = NULL; + struct ieee80211_bss_conf *bss_conf; + + bss_conf = rcu_dereference(vif->link_conf[i]); + if (!bss_conf) + continue; + + if (sta) { + link_sta = rcu_dereference(sta->link[i]); + if (!link_sta) + continue; + } + + if (!is_multicast_ether_addr(hdr->addr1)) { + if (link_sta) + ether_addr_copy(hdr->addr1, link_sta->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); + } else { + /* TODO: Handle multicast frames */ + } + + return bss_conf; + } + + return NULL; +} + static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -1726,8 +1762,21 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, channel = data->tmp_chan; } else { struct ieee80211_bss_conf *bss_conf; - - bss_conf = &txi->control.vif->bss_conf; + u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, + IEEE80211_TX_CTRL_MLO_LINK); + + if (link != IEEE80211_LINK_UNSPECIFIED) + bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); + else + bss_conf = mac80211_hwsim_select_tx_link(data, + txi->control.vif, + control->sta, + hdr); + + if (WARN_ON(!bss_conf)) { + ieee80211_free_txskb(hw, skb); + return; + } chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); if (chanctx_conf) { -- cgit v1.2.3 From af4f2aa35a4429f75e87c876e05fba84920a152e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jul 2022 21:58:00 +0200 Subject: wifi: mac80211_hwsim: fix TX link selection Now that we have a pointer to the TX STA even when it's not authenticated/... yet, fix the TX link selection in hwsim to select only among the valid links for the STA, requiring a STA pointer here. Also implement a simple round-robin between links to make life more interesting. While at it, also consider A3 when translating to link addresses. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 47 ++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 36b8c95150ae..934939aa5fb6 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -228,6 +228,7 @@ static inline void hwsim_clear_magic(struct ieee80211_vif *vif) struct hwsim_sta_priv { u32 magic; + unsigned int last_link; }; #define HWSIM_STA_MAGIC 0x6d537749 @@ -1706,30 +1707,48 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, struct ieee80211_sta *sta, struct ieee80211_hdr *hdr) { + struct hwsim_sta_priv *sp = (void *)sta->drv_priv; int i; + if (!vif->valid_links) + return &vif->bss_conf; + + /* FIXME: handle multicast TX properly */ + if (is_multicast_ether_addr(hdr->addr1) || WARN_ON_ONCE(!sta)) { + unsigned int first_link = ffs(vif->valid_links) - 1; + + return rcu_dereference(vif->link_conf[first_link]); + } + + if (WARN_ON_ONCE(!sta->valid_links)) + return &vif->bss_conf; + for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { struct ieee80211_link_sta *link_sta = NULL; struct ieee80211_bss_conf *bss_conf; + unsigned int link_id; + + /* round-robin the available link IDs */ + link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); - bss_conf = rcu_dereference(vif->link_conf[i]); - if (!bss_conf) + link_sta = rcu_dereference(sta->link[link_id]); + if (!link_sta) continue; - if (sta) { - link_sta = rcu_dereference(sta->link[i]); - if (!link_sta) - continue; - } + bss_conf = rcu_dereference(vif->link_conf[link_id]); + if (WARN_ON_ONCE(!bss_conf)) + continue; - if (!is_multicast_ether_addr(hdr->addr1)) { - if (link_sta) - ether_addr_copy(hdr->addr1, link_sta->addr); - ether_addr_copy(hdr->addr2, bss_conf->addr); - } else { - /* TODO: Handle multicast frames */ - } + /* address translation to link addresses on TX */ + ether_addr_copy(hdr->addr1, link_sta->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); + if (ether_addr_equal(hdr->addr3, sta->addr)) + ether_addr_copy(hdr->addr3, link_sta->addr); + else if (ether_addr_equal(hdr->addr3, vif->addr)) + ether_addr_copy(hdr->addr3, bss_conf->addr); + /* no need to look at A4, if present it's SA */ + sp->last_link = link_id; return bss_conf; } -- cgit v1.2.3 From 425f4b5fce7cdaaddbc9a9be9e6d1915679d63f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jun 2022 13:48:22 +0200 Subject: wifi: mac80211: add API to parse multi-link element Add the necessary API to parse the multi-link element in the future. For now, link only to the element when found so we can use it in the client-side code later. Later, we'll need to fill this in to deal with element fragmentation, parse the STA profile, etc. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/util.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index baaff4c7a79c..cb5b3f9a7d06 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1658,6 +1658,7 @@ struct ieee802_11_elems { const struct ieee80211_aid_response_ie *aid_resp; const struct ieee80211_eht_cap_elem *eht_cap; const struct ieee80211_eht_operation *eht_operation; + const struct ieee80211_multi_link_elem *multi_link; /* length of them, respectively */ u8 ext_capab_len; @@ -2161,6 +2162,8 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, * @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 + * @link_id: the link ID to parse elements for, if a STA profile + * is present in the multi-link element, or -1 to ignore */ struct ieee80211_elems_parse_params { const u8 *start; @@ -2169,6 +2172,7 @@ struct ieee80211_elems_parse_params { u64 filter; u32 crc; struct cfg80211_bss *bss; + int link_id; }; struct ieee802_11_elems * @@ -2186,6 +2190,7 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, .filter = filter, .crc = crc, .bss = bss, + .link_id = -1, }; return ieee802_11_parse_elems_full(¶ms); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fc66b292b1c0..53826c663723 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1022,6 +1022,10 @@ static void ieee80211_parse_extension_element(u32 *crc, if (ieee80211_eht_oper_size_ok(data, len)) elems->eht_operation = data; break; + case WLAN_EID_EXT_EHT_MULTI_LINK: + if (ieee80211_mle_size_ok(data, len)) + elems->multi_link = (void *)data; + break; } } @@ -1524,6 +1528,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) .start = nontransmitted_profile, .len = nontransmitted_profile_len, .action = params->action, + .link_id = params->link_id, }; _ieee802_11_parse_elems_full(&sub, elems, NULL); -- cgit v1.2.3 From 81151ce462e533551f3284bfdb8e0f461c9220e6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jun 2022 21:17:34 +0200 Subject: wifi: mac80211: support MLO authentication/association with one link It might seem a bit pointless to do a multi-link operation connection with just a single link, but this is already a big change, so for now, limit MLO connections to a single link. Extending that to multiple links will require * work on parsing the multi-link element with STA profile properly, including element fragmentation; * checking the per-link status in the multi-link element * implementing logic to have active/inactive links to let drivers decide which links should be active; * implementing multicast RX deduplication; * and likely more. For now this is still useful since it lets us do multi-link connections for the purposes of testing APIs and the higher layers such as wpa_supplicant. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 32 +- net/mac80211/mlme.c | 1072 ++++++++++++++++++++++++++++++++++---------- net/mac80211/tx.c | 2 +- net/wireless/mlme.c | 3 + 4 files changed, 869 insertions(+), 240 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cb5b3f9a7d06..5fc4392ba507 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -389,37 +389,55 @@ struct ieee80211_mgd_auth_data { bool peer_confirmed; bool timeout_started; + u8 ap_addr[ETH_ALEN] __aligned(2); + u16 sae_trans, sae_status; size_t data_len; u8 data[]; }; struct ieee80211_mgd_assoc_data { - struct cfg80211_bss *bss; + struct { + struct cfg80211_bss *bss; + + u8 addr[ETH_ALEN] __aligned(2); + + u8 ap_ht_param; + + struct ieee80211_vht_cap ap_vht_cap; + + size_t elems_len; + u8 *elems; /* pointing to inside ie[] below */ + + ieee80211_conn_flags_t conn_flags; + } link[IEEE80211_MLD_MAX_NUM_LINKS]; + + u8 ap_addr[ETH_ALEN] __aligned(2); + + /* this is for a workaround, so we use it only for non-MLO */ const u8 *supp_rates; + u8 supp_rates_len; unsigned long timeout; int tries; - u16 capability; - u8 prev_bssid[ETH_ALEN]; + u8 prev_ap_addr[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; - u8 supp_rates_len; bool wmm, uapsd; bool need_beacon; bool synced; bool timeout_started; + bool s1g; - u8 ap_ht_param; - - struct ieee80211_vht_cap ap_vht_cap; + unsigned int assoc_link_id; u8 fils_nonces[2 * FILS_NONCE_LEN]; u8 fils_kek[FILS_MAX_KEK_LEN]; size_t fils_kek_len; size_t ie_len; + u8 *ie_pos; /* used to fill ie[] with link[].elems */ u8 ie[]; }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c7fb12d6fb17..e4e501f2713e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -936,37 +936,66 @@ static size_t ieee80211_add_before_he_elems(struct sk_buff *skb, return noffset; } +#define PRESENT_ELEMS_MAX 8 +#define PRESENT_ELEM_EXT_OFFS 0x100 + +static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, u16 capab, + const struct element *ext_capa, + const u16 *present_elems); + static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, u16 *capab, const struct element *ext_capa, const u8 *extra_elems, size_t extra_elems_len, - struct ieee80211_link_data *link) + unsigned int link_id, + struct ieee80211_link_data *link, + u16 *present_elems) { enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; - struct cfg80211_bss *cbss = assoc_data->bss; + struct cfg80211_bss *cbss = assoc_data->link[link_id].bss; struct ieee80211_channel *chan = cbss->channel; const struct ieee80211_sband_iftype_data *iftd; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20; struct ieee80211_chanctx_conf *chanctx_conf; + enum ieee80211_smps_mode smps_mode; + u16 orig_capab = *capab; size_t offset = 0; + int present_elems_len = 0; u8 *pos; int i; - /* - * 5/10 MHz scenarios are only viable without MLO, in which - * case this pointer should be used ... All of this is a bit - * unclear though, not sure this even works at all. - */ - rcu_read_lock(); - chanctx_conf = rcu_dereference(link->conf->chanctx_conf); - if (chanctx_conf) - width = chanctx_conf->def.width; - rcu_read_unlock(); +#define ADD_PRESENT_ELEM(id) do { \ + /* need a last for termination - we use 0 == SSID */ \ + if (!WARN_ON(present_elems_len >= PRESENT_ELEMS_MAX - 1)) \ + present_elems[present_elems_len++] = (id); \ +} while (0) +#define ADD_PRESENT_EXT_ELEM(id) ADD_PRESENT_ELEM(PRESENT_ELEM_EXT_OFFS | (id)) + + if (link) + smps_mode = link->smps_mode; + else if (sdata->u.mgd.powersave) + smps_mode = IEEE80211_SMPS_DYNAMIC; + else + smps_mode = IEEE80211_SMPS_OFF; + + if (link) { + /* + * 5/10 MHz scenarios are only viable without MLO, in which + * case this pointer should be used ... All of this is a bit + * unclear though, not sure this even works at all. + */ + rcu_read_lock(); + chanctx_conf = rcu_dereference(link->conf->chanctx_conf); + if (chanctx_conf) + width = chanctx_conf->def.width; + rcu_read_unlock(); + } sband = local->hw.wiphy->bands[chan->band]; iftd = ieee80211_get_sband_iftype_data(sband, iftype); @@ -996,6 +1025,7 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, *pos++ = 0; /* min tx power */ /* max tx power */ *pos++ = ieee80211_chandef_max_power(&chandef); + ADD_PRESENT_ELEM(WLAN_EID_PWR_CAPABILITY); } /* @@ -1017,6 +1047,7 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, *pos++ = ieee80211_frequency_to_channel(cf); *pos++ = 1; /* one channel in the subband*/ } + ADD_PRESENT_ELEM(WLAN_EID_SUPPORTED_CHANNELS); } /* if present, add any custom IEs that go before HT */ @@ -1025,11 +1056,13 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, offset); if (sband->band != NL80211_BAND_6GHZ && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) + !(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HT)) { ieee80211_add_ht_ie(sdata, skb, - assoc_data->ap_ht_param, - sband, chan, link->smps_mode, - link->u.mgd.conn_flags); + assoc_data->link[link_id].ap_ht_param, + sband, chan, smps_mode, + assoc_data->link[link_id].conn_flags); + ADD_PRESENT_ELEM(WLAN_EID_HT_CAPABILITY); + } /* if present, add any custom IEs that go before VHT */ offset = ieee80211_add_before_vht_elems(skb, extra_elems, @@ -1037,20 +1070,25 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, offset); if (sband->band != NL80211_BAND_6GHZ && - !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) - link->conf->mu_mimo_owner = + !(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_VHT)) { + bool mu_mimo_owner = ieee80211_add_vht_ie(sdata, skb, sband, - &assoc_data->ap_vht_cap, - link->u.mgd.conn_flags); + &assoc_data->link[link_id].ap_vht_cap, + assoc_data->link[link_id].conn_flags); + + if (link) + link->conf->mu_mimo_owner = mu_mimo_owner; + ADD_PRESENT_ELEM(WLAN_EID_VHT_CAPABILITY); + } /* * If AP doesn't support HT, mark HE and EHT as disabled. * If on the 5GHz band, make sure it supports VHT. */ - if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || + if (assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HT || (sband->band == NL80211_BAND_5GHZ && - link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) - link->u.mgd.conn_flags |= + assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_VHT)) + assoc_data->link[link_id].conn_flags |= IEEE80211_CONN_DISABLE_HE | IEEE80211_CONN_DISABLE_EHT; @@ -1059,11 +1097,28 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, extra_elems_len, offset); - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) + if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HE)) { ieee80211_add_he_ie(sdata, skb, sband, - link->u.mgd.conn_flags); + assoc_data->link[link_id].conn_flags); + ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_HE_CAPABILITY); + } - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) + /* + * careful - need to know about all the present elems before + * calling ieee80211_assoc_add_ml_elem(), so add this one if + * we're going to put it after the ML element + */ + if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_EHT)) + ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_EHT_CAPABILITY); + + if (link_id == assoc_data->assoc_link_id) + ieee80211_assoc_add_ml_elem(sdata, skb, orig_capab, ext_capa, + present_elems); + + /* crash if somebody gets it wrong */ + present_elems = NULL; + + if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_EHT)) ieee80211_add_eht_ie(sdata, skb, sband); if (sband->band == NL80211_BAND_S1GHZ) { @@ -1074,29 +1129,185 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata, if (iftd && iftd->vendor_elems.data && iftd->vendor_elems.len) skb_put_data(skb, iftd->vendor_elems.data, iftd->vendor_elems.len); + if (link) + link->u.mgd.conn_flags = assoc_data->link[link_id].conn_flags; + return offset; } +static void ieee80211_add_non_inheritance_elem(struct sk_buff *skb, + const u16 *outer, + const u16 *inner) +{ + unsigned int skb_len = skb->len; + bool added = false; + int i, j; + u8 *len, *list_len = NULL; + + skb_put_u8(skb, WLAN_EID_EXTENSION); + len = skb_put(skb, 1); + skb_put_u8(skb, WLAN_EID_EXT_NON_INHERITANCE); + + for (i = 0; i < PRESENT_ELEMS_MAX && outer[i]; i++) { + u16 elem = outer[i]; + bool have_inner = false; + bool at_extension = false; + + /* should at least be sorted in the sense of normal -> ext */ + WARN_ON(at_extension && elem < PRESENT_ELEM_EXT_OFFS); + + /* switch to extension list */ + if (!at_extension && elem >= PRESENT_ELEM_EXT_OFFS) { + at_extension = true; + if (!list_len) + skb_put_u8(skb, 0); + list_len = NULL; + } + + for (j = 0; j < PRESENT_ELEMS_MAX && inner[j]; j++) { + if (elem == inner[j]) { + have_inner = true; + break; + } + } + + if (have_inner) + continue; + + if (!list_len) { + list_len = skb_put(skb, 1); + *list_len = 0; + } + *list_len += 1; + skb_put_u8(skb, (u8)elem); + } + + if (!added) + skb_trim(skb, skb_len); + else + *len = skb->len - skb_len - 2; +} + +static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, u16 capab, + const struct element *ext_capa, + const u16 *outer_present_elems) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + struct ieee80211_multi_link_elem *ml_elem; + struct ieee80211_mle_basic_common_info *common; + const struct wiphy_iftype_ext_capab *ift_ext_capa; + __le16 eml_capa = 0, mld_capa_ops = 0; + unsigned int link_id; + u8 *ml_elem_len; + void *capab_pos; + + if (!sdata->vif.valid_links) + return; + + ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, + ieee80211_vif_type_p2p(&sdata->vif)); + if (ift_ext_capa) { + eml_capa = cpu_to_le16(ift_ext_capa->eml_capabilities); + mld_capa_ops = cpu_to_le16(ift_ext_capa->mld_capa_and_ops); + } + + skb_put_u8(skb, WLAN_EID_EXTENSION); + ml_elem_len = skb_put(skb, 1); + skb_put_u8(skb, WLAN_EID_EXT_EHT_MULTI_LINK); + ml_elem = skb_put(skb, sizeof(*ml_elem)); + ml_elem->control = + cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC | + IEEE80211_MLC_BASIC_PRES_EML_CAPA | + IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP); + common = skb_put(skb, sizeof(*common)); + common->len = sizeof(*common) + + 2 + /* EML capabilities */ + 2; /* MLD capa/ops */ + memcpy(common->mld_mac_addr, sdata->vif.addr, ETH_ALEN); + skb_put_data(skb, &eml_capa, sizeof(eml_capa)); + /* need indication from userspace to support this */ + mld_capa_ops &= ~cpu_to_le16(IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP); + skb_put_data(skb, &mld_capa_ops, sizeof(mld_capa_ops)); + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + u16 link_present_elems[PRESENT_ELEMS_MAX] = {}; + const u8 *extra_elems; + size_t extra_elems_len; + size_t extra_used; + u8 *subelem_len = NULL; + __le16 ctrl; + + if (!assoc_data->link[link_id].bss || + link_id == assoc_data->assoc_link_id) + continue; + + extra_elems = assoc_data->link[link_id].elems; + extra_elems_len = assoc_data->link[link_id].elems_len; + + skb_put_u8(skb, IEEE80211_MLE_SUBELEM_PER_STA_PROFILE); + subelem_len = skb_put(skb, 1); + + ctrl = cpu_to_le16(link_id | + IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE | + IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT); + skb_put_data(skb, &ctrl, sizeof(ctrl)); + skb_put_u8(skb, 1 + ETH_ALEN); /* STA Info Length */ + skb_put_data(skb, assoc_data->link[link_id].addr, + ETH_ALEN); + /* + * Now add the contents of the (re)association request, + * but the "listen interval" and "current AP address" + * (if applicable) are skipped. So we only have + * the capability field (remember the position and fill + * later), followed by the elements added below by + * calling ieee80211_assoc_link_elems(). + */ + capab_pos = skb_put(skb, 2); + + extra_used = ieee80211_assoc_link_elems(sdata, skb, &capab, + ext_capa, + extra_elems, + extra_elems_len, + link_id, NULL, + link_present_elems); + if (extra_elems) + skb_put_data(skb, extra_elems + extra_used, + extra_elems_len - extra_used); + + put_unaligned_le16(capab, capab_pos); + + ieee80211_add_non_inheritance_elem(skb, outer_present_elems, + link_present_elems); + + ieee80211_fragment_element(skb, subelem_len); + } + + ieee80211_fragment_element(skb, ml_elem_len); +} + static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; - struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_link_data *link; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, qos_info, *ie_start; size_t offset, noffset; - u16 capab = WLAN_CAPABILITY_ESS; - struct ieee80211_supported_band *sband; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; + u16 capab = WLAN_CAPABILITY_ESS, link_capab; __le16 listen_int; struct element *ext_capa = NULL; enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif); - const struct ieee80211_sband_iftype_data *iftd; struct ieee80211_prep_tx_info info = {}; + unsigned int link_id, n_links = 0; + u16 present_elems[PRESENT_ELEMS_MAX] = {}; + const u8 *bssid; void *capab_pos; + size_t size; int ret; /* we know it's writable, cast away the const */ @@ -1107,46 +1318,94 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); - rcu_read_lock(); - chanctx_conf = rcu_dereference(link->conf->chanctx_conf); - if (WARN_ON(!chanctx_conf)) { - rcu_read_unlock(); - return -EINVAL; - } - chan = chanctx_conf->def.chan; - rcu_read_unlock(); - sband = local->hw.wiphy->bands[chan->band]; + size = local->hw.extra_tx_headroom + + sizeof(*mgmt) + /* bit too much but doesn't matter */ + 2 + assoc_data->ssid_len + /* SSID */ + assoc_data->ie_len + /* extra IEs */ + (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) + + 9; /* WMM */ - iftd = ieee80211_get_sband_iftype_data(sband, iftype); + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct cfg80211_bss *cbss = assoc_data->link[link_id].bss; + const struct ieee80211_sband_iftype_data *iftd; + struct ieee80211_supported_band *sband; + + if (!cbss) + continue; + + sband = local->hw.wiphy->bands[cbss->channel->band]; + + n_links++; + /* add STA profile elements length */ + size += assoc_data->link[link_id].elems_len; + /* and supported rates length */ + size += 4 + sband->n_bitrates; + /* supported channels */ + size += 2 + 2 * sband->n_channels; + + iftd = ieee80211_get_sband_iftype_data(sband, iftype); + if (iftd) + size += iftd->vendor_elems.len; + + /* power capability */ + size += 4; + + /* HT, VHT, HE, EHT */ + size += 2 + sizeof(struct ieee80211_ht_cap); + size += 2 + sizeof(struct ieee80211_vht_cap); + size += 2 + 1 + sizeof(struct ieee80211_he_cap_elem) + + sizeof(struct ieee80211_he_mcs_nss_supp) + + IEEE80211_HE_PPE_THRES_MAX_LEN; - skb = alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + /* bit too much but doesn't matter */ - 2 + assoc_data->ssid_len + /* SSID */ - 4 + sband->n_bitrates + /* (extended) rates */ - 4 + /* power capability */ - 2 + 2 * sband->n_channels + /* supported channels */ - 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ - 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */ - 2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */ - 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 */ + if (sband->band == NL80211_BAND_6GHZ) + size += 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa); + + size += 2 + 1 + sizeof(struct ieee80211_eht_cap_elem) + 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 */ - (iftd ? iftd->vendor_elems.len : 0), - GFP_KERNEL); + IEEE80211_EHT_PPE_THRES_MAX_LEN; + + /* non-inheritance element */ + size += 2 + 2 + PRESENT_ELEMS_MAX; + + /* should be the same across all BSSes */ + if (cbss->capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + } + + if (sdata->vif.valid_links) { + /* consider the multi-link element with STA profile */ + size += sizeof(struct ieee80211_multi_link_elem); + /* max common info field in basic multi-link element */ + size += sizeof(struct ieee80211_mle_basic_common_info) + + 2 + /* capa & op */ + 2; /* EML capa */ + + /* + * The capability elements were already considered above; + * note this over-estimates a bit because there's no + * STA profile for the assoc link. + */ + size += (n_links - 1) * + (1 + 1 + /* subelement ID/length */ + 2 + /* STA control */ + 1 + ETH_ALEN + 2 /* STA Info field */); + } + + link = sdata_dereference(sdata->link[assoc_data->assoc_link_id], sdata); + if (WARN_ON(!link)) + return -EINVAL; + + if (WARN_ON(!assoc_data->link[assoc_data->assoc_link_id].bss)) + return -EINVAL; + + bssid = assoc_data->link[assoc_data->assoc_link_id].bss->bssid; + + skb = alloc_skb(size, GFP_KERNEL); if (!skb) return -ENOMEM; skb_reserve(skb, local->hw.extra_tx_headroom); - if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (ifmgd->flags & IEEE80211_STA_ENABLE_RRM) capab |= WLAN_CAPABILITY_RADIO_MEASURE; @@ -1157,21 +1416,21 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; mgmt = skb_put_zero(skb, 24); - memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN); + memcpy(mgmt->da, bssid, ETH_ALEN); + memcpy(mgmt->sa, link->conf->addr, ETH_ALEN); + memcpy(mgmt->bssid, bssid, ETH_ALEN); - listen_int = cpu_to_le16(sband->band == NL80211_BAND_S1GHZ ? + listen_int = cpu_to_le16(assoc_data->s1g ? ieee80211_encode_usf(local->hw.conf.listen_interval) : local->hw.conf.listen_interval); - if (!is_zero_ether_addr(assoc_data->prev_bssid)) { + if (!is_zero_ether_addr(assoc_data->prev_ap_addr)) { skb_put(skb, 10); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); capab_pos = &mgmt->u.reassoc_req.capab_info; mgmt->u.reassoc_req.listen_interval = listen_int; - memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid, - ETH_ALEN); + memcpy(mgmt->u.reassoc_req.current_ap, + assoc_data->prev_ap_addr, ETH_ALEN); info.subtype = IEEE80211_STYPE_REASSOC_REQ; } else { skb_put(skb, 4); @@ -1190,12 +1449,14 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) memcpy(pos, assoc_data->ssid, assoc_data->ssid_len); /* add the elements for the assoc (main) link */ - offset = ieee80211_assoc_link_elems(sdata, skb, &capab, + link_capab = capab; + offset = ieee80211_assoc_link_elems(sdata, skb, &link_capab, ext_capa, assoc_data->ie, assoc_data->ie_len, - link); - put_unaligned_le16(capab, capab_pos); + assoc_data->assoc_link_id, link, + present_elems); + put_unaligned_le16(link_capab, capab_pos); /* if present, add any custom non-vendor IEs */ if (assoc_data->ie_len) { @@ -2394,8 +2655,9 @@ static u32 ieee80211_link_set_associated(struct ieee80211_link_data *link, struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_bss_conf *bss_conf = link->conf; struct ieee80211_bss *bss = (void *)cbss->priv; - u32 changed = 0; + u32 changed = BSS_CHANGED_QOS; + /* not really used in MLO */ sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(beacon_loss_count * bss_conf->beacon_int)); @@ -2457,18 +2719,31 @@ static u32 ieee80211_link_set_associated(struct ieee80211_link_data *link, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, - u32 bss_info_changed) + struct ieee80211_mgd_assoc_data *assoc_data, + u64 changed[IEEE80211_MLD_MAX_NUM_LINKS]) { struct ieee80211_local *local = sdata->local; - struct ieee80211_link_data *link = &sdata->deflink; struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; - - bss_info_changed |= BSS_CHANGED_ASSOC; - bss_info_changed |= ieee80211_link_set_associated(link, cbss); + u64 vif_changed = BSS_CHANGED_ASSOC; + unsigned int link_id; sdata->u.mgd.associated = true; - memcpy(sdata->vif.cfg.ap_addr, cbss->bssid, ETH_ALEN); + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct cfg80211_bss *cbss = assoc_data->link[link_id].bss; + struct ieee80211_link_data *link; + + if (!cbss) + continue; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (WARN_ON(!link)) + return; + + changed[link_id] |= ieee80211_link_set_associated(link, cbss); + } + + memcpy(sdata->vif.cfg.ap_addr, assoc_data->ap_addr, ETH_ALEN); /* just to be sure */ ieee80211_stop_poll(sdata); @@ -2479,15 +2754,41 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, /* Enable ARP filtering */ if (vif_cfg->arp_addr_cnt) - bss_info_changed |= BSS_CHANGED_ARP_FILTER; + vif_changed |= BSS_CHANGED_ARP_FILTER; + + if (sdata->vif.valid_links) { + for (link_id = 0; + link_id < IEEE80211_MLD_MAX_NUM_LINKS; + link_id++) { + struct ieee80211_link_data *link; + struct cfg80211_bss *cbss = assoc_data->link[link_id].bss; - ieee80211_bss_info_change_notify(sdata, bss_info_changed); + if (!cbss) + continue; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (WARN_ON(!link)) + return; + + ieee80211_link_info_change_notify(sdata, link, + changed[link_id]); + + ieee80211_recalc_smps(sdata, link); + } + + ieee80211_vif_cfg_change_notify(sdata, vif_changed); + } else { + ieee80211_bss_info_change_notify(sdata, + vif_changed | changed[0]); + } mutex_lock(&local->iflist_mtx); ieee80211_recalc_ps(local); mutex_unlock(&local->iflist_mtx); - ieee80211_recalc_smps(sdata, &sdata->deflink); + /* leave this here to not change ordering in non-MLO cases */ + if (!sdata->vif.valid_links) + ieee80211_recalc_smps(sdata, &sdata->deflink); ieee80211_recalc_ps_vif(sdata); netif_carrier_on(sdata->dev); @@ -2499,7 +2800,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_link_data *link = &sdata->deflink; + unsigned int link_id; u32 changed = 0; struct ieee80211_prep_tx_info info = { .subtype = stype, @@ -2561,9 +2862,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, drv_mgd_prepare_tx(sdata->local, sdata, &info); } - ieee80211_send_deauth_disassoc(sdata, link->u.mgd.bssid, - link->u.mgd.bssid, stype, reason, - tx, frame_buf); + ieee80211_send_deauth_disassoc(sdata, sdata->vif.cfg.ap_addr, + sdata->vif.cfg.ap_addr, stype, + reason, tx, frame_buf); } /* flush out frame - make sure the deauth was actually sent */ @@ -2572,10 +2873,10 @@ 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(link->u.mgd.bssid); - + /* clear AP addr 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 */ @@ -2620,10 +2921,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ARP_FILTER; sdata->vif.bss_conf.qos = false; - changed |= BSS_CHANGED_QOS; + if (!sdata->vif.valid_links) { + changed |= BSS_CHANGED_QOS; + /* The BSSID (not really interesting) and HT changed */ + changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; + } - /* The BSSID (not really interesting) and HT changed */ - changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); /* disassociated - set to defaults now */ @@ -2644,7 +2947,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags = 0; sdata->deflink.u.mgd.conn_flags = 0; mutex_lock(&local->mtx); - ieee80211_link_release_channel(link); + + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + continue; + ieee80211_link_release_channel(link); + } sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; @@ -2664,6 +2975,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.tx_pwr_env_num = 0; memset(sdata->vif.bss_conf.tx_pwr_env, 0, sizeof(sdata->vif.bss_conf.tx_pwr_env)); + + ieee80211_vif_set_links(sdata, 0); } static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) @@ -2909,8 +3222,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, cbss = sdata->deflink.u.mgd.bss; else if (ifmgd->auth_data) cbss = ifmgd->auth_data->bss; - else if (ifmgd->assoc_data) - cbss = ifmgd->assoc_data->bss; + else if (ifmgd->assoc_data && ifmgd->assoc_data->link[0].bss) + cbss = ifmgd->assoc_data->link[0].bss; else return NULL; @@ -2964,14 +3277,30 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) return; } - tx = !sdata->deflink.csa_block_tx; + /* in MLO assume we have a link where we can TX the frame */ + tx = sdata->vif.valid_links || !sdata->deflink.csa_block_tx; if (!ifmgd->driver_disconnect) { + unsigned int link_id; + /* * AP is probably out of range (or not reachable for another - * reason) so remove the bss struct for that AP. + * reason) so remove the bss structs for that AP. In the case + * of multi-link, it's not clear that all of them really are + * out of range, but if they weren't the driver likely would + * have switched to just have a single link active? */ - cfg80211_unlink_bss(local->hw.wiphy, sdata->deflink.u.mgd.bss); + for (link_id = 0; + link_id < ARRAY_SIZE(sdata->link); + link_id++) { + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + continue; + cfg80211_unlink_bss(local->hw.wiphy, link->u.mgd.bss); + link->u.mgd.bss = NULL; + } } ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, @@ -3086,9 +3415,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, * which is not relevant anymore. */ del_timer_sync(&sdata->u.mgd.timer); - sta_info_destroy_addr(sdata, auth_data->bss->bssid); + sta_info_destroy_addr(sdata, auth_data->ap_addr); - /* FIXME: other links are destroyed? */ + /* 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, @@ -3097,6 +3426,8 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, mutex_lock(&sdata->local->mtx); ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); + + ieee80211_vif_set_links(sdata, 0); } cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); @@ -3125,7 +3456,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, * which is not relevant anymore. */ del_timer_sync(&sdata->u.mgd.timer); - sta_info_destroy_addr(sdata, assoc_data->bss->bssid); + sta_info_destroy_addr(sdata, assoc_data->ap_addr); sdata->deflink.u.mgd.conn_flags = 0; eth_zero_addr(sdata->deflink.u.mgd.bssid); @@ -3140,12 +3471,23 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, if (status != ASSOC_REJECTED) { struct cfg80211_assoc_failure data = { - .bss[0] = assoc_data->bss, .timeout = status == ASSOC_TIMEOUT, }; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(data.bss) != + ARRAY_SIZE(assoc_data->link)); + + for (i = 0; i < ARRAY_SIZE(data.bss); i++) + data.bss[i] = assoc_data->link[i].bss; + + if (sdata->vif.valid_links) + data.ap_mld_addr = assoc_data->ap_addr; cfg80211_assoc_failure(sdata->dev, &data); } + + ieee80211_vif_set_links(sdata, 0); } kfree(assoc_data); @@ -3177,7 +3519,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, (void *)challenge, challenge->datalen + sizeof(*challenge), - auth_data->bss->bssid, auth_data->bss->bssid, + auth_data->ap_addr, auth_data->ap_addr, auth_data->key, auth_data->key_len, auth_data->key_idx, tx_flags); } @@ -3185,7 +3527,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - const u8 *ap_addr = ifmgd->auth_data->bss->bssid; + const u8 *ap_addr = ifmgd->auth_data->ap_addr; struct sta_info *sta; bool result = true; @@ -3218,7 +3560,6 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u8 bssid[ETH_ALEN]; u16 auth_alg, auth_transaction, status_code; struct ieee80211_event event = { .type = MLME_EVENT, @@ -3236,9 +3577,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, if (!ifmgd->auth_data || ifmgd->auth_data->done) return; - memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); - - if (!ether_addr_equal(bssid, mgmt->bssid)) + if (!ether_addr_equal(ifmgd->auth_data->ap_addr, mgmt->bssid)) return; auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); @@ -3399,11 +3738,9 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, } if (ifmgd->associated && - ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) { - const u8 *bssid = sdata->deflink.u.mgd.bssid; - + ether_addr_equal(mgmt->bssid, sdata->vif.cfg.ap_addr)) { sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n", - bssid, reason_code, + sdata->vif.cfg.ap_addr, reason_code, ieee80211_get_reason_code_string(reason_code)); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -3414,12 +3751,10 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, } if (ifmgd->assoc_data && - ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { - const u8 *bssid = ifmgd->assoc_data->bss->bssid; - + ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->ap_addr)) { sdata_info(sdata, "deauthenticated from %pM while associating (Reason: %u=%s)\n", - bssid, reason_code, + ifmgd->assoc_data->ap_addr, reason_code, ieee80211_get_reason_code_string(reason_code)); ieee80211_destroy_assoc_data(sdata, ASSOC_ABANDON); @@ -3442,7 +3777,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, return; if (!ifmgd->associated || - !ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) + !ether_addr_equal(mgmt->bssid, sdata->vif.cfg.ap_addr)) return; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); @@ -3453,7 +3788,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, } sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n", - mgmt->sa, reason_code, + sdata->vif.cfg.ap_addr, reason_code, ieee80211_get_reason_code_string(reason_code)); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -3572,6 +3907,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, .start = elem_start, .len = elem_len, .bss = cbss, + .link_id = link == &sdata->deflink ? -1 : link->link_id, }; bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ; @@ -3585,6 +3921,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, if (!elems) return false; + /* FIXME: use from STA profile element after parsing that */ capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); if (!is_s1g && !elems->supp_rates) { @@ -4454,15 +4791,16 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, } static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, struct ieee80211_mgmt *mgmt, struct ieee802_11_elems *elems, const u8 *elem_start, unsigned int elem_len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; struct ieee80211_local *local = sdata->local; + unsigned int link_id; struct sta_info *sta; - u64 changed = 0; + u64 changed[IEEE80211_MLD_MAX_NUM_LINKS] = {}; int err; mutex_lock(&sdata->local->sta_mtx); @@ -4470,14 +4808,75 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, * station info was already allocated and inserted before * the association and should be available to us */ - sta = sta_info_get(sdata, cbss->bssid); + sta = sta_info_get(sdata, assoc_data->ap_addr); if (WARN_ON(!sta)) goto out_err; - if (!ieee80211_assoc_config_link(&sdata->deflink, &sta->deflink, - cbss, mgmt, elem_start, elem_len, - &changed)) - goto out_err; + if (sdata->vif.valid_links) { + u16 valid_links = 0; + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + if (!assoc_data->link[link_id].bss) + continue; + valid_links |= BIT(link_id); + + if (link_id != assoc_data->assoc_link_id) { + err = ieee80211_sta_allocate_link(sta, link_id); + if (err) + goto out_err; + } + } + + ieee80211_vif_set_links(sdata, valid_links); + } + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct ieee80211_link_data *link; + struct link_sta_info *link_sta; + + if (!assoc_data->link[link_id].bss) + continue; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (WARN_ON(!link)) + goto out_err; + + if (sdata->vif.valid_links) + link_info(link, + "local address %pM, AP link address %pM\n", + link->conf->addr, + assoc_data->link[link_id].bss->bssid); + + link_sta = rcu_dereference_protected(sta->link[link_id], + lockdep_is_held(&local->sta_mtx)); + if (WARN_ON(!link_sta)) + goto out_err; + + if (link_id != assoc_data->assoc_link_id) { + err = ieee80211_prep_channel(sdata, link, + assoc_data->link[link_id].bss, + &link->u.mgd.conn_flags); + if (err) + goto out_err; + } + + err = ieee80211_mgd_setup_link_sta(link, sta, link_sta->pub, + assoc_data->link[link_id].bss); + if (err) + goto out_err; + + if (!ieee80211_assoc_config_link(link, link_sta, + assoc_data->link[link_id].bss, + mgmt, elem_start, elem_len, + &changed[link_id])) + goto out_err; + + if (link_id != assoc_data->assoc_link_id) { + err = ieee80211_sta_activate_link(sta, link_id); + if (err) + goto out_err; + } + } rate_control_rate_init(sta); @@ -4510,7 +4909,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, mutex_unlock(&sdata->local->sta_mtx); - ieee80211_set_associated(sdata, cbss, changed); + ieee80211_set_associated(sdata, assoc_data, changed); /* * If we're using 4-addr mode, let the AP know that we're @@ -4544,7 +4943,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, const u8 *elem_start; unsigned int elem_len; bool reassoc; - struct cfg80211_bss *cbss; struct ieee80211_event event = { .type = MLME_EVENT, .u.mlme.data = ASSOC_EVENT, @@ -4553,17 +4951,17 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct cfg80211_rx_assoc_resp resp = { .uapsd_queues = -1, }; + unsigned int link_id; sdata_assert_lock(sdata); if (!assoc_data) return; - if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid)) + if (!ether_addr_equal(assoc_data->ap_addr, mgmt->bssid) || + !ether_addr_equal(assoc_data->ap_addr, mgmt->sa)) return; - cbss = assoc_data->bss; - /* * AssocResp and ReassocResp have identical structure, so process both * of them in this function. @@ -4575,7 +4973,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control); capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - if (cbss->channel->band == NL80211_BAND_S1GHZ) + if (assoc_data->s1g) elem_start = mgmt->u.s1g_assoc_resp.variable; else elem_start = mgmt->u.assoc_resp.variable; @@ -4600,7 +4998,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems->aid_resp) aid = le16_to_cpu(elems->aid_resp->aid); - else if (cbss->channel->band == NL80211_BAND_S1GHZ) + else if (assoc_data->s1g) aid = 0; /* TODO */ else aid = le16_to_cpu(mgmt->u.assoc_resp.aid); @@ -4613,7 +5011,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", - reassoc ? "Rea" : "A", mgmt->sa, + reassoc ? "Rea" : "A", assoc_data->ap_addr, capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); ifmgd->broken_ap = false; @@ -4623,14 +5021,14 @@ 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->bssid, + cfg80211_assoc_comeback(sdata->dev, assoc_data->ap_addr, le32_to_cpu(elems->timeout_int->value)); tu = le32_to_cpu(elems->timeout_int->value); ms = tu * 1024 / 1000; sdata_info(sdata, "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", - mgmt->sa, tu, ms); + assoc_data->ap_addr, tu, ms); assoc_data->timeout = jiffies + msecs_to_jiffies(ms); assoc_data->timeout_started = true; if (ms > IEEE80211_ASSOC_TIMEOUT) @@ -4640,8 +5038,7 @@ 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, ASSOC_REJECTED); + assoc_data->ap_addr, status_code); event.u.mlme.status = MLME_DENIED; event.u.mlme.reason = status_code; drv_event_callback(sdata->local, sdata, &event); @@ -4654,9 +5051,40 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ifmgd->broken_ap = true; } + if (sdata->vif.valid_links) { + if (!elems->multi_link) { + sdata_info(sdata, + "MLO association with %pM but no multi-link element in response!\n", + assoc_data->ap_addr); + goto abandon_assoc; + } + + if (le16_get_bits(elems->multi_link->control, + IEEE80211_ML_CONTROL_TYPE) != + IEEE80211_ML_CONTROL_TYPE_BASIC) { + sdata_info(sdata, + "bad multi-link element (control=0x%x)\n", + le16_to_cpu(elems->multi_link->control)); + goto abandon_assoc; + } else { + struct ieee80211_mle_basic_common_info *common; + + common = (void *)elems->multi_link->variable; + + if (memcmp(assoc_data->ap_addr, + common->mld_mac_addr, ETH_ALEN)) { + sdata_info(sdata, + "AP MLD MAC address mismatch: got %pM expected %pM\n", + common->mld_mac_addr, + assoc_data->ap_addr); + goto abandon_assoc; + } + } + } + sdata->vif.cfg.aid = aid; - if (!ieee80211_assoc_success(sdata, cbss, mgmt, elems, + if (!ieee80211_assoc_success(sdata, mgmt, elems, elem_start, elem_len)) { /* oops -- internal error -- send timeout for now */ ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); @@ -4666,31 +5094,46 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, drv_event_callback(sdata->local, sdata, &event); sdata_info(sdata, "associated\n"); - /* - * destroy assoc_data afterwards, as otherwise an idle - * recalc after assoc_data is NULL but before associated - * is set can cause the interface to go idle - */ - ieee80211_destroy_assoc_data(sdata, ASSOC_SUCCESS); + info.success = 1; + } + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + continue; + if (!assoc_data->link[link_id].bss) + continue; + resp.links[link_id].bss = assoc_data->link[link_id].bss; + resp.links[link_id].addr = link->conf->addr; - /* get uapsd queues configuration */ + /* get uapsd queues configuration - same for all links */ resp.uapsd_queues = 0; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (sdata->deflink.tx_conf[ac].uapsd) + if (link->tx_conf[ac].uapsd) resp.uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; - - info.success = 1; } - resp.links[0].bss = cbss; + ieee80211_destroy_assoc_data(sdata, + status_code == WLAN_STATUS_SUCCESS ? + ASSOC_SUCCESS : + ASSOC_REJECTED); + resp.buf = (u8 *)mgmt; resp.len = len; resp.req_ies = ifmgd->assoc_req_ies; resp.req_ies_len = ifmgd->assoc_req_ies_len; + if (sdata->vif.valid_links) + resp.ap_mld_addr = assoc_data->ap_addr; cfg80211_rx_assoc_resp(sdata->dev, &resp); notify_driver: drv_mgd_complete_tx(sdata->local, sdata, &info); kfree(elems); + return; +abandon_assoc: + ieee80211_destroy_assoc_data(sdata, ASSOC_ABANDON); + goto notify_driver; } static void ieee80211_rx_bss_info(struct ieee80211_link_data *link, @@ -4948,9 +5391,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, rcu_read_unlock(); if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && - ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { + !WARN_ON(sdata->vif.valid_links) && + ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->link[0].bss)) { elems = ieee802_11_parse_elems(variable, len - baselen, false, - ifmgd->assoc_data->bss); + ifmgd->assoc_data->link[0].bss); if (!elems) return; @@ -5348,7 +5792,7 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { sdata_info(sdata, "authentication with %pM timed out\n", - auth_data->bss->bssid); + auth_data->ap_addr); /* * Most likely AP is not in the range so remove the @@ -5365,7 +5809,7 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) drv_mgd_prepare_tx(local, sdata, &info); sdata_info(sdata, "send auth to %pM (try %d/%d)\n", - auth_data->bss->bssid, auth_data->tries, + auth_data->ap_addr, auth_data->tries, IEEE80211_AUTH_MAX_TRIES); auth_data->expected_transaction = 2; @@ -5382,9 +5826,8 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, auth_data->data, auth_data->data_len, - auth_data->bss->bssid, - auth_data->bss->bssid, NULL, 0, 0, - tx_flags); + auth_data->ap_addr, auth_data->ap_addr, + NULL, 0, 0, tx_flags); if (tx_flags == 0) { if (auth_data->algorithm == WLAN_AUTH_SAE) @@ -5414,19 +5857,20 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) assoc_data->tries++; if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { sdata_info(sdata, "association with %pM timed out\n", - assoc_data->bss->bssid); + assoc_data->ap_addr); /* * Most likely AP is not in the range so remove the * bss struct for that AP. */ - cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss); + cfg80211_unlink_bss(local->hw.wiphy, + assoc_data->link[assoc_data->assoc_link_id].bss); return -ETIMEDOUT; } sdata_info(sdata, "associate with %pM (try %d/%d)\n", - assoc_data->bss->bssid, assoc_data->tries, + assoc_data->ap_addr, assoc_data->tries, IEEE80211_ASSOC_MAX_TRIES); ret = ieee80211_send_assoc(sdata); if (ret) @@ -5510,18 +5954,18 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) */ ieee80211_destroy_auth_data(sdata, false); } else if (ieee80211_auth(sdata)) { - u8 bssid[ETH_ALEN]; + u8 ap_addr[ETH_ALEN]; struct ieee80211_event event = { .type = MLME_EVENT, .u.mlme.data = AUTH_EVENT, .u.mlme.status = MLME_TIMEOUT, }; - memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); + memcpy(ap_addr, ifmgd->auth_data->ap_addr, ETH_ALEN); ieee80211_destroy_auth_data(sdata, false); - cfg80211_auth_timeout(sdata->dev, bssid); + cfg80211_auth_timeout(sdata->dev, ap_addr); drv_event_callback(sdata->local, sdata, &event); } } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) @@ -5689,16 +6133,16 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) sdata_lock(sdata); if (ifmgd->auth_data || ifmgd->assoc_data) { - const u8 *bssid = ifmgd->auth_data ? - ifmgd->auth_data->bss->bssid : - ifmgd->assoc_data->bss->bssid; + const u8 *ap_addr = ifmgd->auth_data ? + ifmgd->auth_data->ap_addr : + ifmgd->assoc_data->ap_addr; /* * If we are trying to authenticate / associate while suspending, * cfg80211 won't know and won't actually abort those attempts, * thus we need to do that ourselves. */ - ieee80211_send_deauth_disassoc(sdata, bssid, bssid, + ieee80211_send_deauth_disassoc(sdata, ap_addr, ap_addr, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DEAUTH_LEAVING, false, frame_buf); @@ -5818,7 +6262,9 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) { - struct ieee80211_local *local = link->sdata->local; + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_local *local = sdata->local; + unsigned int link_id = link->link_id; link->u.mgd.p2p_noa_index = -1; link->u.mgd.conn_flags = 0; @@ -5833,6 +6279,10 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) INIT_WORK(&link->u.mgd.chswitch_work, ieee80211_chswitch_work); timer_setup(&link->u.mgd.chswitch_timer, ieee80211_chswitch_timer, 0); + + if (sdata->u.mgd.assoc_data) + ether_addr_copy(link->conf->addr, + sdata->u.mgd.assoc_data->link[link_id].addr); } /* scan finished notification */ @@ -5884,34 +6334,74 @@ static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies, } static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, bool assoc, + struct cfg80211_bss *cbss, s8 link_id, + const u8 *ap_mld_addr, bool assoc, bool override) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)cbss->priv; struct sta_info *new_sta = NULL; - struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_link_data *link; bool have_sta = false; + bool mlo; int err; - if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) - return -EINVAL; + if (link_id >= 0) { + mlo = true; + if (WARN_ON(!ap_mld_addr)) + return -EINVAL; + err = ieee80211_vif_set_links(sdata, BIT(link_id)); + } else { + if (WARN_ON(ap_mld_addr)) + return -EINVAL; + ap_mld_addr = cbss->bssid; + err = ieee80211_vif_set_links(sdata, 0); + link_id = 0; + mlo = false; + } + + if (err) + return err; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (WARN_ON(!link)) { + err = -ENOLINK; + goto out_err; + } + + if (mlo && !is_valid_ether_addr(link->conf->addr)) + eth_random_addr(link->conf->addr); + + if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) { + err = -EINVAL; + goto out_err; + } /* If a reconfig is happening, bail out */ - if (local->in_reconfig) - return -EBUSY; + if (local->in_reconfig) { + err = -EBUSY; + goto out_err; + } if (assoc) { rcu_read_lock(); - have_sta = sta_info_get(sdata, cbss->bssid); + have_sta = sta_info_get(sdata, ap_mld_addr); rcu_read_unlock(); } if (!have_sta) { - new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); - if (!new_sta) - return -ENOMEM; + if (link_id >= 0) + new_sta = sta_info_alloc_with_link(sdata, ap_mld_addr, + link_id, cbss->bssid, + GFP_KERNEL); + else + new_sta = sta_info_alloc(sdata, ap_mld_addr, GFP_KERNEL); + + if (!new_sta) { + err = -ENOMEM; + goto out_err; + } } /* @@ -5929,20 +6419,29 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, */ if (new_sta) { const struct cfg80211_bss_ies *ies; - struct ieee80211_link_sta *link_sta = &new_sta->sta.deflink; + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + link_sta = rcu_dereference(new_sta->sta.link[link_id]); + if (WARN_ON(!link_sta)) { + rcu_read_unlock(); + sta_info_free(local, new_sta); + err = -EINVAL; + goto out_err; + } err = ieee80211_mgd_setup_link_sta(link, new_sta, link_sta, cbss); if (err) { + rcu_read_unlock(); sta_info_free(local, new_sta); - return err; + goto out_err; } memcpy(link->u.mgd.bssid, cbss->bssid, ETH_ALEN); /* set timing information */ link->conf->beacon_int = cbss->beacon_interval; - rcu_read_lock(); ies = rcu_dereference(cbss->beacon_ies); if (ies) { link->conf->sync_tsf = ies->tsf; @@ -5974,7 +6473,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (err) { if (new_sta) sta_info_free(local, new_sta); - return -EINVAL; + goto out_err; } } @@ -5997,7 +6496,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "failed to insert STA entry for the AP (error %d)\n", err); - return err; + goto out_err; } } else WARN_ON_ONCE(!ether_addr_equal(link->u.mgd.bssid, cbss->bssid)); @@ -6007,13 +6506,16 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, ieee80211_scan_cancel(local); return 0; + +out_err: + ieee80211_vif_set_links(sdata, 0); + return err; } /* config hooks */ 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; @@ -6062,6 +6564,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (!auth_data) return -ENOMEM; + memcpy(auth_data->ap_addr, + req->ap_mld_addr ?: req->bss->bssid, + ETH_ALEN); auth_data->bss = req->bss; if (req->auth_data_len >= 4) { @@ -6124,7 +6629,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->vif.cfg.ap_addr, req->bss->bssid); + sdata->vif.cfg.ap_addr, auth_data->ap_addr); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_UNSPECIFIED, false, frame_buf); @@ -6135,15 +6640,16 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, false); } - sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); + sdata_info(sdata, "authenticate with %pM\n", auth_data->ap_addr); - err = ieee80211_prep_connection(sdata, req->bss, cont_auth, false); + err = ieee80211_prep_connection(sdata, req->bss, req->link_id, + req->ap_mld_addr, cont_auth, false); if (err) goto err_clear; err = ieee80211_auth(sdata); if (err) { - sta_info_destroy_addr(sdata, req->bss->bssid); + sta_info_destroy_addr(sdata, auth_data->ap_addr); goto err_clear; } @@ -6152,13 +6658,15 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return 0; err_clear: - eth_zero_addr(link->u.mgd.bssid); - ieee80211_link_info_change_notify(sdata, &sdata->deflink, - BSS_CHANGED_BSSID); + if (!sdata->vif.valid_links) { + eth_zero_addr(sdata->deflink.u.mgd.bssid); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BSSID); + mutex_lock(&sdata->local->mtx); + ieee80211_link_release_channel(&sdata->deflink); + mutex_unlock(&sdata->local->mtx); + } ifmgd->auth_data = NULL; - mutex_lock(&sdata->local->mtx); - ieee80211_link_release_channel(&sdata->deflink); - mutex_unlock(&sdata->local->mtx); kfree(auth_data); return err; } @@ -6167,37 +6675,60 @@ static ieee80211_conn_flags_t ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data, struct cfg80211_assoc_request *req, - ieee80211_conn_flags_t conn_flags) + ieee80211_conn_flags_t conn_flags, + unsigned int link_id) { struct ieee80211_local *local = sdata->local; const struct cfg80211_bss_ies *beacon_ies; struct ieee80211_supported_band *sband; const struct element *ht_elem, *vht_elem; - struct ieee80211_link_data *link = &sdata->deflink; - struct cfg80211_bss *cbss = req->bss; - struct ieee80211_bss *bss = (void *)cbss->priv; + struct ieee80211_link_data *link; + struct cfg80211_bss *cbss; + struct ieee80211_bss *bss; bool is_5ghz, is_6ghz; + cbss = assoc_data->link[link_id].bss; + if (WARN_ON(!cbss)) + return 0; + + bss = (void *)cbss->priv; + sband = local->hw.wiphy->bands[cbss->channel->band]; if (WARN_ON(!sband)) - return false; + return 0; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (WARN_ON(!link)) + return 0; is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; - assoc_data->supp_rates = bss->supp_rates; - assoc_data->supp_rates_len = bss->supp_rates_len; + /* for MLO connections assume advertising all rates is OK */ + if (!req->ap_mld_addr) { + assoc_data->supp_rates = bss->supp_rates; + assoc_data->supp_rates_len = bss->supp_rates_len; + } + + /* copy and link elems for the STA profile */ + if (req->links[link_id].elems_len) { + memcpy(assoc_data->ie_pos, req->links[link_id].elems, + req->links[link_id].elems_len); + assoc_data->link[link_id].elems = assoc_data->ie_pos; + assoc_data->link[link_id].elems_len = req->links[link_id].elems_len; + assoc_data->ie_pos += req->links[link_id].elems_len; + } rcu_read_lock(); ht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_OPERATION); if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation)) - assoc_data->ap_ht_param = + assoc_data->link[link_id].ap_ht_param = ((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param; else if (!is_6ghz) conn_flags |= IEEE80211_CONN_DISABLE_HT; vht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) { - memcpy(&assoc_data->ap_vht_cap, vht_elem->data, + memcpy(&assoc_data->link[link_id].ap_vht_cap, vht_elem->data, sizeof(struct ieee80211_vht_cap)); } else if (is_5ghz) { link_info(link, @@ -6284,23 +6815,48 @@ ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { + unsigned int assoc_link_id = req->link_id < 0 ? 0 : req->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; - struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; const struct element *ssid_elem; - struct ieee80211_link_data *link = &sdata->deflink; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; ieee80211_conn_flags_t conn_flags = 0; - int i, err; + struct ieee80211_link_data *link; + struct cfg80211_bss *cbss; + struct ieee80211_bss *bss; bool override; + int i, err; + size_t size = sizeof(*assoc_data) + req->ie_len; + + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) + size += req->links[i].elems_len; + + if (req->ap_mld_addr) { + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { + if (!req->links[i].bss) + continue; + if (i == assoc_link_id) + continue; + /* + * For now, support only a single link in MLO, we + * don't have the necessary parsing of the multi- + * link element in the association response, etc. + */ + sdata_info(sdata, + "refusing MLO association with >1 links\n"); + return -EINVAL; + } + } - assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); + assoc_data = kzalloc(size, GFP_KERNEL); if (!assoc_data) return -ENOMEM; + cbss = req->link_id < 0 ? req->bss : req->links[req->link_id].bss; + rcu_read_lock(); - ssid_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_SSID); + ssid_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_SSID); if (!ssid_elem || ssid_elem->datalen > sizeof(assoc_data->ssid)) { rcu_read_unlock(); kfree(assoc_data); @@ -6312,12 +6868,33 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, vif_cfg->ssid_len = assoc_data->ssid_len; rcu_read_unlock(); + if (req->ap_mld_addr) { + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { + if (!req->links[i].bss) + continue; + link = sdata_dereference(sdata->link[i], sdata); + if (link) + ether_addr_copy(assoc_data->link[i].addr, + link->conf->addr); + else + eth_random_addr(assoc_data->link[i].addr); + } + } else { + memcpy(assoc_data->link[0].addr, sdata->vif.addr, ETH_ALEN); + } + + assoc_data->s1g = cbss->channel->band == NL80211_BAND_S1GHZ; + + memcpy(assoc_data->ap_addr, + req->ap_mld_addr ?: req->bss->bssid, + ETH_ALEN); + if (ifmgd->associated) { u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; sdata_info(sdata, "disconnect from AP %pM for new assoc to %pM\n", - sdata->vif.cfg.ap_addr, req->bss->bssid); + sdata->vif.cfg.ap_addr, assoc_data->ap_addr); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_UNSPECIFIED, false, frame_buf); @@ -6342,13 +6919,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, bool match; /* keep sta info, bssid if matching */ - match = ether_addr_equal(sdata->deflink.u.mgd.bssid, - req->bss->bssid); + match = ether_addr_equal(ifmgd->auth_data->ap_addr, + assoc_data->ap_addr); ieee80211_destroy_auth_data(sdata, match); } /* prepare assoc data */ + bss = (void *)cbss->priv; assoc_data->wmm = bss->wmm_used && (local->hw.queues >= IEEE80211_NUM_ACS); @@ -6401,6 +6979,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, conn_flags |= IEEE80211_CONN_DISABLE_EHT; } + if (req->flags & ASSOC_REQ_DISABLE_EHT) + conn_flags |= IEEE80211_CONN_DISABLE_EHT; + memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, sizeof(ifmgd->ht_capa_mask)); @@ -6416,6 +6997,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (req->ie && req->ie_len) { memcpy(assoc_data->ie, req->ie, req->ie_len); assoc_data->ie_len = req->ie_len; + assoc_data->ie_pos = assoc_data->ie + assoc_data->ie_len; + } else { + assoc_data->ie_pos = assoc_data->ie; } if (req->fils_kek) { @@ -6433,15 +7017,35 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, memcpy(assoc_data->fils_nonces, req->fils_nonces, 2 * FILS_NONCE_LEN); - assoc_data->bss = req->bss; - assoc_data->capability = req->bss->capability; - /* default timeout */ assoc_data->timeout = jiffies; assoc_data->timeout_started = true; + assoc_data->assoc_link_id = assoc_link_id; + + if (req->ap_mld_addr) { + for (i = 0; i < ARRAY_SIZE(assoc_data->link); i++) { + assoc_data->link[i].conn_flags = conn_flags; + assoc_data->link[i].bss = req->links[i].bss; + } + + /* if there was no authentication, set up the link */ + err = ieee80211_vif_set_links(sdata, BIT(assoc_link_id)); + if (err) + goto err_clear; + } else { + assoc_data->link[0].conn_flags = conn_flags; + assoc_data->link[0].bss = cbss; + } + + link = sdata_dereference(sdata->link[assoc_link_id], sdata); + if (WARN_ON(!link)) { + err = -EINVAL; + goto err_clear; + } + conn_flags |= ieee80211_setup_assoc_link(sdata, assoc_data, req, - conn_flags); + conn_flags, assoc_link_id); override = link->u.mgd.conn_flags != conn_flags; link->u.mgd.conn_flags |= conn_flags; @@ -6460,7 +7064,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } if (req->prev_bssid) - memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); + memcpy(assoc_data->prev_ap_addr, req->prev_bssid, ETH_ALEN); if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; @@ -6489,21 +7093,25 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, /* kick off associate process */ ifmgd->assoc_data = assoc_data; - if (req->flags & ASSOC_REQ_DISABLE_EHT) - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + for (i = 0; i < ARRAY_SIZE(assoc_data->link); i++) { + if (!assoc_data->link[i].bss) + continue; + if (i == assoc_data->assoc_link_id) + continue; + /* only calculate the flags, hence link == NULL */ + err = ieee80211_prep_channel(sdata, NULL, assoc_data->link[i].bss, + &assoc_data->link[i].conn_flags); + if (err) + goto err_clear; + } - err = ieee80211_prep_connection(sdata, req->bss, true, override); + err = ieee80211_prep_connection(sdata, cbss, req->link_id, + req->ap_mld_addr, true, override); if (err) goto err_clear; - if (link->u.mgd.req_smps == IEEE80211_SMPS_AUTOMATIC) { - if (ifmgd->powersave) - link->smps_mode = IEEE80211_SMPS_DYNAMIC; - else - link->smps_mode = IEEE80211_SMPS_OFF; - } else { - link->smps_mode = link->u.mgd.req_smps; - } + assoc_data->link[assoc_data->assoc_link_id].conn_flags = + link->u.mgd.conn_flags; if (ieee80211_hw_check(&sdata->local->hw, NEED_DTIM_BEFORE_ASSOC)) { const struct cfg80211_bss_ies *beacon_ies; @@ -6549,7 +7157,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, }; if (ifmgd->auth_data && - ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) { + ether_addr_equal(ifmgd->auth_data->ap_addr, req->bssid)) { sdata_info(sdata, "aborting authentication with %pM by local choice (Reason: %u=%s)\n", req->bssid, req->reason_code, @@ -6569,7 +7177,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } if (ifmgd->assoc_data && - ether_addr_equal(ifmgd->assoc_data->bss->bssid, req->bssid)) { + ether_addr_equal(ifmgd->assoc_data->ap_addr, req->bssid)) { sdata_info(sdata, "aborting association with %pM by local choice (Reason: %u=%s)\n", req->bssid, req->reason_code, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1d60eab8308a..34dae26646a6 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2478,7 +2478,7 @@ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, } - sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); + sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); if (!sta) return -ENOLINK; break; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 80f11a29cb86..defce1530115 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -50,6 +50,9 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, /* need to have local link addresses for MLO connections */ WARN_ON(cr.ap_mld_addr && !cr.links[link_id].addr); + printk(KERN_CRIT "BSS pointer 0x%lx\n", (unsigned long)cr.links[link_id].bss); + BUG_ON(!cr.links[link_id].bss->channel); + 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; -- cgit v1.2.3 From 8f5d9e68c90dd6b01afdfda6d9926c6ea4931c00 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Jul 2022 15:04:41 +0200 Subject: wifi: mac80211: remove stray printk Unfortunately, a printk snuck into a previous patch, remove it. Fixes: 81151ce462e5 ("wifi: mac80211: support MLO authentication/association with one link") Signed-off-by: Johannes Berg --- net/wireless/mlme.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index defce1530115..003c57504583 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -50,7 +50,6 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, /* need to have local link addresses for MLO connections */ WARN_ON(cr.ap_mld_addr && !cr.links[link_id].addr); - printk(KERN_CRIT "BSS pointer 0x%lx\n", (unsigned long)cr.links[link_id].bss); BUG_ON(!cr.links[link_id].bss->channel); if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) { -- cgit v1.2.3 From bd363ee5330250b93cb1e0e16c1c54682fcbe595 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Jul 2022 15:11:50 +0200 Subject: wifi: mac80211: mlme: set sta.mlo correctly Due to some changes and rebasing between different patches this fell through the cracks; we need to set sta.mlo if the connection is using MLO. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e4e501f2713e..912095e4e256 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6402,6 +6402,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, err = -ENOMEM; goto out_err; } + + new_sta->sta.mlo = link_id >= 0; } /* -- cgit v1.2.3 From fcc36be423a46f6dc2dcaa9f46aa47526f3e7d82 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 15 Jul 2022 13:35:16 +0300 Subject: wifi: ath11k: mac: fix long line Recent mac80211 API changes introduced a long line warning in ath11k: drivers/net/wireless/ath/ath11k/mac.c:1404: line length of 92 exceeds 90 columns Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220708170052.28615-1-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 92e17d3c634e..d83d3c944594 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1401,7 +1401,8 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) if (!vif->bss_conf.color_change_active && !arvif->bcca_zero_sent) return; - if (vif->bss_conf.color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { + if (vif->bss_conf.color_change_active && + ieee80211_beacon_cntdwn_is_complete(vif)) { arvif->bcca_zero_sent = true; ieee80211_color_change_finish(vif); return; -- cgit v1.2.3 From eaedf62f7aaa4e2efd69c0fbd32ee774456ce361 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Fri, 15 Jul 2022 13:35:18 +0300 Subject: wifi: ath5k: fix repeated words in comments Delete the redundant word 'don't' and 'but'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220708154929.19199-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 85c982e0a1cd..c59c14483177 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1982,7 +1982,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) /* * Check if the previous beacon has gone out. If - * not, don't don't try to post another: skip this + * not, don't try to post another: skip this * period and wait for the next. Missed beacons * indicate a problem and should not occur. If we * miss too many consecutive beacons reset the device. diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index acd0e1dafb7f..ed5d2160a72a 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -410,7 +410,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, /* FIF_CONTROL doc says we should only pass on control frames for this * station. This needs testing. I believe right now this * enables *all* control frames, which is OK.. but - * but we should see if we can improve on granularity */ + * we should see if we can improve on granularity */ if (*new_flags & FIF_CONTROL) rfilt |= AR5K_RX_FILTER_CONTROL; -- cgit v1.2.3 From 7a4836560a6198d245d5732e26f94898b12eb760 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 15 Jul 2022 13:35:18 +0300 Subject: wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi() The simple_write_to_buffer() function will succeed if even a single byte is initialized. However, we need to initialize the whole buffer to prevent information leaks. Just use memdup_user(). Fixes: ff974e408334 ("wil6210: debugfs interface to send raw WMI command") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/Ysg14NdKAZF/hcNG@kili --- drivers/net/wireless/ath/wil6210/debugfs.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 64d6c98174c8..fe84362718de 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1012,18 +1012,12 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, u16 cmdid; int rc, rc1; - if (cmdlen < 0) + if (cmdlen < 0 || *ppos != 0) return -EINVAL; - wmi = kmalloc(len, GFP_KERNEL); - if (!wmi) - return -ENOMEM; - - rc = simple_write_to_buffer(wmi, len, ppos, buf, len); - if (rc < 0) { - kfree(wmi); - return rc; - } + wmi = memdup_user(buf, len); + if (IS_ERR(wmi)) + return PTR_ERR(wmi); cmd = (cmdlen > 0) ? &wmi[1] : NULL; cmdid = le16_to_cpu(wmi->command_id); -- cgit v1.2.3 From 6456741f6427265396d3b7a0e83bf9319334b696 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 20:32:08 +0800 Subject: wifi: ath6kl: fix repeated words in comments Delete the redundant words 'the' and 'of'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709123208.41736-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ath/ath6kl/hif.h | 2 +- drivers/net/wireless/ath/ath6kl/sdio.c | 2 +- drivers/net/wireless/ath/ath6kl/wmi.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index f9d3f3a5edfe..ba16b98c872d 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -92,7 +92,7 @@ struct bus_request { * emode - This indicates the whether the command is to be executed in a * blocking or non-blocking fashion (HIF_SYNCHRONOUS/ * HIF_ASYNCHRONOUS). The read/write data paths in HTC have been - * implemented using the asynchronous mode allowing the the bus + * implemented using the asynchronous mode allowing the bus * driver to indicate the completion of operation through the * registered callback routine. The requirement primarily comes * from the contexts these operations get called from (a driver's diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 6b51a2dceadc..8a43c48ec1cf 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1185,7 +1185,7 @@ static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len) * Wait for first 4 bytes to be in FIFO * If CONSERVATIVE_BMI_READ is enabled, also wait for * a BMI command credit, which indicates that the ENTIRE - * response is available in the the FIFO + * response is available in the FIFO * * CASE 3: length > 128 * Wait for the first 4 bytes to be in FIFO diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 0d99f754b7e7..b4fcfb72991c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -698,7 +698,7 @@ enum auth_mode { /* * NB: these values are ordered carefully; there are lots of - * of implications in any reordering. In particular beware + * implications in any reordering. In particular beware * that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY. */ #define ATH6KL_CIPHER_WEP 0 -- cgit v1.2.3 From 88e67a4f0bf88711359ee5498baf0a6e4ea8e414 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 20:40:36 +0800 Subject: wifi: ath: fix repeated words in comments Delete the redundant word 'have'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709124036.49674-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ath/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index b53ebb3ac9a2..85955572a705 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -48,7 +48,7 @@ * the MAC address to obtain the relevant bits and compare the result with * (frame's BSSID & mask) to see if they match. * - * Simple example: on your card you have have two BSSes you have created with + * Simple example: on your card you have two BSSes you have created with * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. * There is another BSSID-03 but you are not part of it. For simplicity's sake, * assuming only 4 bits for a mac address and for BSSIDs you can then have: -- cgit v1.2.3 From aa6f2be484d764b0221e5732da1a088b1f1cdcd5 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:21:37 +0800 Subject: wifi: wil6210: fix repeated words in comments Delete the redundant word 'for'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709132137.12442-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ath/wil6210/txrx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 1f4c8ec75be8..1ae1bec1b97f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -356,7 +356,7 @@ struct vring_rx_mac { * bit 10 : cmd_dma_it:1 immediate interrupt * bit 11..15 : reserved:5 * bit 16..29 : phy_info_length:14 It is valid when the PII is set. - * When the FFM bit is set bits 29-27 are used for for + * When the FFM bit is set bits 29-27 are used for * Flex Filter Match. Matching Index to one of the L2 * EtherType Flex Filter * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field -- cgit v1.2.3 From ec65e0e9acf758585249e43a51abf082ba1af582 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 20:43:56 +0800 Subject: wifi: wcn36xx: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709124356.52543-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ath/wcn36xx/hal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 874746b5993c..a1afe1f85f0e 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -4142,7 +4142,7 @@ struct wcn36xx_hal_dump_cmd_rsp_msg { /* Length of the responce message */ u32 rsp_length; - /* FIXME: Currently considering the the responce will be less than + /* FIXME: Currently considering the responce will be less than * 100bytes */ u8 rsp_buffer[DUMPCMD_RSP_BUFFER]; } __packed; -- cgit v1.2.3 From 83781f0162d080fec7dcb911afd1bc2f5ad04471 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 12 Jun 2022 23:12:20 +0200 Subject: wifi: p54: Fix an error handling path in p54spi_probe() If an error occurs after a successful call to p54spi_request_firmware(), it must be undone by a corresponding release_firmware() as already done in the error handling path of p54spi_request_firmware() and in the .remove() function. Add the missing call in the error handling path and remove it from p54spi_request_firmware() now that it is the responsibility of the caller to release the firmware Fixes: cd8d3d321285 ("p54spi: p54spi driver") Signed-off-by: Christophe JAILLET Acked-by: Christian Lamparter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/297d2547ff2ee627731662abceeab9dbdaf23231.1655068321.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intersil/p54/p54spi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index f99b7ba69fc3..19152fd449ba 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -164,7 +164,7 @@ static int p54spi_request_firmware(struct ieee80211_hw *dev) ret = p54_parse_firmware(dev, priv->firmware); if (ret) { - release_firmware(priv->firmware); + /* the firmware is released by the caller */ return ret; } @@ -659,6 +659,7 @@ static int p54spi_probe(struct spi_device *spi) return 0; err_free_common: + release_firmware(priv->firmware); free_irq(gpio_to_irq(p54spi_gpio_irq), spi); err_free_gpio_irq: gpio_free(p54spi_gpio_irq); -- cgit v1.2.3 From 0c574060060afa6ee18d99020634fe77b5c52c3d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 4 Jul 2022 15:02:55 +0200 Subject: wifi: p54: Use the bitmap API to allocate bitmaps Use bitmap_zalloc()/bitmap_free() instead of hand-writing them. It is less verbose and it improves the semantic. Signed-off-by: Christophe JAILLET Acked-by: Christian Lamparter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/2755b8b7d85a2db0663d39ea6df823f94f3401b3.1656939750.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intersil/p54/fwio.c | 6 ++---- drivers/net/wireless/intersil/p54/main.c | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index bece14e4ff0d..b52cce38115d 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -173,10 +173,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) * keeping a extra list for uploaded keys. */ - priv->used_rxkeys = kcalloc(BITS_TO_LONGS(priv->rx_keycache_size), - sizeof(long), - GFP_KERNEL); - + priv->used_rxkeys = bitmap_zalloc(priv->rx_keycache_size, + GFP_KERNEL); if (!priv->used_rxkeys) return -ENOMEM; } diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index 0f76d43fda33..26b28d4d680f 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -831,7 +831,7 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->output_limit); kfree(priv->curve_data); kfree(priv->rssi_db); - kfree(priv->used_rxkeys); + bitmap_free(priv->used_rxkeys); kfree(priv->survey); priv->iq_autocal = NULL; priv->output_limit = NULL; -- cgit v1.2.3 From 07db88f11e63d78c5062447faf942745ce8959ff Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 8 Jul 2022 17:15:27 -0700 Subject: wifi: mt7601u: eeprom: fix clang -Wformat warning When building with Clang we encounter the following warning: | drivers/net/wireless/mediatek/mt7601u/eeprom.c:193:5: error: format | specifies type 'char' but the argument has type 'int' [-Werror,-Wformat] | chan_bounds[idx].start + chan_bounds[idx].num - 1); Variadic functions (printf-like) undergo default argument promotion. Documentation/core-api/printk-formats.rst specifically recommends using the promoted-to-type's format flag. Moreover, C11 6.3.1.1 states: (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf) `If an int can represent all values of the original type ..., the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.` With this information in hand, we really should stop using `%hh[dxu]` or `%h[dxu]` as they usually prompt Clang -Wformat warnings as well as go against documented standard recommendations. Link: https://github.com/ClangBuiltLinux/linux/issues/378 Signed-off-by: Justin Stitt Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709001527.618593-1-justinstitt@google.com --- drivers/net/wireless/mediatek/mt7601u/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.c b/drivers/net/wireless/mediatek/mt7601u/eeprom.c index aa3b64902cf9..625bebe60538 100644 --- a/drivers/net/wireless/mediatek/mt7601u/eeprom.c +++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.c @@ -188,7 +188,7 @@ mt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom) if (idx != -1) dev_info(dev->dev, - "EEPROM country region %02hhx (channels %hhd-%hhd)\n", + "EEPROM country region %02x (channels %d-%d)\n", val, chan_bounds[idx].start, chan_bounds[idx].start + chan_bounds[idx].num - 1); else -- cgit v1.2.3 From 68204a696505fe97150d498f32e38c2a926c540f Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 11 Jul 2022 14:29:32 -0700 Subject: wifi: mt7601u: fix clang -Wformat warning When building with Clang we encounter this warning: | drivers/net/wireless/mediatek/mt7601u/debugfs.c:92:6: error: format | specifies type 'unsigned char' but the argument has type 'int' | [-Werror,-Wformat] dev->ee->reg.start + dev->ee->reg.num - 1); The format specifier used is `%hhu` which describes a u8. Both `dev->ee->reg.start` and `.num` are u8 as well. However, the expression as a whole is promoted to an int as you cannot get smaller-than-int from addition. Therefore, to fix the warning, use the promoted-to-type's format specifier -- in this case `%d`. example: ``` uint8_t a = 4, b = 7; int size = sizeof(a + b - 1); printf("%d\n", size); // output: 4 ``` See more: (https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules) "Integer types smaller than int are promoted when an operation is performed on them. If all values of the original type can be represented as an int, the value of the smaller type is converted to an int; otherwise, it is converted to an unsigned int." Signed-off-by: Justin Stitt Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220711212932.1501592-1-justinstitt@google.com --- drivers/net/wireless/mediatek/mt7601u/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c index 20669eacb66e..230b0e1061a7 100644 --- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c +++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c @@ -88,7 +88,7 @@ mt7601u_eeprom_param_show(struct seq_file *file, void *data) dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]); seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp); seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain); - seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start, + seq_printf(file, "Reg channels: %hhu-%d\n", dev->ee->reg.start, dev->ee->reg.start + dev->ee->reg.num - 1); seq_puts(file, "Per rate power:\n"); -- cgit v1.2.3 From bcfd9d7f6840b06d5988c7141127795cf405805e Mon Sep 17 00:00:00 2001 From: Rustam Subkhankulov Date: Thu, 14 Jul 2022 16:48:31 +0300 Subject: wifi: p54: add missing parentheses in p54_flush() The assignment of the value to the variable total in the loop condition must be enclosed in additional parentheses, since otherwise, in accordance with the precedence of the operators, the conjunction will be performed first, and only then the assignment. Due to this error, a warning later in the function after the loop may not occur in the situation when it should. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Rustam Subkhankulov Fixes: 0d4171e2153b ("p54: implement flush callback") Acked-by: Christian Lamparter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220714134831.106004-1-subkhankulov@ispras.ru --- drivers/net/wireless/intersil/p54/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index 26b28d4d680f..b925e327e091 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -683,7 +683,7 @@ static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif, * queues have already been stopped and no new frames can sneak * up from behind. */ - while ((total = p54_flush_count(priv) && i--)) { + while ((total = p54_flush_count(priv)) && i--) { /* waste time */ msleep(20); } -- cgit v1.2.3 From 3598cb6e18626d28d20c8de4ee8217fdd4153d63 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 17 Jul 2022 21:21:52 +0900 Subject: wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lockdep complains use of uninitialized spinlock at ieee80211_do_stop() [1], for commit f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif that is being stopped") guards clear_bit() using fq.lock even before fq_init() from ieee80211_txq_setup_flows() initializes this spinlock. According to discussion [2], Toke was not happy with expanding usage of fq.lock. Since __ieee80211_wake_txqs() is called under RCU read lock, we can instead use synchronize_rcu() for flushing ieee80211_wake_txqs(). Link: https://syzkaller.appspot.com/bug?extid=eceab52db7c4b961e9d6 [1] Link: https://lkml.kernel.org/r/874k0zowh2.fsf@toke.dk [2] Reported-by: syzbot Signed-off-by: Tetsuo Handa Fixes: f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif that is being stopped") Tested-by: syzbot Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/9cc9b81d-75a3-3925-b612-9d0ad3cab82b@I-love.SAKURA.ne.jp --- net/mac80211/iface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3d485835dec2..bf3bc43411ac 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -590,9 +590,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do bool cancel_scan; struct cfg80211_nan_func *func; - spin_lock_bh(&local->fq.lock); clear_bit(SDATA_STATE_RUNNING, &sdata->state); - spin_unlock_bh(&local->fq.lock); + synchronize_rcu(); /* flush _ieee80211_wake_txqs() */ cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; if (cancel_scan) -- cgit v1.2.3 From 15978ea38d79d6c376be672117dfcf646a24d1fe Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:26:37 +0800 Subject: wifi: atmel: fix repeated words in comments Delete the redundant word 'long'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709132637.16717-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/atmel/atmel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c index 35c2e798d98b..0361c8eb2008 100644 --- a/drivers/net/wireless/atmel/atmel.c +++ b/drivers/net/wireless/atmel/atmel.c @@ -3353,7 +3353,7 @@ static void atmel_management_frame(struct atmel_private *priv, priv->beacons_this_sec++; atmel_smooth_qual(priv); if (priv->last_beacon_timestamp) { - /* Note truncate this to 32 bits - kernel can't divide a long long */ + /* Note truncate this to 32 bits - kernel can't divide a long */ u32 beacon_delay = timestamp - priv->last_beacon_timestamp; int beacons = beacon_delay / (beacon_interval * 1000); if (beacons > 1) -- cgit v1.2.3 From e2dfb8a5c605eb989e35132ef96cbbff03ed3ca3 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:31:19 +0800 Subject: wifi: b43: fix repeated words in comments Delete the redundant word 'early'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709133119.21076-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/broadcom/b43/phy_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/b43/phy_common.h b/drivers/net/wireless/broadcom/b43/phy_common.h index 4213caca9117..5ec5233acf40 100644 --- a/drivers/net/wireless/broadcom/b43/phy_common.h +++ b/drivers/net/wireless/broadcom/b43/phy_common.h @@ -88,7 +88,7 @@ enum b43_txpwr_result { * initialized here. * Must not be NULL. * @prepare_hardware: Prepare the PHY. This is called before b43_chip_init to - * do some early early PHY hardware init. + * do some early PHY hardware init. * Can be NULL, if not required. * @init: Initialize the PHY. * Must not be NULL. -- cgit v1.2.3 From 29069fb49837c6e1b2e1ecf48cc9b8925c2e5fbf Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:36:18 +0800 Subject: wifi: brcmfmac: fix repeated words in comments Delete the redundant words 'this' and 'and'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709133618.25958-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 3f5da3bb6aa5..ae5af76e2568 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -89,7 +89,7 @@ struct brcmf_bus_ops { * * @commonrings: commonrings which are always there. * @flowrings: commonrings which are dynamically created and destroyed for data. - * @rx_dataoffset: if set then all rx data has this this offset. + * @rx_dataoffset: if set then all rx data has this offset. * @max_rxbufpost: maximum number of buffers to post for rx. * @max_flowrings: maximum number of tx flow rings supported. * @max_submissionrings: maximum number of submission rings(h2d) supported. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 212fbbe1cd7e..2136c3c434ae 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1617,7 +1617,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) /* Do an SDIO read for the superframe. Configurable iovar to * read directly into the chained packet, or allocate a large - * packet and and copy into the chain. + * packet and copy into the chain. */ sdio_claim_host(bus->sdiodev->func1); errcode = brcmf_sdiod_recv_chain(bus->sdiodev, -- cgit v1.2.3 From 505d6105b6fd6dd18cf9a2c49384c94da0a3b22a Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:42:07 +0800 Subject: wifi: brcmsmac: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709134207.30856-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 8ddfc3d06687..11b33e78127c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -3800,7 +3800,7 @@ static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot) } /* - * Suspend the the MAC and update the slot timing + * Suspend the MAC and update the slot timing * for standard 11b/g (20us slots) or shortslot 11g (9us slots). */ static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot) -- cgit v1.2.3 From ac15a010b66429d2cc4ffa71b25f3b3e04675f9e Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:47:01 +0800 Subject: wifi: ipw2x00: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709134701.36081-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index ed343d4fb9d5..029dacebe751 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -2584,7 +2584,7 @@ static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) * through a couple of memory mapped registers. * * The following is a simplified implementation for pulling data out of the - * the eeprom, along with some helper functions to find information in + * eeprom, along with some helper functions to find information in * the per device private data's copy of the eeprom. * * NOTE: To better understand how these functions work (i.e what is a chip -- cgit v1.2.3 From f29c21516268f1cc8ad260d7efd520caaa52eb83 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 9 Jul 2022 21:53:16 +0800 Subject: wifi: iwlegacy: fix repeated words in comments Delete the redundant words 'to' and 'if'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220709135316.41425-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/intel/iwlegacy/4965-mac.c | 2 +- drivers/net/wireless/intel/iwlegacy/common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index d93900e62e3d..943de47170c7 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -6690,7 +6690,7 @@ il4965_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &il_attribute_group); /* ieee80211_unregister_hw call wil cause il_mac_stop to - * to be called and il4965_down since we are removing the device + * be called and il4965_down since we are removing the device * we need to set S_EXIT_PENDING bit. */ set_bit(S_EXIT_PENDING, &il->status); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 9aa3359a9adc..04d27a26260b 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -4817,7 +4817,7 @@ il_check_stuck_queue(struct il_priv *il, int cnt) #define IL_WD_TICK(timeout) ((timeout) / 4) /* - * Watchdog timer callback, we check each tx queue for stuck, if if hung + * Watchdog timer callback, we check each tx queue for stuck, if hung * we reset the firmware. If everything is fine just rearm the timer. */ void -- cgit v1.2.3 From fb01be6d68360fe698041b1c44266e2d6c941a4c Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sun, 10 Jul 2022 12:10:05 +0800 Subject: wifi: qtnfmac: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220710041005.10950-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/quantenna/qtnfmac/qlink.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 2dda4c5d7427..674461fa7fb3 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -1721,8 +1721,8 @@ enum qlink_chan_stat { * @time_on: amount of time radio operated on that channel. * @time_tx: amount of time radio spent transmitting on the channel. * @time_rx: amount of time radio spent receiving on the channel. - * @cca_busy: amount of time the the primary channel was busy. - * @cca_busy_ext: amount of time the the secondary channel was busy. + * @cca_busy: amount of time the primary channel was busy. + * @cca_busy_ext: amount of time the secondary channel was busy. * @time_scan: amount of radio spent scanning on the channel. * @chan_noise: channel noise. */ -- cgit v1.2.3 From a319b7f0794c34a080aded25d219d8d2410c117e Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sun, 10 Jul 2022 12:14:42 +0800 Subject: wifi: rt2x00: fix repeated words in comments Delete the redundant words 'is' and 'with'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220710041442.16177-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index f7ef2ca38794..8f5772b98f58 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -232,7 +232,7 @@ struct link_qual { * VGC levels * Hardware driver will tune the VGC level during each call * to the link_tuner() callback function. This vgc_level is - * is determined based on the link quality statistics like + * determined based on the link quality statistics like * average RSSI and the false CCA count. * * In some cases the drivers need to differentiate between diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index c0ab2e6a29ad..4202c6517783 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -325,7 +325,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) */ rt2x00queue_stop_queue(rt2x00dev->rx); - /* Do not race with with link tuner. */ + /* Do not race with link tuner. */ mutex_lock(&rt2x00dev->conf_mutex); /* -- cgit v1.2.3 From 4a7fb1c67ef4242100a1a875c19bef2cb846b5ce Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sun, 10 Jul 2022 12:20:40 +0800 Subject: wifi: rtlwifi: fix repeated words in comments Delete the redundant words 'in' and 'scan'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220710042040.22456-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- drivers/net/wireless/realtek/rtlwifi/regd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 519b2643f9f4..837febe4dfa4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -671,7 +671,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* *because we should back channel to - *current_network.chan in in scanning, + *current_network.chan in scanning, *So if set_chan == current_network.chan *we should set it. *because mac80211 tell us wrong bw40 diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index 4cf8face0bbd..0bc4afa4fda3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -178,7 +178,7 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, } } -/* Allows active scan scan on Ch 12 and 13 */ +/* Allows active scan on Ch 12 and 13 */ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) -- cgit v1.2.3 From 9c817cb7e6746d2aac8b89c6c4ebcfe915a8b23f Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sun, 10 Jul 2022 12:25:46 +0800 Subject: wifi: rtl8192se: fix repeated words in comments Delete the redundant word 'not'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220710042546.28504-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c index 4ca299c9de77..bd0b7e365edb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c @@ -1407,7 +1407,7 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); /* If IPS we need to turn LED on. So we not - * not disable BIT 3/7 of reg3. */ + * disable BIT 3/7 of reg3. */ if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW)) tmpu1b &= 0xFB; else -- cgit v1.2.3 From 9a46c7d8d6f8998faff72a4f81e5b9dd523ccfbc Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sun, 10 Jul 2022 12:30:07 +0800 Subject: wifi: rsi: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220710043007.33288-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 9f16128e4ffa..d09998796ac0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -796,7 +796,7 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter, * rsi_sdio_host_intf_read_pkt() - This function reads the packet * from the device. * @adapter: Pointer to the adapter data structure. - * @pkt: Pointer to the packet data to be read from the the device. + * @pkt: Pointer to the packet data to be read from the device. * @length: Length of the data to be read from the device. * * Return: 0 on success, -1 on failure. -- cgit v1.2.3 From f1cee996f1858ba07dce9e377559ea33f318af0f Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sun, 10 Jul 2022 12:34:05 +0800 Subject: wifi: wl1251: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220710043405.38304-1-yuanjilin@cdjrlc.com --- drivers/net/wireless/ti/wl1251/acx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl1251/acx.h b/drivers/net/wireless/ti/wl1251/acx.h index 1da6ba95d3d4..1da6ab664e41 100644 --- a/drivers/net/wireless/ti/wl1251/acx.h +++ b/drivers/net/wireless/ti/wl1251/acx.h @@ -1229,7 +1229,7 @@ struct wl1251_acx_arp_filter { u8 address[16]; /* The IP address used to filter ARP packets. ARP packets that do not match this address are dropped. When the IP Version is 4, the last 12 - bytes of the the address are ignored. */ + bytes of the address are ignored. */ } __attribute__((packed)); struct wl1251_acx_ac_cfg { -- cgit v1.2.3 From 8a9be422f5ff34ec7abec289c6fe862d9e7864d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Jul 2022 15:37:23 +0200 Subject: wifi: mac80211: tx: use AP address in some places for MLO In a few places we need to use the AP (MLD) address, not the deflink BSSID, the link address translation will happen later. To make that work properly for fast-xmit, set up the ap_addr in the vif.cfg earlier. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 6 ++++-- net/mac80211/tx.c | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 912095e4e256..ee1a72519c15 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2743,8 +2743,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, changed[link_id] |= ieee80211_link_set_associated(link, cbss); } - memcpy(sdata->vif.cfg.ap_addr, assoc_data->ap_addr, ETH_ALEN); - /* just to be sure */ ieee80211_stop_poll(sdata); @@ -4893,6 +4891,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && local->hw.queues >= IEEE80211_NUM_ACS; + /* needed for fast-xmit setup in sta_info_move_state() */ + memcpy(sdata->vif.cfg.ap_addr, assoc_data->ap_addr, ETH_ALEN); + err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); @@ -4927,6 +4928,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, return true; out_err: + eth_zero_addr(sdata->vif.cfg.ap_addr); mutex_unlock(&sdata->local->sta_mtx); return false; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 34dae26646a6..cded1b207b73 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2735,7 +2735,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, } else { fc |= cpu_to_le16(IEEE80211_FCTL_TODS); /* BSSID SA DA */ - memcpy(hdr.addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); + memcpy(hdr.addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; @@ -3023,7 +3023,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) } fc |= cpu_to_le16(IEEE80211_FCTL_TODS); /* BSSID SA DA */ - memcpy(hdr->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); + memcpy(hdr->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); build.da_offs = offsetof(struct ieee80211_hdr, addr3); build.sa_offs = offsetof(struct ieee80211_hdr, addr2); build.hdr_len = 24; @@ -3250,7 +3250,7 @@ static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata, */ switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: - bssid = sdata->deflink.u.mgd.bssid; + bssid = sdata->vif.cfg.ap_addr; break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: -- cgit v1.2.3 From 553a282cb25eb62fdda1f3425d48b12372366e03 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 Jul 2022 18:16:51 +0200 Subject: wifi: mac80211: mlme: fix override calculation In my previous changes here, I neglected to take the old conn_flags into account that might still be present from the authentication, and thus ieee80211_setup_assoc_link() can misbehave, as well as the override calculation being wrong. Fix that by ORing in the old flags. Fixes: 1845c1d4a455 ("wifi: mac80211: mlme: refactor assoc link setup") Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ee1a72519c15..2d389e74c953 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7048,6 +7048,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, goto err_clear; } + /* keep old conn_flags from ieee80211_prep_channel() from auth */ + conn_flags |= link->u.mgd.conn_flags; conn_flags |= ieee80211_setup_assoc_link(sdata, assoc_data, req, conn_flags, assoc_link_id); override = link->u.mgd.conn_flags != conn_flags; -- cgit v1.2.3 From 206c8c0680b15d2630900ca27eb971c5d25557e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 09:14:30 +0200 Subject: wifi: mac80211: fix NULL pointer deref with non-MLD STA If we have a non-MLD STA on an AP MLD, we crash while adding the station. Fix that, in this case we need to use the STA's address also on the link data structure. Fixes: f36fe0a2df03 ("wifi: mac80211: fix up link station creation/insertion") Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fe6500b36953..b0fdfc61b2f9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1854,10 +1854,15 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; + /* + * If we have a link ID, it can be a non-MLO station on an AP MLD, + * but we need to have a link_mac in that case as well, so use the + * STA's MAC address in that case. + */ if (params->link_sta_params.link_id >= 0) sta = sta_info_alloc_with_link(sdata, mac, params->link_sta_params.link_id, - params->link_sta_params.link_mac, + params->link_sta_params.link_mac ?: mac, GFP_KERNEL); else sta = sta_info_alloc(sdata, mac, GFP_KERNEL); -- cgit v1.2.3 From 1f6389440cebfbca40cc513da69c54b5c24381b1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 16:40:36 +0200 Subject: wifi: mac80211: fix RX MLD address translation We should only translate addr3 here if it's the BSSID. Fixes: 42fb9148c078 ("wifi: mac80211: do link->MLD address translation on RX") Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cad4b2378218..9054a1e0b0d8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -4776,10 +4776,14 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, ether_addr_copy(hdr->addr1, rx->sdata->vif.addr); if (ether_addr_equal(link_sta->addr, hdr->addr2)) ether_addr_copy(hdr->addr2, rx->sta->addr); - if (ether_addr_equal(link_sta->addr, hdr->addr3)) - ether_addr_copy(hdr->addr3, rx->sta->addr); - else if (ether_addr_equal(link->conf->addr, hdr->addr3)) - ether_addr_copy(hdr->addr3, rx->sdata->vif.addr); + /* translate A3 only if it's the BSSID */ + if (!ieee80211_has_tods(hdr->frame_control) && + !ieee80211_has_fromds(hdr->frame_control)) { + if (ether_addr_equal(link_sta->addr, hdr->addr3)) + ether_addr_copy(hdr->addr3, rx->sta->addr); + else if (ether_addr_equal(link->conf->addr, hdr->addr3)) + ether_addr_copy(hdr->addr3, rx->sdata->vif.addr); + } /* not needed for A4 since it can only carry the SA */ } -- cgit v1.2.3 From e4c9050a0dee71fc24e5d93a1003f18a3c6f6f88 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 16:45:50 +0200 Subject: wifi: mac80211_hwsim: fix address translation for MLO There are two issues here: we need to do the translation even in case mac80211 selected a link, and we should only translate the A3 if it's the BSSID. Fix both. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 54 ++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 934939aa5fb6..39dd437207ca 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1705,7 +1705,8 @@ static struct ieee80211_bss_conf * mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr *hdr, + struct ieee80211_link_sta **link_sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; int i; @@ -1724,30 +1725,20 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, return &vif->bss_conf; for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { - struct ieee80211_link_sta *link_sta = NULL; struct ieee80211_bss_conf *bss_conf; unsigned int link_id; /* round-robin the available link IDs */ link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); - link_sta = rcu_dereference(sta->link[link_id]); - if (!link_sta) + *link_sta = rcu_dereference(sta->link[link_id]); + if (!*link_sta) continue; bss_conf = rcu_dereference(vif->link_conf[link_id]); if (WARN_ON_ONCE(!bss_conf)) continue; - /* address translation to link addresses on TX */ - ether_addr_copy(hdr->addr1, link_sta->addr); - ether_addr_copy(hdr->addr2, bss_conf->addr); - if (ether_addr_equal(hdr->addr3, sta->addr)) - ether_addr_copy(hdr->addr3, link_sta->addr); - else if (ether_addr_equal(hdr->addr3, vif->addr)) - ether_addr_copy(hdr->addr3, bss_conf->addr); - /* no need to look at A4, if present it's SA */ - sp->last_link = link_id; return bss_conf; } @@ -1780,23 +1771,46 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, } else if (txi->hw_queue == 4) { channel = data->tmp_chan; } else { - struct ieee80211_bss_conf *bss_conf; u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, IEEE80211_TX_CTRL_MLO_LINK); + struct ieee80211_vif *vif = txi->control.vif; + struct ieee80211_link_sta *link_sta = NULL; + struct ieee80211_sta *sta = control->sta; + struct ieee80211_bss_conf *bss_conf; - if (link != IEEE80211_LINK_UNSPECIFIED) + if (link != IEEE80211_LINK_UNSPECIFIED) { bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); - else - bss_conf = mac80211_hwsim_select_tx_link(data, - txi->control.vif, - control->sta, - hdr); + if (sta) + link_sta = rcu_dereference(sta->link[link]); + } else { + bss_conf = mac80211_hwsim_select_tx_link(data, vif, sta, + hdr, &link_sta); + } if (WARN_ON(!bss_conf)) { ieee80211_free_txskb(hw, skb); return; } + if (sta && sta->mlo) { + if (WARN_ON(!link_sta)) { + ieee80211_free_txskb(hw, skb); + return; + } + /* address translation to link addresses on TX */ + ether_addr_copy(hdr->addr1, link_sta->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); + /* translate A3 only if it's the BSSID */ + if (!ieee80211_has_tods(hdr->frame_control) && + !ieee80211_has_fromds(hdr->frame_control)) { + if (ether_addr_equal(hdr->addr3, sta->addr)) + ether_addr_copy(hdr->addr3, link_sta->addr); + else if (ether_addr_equal(hdr->addr3, vif->addr)) + ether_addr_copy(hdr->addr3, bss_conf->addr); + } + /* no need to look at A4, if present it's SA */ + } + chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); if (chanctx_conf) { channel = chanctx_conf->def.chan; -- cgit v1.2.3 From 0f13f3c3222a0463013f73b9d4b31ac4ebdc884a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 16:58:18 +0200 Subject: wifi: mac80211: fast-xmit: handle non-MLO clients If there's a non-MLO client, the A2 must be set to the BSSID of the link since no translation will happen in lower layers and it's needed that way for encryption. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cded1b207b73..f246b3d264ee 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3045,7 +3045,21 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ build.da_offs = offsetof(struct ieee80211_hdr, addr1); - memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); + if (sta->sta.mlo || !sdata->vif.valid_links) { + memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); + } else { + unsigned int link_id = sta->deflink.link_id; + struct ieee80211_link_data *link; + + rcu_read_lock(); + link = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link)) { + rcu_read_unlock(); + goto out; + } + memcpy(hdr->addr2, link->conf->addr, ETH_ALEN); + rcu_read_unlock(); + } build.sa_offs = offsetof(struct ieee80211_hdr, addr3); build.hdr_len = 24; break; -- cgit v1.2.3 From 6d8e0f84f89f99c87608569e374d52cf248978ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 16:04:05 +0200 Subject: wifi: mac80211: mlme: set sta.mlo to mlo state At this point, we've already changed link_id to be zero for a non-MLO connection, so use the 'mlo' variable rather than link ID to determine the MLO status of the station. Fixes: bd363ee53302 ("wifi: mac80211: mlme: set sta.mlo correctly") Fixes: 81151ce462e5 ("wifi: mac80211: support MLO authentication/association with one link") Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2d389e74c953..1ced0a4b428e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6393,7 +6393,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (!have_sta) { - if (link_id >= 0) + if (mlo) new_sta = sta_info_alloc_with_link(sdata, ap_mld_addr, link_id, cbss->bssid, GFP_KERNEL); @@ -6405,7 +6405,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, goto out_err; } - new_sta->sta.mlo = link_id >= 0; + new_sta->sta.mlo = mlo; } /* -- cgit v1.2.3 From 9aebce6c97bfd7dafd364be2e5b3af7a78af2662 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 22:23:53 +0200 Subject: wifi: mac80211: validate link address doesn't change When modifying a link station, validate that the link address doesn't change, except the first time the link is created. Fixes: b95eb7f0eee4 ("wifi: cfg80211/mac80211: separate link params from station params") Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b0fdfc61b2f9..fa4379761e12 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1597,7 +1597,7 @@ static void sta_apply_mesh_params(struct ieee80211_local *local, } static int sta_link_apply_parameters(struct ieee80211_local *local, - struct sta_info *sta, + struct sta_info *sta, bool new_link, struct link_station_parameters *params) { int ret = 0; @@ -1618,8 +1618,13 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, 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 (new_link) { + memcpy(link_sta->addr, params->link_mac, ETH_ALEN); + memcpy(link_sta->pub->addr, params->link_mac, ETH_ALEN); + } else if (!ether_addr_equal(link_sta->addr, + params->link_mac)) { + return -EINVAL; + } } if (params->txpwr_set) { @@ -1797,7 +1802,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (params->listen_interval >= 0) sta->listen_interval = params->listen_interval; - ret = sta_link_apply_parameters(local, sta, ¶ms->link_sta_params); + ret = sta_link_apply_parameters(local, sta, false, + ¶ms->link_sta_params); if (ret) return ret; @@ -4650,7 +4656,7 @@ static int sta_add_link_station(struct ieee80211_local *local, if (ret) return ret; - ret = sta_link_apply_parameters(local, sta, params); + ret = sta_link_apply_parameters(local, sta, true, params); if (ret) { ieee80211_sta_free_link(sta, params->link_id); return ret; @@ -4688,7 +4694,7 @@ static int sta_mod_link_station(struct ieee80211_local *local, if (!(sta->sta.valid_links & BIT(params->link_id))) return -EINVAL; - return sta_link_apply_parameters(local, sta, params); + return sta_link_apply_parameters(local, sta, false, params); } static int -- cgit v1.2.3 From 0ad49045f28474b3cbc1f27ec7a4238970734764 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 22:54:27 +0200 Subject: wifi: mac80211: fix link sta hash table handling There are two issues here: we unhash the link stations only directly before freeing the station they belong to, and we also don't unhash all the links correctly in all cases. Fix these issues. Fixes: ba6ddab94fc6 ("wifi: mac80211: maintain link-sta hash table") Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 75122eced104..44e21dee6077 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -358,7 +358,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) if (!(sta->sta.valid_links & BIT(i))) continue; - sta_remove_link(sta, i, true); + sta_remove_link(sta, i, false); } /* @@ -846,6 +846,8 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) return 0; out_remove: + if (sta->sta.valid_links) + link_sta_info_hash_del(local, &sta->deflink); sta_info_hash_del(local, sta); list_del_rcu(&sta->list); out_drop_sta: @@ -1140,7 +1142,7 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; - int ret; + int ret, i; might_sleep(); @@ -1168,6 +1170,18 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) */ drv_sync_rx_queues(local, sta); + for (i = 0; i < ARRAY_SIZE(sta->link); i++) { + struct link_sta_info *link_sta; + + if (!(sta->sta.valid_links & BIT(i))) + continue; + + link_sta = rcu_dereference_protected(sta->link[i], + lockdep_is_held(&local->sta_mtx)); + + link_sta_info_hash_del(local, link_sta); + } + ret = sta_info_hash_del(local, sta); if (WARN_ON(ret)) return ret; -- cgit v1.2.3 From 956b96133763dcfdf1b78de0910631f610df2d7b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 23:01:19 +0200 Subject: wifi: mac80211: more station handling sanity checks Add more sanity checks to the API handling, we shouldn't be able to create a station without links, nor should we be able to add a link to a station that wasn't created as an MLD with links in the first place. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fa4379761e12..f519d9cf6e23 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4649,6 +4649,9 @@ static int sta_add_link_station(struct ieee80211_local *local, if (!sta) return -ENOENT; + if (!sta->sta.valid_links) + return -EINVAL; + if (sta->sta.valid_links & BIT(params->link_id)) return -EALREADY; @@ -4724,6 +4727,10 @@ static int sta_del_link_station(struct ieee80211_sub_if_data *sdata, if (!(sta->sta.valid_links & BIT(params->link_id))) return -EINVAL; + /* must not create a STA without links */ + if (sta->sta.valid_links == BIT(params->link_id)) + return -EINVAL; + ieee80211_sta_remove_link(sta, params->link_id); return 0; -- cgit v1.2.3 From 8876c67e6296b44c283cd748d4888788af3f7942 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jul 2022 08:44:25 +0200 Subject: wifi: nl80211: require MLD address on link STA add/modify We always need the MLD address and link ID to add or modify the link STA, so require it in the API. Fixes: 577e5b8c3924 ("wifi: cfg80211: add API to add/modify/remove a link station") Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b6e640437568..310d22b263d1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15827,14 +15827,13 @@ nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info, if (add && !info->attrs[NL80211_ATTR_MAC]) return -EINVAL; - if (add && !info->attrs[NL80211_ATTR_MLD_ADDR]) + if (!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]); + 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]); -- cgit v1.2.3 From dd820ed6336ad37c870ef2f11e34dcf1a8ff2aa1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jul 2022 09:37:59 +0200 Subject: wifi: mac80211: return error from control port TX for drops If the frame is going to be dropped anyway because ieee80211_lookup_ra_sta() returned an error (and even though it's a bit racy, it will likely continue to do so), return the error out instead of just silently dropping the frame. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f246b3d264ee..772108c2cc6b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5712,6 +5712,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, struct ethhdr *ehdr; u32 ctrl_flags = 0; u32 flags = 0; + int err; /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE * or Pre-Authentication @@ -5772,14 +5773,18 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, * AF_PACKET */ rcu_read_lock(); + err = ieee80211_lookup_ra_sta(sdata, skb, &sta); + if (err) { + rcu_read_unlock(); + return err; + } - if (ieee80211_lookup_ra_sta(sdata, skb, &sta) == 0 && !IS_ERR(sta)) { + if (!IS_ERR(sta)) { u16 queue = __ieee80211_select_queue(sdata, sta, skb); skb_set_queue_mapping(skb, queue); skb_get_hash(skb); } - rcu_read_unlock(); /* mutex lock is only needed for incrementing the cookie counter */ -- cgit v1.2.3 From 9dd1953846c7cd58100a5c6bd90db54e2c60668a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jul 2022 10:26:50 +0200 Subject: wifi: nl80211/mac80211: clarify link ID in control port TX Clarify the link ID behaviour in control port TX, we need it to select the link to transmit on for both MLD and non-MLD receivers, but select the link address as the SA only if the receiver is not an MLD. Fixes: 67207bab9341 ("wifi: cfg80211/mac80211: Support control port TX from specific link") Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 6 ++++++ net/mac80211/tx.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3fa586e38f88..d4d6ba585b41 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1119,6 +1119,12 @@ * has been received. %NL80211_ATTR_FRAME is used to specify the * frame contents. The frame is the raw EAPoL data, without ethernet or * 802.11 headers. + * For an MLD transmitter, the %NL80211_ATTR_MLO_LINK_ID may be given and + * its effect will depend on the destination: If the destination is known + * to be an MLD, this will be used as a hint to select the link to transmit + * the frame on. If the destination is not an MLD, this will select both + * the link to transmit on and the source address will be set to the link + * address of that link. * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added * indicating the protocol type of the received frame; whether the frame diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 772108c2cc6b..06ec152e8188 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2896,9 +2896,35 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, info->flags = info_flags; info->ack_frame_id = info_id; info->band = band; - info->control.flags = ctrl_flags | - u32_encode_bits(link_id, + + if (likely(!cookie)) { + ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); + } else { + unsigned int pre_conf_link_id; + + /* + * ctrl_flags already have been set by + * ieee80211_tx_control_port(), here + * we just sanity check that + */ + + pre_conf_link_id = u32_get_bits(ctrl_flags, + IEEE80211_TX_CTRL_MLO_LINK); + + if (pre_conf_link_id != link_id && + link_id != IEEE80211_LINK_UNSPECIFIED) { +#ifdef CPTCFG_MAC80211_VERBOSE_DEBUG + net_info_ratelimited("%s: dropped frame to %pM with bad link ID request (%d vs. %d)\n", + sdata->name, hdr.addr1, + pre_conf_link_id, link_id); +#endif + ret = -EINVAL; + goto free; + } + } + + info->control.flags = ctrl_flags; return skb; free: @@ -5745,11 +5771,17 @@ 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); + /* we may override the SA for MLO STA later */ if (link_id < 0) { + ctrl_flags |= u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + IEEE80211_TX_CTRL_MLO_LINK); memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); } else { struct ieee80211_bss_conf *link_conf; + ctrl_flags |= u32_encode_bits(link_id, + IEEE80211_TX_CTRL_MLO_LINK); + rcu_read_lock(); link_conf = rcu_dereference(sdata->vif.link_conf[link_id]); if (!link_conf) { @@ -5784,6 +5816,13 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, skb_set_queue_mapping(skb, queue); skb_get_hash(skb); + + /* + * for MLO STA, the SA should be the AP MLD address, but + * the link ID has been selected already + */ + if (sta->sta.mlo) + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); } rcu_read_unlock(); -- cgit v1.2.3 From b18d87f5d1025b55351378f953f644f07b1040b0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jul 2022 12:06:17 +0200 Subject: wifi: mac80211: mlme: fix link_sta setup We need to copy the address to both the private and public portion of the link_sta (the private one is needed for the hash table). Fix this. Fixes: bbe90107e1d9 ("wifi: mac80211: mlme: refactor link station setup") Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1ced0a4b428e..cca05d3c5732 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4213,7 +4213,7 @@ out: static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link, struct sta_info *sta, - struct ieee80211_link_sta *link_sta, + struct link_sta_info *link_sta, struct cfg80211_bss *cbss) { struct ieee80211_sub_if_data *sdata = link->sdata; @@ -4227,6 +4227,7 @@ static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link, struct ieee80211_supported_band *sband; memcpy(link_sta->addr, cbss->bssid, ETH_ALEN); + memcpy(link_sta->pub->addr, cbss->bssid, ETH_ALEN); /* TODO: S1G Basic Rate Set is expressed elsewhere */ if (cbss->channel->band == NL80211_BAND_S1GHZ) { @@ -4259,7 +4260,7 @@ static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link, } if (rates) - link_sta->supp_rates[cbss->channel->band] = rates; + link_sta->pub->supp_rates[cbss->channel->band] = rates; else link_info(link, "No rates found, keeping mandatory only\n"); @@ -4858,7 +4859,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, goto out_err; } - err = ieee80211_mgd_setup_link_sta(link, sta, link_sta->pub, + err = ieee80211_mgd_setup_link_sta(link, sta, link_sta, assoc_data->link[link_id].bss); if (err) goto out_err; @@ -6423,10 +6424,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, */ if (new_sta) { const struct cfg80211_bss_ies *ies; - struct ieee80211_link_sta *link_sta; + struct link_sta_info *link_sta; rcu_read_lock(); - link_sta = rcu_dereference(new_sta->sta.link[link_id]); + link_sta = rcu_dereference(new_sta->link[link_id]); if (WARN_ON(!link_sta)) { rcu_read_unlock(); sta_info_free(local, new_sta); -- cgit v1.2.3 From 177577dbd2235a3a65f34a6cd618fe961a4dcaba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jul 2022 12:08:29 +0200 Subject: wifi: mac80211: sta_info: fix link_sta insertion When inserting a link STA, make sure it doesn't exist first and add lockdep assertions that we cannot modify the hash table without holding the sta_mtx, so this check is really correct. Also return without hashing if the driver failed, and warn if the hashing fails, which shouldn't happen due to the check described above. Fixes: cb71f1d136a6 ("wifi: mac80211: add sta link addition/removal") Fixes: ba6ddab94fc6 ("wifi: mac80211: maintain link-sta hash table") Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 44e21dee6077..cb23da9aff1e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -99,6 +99,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, static int link_sta_info_hash_add(struct ieee80211_local *local, struct link_sta_info *link_sta) { + lockdep_assert_held(&local->sta_mtx); return rhltable_insert(&local->link_sta_hash, &link_sta->link_hash_node, link_sta_rht_params); @@ -107,6 +108,7 @@ static int link_sta_info_hash_add(struct ieee80211_local *local, static int link_sta_info_hash_del(struct ieee80211_local *local, struct link_sta_info *link_sta) { + lockdep_assert_held(&local->sta_mtx); return rhltable_remove(&local->link_sta_hash, &link_sta->link_hash_node, link_sta_rht_params); @@ -2765,6 +2767,14 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) if (WARN_ON(old_links == new_links || !link_sta)) return -EINVAL; + rcu_read_lock(); + if (link_sta_info_hash_lookup(sdata->local, link_sta->addr)) { + rcu_read_unlock(); + return -EALREADY; + } + /* we only modify under the mutex so this is fine */ + rcu_read_unlock(); + sta->sta.valid_links = new_links; if (!test_sta_flag(sta, WLAN_STA_INSERTED)) { @@ -2777,12 +2787,13 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) if (ret) { sta->sta.valid_links = old_links; sta_remove_link(sta, link_id, false); + return ret; } hash: - link_sta_info_hash_add(sdata->local, link_sta); - - return ret; + ret = link_sta_info_hash_add(sdata->local, link_sta); + WARN_ON(ret); + return 0; } void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) -- cgit v1.2.3 From c204d9df02020e2ed762d159112a4b15f6580e28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Jul 2022 22:35:44 +0200 Subject: wifi: mac80211_hwsim: handle links for wmediumd/virtio For wmediumd/virtio, handle both the RX channel for links, as well as the link addresses when links are added/removed. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 40 ++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 39dd437207ca..6e55f153ff26 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2995,6 +2995,24 @@ static int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw, u16 old_links, u16 new_links, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) { + unsigned long rem = old_links & ~new_links ?: BIT(0); + unsigned long add = new_links & ~old_links; + int i; + + for_each_set_bit(i, &rem, IEEE80211_MLD_MAX_NUM_LINKS) + mac80211_hwsim_config_mac_nl(hw, old[i]->addr, false); + + for_each_set_bit(i, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf; + + /* FIXME: figure out how to get the locking here */ + link_conf = rcu_dereference_protected(vif->link_conf[i], 1); + if (WARN_ON(!link_conf)) + continue; + + mac80211_hwsim_config_mac_nl(hw, link_conf->addr, true); + } + return 0; } @@ -4478,16 +4496,28 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, /* A frame is received from user space */ memset(&rx_status, 0, sizeof(rx_status)); if (info->attrs[HWSIM_ATTR_FREQ]) { + struct tx_iter_data iter_data = {}; + /* throw away off-channel packets, but allow both the temporary - * ("hw" scan/remain-on-channel) and regular channel, since the - * internal datapath also allows this + * ("hw" scan/remain-on-channel), regular channels and links, + * since the internal datapath also allows this */ - mutex_lock(&data2->mutex); rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); - if (rx_status.freq != channel->center_freq) { - mutex_unlock(&data2->mutex); + iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, + rx_status.freq); + if (!iter_data.channel) goto out; + + mutex_lock(&data2->mutex); + if (!hwsim_chans_compat(iter_data.channel, channel)) { + ieee80211_iterate_active_interfaces_atomic( + data2->hw, IEEE80211_IFACE_ITER_NORMAL, + mac80211_hwsim_tx_iter, &iter_data); + if (!iter_data.receive) { + mutex_unlock(&data2->mutex); + goto out; + } } mutex_unlock(&data2->mutex); } else { -- cgit v1.2.3 From 0903f899418ee0235e4ad756f5502162f29b49b9 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 27 Jan 2022 14:39:46 +0200 Subject: wifi: ieee80211: add helper functions for detecting TM/FTM frames Add helper functions for detection timing measurement and fine timing measurement frames. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index cca564372d16..55e6f4ad0ca6 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1332,6 +1332,15 @@ struct ieee80211_mgmt { u8 action_code; u8 variable[]; } __packed s1g; + struct { + u8 action_code; + u8 dialog_token; + u8 follow_up; + u32 tod; + u32 toa; + u8 max_tod_error; + u8 max_toa_error; + } __packed wnm_timing_msr; } u; } __packed action; } u; @@ -3522,6 +3531,17 @@ enum ieee80211_mesh_actioncode { WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE, }; +/* Unprotected WNM action codes */ +enum ieee80211_unprotected_wnm_actioncode { + WLAN_UNPROTECTED_WNM_ACTION_TIM = 0, + WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE = 1, +}; + +/* Public action codes */ +enum ieee80211_public_actioncode { + WLAN_PUBLIC_ACTION_FTM_RESPONSE = 33, +}; + /* Security key length */ enum ieee80211_key_len { WLAN_KEY_LEN_WEP40 = 5, @@ -4311,6 +4331,40 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb) return true; } +static inline bool ieee80211_is_timing_measurement(struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (void *)skb->data; + + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return false; + + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + + if (mgmt->u.action.category == WLAN_CATEGORY_WNM_UNPROTECTED && + mgmt->u.action.u.wnm_timing_msr.action_code == + WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE && + skb->len >= offsetofend(typeof(*mgmt), u.action.u.wnm_timing_msr)) + return true; + + return false; +} + +static inline bool ieee80211_is_ftm(struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (void *)skb->data; + + if (!ieee80211_is_public_action((void *)mgmt, skb->len)) + return false; + + if (mgmt->u.action.u.ftm.action_code == + WLAN_PUBLIC_ACTION_FTM_RESPONSE && + skb->len >= offsetofend(typeof(*mgmt), u.action.u.ftm)) + return true; + + return false; +} + struct element { u8 id; u8 datalen; -- cgit v1.2.3 From 80b0ed70a271d375feb2286696ca8af147a035cf Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 26 Jan 2022 16:06:35 +0200 Subject: wifi: nl80211: add RX and TX timestamp attributes Add attributes for reporting hardware timestamps for management frames RX and TX. These attributes will be used for reporting hardware timestamps for Timing measurement and Fine Timing Measurement action frames, which will allow userspace applications to measure the path delay between devices and sync clocks. For TX, these attributes are used for reporting the frame RX time and the ack TX time. For TX, they are used for reporting the frame TX time and the ack RX time. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d4d6ba585b41..5275dcbc5ee8 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -764,6 +764,9 @@ * %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA * counters which will be updated to the current value. This attribute * is used during CSA period. + * For RX notification, %NL80211_ATTR_RX_HW_TIMESTAMP may be included to + * indicate the frame RX timestamp and %NL80211_ATTR_TX_HW_TIMESTAMP may + * be included to indicate the ack TX timestamp. * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this * command may be used with the corresponding cookie to cancel the wait * time if it is known that it is no longer necessary. This command is @@ -774,7 +777,9 @@ * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies * the TX command and %NL80211_ATTR_FRAME includes the contents of the * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged - * the frame. + * the frame. %NL80211_ATTR_TX_HW_TIMESTAMP may be included to indicate the + * tx timestamp and %NL80211_ATTR_RX_HW_TIMESTAMP may be included to + * indicate the ack RX timestamp. * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for * backward compatibility. * @@ -2720,6 +2725,18 @@ enum nl80211_commands { * @NL80211_ATTR_EML_CAPABILITY: EML Capability information (u16) * @NL80211_ATTR_MLD_CAPA_AND_OPS: MLD Capabilities and Operations (u16) * + * @NL80211_ATTR_TX_HW_TIMESTAMP: Hardware timestamp for TX operation in + * nanoseconds (u64). This is the device clock timestamp so it will + * probably reset when the device is stopped or the firmware is reset. + * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the frame TX + * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates + * the ack TX timestamp. + * @NL80211_ATTR_RX_HW_TIMESTAMP: Hardware timestamp for RX operation in + * nanoseconds (u64). This is the device clock timestamp so it will + * probably reset when the device is stopped or the firmware is reset. + * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the ack RX + * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates + * the incoming frame RX timestamp. * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3245,6 +3262,9 @@ enum nl80211_attrs { NL80211_ATTR_EML_CAPABILITY, NL80211_ATTR_MLD_CAPA_AND_OPS, + NL80211_ATTR_TX_HW_TIMESTAMP, + NL80211_ATTR_RX_HW_TIMESTAMP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, -- cgit v1.2.3 From ea7d50c925cec96b22655c4dc8672fbd59355bed Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 26 Jan 2022 19:13:47 +0200 Subject: wifi: cfg80211: add a function for reporting TX status with hardware timestamps Add a function for reporting TX status with hardware timestamps. This function shall be used for reporting the TX status of Timing measurement and Fine timing measurement action frames by devices that support reporting hardware timestamps. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 47 +++++++++++++++++++++++++++++++++++++++++++++-- net/wireless/nl80211.c | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d5af3a7fc2b4..43d54f5c84f9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7837,6 +7837,38 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, flags); } +/** + * struct cfg80211_tx_status - TX status for management frame information + * + * @cookie: Cookie returned by cfg80211_ops::mgmt_tx() + * @tx_tstamp: hardware TX timestamp in nanoseconds + * @ack_tstamp: hardware ack RX timestamp in nanoseconds + * @buf: Management frame (header + body) + * @len: length of the frame data + * @ack: Whether frame was acknowledged + */ +struct cfg80211_tx_status { + u64 cookie; + u64 tx_tstamp; + u64 ack_tstamp; + const u8 *buf; + size_t len; + bool ack; +}; + +/** + * cfg80211_mgmt_tx_status_ext - TX status notification with extended info + * @wdev: wireless device receiving the frame + * @status: TX status data + * @gfp: context flags + * + * This function is called whenever a management frame was requested to be + * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the + * transmission attempt with extended info. + */ +void cfg80211_mgmt_tx_status_ext(struct wireless_dev *wdev, + struct cfg80211_tx_status *status, gfp_t gfp); + /** * cfg80211_mgmt_tx_status - notification of TX status for management frame * @wdev: wireless device receiving the frame @@ -7850,8 +7882,19 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the * transmission attempt. */ -void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp); +static inline void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, + u64 cookie, const u8 *buf, + size_t len, bool ack, gfp_t gfp) +{ + struct cfg80211_tx_status status = { + .cookie = cookie, + .buf = buf, + .len = len, + .ack = ack + }; + + cfg80211_mgmt_tx_status_ext(wdev, &status, gfp); +} /** * cfg80211_control_port_tx_status - notification of TX status for control diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 310d22b263d1..a3934f443a84 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18396,8 +18396,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, return -ENOBUFS; } -static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, - const u8 *buf, size_t len, bool ack, +static void nl80211_frame_tx_status(struct wireless_dev *wdev, + struct cfg80211_tx_status *status, gfp_t gfp, enum nl80211_commands command) { struct wiphy *wiphy = wdev->wiphy; @@ -18407,11 +18407,13 @@ static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, void *hdr; if (command == NL80211_CMD_FRAME_TX_STATUS) - trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); + trace_cfg80211_mgmt_tx_status(wdev, status->cookie, + status->ack); else - trace_cfg80211_control_port_tx_status(wdev, cookie, ack); + trace_cfg80211_control_port_tx_status(wdev, status->cookie, + status->ack); - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + status->len, gfp); if (!msg) return; @@ -18426,10 +18428,16 @@ static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, netdev->ifindex)) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf) || - nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie, + nla_put(msg, NL80211_ATTR_FRAME, status->len, status->buf) || + nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, status->cookie, NL80211_ATTR_PAD) || - (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) + (status->ack && nla_put_flag(msg, NL80211_ATTR_ACK)) || + (status->tx_tstamp && + nla_put_u64_64bit(msg, NL80211_ATTR_TX_HW_TIMESTAMP, + status->tx_tstamp, NL80211_ATTR_PAD)) || + (status->ack_tstamp && + nla_put_u64_64bit(msg, NL80211_ATTR_RX_HW_TIMESTAMP, + status->ack_tstamp, NL80211_ATTR_PAD))) goto nla_put_failure; genlmsg_end(msg, hdr); @@ -18446,18 +18454,24 @@ void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { - nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp, + struct cfg80211_tx_status status = { + .cookie = cookie, + .buf = buf, + .len = len, + .ack = ack + }; + + nl80211_frame_tx_status(wdev, &status, gfp, NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS); } EXPORT_SYMBOL(cfg80211_control_port_tx_status); -void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp) +void cfg80211_mgmt_tx_status_ext(struct wireless_dev *wdev, + struct cfg80211_tx_status *status, gfp_t gfp) { - nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp, - NL80211_CMD_FRAME_TX_STATUS); + nl80211_frame_tx_status(wdev, status, gfp, NL80211_CMD_FRAME_TX_STATUS); } -EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +EXPORT_SYMBOL(cfg80211_mgmt_tx_status_ext); static int __nl80211_rx_control_port(struct net_device *dev, struct sk_buff *skb, -- cgit v1.2.3 From 00b3d8401019e6abf89ea577cb1de060ea65e3fd Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Sun, 30 Jan 2022 18:17:51 +0200 Subject: wifi: cfg80211/nl80211: move rx management data into a struct The functions for reporting rx management take many arguments. Collect all the arguments into a struct, which also make it easier to add more arguments if needed. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- net/wireless/mlme.c | 21 +++++++++--------- net/wireless/nl80211.c | 19 ++++++++-------- net/wireless/nl80211.h | 5 ++--- net/wireless/trace.h | 8 +++---- 5 files changed, 81 insertions(+), 32 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 43d54f5c84f9..535e326a35b0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7792,6 +7792,39 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, enum nl80211_connect_failed_reason reason, gfp_t gfp); +/** + * struct cfg80211_rx_info - received management frame info + * + * @freq: Frequency on which the frame was received in kHz + * @sig_dbm: signal strength in dBm, or 0 if unknown + * @buf: Management frame (header + body) + * @len: length of the frame data + * @flags: flags, as defined in enum nl80211_rxmgmt_flags + */ +struct cfg80211_rx_info { + int freq; + int sig_dbm; + const u8 *buf; + size_t len; + u32 flags; +}; + +/** + * cfg80211_rx_mgmt_ext - management frame notification with extended info + * @wdev: wireless device receiving the frame + * @info: RX info as defined in struct cfg80211_rx_info + * + * This function is called whenever an Action frame is received for a station + * mode interface, but is not processed in kernel. + * + * Return: %true if a user space application has registered for this frame. + * For action frames, that makes it responsible for rejecting unrecognized + * action frames; %false otherwise, in which case for action frames the + * driver is responsible for rejecting the frame. + */ +bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev, + struct cfg80211_rx_info *info); + /** * cfg80211_rx_mgmt_khz - notification of received, unprocessed management frame * @wdev: wireless device receiving the frame @@ -7809,8 +7842,20 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * action frames; %false otherwise, in which case for action frames the * driver is responsible for rejecting the frame. */ -bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags); +static inline bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, + int sig_dbm, const u8 *buf, size_t len, + u32 flags) +{ + struct cfg80211_rx_info info = { + .freq = freq, + .sig_dbm = sig_dbm, + .buf = buf, + .len = len, + .flags = flags + }; + + return cfg80211_rx_mgmt_ext(wdev, &info); +} /** * cfg80211_rx_mgmt - notification of received, unprocessed management frame @@ -7833,8 +7878,15 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, const u8 *buf, size_t len, u32 flags) { - return cfg80211_rx_mgmt_khz(wdev, MHZ_TO_KHZ(freq), sig_dbm, buf, len, - flags); + struct cfg80211_rx_info info = { + .freq = MHZ_TO_KHZ(freq), + .sig_dbm = sig_dbm, + .buf = buf, + .len = len, + .flags = flags + }; + + return cfg80211_rx_mgmt_ext(wdev, &info); } /** diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 003c57504583..581df7f4c524 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -4,7 +4,7 @@ * * Copyright (c) 2009, Jouni Malinen * Copyright (c) 2015 Intel Deutschland GmbH - * Copyright (C) 2019-2020 Intel Corporation + * Copyright (C) 2019-2020, 2022 Intel Corporation */ #include @@ -791,15 +791,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return rdev_mgmt_tx(rdev, wdev, params, cookie); } -bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags) +bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev, + struct cfg80211_rx_info *info) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_mgmt_registration *reg; const struct ieee80211_txrx_stypes *stypes = &wiphy->mgmt_stypes[wdev->iftype]; - struct ieee80211_mgmt *mgmt = (void *)buf; + struct ieee80211_mgmt *mgmt = (void *)info->buf; const u8 *data; int data_len; bool result = false; @@ -807,7 +807,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); u16 stype; - trace_cfg80211_rx_mgmt(wdev, freq, sig_dbm); + trace_cfg80211_rx_mgmt(wdev, info); stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; if (!(stypes->rx & BIT(stype))) { @@ -815,8 +815,8 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, return false; } - data = buf + ieee80211_hdrlen(mgmt->frame_control); - data_len = len - ieee80211_hdrlen(mgmt->frame_control); + data = info->buf + ieee80211_hdrlen(mgmt->frame_control); + data_len = info->len - ieee80211_hdrlen(mgmt->frame_control); spin_lock_bh(&rdev->mgmt_registrations_lock); @@ -833,9 +833,8 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, - freq, sig_dbm, - buf, len, flags, GFP_ATOMIC)) + if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, info, + GFP_ATOMIC)) continue; result = true; @@ -847,7 +846,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, trace_cfg80211_return_bool(result); return result; } -EXPORT_SYMBOL(cfg80211_rx_mgmt_khz); +EXPORT_SYMBOL(cfg80211_rx_mgmt_ext); void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a3934f443a84..80d3471041d1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18356,14 +18356,13 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlportid, - int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags, gfp_t gfp) + struct cfg80211_rx_info *info, gfp_t gfp) { struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + info->len, gfp); if (!msg) return -ENOMEM; @@ -18378,13 +18377,13 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, netdev->ifindex)) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, freq % 1000) || - (sig_dbm && - nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf) || - (flags && - nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags))) + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(info->freq)) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, info->freq % 1000) || + (info->sig_dbm && + nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, info->sig_dbm)) || + nla_put(msg, NL80211_ATTR_FRAME, info->len, info->buf) || + (info->flags && + nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags))) goto nla_put_failure; genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index a7e8e0917c1c..855d540ddfb9 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Portions of this file - * Copyright (C) 2018, 2020-2021 Intel Corporation + * Copyright (C) 2018, 2020-2022 Intel Corporation */ #ifndef __NET_WIRELESS_NL80211_H #define __NET_WIRELESS_NL80211_H @@ -105,8 +105,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlpid, - int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags, gfp_t gfp); + struct cfg80211_rx_info *info, gfp_t gfp); void nl80211_radar_notify(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 592b9e9e821a..10b2fd9bacb5 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3096,8 +3096,8 @@ DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_del_sta, ); TRACE_EVENT(cfg80211_rx_mgmt, - TP_PROTO(struct wireless_dev *wdev, int freq, int sig_dbm), - TP_ARGS(wdev, freq, sig_dbm), + TP_PROTO(struct wireless_dev *wdev, struct cfg80211_rx_info *info), + TP_ARGS(wdev, info), TP_STRUCT__entry( WDEV_ENTRY __field(int, freq) @@ -3105,8 +3105,8 @@ TRACE_EVENT(cfg80211_rx_mgmt, ), TP_fast_assign( WDEV_ASSIGN; - __entry->freq = freq; - __entry->sig_dbm = sig_dbm; + __entry->freq = info->freq; + __entry->sig_dbm = info->sig_dbm; ), TP_printk(WDEV_PR_FMT ", freq: "KHZ_F", sig dbm: %d", WDEV_PR_ARG, PR_KHZ(__entry->freq), __entry->sig_dbm) -- cgit v1.2.3 From 1ff715ffa0ec1b5af9093c43185e686f575f15cc Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 27 Jan 2022 13:56:29 +0200 Subject: wifi: cfg80211: add hardware timestamps to frame RX info Add hardware timestamps to management frame RX info. This shall be used by drivers that support hardware timestamping for Timing measurement and Fine timing measurement action frames RX. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ net/wireless/nl80211.c | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 535e326a35b0..2f5c271bcde1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7800,6 +7800,8 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * @buf: Management frame (header + body) * @len: length of the frame data * @flags: flags, as defined in enum nl80211_rxmgmt_flags + * @rx_tstamp: Hardware timestamp of frame RX in nanoseconds + * @ack_tstamp: Hardware timestamp of ack TX in nanoseconds */ struct cfg80211_rx_info { int freq; @@ -7807,6 +7809,8 @@ struct cfg80211_rx_info { const u8 *buf; size_t len; u32 flags; + u64 rx_tstamp; + u64 ack_tstamp; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 80d3471041d1..e5ed0950ef0b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18383,7 +18383,15 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, info->sig_dbm)) || nla_put(msg, NL80211_ATTR_FRAME, info->len, info->buf) || (info->flags && - nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags))) + nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags)) || + (info->rx_tstamp && nla_put_u64_64bit(msg, + NL80211_ATTR_RX_HW_TIMESTAMP, + info->rx_tstamp, + NL80211_ATTR_PAD)) || + (info->ack_tstamp && nla_put_u64_64bit(msg, + NL80211_ATTR_TX_HW_TIMESTAMP, + info->ack_tstamp, + NL80211_ATTR_PAD))) goto nla_put_failure; genlmsg_end(msg, hdr); -- cgit v1.2.3 From f9202638df34474f862109731203e71d8e71f85e Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 26 Jan 2022 11:15:31 +0200 Subject: wifi: mac80211: add hardware timestamps for RX and TX When the low level driver reports hardware timestamps for frame TX status or frame RX, pass the timestamps to cfg80211. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/mac80211.h | 28 +++++++++++++++++++++++++++- net/mac80211/rx.c | 30 ++++++++++++++++++++++-------- net/mac80211/status.c | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6f856da28d71..e9f8be7ba9a6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -125,6 +125,22 @@ * via the usual ieee80211_tx_dequeue). */ +/** + * DOC: HW timestamping + * + * Timing Measurement and Fine Timing Measurement require accurate timestamps + * of the action frames TX/RX and their respective acks. + * + * To report hardware timestamps for Timing Measurement or Fine Timing + * Measurement frame RX, the low level driver should set the SKB's hwtstamp + * field to the frame RX timestamp and report the ack TX timestamp in the + * ieee80211_rx_status struct. + * + * Similarly, To report hardware timestamps for Timing Measurement or Fine + * Timing Measurement frame TX, the driver should set the SKB's hwtstamp field + * to the frame TX timestamp and report the ack RX timestamp in the + * ieee80211_tx_status struct. + */ struct device; /** @@ -1176,12 +1192,16 @@ struct ieee80211_rate_status { * @rates: Mrr stages that were used when sending the packet * @n_rates: Number of mrr stages (count of instances for @rates) * @free_list: list where processed skbs are stored to be free'd by the driver + * @ack_hwtstamp: Hardware timestamp of the received ack in nanoseconds + * Only needed for Timing measurement and Fine timing measurement action + * frames. Only reported by devices that have timestamping enabled. */ struct ieee80211_tx_status { struct ieee80211_sta *sta; struct ieee80211_tx_info *info; struct sk_buff *skb; struct ieee80211_rate_status *rates; + ktime_t ack_hwtstamp; u8 n_rates; struct list_head *free_list; @@ -1419,6 +1439,9 @@ enum mac80211_rx_encoding { * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * @boottime_ns: CLOCK_BOOTTIME timestamp the frame was received at, this is * needed only for beacons and probe responses that update the scan cache. + * @ack_tx_hwtstamp: Hardware timestamp for the ack TX in nanoseconds. Only + * needed for Timing measurement and Fine timing measurement action frames. + * Only reported by devices that have timestamping enabled. * @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use * it but can store it and pass it back to the driver for synchronisation * @band: the active band when this frame was received @@ -1452,7 +1475,10 @@ enum mac80211_rx_encoding { */ struct ieee80211_rx_status { u64 mactime; - u64 boottime_ns; + union { + u64 boottime_ns; + ktime_t ack_tx_hwtstamp; + }; u32 device_timestamp; u32 ampdu_reference; u32 flag; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9054a1e0b0d8..ef9c2fcd68f5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3644,7 +3644,11 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - int sig = 0; + struct cfg80211_rx_info info = { + .freq = ieee80211_rx_status_to_khz(status), + .buf = rx->skb->data, + .len = rx->skb->len + }; /* skip known-bad action frames and return them in the next handler */ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) @@ -3659,11 +3663,15 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) - sig = status->signal; + info.sig_dbm = status->signal; + + if (ieee80211_is_timing_measurement(rx->skb) || + ieee80211_is_ftm(rx->skb)) { + info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp); + info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp); + } - if (cfg80211_rx_mgmt_khz(&rx->sdata->wdev, - ieee80211_rx_status_to_khz(status), sig, - rx->skb->data, rx->skb->len, 0)) { + if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) { if (rx->sta) rx->sta->deflink.rx_stats.packets++; dev_kfree_skb(rx->skb); @@ -4758,8 +4766,10 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, } if (!consume) { - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) { + struct skb_shared_hwtstamps *shwt; + + rx->skb = skb_copy(skb, GFP_ATOMIC); + if (!rx->skb) { if (net_ratelimit()) wiphy_debug(local->hw.wiphy, "failed to copy skb for %s\n", @@ -4767,7 +4777,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, return true; } - rx->skb = skb; + /* skb_copy() does not copy the hw timestamps, so copy it + * explicitly + */ + shwt = skb_hwtstamps(rx->skb); + shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp; } if (unlikely(link_sta)) { diff --git a/net/mac80211/status.c b/net/mac80211/status.c index fad457f99711..8e77fd2e9fdf 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -624,9 +624,11 @@ ieee80211_sdata_from_skb(struct ieee80211_local *local, struct sk_buff *skb) } static void ieee80211_report_ack_skb(struct ieee80211_local *local, - struct ieee80211_tx_info *info, - bool acked, bool dropped) + struct sk_buff *orig_skb, + bool acked, bool dropped, + ktime_t ack_hwtstamp) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(orig_skb); struct sk_buff *skb; unsigned long flags; @@ -643,6 +645,19 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, struct ieee80211_hdr *hdr = (void *)skb->data; bool is_valid_ack_signal = !!(info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID); + struct cfg80211_tx_status status = { + .cookie = cookie, + .buf = skb->data, + .len = skb->len, + .ack = acked, + }; + + if (ieee80211_is_timing_measurement(orig_skb) || + ieee80211_is_ftm(orig_skb)) { + status.tx_tstamp = + ktime_to_ns(skb_hwtstamps(orig_skb)->hwtstamp); + status.ack_tstamp = ktime_to_ns(ack_hwtstamp); + } rcu_read_lock(); sdata = ieee80211_sdata_from_skb(local, skb); @@ -662,9 +677,9 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, is_valid_ack_signal, GFP_ATOMIC); else if (ieee80211_is_mgmt(hdr->frame_control)) - cfg80211_mgmt_tx_status(&sdata->wdev, cookie, - skb->data, skb->len, - acked, GFP_ATOMIC); + cfg80211_mgmt_tx_status_ext(&sdata->wdev, + &status, + GFP_ATOMIC); else pr_warn("Unknown status report in ack skb\n"); @@ -681,7 +696,8 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, } static void ieee80211_report_used_skb(struct ieee80211_local *local, - struct sk_buff *skb, bool dropped) + struct sk_buff *skb, bool dropped, + ktime_t ack_hwtstamp) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 tx_time_est = ieee80211_info_get_tx_time_est(info); @@ -744,7 +760,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, rcu_read_unlock(); } else if (info->ack_frame_id) { - ieee80211_report_ack_skb(local, info, acked, dropped); + ieee80211_report_ack_skb(local, skb, acked, dropped, + ack_hwtstamp); } if (!dropped && skb->destructor) { @@ -1038,7 +1055,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, jiffies + msecs_to_jiffies(10)); } - ieee80211_report_used_skb(local, skb, false); + ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp); /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); @@ -1201,7 +1218,7 @@ free: if (!skb) return; - ieee80211_report_used_skb(local, skb, false); + ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp); if (status->free_list) list_add_tail(&skb->list, status->free_list); else @@ -1262,8 +1279,9 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); + ktime_t kt = ktime_set(0, 0); - ieee80211_report_used_skb(local, skb, true); + ieee80211_report_used_skb(local, skb, true, kt); dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ieee80211_free_txskb); -- cgit v1.2.3 From 6074c9e5747158ab1e6aebedb87f64be77401fd8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 10:40:44 +0200 Subject: wifi: cfg80211: report link ID in NL80211_CMD_FRAME If given by the underlying driver, report the link ID for MLO in NL80211_CMD_FRAME. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 +++++ net/wireless/nl80211.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2f5c271bcde1..8545ed098d90 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7797,6 +7797,9 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * * @freq: Frequency on which the frame was received in kHz * @sig_dbm: signal strength in dBm, or 0 if unknown + * @have_link_id: indicates the frame was received on a link of + * an MLD, i.e. the @link_id field is valid + * @link_id: the ID of the link the frame was received on * @buf: Management frame (header + body) * @len: length of the frame data * @flags: flags, as defined in enum nl80211_rxmgmt_flags @@ -7806,6 +7809,8 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, struct cfg80211_rx_info { int freq; int sig_dbm; + bool have_link_id; + u8 link_id; const u8 *buf; size_t len; u32 flags; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e5ed0950ef0b..60b8406b8d7e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18377,6 +18377,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, netdev->ifindex)) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || + (info->have_link_id && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, info->link_id)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(info->freq)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, info->freq % 1000) || (info->sig_dbm && -- cgit v1.2.3 From 2ec833a5aafc49142a9b2988a3225ebfa47ccd27 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 10:42:19 +0200 Subject: wifi: mac80211: report link ID to cfg80211 on mgmt RX For frames received on an MLD, report the link ID to userspace. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ef9c2fcd68f5..6cb5989c6ae2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3647,7 +3647,9 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) struct cfg80211_rx_info info = { .freq = ieee80211_rx_status_to_khz(status), .buf = rx->skb->data, - .len = rx->skb->len + .len = rx->skb->len, + .link_id = rx->link_id, + .have_link_id = rx->link_id >= 0, }; /* skip known-bad action frames and return them in the next handler */ -- cgit v1.2.3 From 95f498bb49f7030c1f40236107e5241e50f79ade Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 12:13:46 +0200 Subject: wifi: nl80211: add MLO link ID to the NL80211_CMD_FRAME TX API Allow optionally specifying the link ID to transmit on, which can be done instead of the link frequency, on an MLD addressed frame. Both can also be omitted in which case the frame must be MLD addressed and link selection (and address translation) will be done on lower layers. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 4 ++++ net/wireless/nl80211.c | 12 ++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8545ed098d90..908d58393484 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3411,6 +3411,9 @@ struct cfg80211_update_ft_ies_params { * @dont_wait_for_ack: tells the low level not to wait for an ack * @n_csa_offsets: length of csa_offsets array * @csa_offsets: array of all the csa offsets in the frame + * @link_id: for MLO, the link ID to transmit on, -1 if not given; note + * that the link ID isn't validated (much), it's in range but the + * link might not exist (or be used by the receiver STA) */ struct cfg80211_mgmt_tx_params { struct ieee80211_channel *chan; @@ -3422,6 +3425,7 @@ struct cfg80211_mgmt_tx_params { bool dont_wait_for_ack; int n_csa_offsets; const u16 *csa_offsets; + int link_id; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5275dcbc5ee8..ffb7c573e299 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -764,6 +764,10 @@ * %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA * counters which will be updated to the current value. This attribute * is used during CSA period. + * For TX on an MLD, the frequency can be omitted and the link ID be + * specified, or if transmitting to a known peer MLD (with MLD addresses + * in the frame) both can be omitted and the link will be selected by + * lower layers. * For RX notification, %NL80211_ATTR_RX_HW_TIMESTAMP may be included to * indicate the frame RX timestamp and %NL80211_ATTR_TX_HW_TIMESTAMP may * be included to indicate the ack TX timestamp. diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 60b8406b8d7e..2705e3ee8fc4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12256,6 +12256,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) wdev_unlock(wdev); return -EBUSY; } + + params.link_id = nl80211_link_id_or_invalid(info->attrs); + /* + * This now races due to the unlock, but we cannot check + * the valid links for the _station_ anyway, so that's up + * to the driver. + */ + if (params.link_id >= 0 && + !(wdev->valid_links & BIT(params.link_id))) { + wdev_unlock(wdev); + return -EINVAL; + } wdev_unlock(wdev); params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); -- cgit v1.2.3 From e1e68b14c5f85f2ad43d06a1b2f0d0fcc8dbdd62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 21:36:08 +0200 Subject: wifi: mac80211: expand ieee80211_mgmt_tx() for MLO There are a couple of new things that should be possible with MLO: * selecting the link to transmit to a station by link ID, which a previous patch added to the nl80211 API * selecting the link by frequency, similarly * allowing transmittion to an MLD without specifying any channel or link ID, with MLD addresses Enable these use cases. Also fix the address comparison in client mode to use the AP (MLD) address. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 +++- net/mac80211/agg-tx.c | 4 ++-- net/mac80211/ieee80211_i.h | 8 ++++---- net/mac80211/offchannel.c | 47 ++++++++++++++++++++++++++++++++-------------- net/mac80211/rx.c | 2 +- net/mac80211/tx.c | 11 ++++++++--- 6 files changed, 51 insertions(+), 25 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e9f8be7ba9a6..1afd45239fe6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -885,7 +885,9 @@ enum mac80211_tx_info_flags { * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this * frame should be transmitted on the specific link. This really is * only relevant for frames that do not have data present, and is - * also not used for 802.3 format frames. + * also not used for 802.3 format frames. Note that even if the frame + * is on a specific link, address translation might still apply if + * it's intended for an MLD. * * These flags are used in tx_info->control.flags. */ diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b13f4b7b740d..07c892aa8c73 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -106,7 +106,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.addba_req.start_seq_num = cpu_to_le16(start_seq_num << 4); - ieee80211_tx_skb_tid(sdata, skb, tid); + ieee80211_tx_skb_tid(sdata, skb, tid, -1); } void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) @@ -135,7 +135,7 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | IEEE80211_TX_CTL_REQ_TX_STATUS; - ieee80211_tx_skb_tid(sdata, skb, tid); + ieee80211_tx_skb_tid(sdata, skb, tid, -1); } EXPORT_SYMBOL(ieee80211_send_bar); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5fc4392ba507..4ec6fb96ba41 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2141,7 +2141,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct sk_buff *skb); void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid, + struct sk_buff *skb, int tid, int link_id, enum nl80211_band band); /* sta_out needs to be checked for ERR_PTR() before using */ @@ -2155,18 +2155,18 @@ ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, enum nl80211_band band) { rcu_read_lock(); - __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + __ieee80211_tx_skb_tid_band(sdata, skb, tid, -1, band); rcu_read_unlock(); } void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid); + struct sk_buff *skb, int tid, int link_id); static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ - ieee80211_tx_skb_tid(sdata, skb, 7); + ieee80211_tx_skb_tid(sdata, skb, 7, -1); } /** diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index be79ae68754e..d78c82d6b696 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -769,9 +769,11 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb; - struct sta_info *sta; + struct sta_info *sta = NULL; const struct ieee80211_mgmt *mgmt = (void *)params->buf; bool need_offchan = false; + bool mlo_sta = false; + int link_id = -1; u32 flags; int ret; u8 *data; @@ -804,16 +806,30 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, !ieee80211_vif_is_mesh(&sdata->vif) && !sdata->bss->active) need_offchan = true; + + rcu_read_lock(); + sta = sta_info_get_bss(sdata, mgmt->da); + mlo_sta = sta && sta->sta.mlo; + if (!ieee80211_is_action(mgmt->frame_control) || mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED || - mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) + mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { + rcu_read_unlock(); break; - rcu_read_lock(); - sta = sta_info_get_bss(sdata, mgmt->da); - rcu_read_unlock(); - if (!sta) + } + + if (!sta) { + rcu_read_unlock(); return -ENOLINK; + } + if (params->link_id >= 0 && + !(sta->sta.valid_links & BIT(params->link_id))) { + rcu_read_unlock(); + return -ENOLINK; + } + link_id = params->link_id; + rcu_read_unlock(); break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -821,8 +837,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, if (!sdata->u.mgd.associated || (params->offchan && params->wait && local->ops->remain_on_channel && - memcmp(sdata->deflink.u.mgd.bssid, - mgmt->bssid, ETH_ALEN))) + memcmp(sdata->vif.cfg.ap_addr, mgmt->bssid, ETH_ALEN))) need_offchan = true; sdata_unlock(sdata); break; @@ -843,7 +858,9 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, mutex_lock(&local->mtx); /* Check if the operating channel is the requested channel */ - if (!need_offchan) { + if (!params->chan && mlo_sta) { + need_offchan = false; + } else if (!need_offchan) { struct ieee80211_chanctx_conf *chanctx_conf = NULL; int i; @@ -860,6 +877,12 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, if (!chanctx_conf) continue; + if (mlo_sta && params->chan == chanctx_conf->def.chan && + ether_addr_equal(sdata->vif.addr, mgmt->sa)) { + link_id = i; + break; + } + if (ether_addr_equal(conf->addr, mgmt->sa)) break; @@ -870,10 +893,6 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, need_offchan = params->chan && (params->chan != chanctx_conf->def.chan); - } else if (!params->chan) { - ret = -EINVAL; - rcu_read_unlock(); - goto out_unlock; } else { need_offchan = true; } @@ -943,7 +962,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, } if (!need_offchan) { - ieee80211_tx_skb(sdata, skb); + ieee80211_tx_skb_tid(sdata, skb, 7, link_id); ret = 0; goto out_unlock; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6cb5989c6ae2..58ff2cc7bcc9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3774,7 +3774,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) local->hw.offchannel_tx_hw_queue; } - __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, + __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1, status->band); } dev_kfree_skb(rx->skb); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 06ec152e8188..f24565064f08 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5647,7 +5647,7 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) EXPORT_SYMBOL(ieee80211_unreserve_tid); void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid, + struct sk_buff *skb, int tid, int link_id, enum nl80211_band band) { const struct ieee80211_hdr *hdr = (void *)skb->data; @@ -5666,6 +5666,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, if (!sdata->vif.valid_links) { link = 0; + } else if (link_id >= 0) { + link = link_id; } else if (memcmp(sdata->vif.addr, hdr->addr2, ETH_ALEN) == 0) { /* address from the MLD */ link = IEEE80211_LINK_UNSPECIFIED; @@ -5702,13 +5704,14 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, } void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid) + struct sk_buff *skb, int tid, int link_id) { struct ieee80211_chanctx_conf *chanctx_conf; enum nl80211_band band; rcu_read_lock(); if (!sdata->vif.valid_links) { + WARN_ON(link_id >= 0); chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { @@ -5718,11 +5721,13 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, } band = chanctx_conf->def.chan->band; } else { + WARN_ON(link_id >= 0 && + !(sdata->vif.valid_links & BIT(link_id))); /* MLD transmissions must not rely on the band */ band = 0; } - __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + __ieee80211_tx_skb_tid_band(sdata, skb, tid, link_id, band); rcu_read_unlock(); } -- cgit v1.2.3 From 963d0e8d08d97f9133b9fd00354ebc1a2467484b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jul 2022 10:56:48 +0200 Subject: wifi: mac80211: optionally implement MLO multicast TX For drivers using software encryption for multicast TX, such as mac80211_hwsim, mac80211 needs to duplicate the multicast frames on each link, if MLO is enabled. Do this, but don't just make it dependent on the key but provide a separate flag for drivers to opt out of this. This is not very efficient, I expect that drivers will do it in firmware/hardware or at least with DMA engine assistence, so this is mostly for hwsim. To make this work, also implement the SNS11 sequence number space that an AP MLD shall have, and modify the API to the __ieee80211_subif_start_xmit() function to always require the link ID bits to be set. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 10 +++++ net/mac80211/debugfs.c | 3 +- net/mac80211/ieee80211_i.h | 1 + net/mac80211/tdls.c | 3 +- net/mac80211/tx.c | 91 +++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 97 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1afd45239fe6..1e04961148bf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -882,6 +882,8 @@ enum mac80211_tx_info_flags { * @IEEE80211_TX_CTRL_DONT_REORDER: This frame should not be reordered * relative to other frames that have this flag set, independent * of their QoS TID or other priority field values. + * @IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX: first MLO TX, used mostly internally + * for sequence number assignment * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this * frame should be transmitted on the specific link. This really is * only relevant for frames that do not have data present, and is @@ -901,10 +903,14 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6), IEEE80211_TX_CTRL_NO_SEQNO = BIT(7), IEEE80211_TX_CTRL_DONT_REORDER = BIT(8), + IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX = BIT(9), IEEE80211_TX_CTRL_MLO_LINK = 0xf0000000, }; #define IEEE80211_LINK_UNSPECIFIED 0xf +#define IEEE80211_TX_CTRL_MLO_LINK_UNSPEC \ + u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, \ + IEEE80211_TX_CTRL_MLO_LINK) /** * enum mac80211_tx_status_flags - flags to describe transmit status @@ -2524,6 +2530,9 @@ struct ieee80211_txq { * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color * collision detection and doesn't need it in software. * + * @IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX: Hardware/driver handles transmitting + * multicast frames on all links, mac80211 should not do that. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2580,6 +2589,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP, IEEE80211_HW_DETECTS_COLOR_COLLISION, + IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 4d4341249759..78c7d60e8667 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -4,7 +4,7 @@ * * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018 - 2019, 2021 Intel Corporation + * Copyright (C) 2018 - 2019, 2021-2022 Intel Corporation */ #include @@ -495,6 +495,7 @@ static const char *hw_flag_names[] = { FLAG(SUPPORTS_RX_DECAP_OFFLOAD), FLAG(SUPPORTS_CONC_MON_RX_DECAP), FLAG(DETECTS_COLOR_COLLISION), + FLAG(MLO_MCAST_MULTI_LINK_TX), #undef FLAG }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4ec6fb96ba41..f93b57799e94 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1029,6 +1029,7 @@ struct ieee80211_sub_if_data { struct ieee80211_key __rcu *default_unicast_key; u16 sequence_number; + u16 mld_mcast_seq; __be16 control_port_protocol; bool control_port_no_encrypt; bool control_port_no_preauth; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 36bfc54b3d2d..f4b4d25eef95 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1054,7 +1054,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, /* disable bottom halves when entering the Tx path */ local_bh_disable(); - __ieee80211_subif_start_xmit(skb, dev, flags, 0, NULL); + __ieee80211_subif_start_xmit(skb, dev, flags, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, NULL); local_bh_enable(); return ret; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f24565064f08..45df9932d0ba 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -822,6 +822,16 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) if (info->control.flags & IEEE80211_TX_CTRL_NO_SEQNO) return TX_CONTINUE; + /* SNS11 from 802.11be 10.3.2.14 */ + if (unlikely(is_multicast_ether_addr(hdr->addr1) && + info->control.vif->valid_links && + info->control.vif->type == NL80211_IFTYPE_AP)) { + if (info->control.flags & IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX) + tx->sdata->mld_mcast_seq += 0x10; + hdr->seq_ctrl = cpu_to_le16(tx->sdata->mld_mcast_seq); + return TX_CONTINUE; + } + /* * Anything but QoS data that has a sequence number field * (is long enough) gets a sequence number from the global @@ -2570,7 +2580,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx_conf *chanctx_conf = NULL; enum nl80211_band band; int ret; - u8 link_id = IEEE80211_LINK_UNSPECIFIED; + u8 link_id = u32_get_bits(ctrl_flags, IEEE80211_TX_CTRL_MLO_LINK); if (IS_ERR(sta)) sta = NULL; @@ -2630,8 +2640,18 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, goto free; } memcpy(hdr.addr2, link->conf->addr, ETH_ALEN); - } else { + } else if (link_id == IEEE80211_LINK_UNSPECIFIED) { memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + } else { + struct ieee80211_bss_conf *conf; + + conf = rcu_dereference(sdata->vif.link_conf[link_id]); + if (unlikely(!conf)) { + ret = -ENOLINK; + goto free; + } + + memcpy(hdr.addr2, conf->addr, ETH_ALEN); } memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); @@ -4222,9 +4242,6 @@ static bool ieee80211_multicast_to_unicast(struct sk_buff *skb, const struct vlan_ethhdr *ethvlan = (void *)skb->data; __be16 ethertype; - if (likely(!is_multicast_ether_addr(eth->h_dest))) - return false; - switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: if (sdata->u.vlan.sta) @@ -4308,6 +4325,44 @@ out: rcu_read_unlock(); } +static void ieee80211_mlo_multicast_tx_one(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, u32 ctrl_flags, + unsigned int link_id) +{ + struct sk_buff *out; + + out = skb_copy(skb, GFP_ATOMIC); + if (!out) + return; + + ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); + __ieee80211_subif_start_xmit(out, sdata->dev, 0, ctrl_flags, NULL); +} + +static void ieee80211_mlo_multicast_tx(struct net_device *dev, + struct sk_buff *skb) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + unsigned long links = sdata->vif.valid_links; + unsigned int link; + u32 ctrl_flags = IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX; + + if (hweight16(links) == 1) { + ctrl_flags |= u32_encode_bits(ffs(links) - 1, + IEEE80211_TX_CTRL_MLO_LINK); + + __ieee80211_subif_start_xmit(skb, sdata->dev, 0, ctrl_flags, + NULL); + return; + } + + for_each_set_bit(link, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + ieee80211_mlo_multicast_tx_one(sdata, skb, ctrl_flags, link); + ctrl_flags = 0; + } + kfree_skb(skb); +} + /** * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs * @skb: packet to be sent @@ -4318,15 +4373,30 @@ out: netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + const struct ethhdr *eth = (void *)skb->data; + + if (likely(!is_multicast_ether_addr(eth->h_dest))) + goto normal; + if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) { struct sk_buff_head queue; __skb_queue_head_init(&queue); ieee80211_convert_to_unicast(skb, dev, &queue); while ((skb = __skb_dequeue(&queue))) - __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); + __ieee80211_subif_start_xmit(skb, dev, 0, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); + } else if (sdata->vif.valid_links && + sdata->vif.type == NL80211_IFTYPE_AP && + !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) { + ieee80211_mlo_multicast_tx(dev, skb); } else { - __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); +normal: + __ieee80211_subif_start_xmit(skb, dev, 0, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); } return NETDEV_TX_OK; @@ -4410,7 +4480,9 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, if (tid_tx) { if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { /* fall back to non-offload slow path */ - __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); + __ieee80211_subif_start_xmit(skb, dev, 0, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); return; } @@ -4512,7 +4584,8 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, goto out; } - skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, 0, NULL); + skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, NULL); if (IS_ERR(skb)) goto out; -- cgit v1.2.3 From 56057da4569bd716771cf4cfd031ce9876ef2516 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jul 2022 13:08:13 +0200 Subject: wifi: mac80211: rx: track link in RX data We'll need the link e.g. for decrypt, and shouldn't be looking it up all the time later, so track it in the RX data. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/rx.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f93b57799e94..e192e1ec0261 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -211,6 +211,7 @@ struct ieee80211_rx_data { struct sk_buff *skb; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; struct sta_info *sta; struct ieee80211_key *key; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 58ff2cc7bcc9..57df21e2170a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3990,6 +3990,9 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, */ rx->skb = skb; + if (WARN_ON_ONCE(!rx->link)) + goto rxh_next; + CALL_RXH(ieee80211_rx_h_check_more_data); CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll); CALL_RXH(ieee80211_rx_h_sta_process); @@ -4118,6 +4121,7 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid, rx.sta = sta; rx.sdata = sta->sdata; + rx.link = &rx.sdata->deflink; rx.local = sta->local; rcu_read_lock(); @@ -4758,12 +4762,22 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, if (!ieee80211_accept_frame(rx)) return false; + if (rx->link_id >= 0) { + link = rcu_dereference(rx->sdata->link[rx->link_id]); + + /* we might race link removal */ + if (!link) + return true; + rx->link = link; + } else { + rx->link = &sdata->deflink; + } + if (unlikely(!is_multicast_ether_addr(hdr->addr1) && rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) { link_sta = rcu_dereference(rx->sta->link[rx->link_id]); - link = rcu_dereference(rx->sdata->link[rx->link_id]); - if (WARN_ON_ONCE(!link_sta || !link)) + if (WARN_ON_ONCE(!link_sta)) return true; } @@ -4833,6 +4847,7 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, rx.sta = container_of(pubsta, struct sta_info, sta); rx.sdata = rx.sta->sdata; + rx.link = &rx.sdata->deflink; fast_rx = rcu_dereference(rx.sta->fast_rx); if (!fast_rx) -- cgit v1.2.3 From 1773af9d6a3f1f2f67e111196fa8fb9106a7c20d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jul 2022 19:54:20 +0200 Subject: wifi: mac80211: verify link addresses are different When adding multiple links, verify that they all have different addresses. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bf3bc43411ac..e544621ead0e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -444,6 +444,32 @@ static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata, } } +static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata) +{ + unsigned int i, j; + + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { + struct ieee80211_link_data *link1; + + link1 = sdata_dereference(sdata->link[i], sdata); + if (!link1) + continue; + for (j = i + 1; j < IEEE80211_MLD_MAX_NUM_LINKS; j++) { + struct ieee80211_link_data *link2; + + link2 = sdata_dereference(sdata->link[j], sdata); + if (!link2) + continue; + + if (ether_addr_equal(link1->conf->addr, + link2->conf->addr)) + return -EALREADY; + } + } + + return 0; +} + static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, struct link_container **to_free, u16 new_links) @@ -518,10 +544,14 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, sdata->vif.valid_links = new_links; - /* tell the driver */ - ret = drv_change_vif_links(sdata->local, sdata, - old_links, new_links, - old); + ret = ieee80211_check_dup_link_addrs(sdata); + if (!ret) { + /* 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)); -- cgit v1.2.3 From 4ca04ed36478e21b037fc379a7e6f52d0e6d8d52 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jul 2022 23:35:21 +0200 Subject: wifi: mac80211: mlme: transmit assoc frame with address translation To transmit the association frame to the right station and with address translation, use the correct addresses there and set up the AP address in the configuration earlier so it's applied during the transmit of auth/assoc frames. Fixes: 81151ce462e5 ("wifi: mac80211: support MLO authentication/association with one link") Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cca05d3c5732..8c614daedeb8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1305,7 +1305,6 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) struct ieee80211_prep_tx_info info = {}; unsigned int link_id, n_links = 0; u16 present_elems[PRESENT_ELEMS_MAX] = {}; - const u8 *bssid; void *capab_pos; size_t size; int ret; @@ -1398,8 +1397,6 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) if (WARN_ON(!assoc_data->link[assoc_data->assoc_link_id].bss)) return -EINVAL; - bssid = assoc_data->link[assoc_data->assoc_link_id].bss->bssid; - skb = alloc_skb(size, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -1416,9 +1413,9 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; mgmt = skb_put_zero(skb, 24); - memcpy(mgmt->da, bssid, ETH_ALEN); - memcpy(mgmt->sa, link->conf->addr, ETH_ALEN); - memcpy(mgmt->bssid, bssid, ETH_ALEN); + memcpy(mgmt->da, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN); listen_int = cpu_to_le16(assoc_data->s1g ? ieee80211_encode_usf(local->hw.conf.listen_interval) : @@ -4892,9 +4889,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && local->hw.queues >= IEEE80211_NUM_ACS; - /* needed for fast-xmit setup in sta_info_move_state() */ - memcpy(sdata->vif.cfg.ap_addr, assoc_data->ap_addr, ETH_ALEN); - err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); @@ -6647,6 +6641,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "authenticate with %pM\n", auth_data->ap_addr); + /* needed for transmitting the auth frame(s) properly */ + memcpy(sdata->vif.cfg.ap_addr, auth_data->ap_addr, ETH_ALEN); + err = ieee80211_prep_connection(sdata, req->bss, req->link_id, req->ap_mld_addr, cont_auth, false); if (err) @@ -7112,6 +7109,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, goto err_clear; } + /* needed for transmitting the assoc frames properly */ + memcpy(sdata->vif.cfg.ap_addr, assoc_data->ap_addr, ETH_ALEN); + err = ieee80211_prep_connection(sdata, cbss, req->link_id, req->ap_mld_addr, true, override); if (err) -- cgit v1.2.3 From 45b12570a4bb3ed6fc364a4b1514911a3a4df177 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jul 2022 00:07:29 +0200 Subject: wifi: mac80211: remove erroneous sband/link validation In sta_apply_parameters(), we really no longer need to check that the link or sband exists, in fact, that's harmful if link 0 doesn't exist, since then this will fail. Just remove this check, it was added for validation of the sband where used, but it's not used here, it's now only used in sta_link_apply_parameters() which has an own lookup and check. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f519d9cf6e23..a4f6971b7a19 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1684,21 +1684,9 @@ static int sta_apply_parameters(struct ieee80211_local *local, struct sta_info *sta, struct station_parameters *params) { - 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; - struct ieee80211_link_data *link; u32 mask, set; - - link = sdata_dereference(sdata->link[link_id], sdata); - if (!link) - return -ENOLINK; - - sband = ieee80211_get_link_sband(link); - if (!sband) - return -EINVAL; + int ret = 0; mask = params->sta_flags_mask; set = params->sta_flags_set; -- cgit v1.2.3 From 9f781533bb028edb3e8e10e79fb87e85a4dc6987 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 12 Jul 2022 12:22:50 +0300 Subject: wifi: mac80211: add macros to loop over active links Add a preliminary version which will be updated later to loop over vif's and sta's active links. Signed-off-by: Gregory Greenman Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1e04961148bf..f198af600b5e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1856,6 +1856,13 @@ struct ieee80211_vif { u8 drv_priv[] __aligned(sizeof(void *)); }; +/* FIXME: for now loop over all the available links; later will be changed + * to loop only over the active links. + */ +#define for_each_vif_active_link(vif, link, link_id) \ + for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \ + if ((link = rcu_dereference((vif)->link_conf[link_id]))) + static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) { #ifdef CONFIG_MAC80211_MESH @@ -2248,6 +2255,14 @@ struct ieee80211_sta { u8 drv_priv[] __aligned(sizeof(void *)); }; +/* FIXME: need to loop only over links which are active and check the actual + * lock + */ +#define for_each_sta_active_link(sta, link_sta, link_id) \ + for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \ + if (((link_sta) = rcu_dereference_protected((sta)->link[link_id],\ + 1))) \ + /** * enum sta_notify_cmd - sta notify command * -- cgit v1.2.3 From a94c90d32193ceac2aa5fc36f3833deeeb85bf8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jul 2022 11:01:18 +0200 Subject: wifi: mac80211: mlme: fix disassoc with MLO In MLO we shouldn't call ieee80211_bss_info_change_notify(), call that only (for backward compatibility) without MLO, and otherwise ieee80211_vif_cfg_change_notify(). Similarly, ieee80211_reset_erp_info() only applies to the current link, and in MLO we assume the driver doesn't really need that. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8c614daedeb8..3d4ab711f0d1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2878,7 +2878,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta_info_flush(sdata); /* finally reset all BSS / config parameters */ - changed |= ieee80211_reset_erp_info(sdata); + if (!sdata->vif.valid_links) + changed |= ieee80211_reset_erp_info(sdata); ieee80211_led_assoc(local, 0); changed |= BSS_CHANGED_ASSOC; @@ -2920,10 +2921,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_QOS; /* The BSSID (not really interesting) and HT changed */ changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; + ieee80211_bss_info_change_notify(sdata, changed); + } else { + ieee80211_vif_cfg_change_notify(sdata, changed); } - ieee80211_bss_info_change_notify(sdata, changed); - /* disassociated - set to defaults now */ ieee80211_set_wmm_default(&sdata->deflink, false, false); -- cgit v1.2.3 From fa28981b35128132aeb69a0a2ea2ff1c49bea6d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jul 2022 11:15:20 +0200 Subject: wifi: mac80211: fix link data leak During the code reshuffling, I accidentally set this to NULL before using it, fix that to fix the link data leak. Fixes: d3e2439b0f33 ("wifi: mac80211: fix link manipulation") Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e544621ead0e..95b58c5cac07 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -514,18 +514,18 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, /* grab old links to free later */ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + if (rcu_access_pointer(sdata->link[link_id]) != &sdata->deflink) { + /* + * 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); + } + 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 */ -- cgit v1.2.3