mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 15:12:13 +02:00
- cfg80211: new APIs for NAN (Neighbor Aware Networking,
aka Wi-Fi Aware) so less work must be in firmware
- mt76:
- mt7996/mt7925 MLO fixes/improvements
- mt7996 NPU support (HW eth/wifi traffic offload)
- iwlwifi: UNII-9 and continuing UHR work
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmnFTegACgkQ10qiO8sP
aABpghAAmcubFELG/ivDfwujEXjeKRU4CGcFPWDnOwBo28w8bQ36SoKRh251BUSL
4XCEwZwPR2gFI77bJ7fLn1gsRNd8Cv+t8wsi2K3TV3bOy6wCxH85A7l4GmN5vGzP
9MLcAAT7R684YAC4gFAi3DqFmSucd/ZodAt93Cw7+ikXq2tvrbR5wgUv9AQ5mUIw
f5cqocOOv+4IbSL+r2cQnCAKLGWxVMJpoiWuAPpIQn7odcrncrhvBIG3l9ZC4KOL
BKiO+YpK8Yg3+uc9zrz+RwOcQx6TjzgAydFY/AnqOmGfQ2dGaWC/zy/5stCOVrfd
mAqw4jr14eAumUoHQoNrOBsWikuDBKmYMjHVObR3cKB9jJ/54CHtSYJVueg9gdhP
4+s5lNkX0zEt76wimYQRpCkYhalBUZMwUv3HFnab99PDDmWvNFS8uHi8i2g7U81i
yVdxI3MbQp2SRgJMDbKQPziSad1qJyIzg/LoN9fb6GV1DoNZ3IZabgVMOA2IoB0L
zYi3Yuyo63yhDh2Np9uzDsIRQAbTCdbou2fzPqy6CvOyG6JXxCI8PZpZAN7dqYxc
u8rljjaxQ4IYfBWrryFdHzIrYHJLo/B4g8kSFE+vzLiFblFmTxBoziHDWpJ4u5im
YTyOyBYAtzQf0l8cZPKzRq+AuVgIuJVNV/3zyxnoFxfqg/lUWNk=
=zap4
-----END PGP SIGNATURE-----
Merge tag 'wireless-next-2026-03-26' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says:
====================
A fairly big set of changes all over, notably with:
- cfg80211: new APIs for NAN (Neighbor Aware Networking,
aka Wi-Fi Aware) so less work must be in firmware
- mt76:
- mt7996/mt7925 MLO fixes/improvements
- mt7996 NPU support (HW eth/wifi traffic offload)
- iwlwifi: UNII-9 and continuing UHR work
* tag 'wireless-next-2026-03-26' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (230 commits)
wifi: mac80211: ignore reserved bits in reconfiguration status
wifi: cfg80211: allow protected action frame TX for NAN
wifi: ieee80211: Add some missing NAN definitions
wifi: nl80211: Add a notification to notify NAN channel evacuation
wifi: nl80211: add NL80211_CMD_NAN_ULW_UPDATE notification
wifi: nl80211: allow reporting spurious NAN Data frames
wifi: cfg80211: allow ToDS=0/FromDS=0 data frames on NAN data interfaces
wifi: nl80211: define an API for configuring the NAN peer's schedule
wifi: nl80211: add support for NAN stations
wifi: cfg80211: separately store HT, VHT and HE capabilities for NAN
wifi: cfg80211: add support for NAN data interface
wifi: cfg80211: make sure NAN chandefs are valid
wifi: cfg80211: Add an API to configure local NAN schedule
wifi: mac80211: cleanup error path of ieee80211_do_open
wifi: mac80211: extract channel logic from link logic
wifi: iwlwifi: mld: set RX_FLAG_RADIOTAP_TLV_AT_END generically
wifi: iwlwifi: reduce the number of prints upon firmware crash
wifi: iwlwifi: fix the description of SESSION_PROTECTION_CMD
wifi: iwlwifi: mld: introduce iwl_mld_vif_fw_id_valid
wifi: iwlwifi: mld: block EMLSR during TDLS connections
...
====================
Link: https://patch.msgid.link/20260326152021.305959-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
225 lines
5.3 KiB
C
225 lines
5.3 KiB
C
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
/*
|
|
* Copyright (C) 2024 Felix Fietkau <nbd@nbd.name>
|
|
*/
|
|
#include "mt76.h"
|
|
|
|
static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
|
|
{
|
|
struct mt76_phy *phy = dev->scan.phy;
|
|
struct cfg80211_scan_info info = {
|
|
.aborted = abort,
|
|
};
|
|
|
|
if (!phy)
|
|
return;
|
|
|
|
clear_bit(MT76_SCANNING, &phy->state);
|
|
|
|
if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel &&
|
|
!test_bit(MT76_MCU_RESET, &dev->phy.state)) {
|
|
mt76_set_channel(phy, &phy->main_chandef, false);
|
|
mt76_offchannel_notify(phy, false);
|
|
}
|
|
mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
|
|
memset(&dev->scan, 0, sizeof(dev->scan));
|
|
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
|
|
ieee80211_scan_completed(phy->hw, &info);
|
|
}
|
|
|
|
void mt76_abort_scan(struct mt76_dev *dev)
|
|
{
|
|
spin_lock_bh(&dev->scan_lock);
|
|
dev->scan.beacon_wait = false;
|
|
spin_unlock_bh(&dev->scan_lock);
|
|
|
|
cancel_delayed_work_sync(&dev->scan_work);
|
|
mt76_scan_complete(dev, true);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt76_abort_scan);
|
|
|
|
static void
|
|
mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
|
|
{
|
|
struct cfg80211_scan_request *req = dev->scan.req;
|
|
struct ieee80211_vif *vif = dev->scan.vif;
|
|
struct mt76_vif_link *mvif = dev->scan.mlink;
|
|
enum nl80211_band band = dev->scan.chan->band;
|
|
struct mt76_phy *phy = dev->scan.phy;
|
|
struct ieee80211_tx_info *info;
|
|
struct sk_buff *skb;
|
|
|
|
skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid,
|
|
ssid->ssid_len, req->ie_len);
|
|
if (!skb)
|
|
return;
|
|
|
|
if (is_unicast_ether_addr(req->bssid)) {
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
|
ether_addr_copy(hdr->addr1, req->bssid);
|
|
ether_addr_copy(hdr->addr3, req->bssid);
|
|
}
|
|
|
|
if (req->ie_len)
|
|
skb_put_data(skb, req->ie, req->ie_len);
|
|
|
|
skb->priority = 7;
|
|
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
|
|
|
rcu_read_lock();
|
|
|
|
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
|
|
goto out;
|
|
|
|
info = IEEE80211_SKB_CB(skb);
|
|
if (req->no_cck)
|
|
info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
|
|
info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK;
|
|
|
|
mt76_tx(phy, NULL, mvif->wcid, skb);
|
|
|
|
out:
|
|
rcu_read_unlock();
|
|
}
|
|
|
|
void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan)
|
|
{
|
|
struct mt76_phy *phy;
|
|
|
|
spin_lock(&dev->scan_lock);
|
|
|
|
if (!dev->scan.beacon_wait || dev->scan.beacon_received ||
|
|
dev->scan.chan != chan)
|
|
goto out;
|
|
|
|
phy = dev->scan.phy;
|
|
if (!phy)
|
|
goto out;
|
|
|
|
dev->scan.beacon_received = true;
|
|
ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0);
|
|
|
|
out:
|
|
spin_unlock(&dev->scan_lock);
|
|
}
|
|
|
|
void mt76_scan_work(struct work_struct *work)
|
|
{
|
|
struct mt76_dev *dev = container_of(work, struct mt76_dev,
|
|
scan_work.work);
|
|
struct cfg80211_scan_request *req = dev->scan.req;
|
|
struct cfg80211_chan_def chandef = {};
|
|
struct mt76_phy *phy = dev->scan.phy;
|
|
int duration = HZ / 9; /* ~110 ms */
|
|
bool beacon_rx, offchannel = true;
|
|
int i;
|
|
|
|
if (!phy || !req)
|
|
return;
|
|
|
|
spin_lock_bh(&dev->scan_lock);
|
|
beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received;
|
|
dev->scan.beacon_wait = false;
|
|
spin_unlock_bh(&dev->scan_lock);
|
|
|
|
if (beacon_rx)
|
|
goto probe;
|
|
|
|
if (dev->scan.chan_idx >= req->n_channels) {
|
|
mt76_scan_complete(dev, false);
|
|
return;
|
|
}
|
|
|
|
if (dev->scan.chan && phy->num_sta && phy->offchannel) {
|
|
dev->scan.chan = NULL;
|
|
mt76_set_channel(phy, &phy->main_chandef, false);
|
|
mt76_offchannel_notify(phy, false);
|
|
goto out;
|
|
}
|
|
|
|
dev->scan.chan = req->channels[dev->scan.chan_idx++];
|
|
offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef);
|
|
|
|
if (offchannel)
|
|
mt76_offchannel_notify(phy, true);
|
|
mt76_set_channel(phy, &chandef, offchannel);
|
|
|
|
if (!req->n_ssids)
|
|
goto out;
|
|
|
|
if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) {
|
|
spin_lock_bh(&dev->scan_lock);
|
|
dev->scan.beacon_received = false;
|
|
dev->scan.beacon_wait = true;
|
|
spin_unlock_bh(&dev->scan_lock);
|
|
goto out;
|
|
}
|
|
|
|
probe:
|
|
if (phy->offchannel)
|
|
duration = HZ / 16; /* ~60 ms */
|
|
local_bh_disable();
|
|
for (i = 0; i < req->n_ssids; i++)
|
|
mt76_scan_send_probe(dev, &req->ssids[i]);
|
|
local_bh_enable();
|
|
|
|
out:
|
|
if (dev->scan.chan && phy->offchannel)
|
|
duration = max_t(int, duration,
|
|
msecs_to_jiffies(req->duration +
|
|
(req->duration >> 5)));
|
|
|
|
ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, duration);
|
|
}
|
|
|
|
int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|
struct ieee80211_scan_request *req)
|
|
{
|
|
struct mt76_phy *phy = hw->priv;
|
|
struct mt76_dev *dev = phy->dev;
|
|
struct mt76_vif_link *mlink;
|
|
int ret = 0;
|
|
|
|
if (hw->wiphy->n_radio > 1) {
|
|
phy = dev->band_phys[req->req.channels[0]->band];
|
|
if (!phy)
|
|
return -EINVAL;
|
|
}
|
|
|
|
mutex_lock(&dev->mutex);
|
|
|
|
if (dev->scan.req || phy->roc_vif ||
|
|
test_bit(MT76_MCU_RESET, &dev->phy.state)) {
|
|
ret = -EBUSY;
|
|
goto out;
|
|
}
|
|
|
|
mlink = mt76_get_vif_phy_link(phy, vif);
|
|
if (IS_ERR(mlink)) {
|
|
ret = PTR_ERR(mlink);
|
|
goto out;
|
|
}
|
|
|
|
memset(&dev->scan, 0, sizeof(dev->scan));
|
|
dev->scan.req = &req->req;
|
|
dev->scan.vif = vif;
|
|
dev->scan.phy = phy;
|
|
dev->scan.mlink = mlink;
|
|
ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0);
|
|
|
|
out:
|
|
mutex_unlock(&dev->mutex);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt76_hw_scan);
|
|
|
|
void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
{
|
|
struct mt76_phy *phy = hw->priv;
|
|
|
|
mt76_abort_scan(phy->dev);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt76_cancel_hw_scan);
|