summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-01-12 17:02:02 -0800
committerJakub Kicinski <kuba@kernel.org>2026-01-12 17:02:02 -0800
commit669aa3e3faa8ae876c169cde5b234828275caef8 (patch)
treea834c4b24c8a5e463c13112f9998d6685857d96d /net
parent2f2d896ec59a11a9baaa56818466db7a3178c041 (diff)
parent46e7ced3ef5b56c90ae30634aade96d241a2dfef (diff)
downloadlinux-next-669aa3e3faa8ae876c169cde5b234828275caef8.tar.gz
linux-next-669aa3e3faa8ae876c169cde5b234828275caef8.zip
Merge tag 'wireless-next-2026-01-12' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says: ==================== First set of changes for the current -next cycle, of note: - ath12k gets an overhaul to support multi-wiphy device wiphy and pave the way for future device support in the same driver (rather than splitting to ath13k) - mac80211 gets some better iteration macros * tag 'wireless-next-2026-01-12' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (120 commits) wifi: mac80211: remove width argument from ieee80211_parse_bitrates wifi: mac80211_hwsim: remove NAN by default wifi: mac80211: improve station iteration ergonomics wifi: mac80211: improve interface iteration ergonomics wifi: cfg80211: include S1G_NO_PRIMARY flag when sending channel wifi: mac80211: unexport ieee80211_get_bssid() wl1251: Replace strncpy with strscpy in wl1251_acx_fw_version wifi: iwlegacy: 3945-rs: remove redundant pointer check in il3945_rs_tx_status() and il3945_rs_get_rate() wifi: mac80211: don't send an unused argument to ieee80211_check_combinations wifi: libertas: fix WARNING in usb_tx_block wifi: mwifiex: Allocate dev name earlier for interface workqueue name wifi: wlcore: sdio: Use pm_ptr instead of #ifdef CONFIG_PM wifi: cfg80211: Fix use_for flag update on BSS refresh wifi: brcmfmac: rename function that frees vif wifi: brcmfmac: fix/add kernel-doc comments wifi: mac80211: Update csa_finalize to use link_id wifi: cfg80211: add cfg80211_stop_link() for per-link teardown wifi: ath12k: Skip DP peer creation for scan vdev wifi: ath12k: move firmware stats request outside of atomic context wifi: ath12k: add the missing RCU lock in ath12k_dp_tx_free_txbuf() ... ==================== Link: https://patch.msgid.link/20260112185836.378736-3-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c21
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mlme.c2
-rw-r--r--net/mac80211/parse.c3
-rw-r--r--net/mac80211/util.c76
-rw-r--r--net/wireless/core.c24
-rw-r--r--net/wireless/core.h4
-rw-r--r--net/wireless/nl80211.c3
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/scan.c2
-rw-r--r--net/wireless/sysfs.c2
-rw-r--r--net/wireless/trace.h13
-rw-r--r--net/wireless/util.c5
13 files changed, 114 insertions, 46 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c81091a5cc3a..fe6be11a7f44 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2125,8 +2125,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
if (params->supported_rates &&
params->supported_rates_len &&
- !ieee80211_parse_bitrates(link->conf->chanreq.oper.width,
- sband, params->supported_rates,
+ !ieee80211_parse_bitrates(sband, params->supported_rates,
params->supported_rates_len,
&link_sta->pub->supp_rates[sband->band]))
return -EINVAL;
@@ -2987,8 +2986,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
return -EINVAL;
if (params->basic_rates) {
- if (!ieee80211_parse_bitrates(link->conf->chanreq.oper.width,
- wiphy->bands[sband->band],
+ if (!ieee80211_parse_bitrates(sband,
params->basic_rates,
params->basic_rates_len,
&link->conf->basic_rates))
@@ -4151,12 +4149,21 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
static void ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
{
struct ieee80211_sub_if_data *sdata = link_data->sdata;
+ int link_id = -1;
if (__ieee80211_csa_finalize(link_data)) {
sdata_info(sdata, "failed to finalize CSA on link %d, disconnecting\n",
link_data->link_id);
- cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev,
- GFP_KERNEL);
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_P2P_GO)
+ /*
+ * link_id is expected only for AP/P2P_GO type
+ * currently
+ */
+ link_id = link_data->link_id;
+
+ cfg80211_stop_link(sdata->local->hw.wiphy, &sdata->wdev,
+ link_id, GFP_KERNEL);
}
}
@@ -4400,7 +4407,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
goto out;
/* if reservation is invalid then this will fail */
- err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0, -1);
+ err = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
if (err) {
ieee80211_link_unreserve_chanctx(link_data);
goto out;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9d9313eee59f..649ea9d2ae9b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2660,8 +2660,7 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata);
u8 *ieee80211_ie_build_he_oper(u8 *pos, const struct cfg80211_chan_def *chandef);
u8 *ieee80211_ie_build_eht_oper(u8 *pos, const struct cfg80211_chan_def *chandef,
const struct ieee80211_sta_eht_cap *eht_cap);
-int ieee80211_parse_bitrates(enum nl80211_chan_width width,
- const struct ieee80211_supported_band *sband,
+int ieee80211_parse_bitrates(const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates);
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ad53dedd929c..ddff090e7dce 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1548,7 +1548,7 @@ static void ieee80211_assoc_add_rates(struct ieee80211_local *local,
* in the association request (e.g. D-Link DAP 1353 in
* b-only mode)...
*/
- ieee80211_parse_bitrates(width, sband,
+ ieee80211_parse_bitrates(sband,
assoc_data->supp_rates,
assoc_data->supp_rates_len,
&rates);
diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
index bfc4ecb7a048..667021bc60c6 100644
--- a/net/mac80211/parse.c
+++ b/net/mac80211/parse.c
@@ -1115,8 +1115,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
}
EXPORT_SYMBOL_IF_KUNIT(ieee802_11_parse_elems_full);
-int ieee80211_parse_bitrates(enum nl80211_chan_width width,
- const struct ieee80211_supported_band *sband,
+int ieee80211_parse_bitrates(const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates)
{
struct ieee80211_rate *br;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0c46009a3d63..7d7650c91f4f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -101,7 +101,6 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
return NULL;
}
-EXPORT_SYMBOL(ieee80211_get_bssid);
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
{
@@ -800,20 +799,56 @@ void ieee80211_iterate_active_interfaces_atomic(
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
-void ieee80211_iterate_active_interfaces_mtx(
- struct ieee80211_hw *hw, u32 iter_flags,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
- void *data)
+struct ieee80211_vif *
+__ieee80211_iterate_interfaces(struct ieee80211_hw *hw,
+ struct ieee80211_vif *prev,
+ u32 iter_flags)
{
+ bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
+ struct ieee80211_sub_if_data *sdata = NULL, *monitor;
struct ieee80211_local *local = hw_to_local(hw);
lockdep_assert_wiphy(hw->wiphy);
- __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
- iterator, data);
+ if (prev)
+ sdata = vif_to_sdata(prev);
+
+ monitor = rcu_dereference_check(local->monitor_sdata,
+ lockdep_is_held(&hw->wiphy->mtx));
+ if (monitor && monitor == sdata)
+ return NULL;
+
+ sdata = list_prepare_entry(sdata, &local->interfaces, list);
+ list_for_each_entry_continue(sdata, &local->interfaces, list) {
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_MONITOR:
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ continue;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ continue;
+ default:
+ break;
+ }
+ if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
+ active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+ continue;
+ if ((iter_flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) &&
+ !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+ continue;
+ if (ieee80211_sdata_running(sdata) || !active_only)
+ return &sdata->vif;
+ }
+
+ if (monitor && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
+ (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
+ monitor->flags & IEEE80211_SDATA_IN_DRIVER))
+ return &monitor->vif;
+
+ return NULL;
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_mtx);
+EXPORT_SYMBOL_GPL(__ieee80211_iterate_interfaces);
static void __iterate_stations(struct ieee80211_local *local,
void (*iterator)(void *data,
@@ -844,18 +879,29 @@ void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic);
-void ieee80211_iterate_stations_mtx(struct ieee80211_hw *hw,
- void (*iterator)(void *data,
- struct ieee80211_sta *sta),
- void *data)
+struct ieee80211_sta *
+__ieee80211_iterate_stations(struct ieee80211_hw *hw,
+ struct ieee80211_sta *prev)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta = NULL;
lockdep_assert_wiphy(local->hw.wiphy);
- __iterate_stations(local, iterator, data);
+ if (prev)
+ sta = container_of(prev, struct sta_info, sta);
+
+ sta = list_prepare_entry(sta, &local->sta_list, list);
+ list_for_each_entry_continue(sta, &local->sta_list, list) {
+ if (!sta->uploaded)
+ continue;
+
+ return &sta->sta;
+ }
+
+ return NULL;
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_mtx);
+EXPORT_SYMBOL_GPL(__ieee80211_iterate_stations);
struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
{
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 9a420d627d3c..d0c7d9ff03b3 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -347,7 +347,7 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
guard(wiphy)(&rdev->wiphy);
- cfg80211_leave(rdev, wdev);
+ cfg80211_leave(rdev, wdev, -1);
cfg80211_remove_virtual_intf(rdev, wdev);
}
}
@@ -1371,7 +1371,8 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
}
void cfg80211_leave(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev)
+ struct wireless_dev *wdev,
+ int link_id)
{
struct net_device *dev = wdev->netdev;
struct cfg80211_sched_scan_request *pos, *tmp;
@@ -1409,7 +1410,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
- cfg80211_stop_ap(rdev, dev, -1, true);
+ cfg80211_stop_ap(rdev, dev, link_id, true);
break;
case NL80211_IFTYPE_OCB:
cfg80211_leave_ocb(rdev, dev);
@@ -1430,27 +1431,34 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
}
}
-void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
- gfp_t gfp)
+void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int link_id, gfp_t gfp)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_event *ev;
unsigned long flags;
- trace_cfg80211_stop_iface(wiphy, wdev);
+ /* Only AP/GO interfaces may have a specific link_id */
+ if (WARN_ON_ONCE(link_id != -1 &&
+ wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO))
+ link_id = -1;
+
+ trace_cfg80211_stop_link(wiphy, wdev, link_id);
ev = kzalloc(sizeof(*ev), gfp);
if (!ev)
return;
ev->type = EVENT_STOPPED;
+ ev->link_id = link_id;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
queue_work(cfg80211_wq, &rdev->event_work);
}
-EXPORT_SYMBOL(cfg80211_stop_iface);
+EXPORT_SYMBOL(cfg80211_stop_link);
void cfg80211_init_wdev(struct wireless_dev *wdev)
{
@@ -1589,7 +1597,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break;
case NETDEV_GOING_DOWN:
scoped_guard(wiphy, &rdev->wiphy) {
- cfg80211_leave(rdev, wdev);
+ cfg80211_leave(rdev, wdev, -1);
cfg80211_remove_links(wdev);
}
/* since we just did cfg80211_leave() nothing to do there */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 63dcf315dba7..6ac57b7b2615 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -289,6 +289,7 @@ struct cfg80211_event {
u8 td_bitmap_len;
} pa;
};
+ int link_id;
};
struct cfg80211_cached_keys {
@@ -537,7 +538,8 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
void cfg80211_leave(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev);
+ struct wireless_dev *wdev,
+ int link_id);
void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c961cd42a832..225580507a4b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1314,6 +1314,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
if ((chan->flags & IEEE80211_CHAN_NO_16MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_16MHZ))
goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_S1G_NO_PRIMARY) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_S1G_NO_PRIMARY))
+ goto nla_put_failure;
}
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 73cab51f6379..a8ab0ab22d90 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2442,7 +2442,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy)
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
if (!reg_wdev_chan_valid(wiphy, wdev))
- cfg80211_leave(rdev, wdev);
+ cfg80211_leave(rdev, wdev, -1);
}
static void reg_check_chans_work(struct work_struct *work)
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 7546647752fd..eb0e77813d46 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1959,7 +1959,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
ether_addr_copy(known->parent_bssid, new->parent_bssid);
known->pub.max_bssid_indicator = new->pub.max_bssid_indicator;
known->pub.bssid_index = new->pub.bssid_index;
- known->pub.use_for &= new->pub.use_for;
+ known->pub.use_for = new->pub.use_for;
known->pub.cannot_use_reasons = new->pub.cannot_use_reasons;
known->bss_source = new->bss_source;
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 8d142856e385..2e0ea69b9604 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -88,7 +88,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
struct wireless_dev *wdev;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
- cfg80211_leave(rdev, wdev);
+ cfg80211_leave(rdev, wdev, -1);
}
static int wiphy_suspend(struct device *dev)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 2b71f1d867a0..643ccf4f0227 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3915,19 +3915,22 @@ TRACE_EVENT(cfg80211_ft_event,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->target_ap)
);
-TRACE_EVENT(cfg80211_stop_iface,
- TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
- TP_ARGS(wiphy, wdev),
+TRACE_EVENT(cfg80211_stop_link,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int link_id),
+ TP_ARGS(wiphy, wdev, link_id),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
+ __field(int, link_id)
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
+ __entry->link_id = link_id;
),
- TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
- WIPHY_PR_ARG, WDEV_PR_ARG)
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id)
);
TRACE_EVENT(cfg80211_pmsr_report,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 27e8a2f52f04..cc55b759694e 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1144,7 +1144,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
ev->ij.channel);
break;
case EVENT_STOPPED:
- cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
+ cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev,
+ ev->link_id);
break;
case EVENT_PORT_AUTHORIZED:
__cfg80211_port_authorized(wdev, ev->pa.peer_addr,
@@ -1203,7 +1204,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
dev->ieee80211_ptr->use_4addr = false;
rdev_set_qos_map(rdev, dev, NULL);
- cfg80211_leave(rdev, dev->ieee80211_ptr);
+ cfg80211_leave(rdev, dev->ieee80211_ptr, -1);
cfg80211_process_rdev_events(rdev);
cfg80211_mlme_purge_registrations(dev->ieee80211_ptr);