| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/24 22:58 | flow | patch-triage |
6mArgs:null Results: {
"EnableConfigs": [
"MT7925U",
"MT7925E"
],
"FocusSymbols": [
"mt7925_nan_deferred_work",
"mt7925_nan_update_phy_setting",
"mt7925_nan_seed_link_sta",
"mt7925_nan_enable",
"mt7925_nan_disable",
"mt7925_nan_mcu_event",
"mt7925_nan_local_sched_changed",
"mt792x_nan_set_peer_schedule",
"mt792x_nan_set_peer_rec",
"mt792x_nan_map_sta_rec"
],
"KMSANReasoning": "The patch modifies the mt7925 driver to add new features and fixes related to NAN (Neighbor Awareness Networking). It introduces new structures sent to the firmware (e.g., `mt7925_nan_update_phy_setting_tlv`, `mt7925_nan_update_ulw_tlv`, `mt7925_nan_sched_update_crb_tlv`) and one structure sent to user space (`mt7925_nan_ulw_attr` via `cfg80211_nan_ulw_update`). \n\nAll structures sent to the firmware are either explicitly zero-initialized (e.g., `req = {}` in `mt7925_nan_update_phy_setting`) or allocated using `mt76_connac_mcu_add_tlv`, which internally uses `skb_put_zero` to fully zero-initialize the TLV payload before specific fields are assigned. \n\nThe structure sent to user space (`mt7925_nan_ulw_attr`) is a `__packed` struct allocated on the stack in `mt7925_nan_handle_ulw_update`. All 9 of its fields are explicitly assigned before it is passed to `cfg80211_nan_ulw_update`, ensuring no uninitialized stack memory or padding bytes are leaked to user space.\n\nThe deferred work mechanism (`mt7925_nan_deferred_work`) uses `cluster_id` copied from `dev-\u003enan_started_cluster_id`. The `dev` structure is allocated with `kzalloc` (via `ieee80211_alloc_hw`), so `nan_started_cluster_id` is zero-initialized. It is only used if the `MT7925_NAN_DEFERRED_STARTED_CLUSTER` bit is set, which only happens after it has been populated with data from the firmware.\n\nSince all stack and heap structures introduced or modified by this patch are fully initialized or zeroed before being read, copied, or sent to user space/firmware, there is no risk of uninitialized memory usage or info-leaks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or memory corruption bugs. A dedicated KMSAN fuzzing session is not justified.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies NAN (Neighbor Awareness Networking) functionality in the MediaTek MT7925 Wi-Fi driver. It adds deferred work for NAN events, updates PHY settings, and refactors NAN enable/disable and peer scheduling logic. The driver supports USB (MT7925U) which can be emulated and fuzzed via syzkaller's USB gadget framework, making these changes reachable and worth fuzzing.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/24 22:58 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit d5bb2726534f601faa0c0ec8575f8d350eed3738\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Aug 24 22:58:34 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c\nindex cd22fcc021b1e..8c3049b66a857 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c\n@@ -270,6 +270,8 @@ int mt7925_register_device(struct mt792x_dev *dev)\n \n \tINIT_WORK(\u0026dev-\u003ereset_work, mt7925_mac_reset_work);\n \tINIT_WORK(\u0026dev-\u003einit_work, mt7925_init_work);\n+\tINIT_WORK(\u0026dev-\u003enan_deferred_work, mt7925_nan_deferred_work);\n+\tspin_lock_init(\u0026dev-\u003enan_deferred_lock);\n \n \tINIT_WORK(\u0026dev-\u003ephy.roc_work, mt7925_roc_work);\n \ttimer_setup(\u0026dev-\u003ephy.roc_timer, mt792x_roc_timer, 0);\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c\nindex 84b55f008b3d3..051a0c8aed587 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c\n@@ -964,6 +964,21 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,\n \n \tlink_conf = mt792x_vif_to_bss_conf(vif, link_id);\n \n+\t/* NAN_DATA (NDI) peers skip association - fill link_sta caps\n+\t * from sband and push BSS_INFO with correct phymode + RLM.\n+\t */\n+\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\n+\t\tstruct ieee80211_chanctx_conf *nan_ctx;\n+\n+\t\tnan_ctx = mt7925_nan_seed_link_sta(dev, link_sta);\n+\t\tmconf-\u003emt76.ctx = nan_ctx;\n+\n+\t\tret = mt7925_mcu_add_bss_info(\u0026dev-\u003ephy, nan_ctx,\n+\t\t\t\t\t link_conf, link_sta, true);\n+\t\tif (ret)\n+\t\t\tgoto out_pm;\n+\t}\n+\n \t/* should update bss info before STA add */\n \tif (vif-\u003etype == NL80211_IFTYPE_STATION \u0026\u0026 !link_sta-\u003esta-\u003etdls) {\n \t\tstruct mt792x_link_sta *mlink_bc;\n@@ -2587,26 +2602,18 @@ static int mt7925_start_nan(struct ieee80211_hw *hw,\n \tcfg80211_chandef_create(\u0026link_conf-\u003echanreq.oper, chan,\n \t\t\t\tNL80211_CHAN_NO_HT);\n \n-\terr = mt7925_mcu_add_bss_info(\u0026dev-\u003ephy, NULL, link_conf,\n-\t\t\t\t NULL, true);\n+\terr = mt7925_mcu_add_bss_info(\u0026dev-\u003ephy, NULL,\n+\t\t\t\t link_conf, NULL, true);\n \tif (err \u003c 0)\n \t\tgoto out;\n \n-\tdev-\u003enan_vif = vif;\n-\n-\terr = mt7925_nan_set_nmi_addr(dev, vif-\u003eaddr);\n-\tif (err)\n-\t\tgoto rollback_bss;\n-\n \terr = mt7925_nan_enable(vif, dev, conf);\n-\tif (err)\n-\t\tgoto rollback_bss;\n-\n-\tgoto out;\n+\tif (err) {\n+\t\tmt7925_mcu_add_bss_info(\u0026dev-\u003ephy, NULL, link_conf, NULL, false);\n+\t\tgoto out;\n+\t}\n \n-rollback_bss:\n-\tdev-\u003enan_vif = NULL;\n-\tmt7925_mcu_add_bss_info(\u0026dev-\u003ephy, NULL, link_conf, NULL, false);\n+\terr = mt7925_nan_update_phy_setting(dev);\n \n out:\n \tmt792x_mutex_release(dev);\n@@ -2621,6 +2628,13 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,\n \tstruct mt792x_dev *dev = mt792x_hw_dev(hw);\n \tint err, ret;\n \n+\t/* Drop a deferred event queued just before stop so a stale cluster_id\n+\t * cannot leak into a restart; the work re-checks liveness anyway.\n+\t */\n+\tspin_lock_bh(\u0026dev-\u003enan_deferred_lock);\n+\tdev-\u003enan_deferred_pending = 0;\n+\tspin_unlock_bh(\u0026dev-\u003enan_deferred_lock);\n+\n \tmt792x_mutex_acquire(dev);\n \n \terr = mt7925_nan_disable(vif, dev);\n@@ -2630,9 +2644,6 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,\n \tif (!err)\n \t\terr = ret;\n \n-\tif (dev-\u003enan_vif == vif)\n-\t\tdev-\u003enan_vif = NULL;\n-\n \tmt792x_mutex_release(dev);\n \n \treturn err;\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c\nindex fa29c486a4553..1cfc209f9be5c 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c\n@@ -1914,11 +1914,9 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,\n \tphy = (struct sta_rec_phy *)tlv;\n \n \tif (mt7925_vif_is_nan(vif)) {\n-\t\tenum nl80211_band band = chandef-\u003echan ? chandef-\u003echan-\u003eband\n-\t\t\t\t\t\t : NL80211_BAND_2GHZ;\n \t\tphy-\u003ephy_type = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_ERP;\n \t\tphy-\u003ephy_type |= mt76_connac_get_phy_mode_v2(mvif-\u003ephy-\u003emt76, vif,\n-\t\t\t\t\t\t\t band,\n+\t\t\t\t\t\t\t NL80211_BAND_5GHZ,\n \t\t\t\t\t\t\t link_sta);\n \t} else {\n \t\tphy-\u003ephy_type = mt76_connac_get_phy_mode_v2(mvif-\u003ephy-\u003emt76, vif,\n@@ -2003,7 +2001,11 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,\n \tra_info = (struct sta_rec_ra_info *)tlv;\n \n \tif (mt7925_vif_is_nan(vif))\n-\t\tband = chandef-\u003echan ? chandef-\u003echan-\u003eband : NL80211_BAND_2GHZ;\n+\t\t/* NAN is OFDM-only per spec; borrow the 5 GHz band lookup to\n+\t\t * avoid PHY_TYPE_BIT_HR_DSSS/CCK bits being added to phy_type.\n+\t\t * NAN interfaces have no chanctx, so chandef-\u003echan is always NULL.\n+\t\t */\n+\t\tband = NL80211_BAND_5GHZ;\n \telse\n \t\tband = chandef-\u003echan-\u003eband;\n \n@@ -2847,7 +2849,7 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy,\n \tbmc = (struct bss_rate_tlv *)tlv;\n \n \tif (mt7925_vif_is_nan(vif))\n-\t\tband = chandef-\u003echan ? chandef-\u003echan-\u003eband : NL80211_BAND_2GHZ;\n+\t\tband = NL80211_BAND_5GHZ;\n \telse\n \t\tband = chandef-\u003echan-\u003eband;\n \ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h\nindex 321e732347f2f..33782d9ba9ed4 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h\n@@ -361,6 +361,7 @@ void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac,\n void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac,\n \t\t\t\t\tstruct ieee80211_vif *vif);\n void mt7925_set_ipv6_ns_work(struct work_struct *work);\n+void mt7925_nan_deferred_work(struct work_struct *work);\n \n int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,\n \t\t\t bool enable);\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c\nindex d260e803d056f..8a59f7b1aee25 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c\n@@ -32,8 +32,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,\n \tif (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan))\n \t\treturn;\n \n-\treq-\u003econfig_support_5g = 1;\n-\treq-\u003esupport_5g_val = 1;\n \treq-\u003econfig_5g_channel = 1;\n \n \tif (chan-\u003ehw_value == NAN_5G_LOW_DISC_CHANNEL)\n@@ -44,73 +42,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,\n \treq-\u003echannel_5g_val = cpu_to_le32(ch5g);\n }\n \n-static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req,\n-\t\t\t\t struct cfg80211_nan_conf *conf)\n-{\n-\tif (!conf-\u003eband_cfgs[NL80211_BAND_2GHZ].chan)\n-\t\treturn;\n-\n-\treq-\u003econfig_2dot4g_support = 1;\n-\treq-\u003esupport_2dot4g_val = 1;\n-}\n-\n-static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req,\n-\t\t\t\t const u8 *cluster_id)\n-{\n-\tif (!cluster_id)\n-\t\treturn;\n-\n-\treq-\u003ecluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] \u003c\u003c 8);\n-\treq-\u003ecluster_low = cpu_to_le16((u16)cluster_id[3]);\n-}\n-\n-static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req,\n-\t\t\t\t struct cfg80211_nan_conf *conf)\n-{\n-\tif (conf-\u003eband_cfgs[NL80211_BAND_2GHZ].awake_dw_interval \u003e 0) {\n-\t\treq-\u003econfig_dw.config_2dot4g_dw_band = 1;\n-\t\treq-\u003econfig_dw.dw_2dot4g_interval_val =\n-\t\t\tcpu_to_le32(conf-\u003eband_cfgs[NL80211_BAND_2GHZ].awake_dw_interval);\n-\t}\n-\n-\tif (conf-\u003eband_cfgs[NL80211_BAND_5GHZ].awake_dw_interval \u003e 0) {\n-\t\treq-\u003econfig_dw.config_5g_dw_band = 1;\n-\t\treq-\u003econfig_dw.dw_5g_interval_val =\n-\t\t\tcpu_to_le32(conf-\u003eband_cfgs[NL80211_BAND_5GHZ].awake_dw_interval);\n-\t}\n-}\n-\n-static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req,\n-\t\t\t\t struct cfg80211_nan_conf *conf)\n-{\n-\tif (conf-\u003ediscovery_beacon_interval \u003e 0) {\n-\t\treq-\u003econfig_2dot4g_beacons = true;\n-\t\treq-\u003ebeacon_2dot4g_val = conf-\u003ediscovery_beacon_interval;\n-\t}\n-}\n-\n-static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req,\n-\t\t\t\t\t struct cfg80211_nan_conf *conf)\n-{\n-\tif (conf-\u003eband_cfgs[NL80211_BAND_2GHZ].chan) {\n-\t\treq-\u003econfig_2dot4g_rssi_close = 1;\n-\t\treq-\u003erssi_close_2dot4g_val =\n-\t\t\tabs(conf-\u003eband_cfgs[NL80211_BAND_2GHZ].rssi_close);\n-\t\treq-\u003econfig_2dot4g_rssi_middle = 1;\n-\t\treq-\u003erssi_middle_2dot4g_val =\n-\t\t\tabs(conf-\u003eband_cfgs[NL80211_BAND_2GHZ].rssi_middle);\n-\t}\n-\n-\tif (conf-\u003eband_cfgs[NL80211_BAND_5GHZ].chan) {\n-\t\treq-\u003econfig_5g_rssi_close = 1;\n-\t\treq-\u003erssi_close_5g_val =\n-\t\t\tabs(conf-\u003eband_cfgs[NL80211_BAND_5GHZ].rssi_close);\n-\t\treq-\u003econfig_5g_rssi_middle = 1;\n-\t\treq-\u003erssi_middle_5g_val =\n-\t\t\tabs(conf-\u003eband_cfgs[NL80211_BAND_5GHZ].rssi_middle);\n-\t}\n-}\n-\n static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req,\n \t\t\t\t struct cfg80211_nan_conf *conf)\n {\n@@ -144,101 +75,6 @@ mt7925_nan_update_conf(struct mt792x_vif *mvif,\n \tmemcpy(mvif-\u003enan.conf.cluster_id, conf-\u003ecluster_id, ETH_ALEN);\n }\n \n-int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr)\n-{\n-\tstruct mt76_dev *mdev;\n-\tstruct {\n-\t\tu8 rsv[4];\n-\t\tstruct mt7925_nan_nmi_addr_tlv nmi_addr_tlv;\n-\t} nmi_cmd = {\n-\t\t.rsv = { 0 },\n-\t\t.nmi_addr_tlv = {\n-\t\t\t.tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS),\n-\t\t\t.len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)),\n-\t\t},\n-\t};\n-\tint ret;\n-\n-\tif (!dev || !addr)\n-\t\treturn -EINVAL;\n-\n-\tif (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) {\n-\t\tdev_err(dev-\u003emt76.dev, \"NAN: invalid NMI address %pM\\n\", addr);\n-\t\treturn -EINVAL;\n-\t}\n-\n-\tmdev = \u0026dev-\u003emt76;\n-\tmemcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN);\n-\n-\tret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), \u0026nmi_cmd,\n-\t\t\t\tsizeof(nmi_cmd), true);\n-\n-\treturn ret;\n-}\n-\n-int mt7925_nan_enable(struct ieee80211_vif *vif,\n-\t\t struct mt792x_dev *dev,\n-\t\t struct cfg80211_nan_conf *conf)\n-{\n-\tstruct mt792x_vif *mvif = (struct mt792x_vif *)vif-\u003edrv_priv;\n-\tstruct mt76_dev *mdev = \u0026dev-\u003emt76;\n-\tstruct {\n-\t\tu8 rsv[4];\n-\t\tstruct mt7925_nan_enable_req_tlv nan_req_tlv;\n-\t} nan_cmd = {\n-\t\t.rsv = { 0 },\n-\t\t.nan_req_tlv = {\n-\t\t\t.tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST),\n-\t\t\t.len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)),\n-\t\t\t.config_random_factor_force = 0,\n-\t\t\t.random_factor_force_val = 0,\n-\t\t\t.config_hop_count_force = 0,\n-\t\t\t.hop_count_force_val = 0,\n-\t\t},\n-\t};\n-\tstruct mt7925_nan_enable_req_tlv *p_nan_req_tlv = \u0026nan_cmd.nan_req_tlv;\n-\tint ret;\n-\n-\tif (!vif || !dev || !conf)\n-\t\treturn -EINVAL;\n-\n-\tp_nan_req_tlv-\u003emaster_pref = conf-\u003emaster_pref;\n-\n-\tmt7925_nan_set_2g_support(p_nan_req_tlv, conf);\n-\tmt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf);\n-\tmt7925_nan_set_cluster_id(p_nan_req_tlv, conf-\u003ecluster_id);\n-\tmt7925_nan_set_dw_interval(p_nan_req_tlv, conf);\n-\tmt7925_nan_set_disc_beacon(p_nan_req_tlv, conf);\n-\tmt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf);\n-\tmt7925_nan_set_scan_params(p_nan_req_tlv, conf);\n-\n-\tmt7925_nan_update_conf(mvif, conf);\n-\n-\tret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), \u0026nan_cmd, sizeof(nan_cmd), true);\n-\n-\treturn ret;\n-}\n-\n-int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)\n-{\n-\tstruct mt76_dev *mdev = \u0026dev-\u003emt76;\n-\tstruct {\n-\t\tu8 rsv[4];\n-\t\tstruct tlv nan_dis_tlv;\n-\t} nan_cmd = {\n-\t\t.rsv = { 0 },\n-\t\t.nan_dis_tlv = {\n-\t\t\t.tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),\n-\t\t\t.len = cpu_to_le16(sizeof(struct tlv)),\n-\t\t},\n-\t};\n-\n-\tif (!dev)\n-\t\treturn -EINVAL;\n-\n-\treturn mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), \u0026nan_cmd, sizeof(nan_cmd), true);\n-}\n-\n static int\n mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)\n {\n@@ -357,6 +193,213 @@ mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)\n \treturn 0;\n }\n \n+/* FW rate set bit definitions (matches FW wlan_def_cmm.h) */\n+#define NAN_RATE_SET_BIT_1M\tBIT(0)\n+#define NAN_RATE_SET_BIT_2M\tBIT(1)\n+#define NAN_RATE_SET_BIT_5_5M\tBIT(2)\n+#define NAN_RATE_SET_BIT_11M\tBIT(3)\n+#define NAN_RATE_SET_BIT_6M\tBIT(6)\n+#define NAN_RATE_SET_BIT_9M\tBIT(7)\n+#define NAN_RATE_SET_BIT_12M\tBIT(8)\n+#define NAN_RATE_SET_BIT_18M\tBIT(9)\n+#define NAN_RATE_SET_BIT_24M\tBIT(10)\n+#define NAN_RATE_SET_BIT_36M\tBIT(11)\n+#define NAN_RATE_SET_BIT_48M\tBIT(12)\n+#define NAN_RATE_SET_BIT_54M\tBIT(13)\n+\n+#define NAN_RATE_SET_ALL_A\t(NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_9M | \\\n+\t\t\t\t NAN_RATE_SET_BIT_12M | NAN_RATE_SET_BIT_18M | \\\n+\t\t\t\t NAN_RATE_SET_BIT_24M | NAN_RATE_SET_BIT_36M | \\\n+\t\t\t\t NAN_RATE_SET_BIT_48M | NAN_RATE_SET_BIT_54M)\n+\n+/* 5G basic: 6M+12M+24M (OFDM) */\n+#define NAN_BASIC_RATE_SET_5G\t(NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_12M | \\\n+\t\t\t\t NAN_RATE_SET_BIT_24M)\n+\n+/* GF_MODE_DISALLOWED = 2, RIFS_MODE_DISALLOWED = 1 */\n+#define NAN_GF_MODE_DISALLOWED\t\t2\n+#define NAN_RIFS_MODE_DISALLOWED\t1\n+\n+int mt7925_nan_update_phy_setting(struct mt792x_dev *dev)\n+{\n+\tstruct mt76_phy *mphy = \u0026dev-\u003emphy;\n+\tstruct ieee80211_supported_band *sband_5g;\n+\tstruct mt7925_nan_phy_setting *phy;\n+\tstruct {\n+\t\tu8 rsv[4];\n+\t\tstruct mt7925_nan_update_phy_setting_tlv tlv;\n+\t} req = {};\n+\n+\tsband_5g = mphy-\u003ehw-\u003ewiphy-\u003ebands[NL80211_BAND_5GHZ];\n+\n+\treq.tlv.tag = cpu_to_le16(NAN_UNI_CMD_UPDATE_PHY_SETTING);\n+\treq.tlv.len = cpu_to_le16(sizeof(req.tlv));\n+\n+\t/* 2G: ERP + HT (no CCK/HR_DSSS - NAN uses OFDM only) */\n+\tphy = \u0026req.tlv.phy_2g;\n+\tphy-\u003ephy_type_set = PHY_TYPE_BIT_ERP | PHY_TYPE_BIT_HT;\n+\tphy-\u003enon_ht_basic_phy_type = PHY_TYPE_ERP_INDEX;\n+\tphy-\u003euse_short_preamble = 1;\n+\tphy-\u003euse_short_slot_time = 1;\n+\tphy-\u003eoperational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);\n+\tphy-\u003ebss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);\n+\tphy-\u003egf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);\n+\tphy-\u003erifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);\n+\n+\t/* 5G: OFDM + HT + VHT (NAN_MODE_11A) */\n+\tphy = \u0026req.tlv.phy_5g;\n+\tphy-\u003ephy_type_set = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HT |\n+\t\t\t PHY_TYPE_BIT_VHT;\n+\tphy-\u003enon_ht_basic_phy_type = PHY_TYPE_OFDM_INDEX;\n+\tphy-\u003euse_short_preamble = 1;\n+\tphy-\u003euse_short_slot_time = 1;\n+\tphy-\u003eoperational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);\n+\tphy-\u003ebss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);\n+\tphy-\u003egf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);\n+\tphy-\u003erifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);\n+\n+\t/* VHT basic MCS set from sband capability */\n+\tif (sband_5g \u0026\u0026 sband_5g-\u003evht_cap.vht_supported)\n+\t\tphy-\u003evht_basic_mcs_set =\n+\t\t\tsband_5g-\u003evht_cap.vht_mcs.rx_mcs_map;\n+\n+\treturn mt76_mcu_send_msg(\u0026dev-\u003emt76, MCU_UNI_CMD(NAN),\n+\t\t\t\t \u0026req, sizeof(req), true);\n+}\n+\n+struct ieee80211_chanctx_conf *\n+mt7925_nan_seed_link_sta(struct mt792x_dev *dev,\n+\t\t\t struct ieee80211_link_sta *link_sta)\n+{\n+\tstruct ieee80211_supported_band *sband_2g, *sband_5g;\n+\tstruct ieee80211_chanctx_conf *nan_ctx = NULL;\n+\tstruct ieee80211_vif *nan_vif = dev-\u003enan_vif;\n+\n+\t/* Fill HT cap from 2G sband */\n+\tsband_2g = dev-\u003emphy.hw-\u003ewiphy-\u003ebands[NL80211_BAND_2GHZ];\n+\tsband_5g = dev-\u003emphy.hw-\u003ewiphy-\u003ebands[NL80211_BAND_5GHZ];\n+\tif (sband_2g)\n+\t\tlink_sta-\u003eht_cap = sband_2g-\u003eht_cap;\n+\n+\tlink_sta-\u003esta-\u003ewme = true;\n+\tlink_sta-\u003erx_nss = hweight8(dev-\u003emphy.antenna_mask);\n+\n+\t/* Get chanctx from NAN schedule.\n+\t * Prefer 5G committed slot for wider BW (VHT), fallback\n+\t * to first valid slot if no 5G data slot is scheduled.\n+\t */\n+\tif (nan_vif) {\n+\t\tstruct ieee80211_nan_channel **slots =\n+\t\t\tnan_vif-\u003ecfg.nan_sched.schedule;\n+\t\tint i;\n+\n+\t\tfor (i = 0; i \u003c CFG80211_NAN_SCHED_NUM_TIME_SLOTS; i++) {\n+\t\t\tstruct ieee80211_chanctx_conf *ctx;\n+\n+\t\t\tif (!slots[i] || IS_ERR(slots[i]) ||\n+\t\t\t !slots[i]-\u003echanctx_conf)\n+\t\t\t\tcontinue;\n+\n+\t\t\tctx = slots[i]-\u003echanctx_conf;\n+\t\t\tif (!nan_ctx)\n+\t\t\t\tnan_ctx = ctx;\n+\t\t\tif (ctx-\u003edef.chan-\u003eband == NL80211_BAND_5GHZ) {\n+\t\t\t\tnan_ctx = ctx;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Capability describes what the device can do and must not be\n+\t * filtered by the current schedule - firmware gates the VHT rate\n+\t * mode per the data schedule and re-derives it on schedule\n+\t * change, which only works if the caps are present up front.\n+\t */\n+\tif (sband_5g)\n+\t\tlink_sta-\u003evht_cap = sband_5g-\u003evht_cap;\n+\n+\t/* Bandwidth here is the capability ceiling, not the operating\n+\t * width - the per-slot operating bandwidth follows the current\n+\t * slot channel via the firmware RLM sync, so deriving it from\n+\t * the schedule at STA-add time would cap a later 5 GHz schedule\n+\t * at the bring-up width.\n+\t */\n+\tlink_sta-\u003ebandwidth = IEEE80211_STA_RX_BW_80;\n+\n+\treturn nan_ctx;\n+}\n+\n+int mt7925_nan_enable(struct ieee80211_vif *vif,\n+\t\t struct mt792x_dev *dev,\n+\t\t struct cfg80211_nan_conf *conf)\n+{\n+\tstruct mt792x_vif *mvif = (struct mt792x_vif *)vif-\u003edrv_priv;\n+\tstruct mt76_dev *mdev = \u0026dev-\u003emt76;\n+\tstruct mt7925_nan_common_hdr *hdr;\n+\tstruct mt7925_nan_enable_req_tlv *req;\n+\tstruct sk_buff *skb;\n+\n+\tif (!vif || !dev || !conf)\n+\t\treturn -EINVAL;\n+\n+\tskb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_ENABLE_MAX_SIZE);\n+\tif (!skb)\n+\t\treturn -ENOMEM;\n+\n+\thdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));\n+\tmemset(hdr, 0, sizeof(*hdr));\n+\n+\t/* Set cluster id before joining cluster */\n+\tif (mt7925_nan_cluster_id_tlv(skb, conf-\u003ecluster_id)) {\n+\t\tdev_kfree_skb(skb);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\t/* NAN enable request tlv */\n+\treq = (struct mt7925_nan_enable_req_tlv *)\n+\t\tmt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_ENABLE_REQUEST,\n+\t\t\t\t\tsizeof(*req));\n+\tif (!req) {\n+\t\tdev_kfree_skb(skb);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treq-\u003emaster_pref = conf-\u003emaster_pref;\n+\n+\tmt7925_nan_set_5g_channel(dev, req, conf);\n+\tmt7925_nan_set_scan_params(req, conf);\n+\n+\tif (mt7925_nan_dw_tlv(skb, conf) ||\n+\t mt7925_nan_sync_rssi_tlv(skb, conf)) {\n+\t\tdev_kfree_skb(skb);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tmt7925_nan_update_conf(mvif, conf);\n+\n+\treturn mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);\n+}\n+\n+int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)\n+{\n+\tstruct mt76_dev *mdev = \u0026dev-\u003emt76;\n+\tstruct {\n+\t\tu8 rsv[4];\n+\t\tstruct tlv nan_dis_tlv;\n+\t} nan_cmd = {\n+\t\t.rsv = { 0 },\n+\t\t.nan_dis_tlv = {\n+\t\t\t.tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),\n+\t\t\t.len = cpu_to_le16(sizeof(struct tlv)),\n+\t\t},\n+\t};\n+\n+\tif (!dev)\n+\t\treturn -EINVAL;\n+\n+\treturn mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), \u0026nan_cmd, sizeof(nan_cmd), true);\n+}\n+\n int mt7925_nan_change_configure(struct ieee80211_vif *vif,\n \t\t\t\tstruct mt792x_dev *dev,\n \t\t\t\tstruct cfg80211_nan_conf *conf)\n@@ -473,8 +516,26 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)\n \tdev_dbg(dev-\u003emt76.dev, \"nan: evt=%u cluster=%pM\\n\",\n \t\tde_evt-\u003eevent_type, de_evt-\u003ecluster_id);\n \n-\tif (de_evt-\u003eevent_type != NAN_EVENT_ID_JOINED_CLUSTER)\n+\tif (de_evt-\u003eevent_type != NAN_EVENT_ID_JOINED_CLUSTER \u0026\u0026\n+\t de_evt-\u003eevent_type != NAN_EVENT_ID_STARTED_CLUSTER)\n+\t\treturn;\n+\n+\t/* STARTED_CLUSTER fires during NAN_START, before nan.started is set and\n+\t * before the supplicant subscribes - defer past NAN_START via the work\n+\t * so ieee80211_nan_cluster_joined() actually reaches userspace.\n+\t */\n+\tif (de_evt-\u003eevent_type == NAN_EVENT_ID_STARTED_CLUSTER) {\n+\t\tdev_dbg(dev-\u003emt76.dev,\n+\t\t\t\"nan: deferring STARTED_CLUSTER cluster=%pM\\n\",\n+\t\t\tcluster_id);\n+\t\tspin_lock_bh(\u0026dev-\u003enan_deferred_lock);\n+\t\tmemcpy(dev-\u003enan_started_cluster_id, cluster_id, ETH_ALEN);\n+\t\tset_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER,\n+\t\t\t\u0026dev-\u003enan_deferred_pending);\n+\t\tspin_unlock_bh(\u0026dev-\u003enan_deferred_lock);\n+\t\tieee80211_queue_work(dev-\u003emt76.hw, \u0026dev-\u003enan_deferred_work);\n \t\treturn;\n+\t}\n \n \tif (!dev-\u003enan_vif || !ieee80211_vif_nan_started(dev-\u003enan_vif)) {\n \t\tdev_warn(dev-\u003emt76.dev, \"nan: joined-cluster event but NAN not started\\n\");\n@@ -487,7 +548,110 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)\n \tdev_dbg(dev-\u003emt76.dev, \"nan: own_nmi=%pM master_nmi=%pM\\n\",\n \t\tde_evt-\u003eown_nmi, de_evt-\u003emaster_nmi);\n \n-\tieee80211_nan_cluster_joined(dev-\u003enan_vif, cluster_id, true, GFP_KERNEL);\n+\t/* joined an existing cluster, not a self-anchored new one */\n+\tieee80211_nan_cluster_joined(dev-\u003enan_vif, cluster_id, false, GFP_KERNEL);\n+}\n+\n+/* Runs the deferred NAN MCU events in process context; takes wiphy_lock\n+ * before nan_vif, which the NAN stop path frees under that mutex.\n+ */\n+void\n+mt7925_nan_deferred_work(struct work_struct *work)\n+{\n+\tstruct mt792x_dev *dev = container_of(work, struct mt792x_dev,\n+\t\t\t\t\t nan_deferred_work);\n+\tstruct ieee80211_vif *vif;\n+\tunsigned long pending;\n+\tu8 cluster_id[ETH_ALEN];\n+\n+\tspin_lock_bh(\u0026dev-\u003enan_deferred_lock);\n+\tpending = dev-\u003enan_deferred_pending;\n+\tdev-\u003enan_deferred_pending = 0;\n+\tmemcpy(cluster_id, dev-\u003enan_started_cluster_id, ETH_ALEN);\n+\tspin_unlock_bh(\u0026dev-\u003enan_deferred_lock);\n+\n+\tif (!pending)\n+\t\treturn;\n+\n+\twiphy_lock(dev-\u003emt76.hw-\u003ewiphy);\n+\tvif = dev-\u003enan_vif;\n+\tif (!vif || !ieee80211_vif_nan_started(vif))\n+\t\tgoto out;\n+\n+\tif (test_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, \u0026pending))\n+\t\tieee80211_nan_cluster_joined(vif, cluster_id, true, GFP_KERNEL);\n+\n+\tif (test_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, \u0026pending))\n+\t\tieee80211_nan_sched_update_done(vif);\n+out:\n+\twiphy_unlock(dev-\u003emt76.hw-\u003ewiphy);\n+}\n+\n+static void\n+mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)\n+{\n+\tstruct mt7925_nan_ulw_event *evt;\n+\tstruct mt7925_nan_ulw_attr attr;\n+\tstruct wireless_dev *wdev;\n+\tu16 len;\n+\n+\tif (!dev || !tlv)\n+\t\treturn;\n+\n+\tif (!dev-\u003enan_vif || !ieee80211_vif_nan_started(dev-\u003enan_vif))\n+\t\treturn;\n+\n+\tlen = le16_to_cpu(tlv-\u003elen);\n+\tif (len \u003c sizeof(*tlv) + sizeof(*evt)) {\n+\t\tdev_warn(dev-\u003emt76.dev,\n+\t\t\t \"nan: short ulw event tlv len=%u\\n\", len);\n+\t\treturn;\n+\t}\n+\n+\tevt = (struct mt7925_nan_ulw_event *)tlv-\u003edata;\n+\twdev = ieee80211_vif_to_wdev(dev-\u003enan_vif);\n+\tif (!wdev)\n+\t\treturn;\n+\n+\tdev_dbg(dev-\u003emt76.dev,\n+\t\t\"nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\\n\",\n+\t\twdev, wdev-\u003eowner_nlportid,\n+\t\tevt-\u003esched_id, evt-\u003eseq_id, le32_to_cpu(evt-\u003eduration));\n+\n+\t/* Reorder the FW fields into NAN spec Table 109 attribute layout */\n+\tattr.attr_id = NAN_ULW_ATTR_ID;\n+\tattr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD);\n+\tattr.sched_id = evt-\u003esched_id;\n+\tattr.seq_id = evt-\u003eseq_id;\n+\tattr.start_time = evt-\u003estart_time;\n+\tattr.duration = evt-\u003eduration;\n+\tattr.period = evt-\u003eperiod;\n+\tattr.count_down = evt-\u003ecount_down;\n+\tattr.ulw_overwrite = evt-\u003eulw_overwrite;\n+\n+\tcfg80211_nan_ulw_update(wdev, (const u8 *)\u0026attr, sizeof(attr),\n+\t\t\t\tGFP_KERNEL);\n+}\n+\n+static void\n+mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv)\n+{\n+\tstruct ieee80211_vif *vif;\n+\n+\tif (!dev || !tlv)\n+\t\treturn;\n+\n+\tvif = dev-\u003enan_vif;\n+\tif (!vif || !ieee80211_vif_nan_started(vif))\n+\t\treturn;\n+\n+\t/* Runs in the BH-disabled MCU-event RX path; the mac80211 helper needs\n+\t * the wiphy mutex and may sleep, so hand it to the work instead.\n+\t */\n+\tspin_lock_bh(\u0026dev-\u003enan_deferred_lock);\n+\tset_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, \u0026dev-\u003enan_deferred_pending);\n+\tspin_unlock_bh(\u0026dev-\u003enan_deferred_lock);\n+\tieee80211_queue_work(dev-\u003emt76.hw, \u0026dev-\u003enan_deferred_work);\n }\n \n void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)\n@@ -515,9 +679,15 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)\n \t\tcase NAN_UNI_EVENT_ID_DE_EVENT_IND:\n \t\t\tmt7925_nan_mcu_handle_de_event(dev, tlv);\n \t\t\tbreak;\n-\t\tcase NAN_UNI_EVENT_REPORT_DW_END:\n+\t\tcase NAN_UNI_EVENT_REPORT_DW_START:\n \t\t\tmt7925_nan_handle_dw_ind(dev, tlv);\n \t\t\tbreak;\n+\t\tcase NAN_UNI_EVENT_ID_ULW_UPDATE:\n+\t\t\tmt7925_nan_handle_ulw_update(dev, tlv);\n+\t\t\tbreak;\n+\t\tcase NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE:\n+\t\t\tmt7925_nan_handle_sched_update_done(dev, tlv);\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n@@ -555,6 +725,7 @@ static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,\n \tavail_ctrl_tlv-\u003eavail_ctrl =\n \t\tcpu_to_le16(ctrl \u0026 NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);\n \tavail_ctrl_tlv-\u003eseq_id = seq_id;\n+\tavail_ctrl_tlv-\u003eis_deferred = sched-\u003edeferred ? 1 : 0;\n \n \treturn 0;\n }\n@@ -584,9 +755,14 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,\n \n \t\t\tif (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) ==\n \t\t\t slot_chan-\u003echan-\u003ehw_value) {\n-\t\t\t\tu32 map = le32_to_cpu(ch_list[j].avail_map[0]);\n+\t\t\t\tu32 dw;\n \n-\t\t\t\tch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i));\n+\t\t\t\tfor (dw = 0; dw \u003c NAN_TOTAL_DW; dw++) {\n+\t\t\t\t\tu32 map = le32_to_cpu(ch_list[j].avail_map[dw]);\n+\n+\t\t\t\t\tch_list[j].avail_map[dw] =\n+\t\t\t\t\t\tcpu_to_le32(map | BIT(i));\n+\t\t\t\t}\n \t\t\t\tle32_add_cpu(\u0026ch_list[j].num, 1);\n \t\t\t\tis_found = true;\n \t\t\t\tbreak;\n@@ -594,12 +770,18 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,\n \t\t}\n \n \t\tif (!is_found \u0026\u0026 num_channels \u003c NAN_TIMELINE_MGMT_CHNL_LIST_NUM) {\n+\t\t\tu32 dw;\n+\n \t\t\tch_list[num_channels].ch_info =\n-\t\t\t\tcpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS,\n+\t\t\t\tcpu_to_le32(FIELD_PREP(NAN_CH_CTRL_CH_TYPE,\n+\t\t\t\t\t\t NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL) |\n+\t\t\t\t\t FIELD_PREP(NAN_CH_CTRL_OP_CLASS,\n \t\t\t\t\t\t slot-\u003echannel_entry[0]) |\n \t\t\t\t\t FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH,\n \t\t\t\t\t\t slot_chan-\u003echan-\u003ehw_value));\n-\t\t\tch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i));\n+\t\t\tfor (dw = 0; dw \u003c NAN_TOTAL_DW; dw++)\n+\t\t\t\tch_list[num_channels].avail_map[dw] =\n+\t\t\t\t\tcpu_to_le32(BIT(i));\n \t\t\tle32_add_cpu(\u0026ch_list[num_channels].num, 1);\n \t\t\tch_list[num_channels].is_valid++;\n \t\t\tnum_channels++;\n@@ -647,15 +829,12 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,\n {\n \tstruct mt7925_nan_common_hdr *hdr;\n \tstruct mt76_dev *mdev;\n-\tbool deferred;\n \tstruct sk_buff *skb;\n-\tint ret = -ENOMEM;\n \n \tif (!dev || !vif)\n \t\treturn;\n \n \tmdev = \u0026dev-\u003emt76;\n-\tdeferred = vif-\u003ecfg.nan_sched.deferred;\n \n \tmt792x_mutex_acquire(dev);\n \n@@ -672,19 +851,9 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,\n \t\tgoto out;\n \t}\n \n-\tret = mt76_mcu_skb_send_msg(mdev, skb,\n-\t\t\t\t MCU_UNI_CMD(NAN), true);\n+\tmt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), false);\n out:\n \tmt792x_mutex_release(dev);\n-\n-\tif (deferred) {\n-\t\tif (ret)\n-\t\t\tdev_err(mdev-\u003edev,\n-\t\t\t\t\"NAN: local schedule update failed: %d\\n\",\n-\t\t\t\tret);\n-\n-\t\tieee80211_nan_sched_update_done(vif);\n-\t}\n }\n \n static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,\n@@ -712,23 +881,6 @@ static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,\n \treturn 0;\n }\n \n-static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif)\n-{\n-\tstruct wiphy *wiphy;\n-\tu8 bands = 0;\n-\n-\tif (!mvif || !mvif-\u003ephy)\n-\t\treturn BIT(NAN_SUPPORTED_BAND_ID_2P4G);\n-\n-\twiphy = mvif-\u003ephy-\u003emt76-\u003ehw-\u003ewiphy;\n-\tif (wiphy-\u003enan_supported_bands \u0026 BIT(NL80211_BAND_2GHZ))\n-\t\tbands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G);\n-\tif (wiphy-\u003enan_supported_bands \u0026 BIT(NL80211_BAND_5GHZ))\n-\t\tbands |= BIT(NAN_SUPPORTED_BAND_ID_5G);\n-\n-\treturn bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G);\n-}\n-\n static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,\n \t\t\t\t struct ieee80211_sta *sta,\n \t\t\t\t struct mt792x_sta *msta)\n@@ -755,8 +907,7 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,\n \n \tpeer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv;\n \tpeer_cap_tlv-\u003esch_idx = cpu_to_le32(msta-\u003enan_sched.sch_idx);\n-\tpeer_cap_tlv-\u003esupported_bands =\n-\t\tmt7925_nan_get_supported_bands(msta-\u003evif);\n+\tpeer_cap_tlv-\u003esupported_bands = BIT(NAN_SUPPORTED_BAND_ID_2P4G);\n \tpeer_cap_tlv-\u003emax_chnl_switch_time = cpu_to_le16(sched-\u003emax_chan_switch);\n \n \tfor (i = 0; i \u003c sched-\u003en_channels; i++) {\n@@ -785,52 +936,40 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,\n \n static void\n mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv,\n-\t\t\t struct ieee80211_vif *vif,\n \t\t\t struct ieee80211_nan_peer_sched *sched)\n {\n-\tstruct ieee80211_nan_sched_cfg *local_sched;\n-\tu8 local_map_id;\n \tu32 m, slot;\n \n-\tif (!vif || !sched)\n+\tif (!sched)\n \t\treturn;\n \n-\tlocal_sched = \u0026vif-\u003ecfg.nan_sched;\n-\tlocal_map_id = mt7925_nan_avail_attr_ctrl(local_sched) \u0026\n-\t\t NAN_AVAIL_CTRL_MAPID;\n-\n \tfor (m = 0; m \u003c CFG80211_NAN_MAX_PEER_MAPS \u0026\u0026\n \t m \u003c NAN_TIMELINE_MGMT_SIZE; m++) {\n+\t\tstruct ieee80211_nan_peer_map *map = \u0026sched-\u003emaps[m];\n \t\tstruct mt7925_nan_sched_timeline *tl =\n \t\t\t\u0026crb_tlv-\u003ecomm_faw_timeline[m];\n-\t\tstruct ieee80211_nan_peer_map *map = \u0026sched-\u003emaps[m];\n-\t\tu32 avail_map = 0;\n \n \t\tif (map-\u003emap_id == CFG80211_NAN_INVALID_MAP_ID)\n \t\t\tcontinue;\n \n \t\ttl-\u003emap_id = map-\u003emap_id;\n-\t\ttl-\u003elocal_map_id = local_map_id;\n \n+\t\t/*\n+\t\t * Convert peer schedule slots to FW avail_map bitmap.\n+\t\t * Each bit represents one time slot where the peer has\n+\t\t * committed availability. Fill all DW intervals the same.\n+\t\t */\n \t\tfor (slot = 0; slot \u003c CFG80211_NAN_SCHED_NUM_TIME_SLOTS;\n \t\t slot++) {\n-\t\t\tstruct ieee80211_nan_channel *local_ch;\n-\t\t\tstruct ieee80211_nan_channel *peer_ch;\n-\n-\t\t\tlocal_ch = local_sched-\u003eschedule[slot];\n-\t\t\tpeer_ch = map-\u003eslots[slot];\n+\t\t\tstruct ieee80211_nan_channel *ch = map-\u003eslots[slot];\n+\t\t\tu32 dw;\n \n-\t\t\tif (!local_ch || !local_ch-\u003echanctx_conf ||\n-\t\t\t !peer_ch || !peer_ch-\u003echanctx_conf)\n+\t\t\tif (!ch || !ch-\u003echanctx_conf)\n \t\t\t\tcontinue;\n \n-\t\t\tif (local_ch-\u003echanctx_conf != peer_ch-\u003echanctx_conf)\n-\t\t\t\tcontinue;\n-\n-\t\t\tavail_map |= BIT(slot);\n+\t\t\tfor (dw = 0; dw \u003c NAN_TOTAL_DW; dw++)\n+\t\t\t\ttl-\u003eavail_map[dw] |= cpu_to_le32(BIT(slot));\n \t\t}\n-\n-\t\ttl-\u003eavail_map[0] = cpu_to_le32(avail_map);\n \t}\n }\n \n@@ -856,8 +995,38 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb,\n \tcrb_tlv-\u003eis_use_ranging = false;\n \tcrb_tlv-\u003ecomm_ndc_ctrl.is_valid = false;\n \n-\tmt7925_nan_fill_crb_committed(crb_tlv, msta-\u003evif-\u003ephy-\u003edev-\u003enan_vif,\n-\t\t\t\t sta-\u003enan_sched);\n+\tmt7925_nan_fill_crb_committed(crb_tlv, sta-\u003enan_sched);\n+\n+\treturn 0;\n+}\n+\n+static int\n+mt7925_nan_peer_ulw_tlv(struct sk_buff *skb,\n+\t\t\tstruct ieee80211_sta *sta,\n+\t\t\tstruct mt792x_sta *msta)\n+{\n+\tstruct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL;\n+\tstruct ieee80211_nan_peer_sched *sched = NULL;\n+\tstruct tlv *tlv = NULL;\n+\n+\tif (!skb || !sta || !msta)\n+\t\treturn -EINVAL;\n+\n+\tsched = sta-\u003enan_sched;\n+\tif (!sched || !sched-\u003einit_ulw || !sched-\u003eulw_size)\n+\t\treturn 0; /* No ULW to send, not an error */\n+\n+\tif (sched-\u003eulw_size \u003e NAN_ULW_MAX_SIZE)\n+\t\treturn -EINVAL;\n+\n+\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW,\n+\t\t\t\t sizeof(struct mt7925_nan_update_ulw_tlv));\n+\tif (!tlv)\n+\t\treturn -ENOMEM;\n+\n+\tulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv;\n+\tether_addr_copy(ulw_tlv-\u003enmi_addr, sta-\u003eaddr);\n+\tmemcpy(ulw_tlv-\u003eulw_attr, sched-\u003einit_ulw, sched-\u003eulw_size);\n \n \treturn 0;\n }\n@@ -914,6 +1083,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,\n \t\tgoto free_skb;\n \t}\n \n+\tret = mt7925_nan_peer_ulw_tlv(skb, sta, msta);\n+\tif (ret)\n+\t\tgoto free_skb;\n+\n \tret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);\n \tif (ret \u0026\u0026 idx_allocated)\n \t\tgoto clear_idx;\n@@ -935,18 +1108,18 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,\n int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,\n \t\t\t struct ieee80211_sta *sta)\n {\n+\tstruct mt7925_nan_sched_update_crb_tlv *crb_tlv;\n \tstruct mt7925_nan_common_hdr *hdr;\n \tstruct mt792x_sta *msta;\n \tstruct mt792x_nan *nan;\n \tstruct sk_buff *skb;\n+\tstruct tlv *tlv;\n \tint ret;\n \n \tif (!mdev || !sta)\n \t\treturn -EINVAL;\n \n-\tskb = mt76_mcu_msg_alloc(mdev, NULL,\n-\t\t\t\t sizeof(struct mt7925_nan_common_hdr) +\n-\t\t\t\t sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv));\n+\tskb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE);\n \tif (!skb)\n \t\treturn -ENOMEM;\n \n@@ -961,6 +1134,25 @@ int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,\n \t\treturn 0;\n \t}\n \n+\t/* Send a zero-avail_map CRB TLV before deactivating the peer record so\n+\t * firmware clears the committed schedule slots for this peer. Without\n+\t * this, stale CRB entries linger and cause scheduling conflicts for\n+\t * subsequent NDP connections that reuse the same sch_idx.\n+\t */\n+\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB,\n+\t\t\t\t sizeof(struct mt7925_nan_sched_update_crb_tlv));\n+\tif (!tlv) {\n+\t\tdev_kfree_skb(skb);\n+\t\treturn -ENOMEM;\n+\t}\n+\tcrb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv;\n+\tcrb_tlv-\u003esch_idx = msta-\u003enan_sched.sch_idx;\n+\tcrb_tlv-\u003eflags = NAN_CRB_USE_DATA_PATH;\n+\tcrb_tlv-\u003eis_use_ranging = false;\n+\tcrb_tlv-\u003ecomm_ndc_ctrl.is_valid = false;\n+\t/* avail_map is zero-initialised by mt76_connac_mcu_add_tlv */\n+\n+\t/* Deactivate peer record and release connection index */\n \tif (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) {\n \t\tdev_kfree_skb(skb);\n \t\treturn -ENOMEM;\n@@ -990,13 +1182,11 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,\n \tstruct sk_buff *skb;\n \tint ndp_ctx_id = 0;\n \tint ret = -ENOMEM;\n-\tstruct mt792x_dev *dev;\n \tstruct tlv *tlv;\n \n \tif (!mdev || !vif || !sta)\n \t\treturn -EINVAL;\n \n-\tdev = container_of(mdev, struct mt792x_dev, mt76);\n \tmsta = (struct mt792x_sta *)sta-\u003edrv_priv;\n \tmvif = (struct mt792x_vif *)vif-\u003edrv_priv;\n \n@@ -1012,33 +1202,6 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,\n \tmemcpy(nmi_addr, nmi_sta-\u003eaddr, ETH_ALEN);\n \tnmi_msta = (struct mt792x_sta *)nmi_sta-\u003edrv_priv;\n \n-\tif (!nmi_msta-\u003enan_sched.idx_assigned) {\n-\t\tif (!nmi_sta-\u003enan_sched) {\n-\t\t\trcu_read_unlock();\n-\t\t\tdev_err(mdev-\u003edev,\n-\t\t\t\t\"NAN: peer schedule missing for NDI sta %pM\\n\",\n-\t\t\t\tsta-\u003eaddr);\n-\t\t\treturn -EAGAIN;\n-\t\t}\n-\n-\t\trcu_read_unlock();\n-\t\tret = mt792x_nan_set_peer_schedule(dev, nmi_sta);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\trcu_read_lock();\n-\t\tnmi_sta = rcu_dereference(sta-\u003enmi);\n-\t\tif (!nmi_sta) {\n-\t\t\trcu_read_unlock();\n-\t\t\tdev_err(mdev-\u003edev,\n-\t\t\t\t\"NAN: NMI sta not found for NDI sta %pM\\n\",\n-\t\t\t\tsta-\u003eaddr);\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\n-\t\tnmi_msta = (struct mt792x_sta *)nmi_sta-\u003edrv_priv;\n-\t}\n-\n \tndp_ctx_id = find_first_zero_bit(\u0026nmi_msta-\u003enan_sched.ndp_ctx_bitmap,\n \t\t\t\t\t NAN_MAX_NDP_CXT);\n \tif (ndp_ctx_id \u003e= NAN_MAX_NDP_CXT) {\n@@ -1073,7 +1236,7 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,\n \tmemcpy(map_tlv-\u003enmi_addr, nmi_addr, ETH_ALEN);\n \tmap_tlv-\u003esta_rec_idx = msta-\u003edeflink.wcid.idx;\n \tmap_tlv-\u003endp_ctx_id = ndp_ctx_id;\n-\tmap_tlv-\u003erole_idx = cpu_to_le32(mvif-\u003ebss_conf.mt76.idx);\n+\tmap_tlv-\u003erole_idx = NAN_BSS_INDEX_BAND0;\n \tmemcpy(map_tlv-\u003endi_addr, vif-\u003eaddr, ETH_ALEN);\n \n \tret = mt76_mcu_skb_send_msg(mdev, skb,\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h\nindex f55730e25f462..d81d84a222d90 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h\n@@ -28,6 +28,12 @@\n #define NAN_MAX_CONN_CFG\t\t8\n #define NAN_MAX_NDP_CXT\t\t\t4\n \n+#define MT7925_NAN_ENABLE_MAX_SIZE\t\t\t\t\t\\\n+\t(sizeof(struct mt7925_nan_common_hdr) +\t\t\t\t\\\n+\t sizeof(struct mt7925_nan_enable_req_tlv) +\t\t\t\\\n+\t sizeof(struct mt7925_nan_dw_interval_tlv) +\t\t\t\\\n+\t sizeof(struct mt7925_nan_cluster_id_tlv) +\t\t\t\\\n+\t sizeof(struct mt7925_nan_sync_rssi_tlv))\n #define MT7925_NAN_CONF_MAX_SIZE\t\t\t\t\t\\\n \t(sizeof(struct mt7925_nan_common_hdr) +\t\t\t\t\\\n \t sizeof(struct mt7925_nan_master_preference_tlv) +\t\t\\\n@@ -44,7 +50,8 @@\n \t(sizeof(struct mt7925_nan_common_hdr) +\t\t\t\t\\\n \t sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) +\t\t\\\n \t sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) +\t\t\\\n-\t sizeof(struct mt7925_nan_sched_update_crb_tlv))\n+\t sizeof(struct mt7925_nan_sched_update_crb_tlv) +\t\t\\\n+\t sizeof(struct mt7925_nan_update_ulw_tlv))\n \n /* NAN Availability Attribute */\n #define NAN_AVAIL_ATTR_ID_OFFSET\t0\n@@ -65,6 +72,8 @@\n #define UNII3_LOWER_BOUND\t149\n #define UNII3_UPPER_BOUND\t165\n \n+#define NAN_BSS_INDEX_BAND0 0\n+\n enum nan_uni_cmd_tag {\n \tNAN_UNI_CMD_SET_MASTER_PREFERENCE\t= 0,\n \tNAN_UNI_CMD_ENABLE_REQUEST\t\t= 7,\n@@ -73,6 +82,8 @@ enum nan_uni_cmd_tag {\n \tNAN_UNI_CMD_UPDATE_CRB\t\t\t= 10,\n \tNAN_UNI_CMD_MANAGE_PEER_SCH_RECORD\t= 12,\n \tNAN_UNI_CMD_MAP_STA_RECORD\t\t= 13,\n+\tNAN_UNI_CMD_UPDATE_ULW\t\t\t= 16,\n+\tNAN_UNI_CMD_UPDATE_PHY_SETTING\t\t= 18,\n \tNAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL\t= 20,\n \tNAN_UNI_CMD_UPDATE_PEER_CAPABILITY\t= 21,\n \tNAN_UNI_CMD_CHANGE_NMI_ADDRESS\t\t= 24,\n@@ -84,14 +95,25 @@ enum nan_uni_cmd_tag {\n \n enum nan_uni_event_tag {\n \tNAN_UNI_EVENT_ID_DE_EVENT_IND\t\t= 19,\n+\tNAN_UNI_EVENT_ID_ULW_UPDATE\t\t= 39,\n+\tNAN_UNI_EVENT_ID_SCHED_UPDATE_DONE\t= 43,\n+\tNAN_UNI_EVENT_REPORT_DW_START\t\t= 59,\n \tNAN_UNI_EVENT_REPORT_DW_END\t\t= 60,\n };\n \n enum nan_disc_event_type {\n \tNAN_EVENT_ID_DISC_MAC_ADDR\t\t= 0,\n+\tNAN_EVENT_ID_STARTED_CLUSTER\t\t= 1,\n \tNAN_EVENT_ID_JOINED_CLUSTER\t\t= 2,\n };\n \n+/* bit indices into mt792x_dev-\u003enan_deferred_pending, set from the atomic\n+ * MCU-event RX path and consumed by mt7925_nan_deferred_work()\n+ */\n+enum mt7925_nan_deferred_event {\n+\tMT7925_NAN_DEFERRED_STARTED_CLUSTER,\n+\tMT7925_NAN_DEFERRED_SCHED_UPDATE_DONE,\n+};\n /* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */\n enum nan_supported_bands {\n \tNAN_SUPPORTED_BAND_ID_2P4G = 2,\n@@ -108,12 +130,15 @@ enum nan_peer_supported_bands {\n \tNAN_SUPPORTED_BN_NUM\n };\n \n+#define NAN_CH_CTRL_CH_TYPE\t\tBIT(0)\n #define NAN_CH_CTRL_OP_CLASS\t\tGENMASK(15, 8)\n #define NAN_CH_CTRL_PRIMARY_CH\t\tGENMASK(23, 16)\n \n #define NAN_CRB_USE_DATA_PATH\t\tBIT(0)\n #define NAN_CRB_AVAIL_6G_FORMAT\t\tGENMASK(2, 1)\n \n+#define NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL\t1\n+\n struct mt7925_nan_social_ch_scan_params {\n \tu8 dwell_time[NAN_MAX_SOCIAL_CHANNELS];\n \t__le16 scan_period[NAN_MAX_SOCIAL_CHANNELS];\n@@ -153,6 +178,32 @@ struct nan_rpt_dw_evt {\n \t__le16 dw_num;\n };\n \n+#define NAN_ULW_ATTR_ID\t\t0x17\n+#define NAN_ULW_FIXED_PAYLOAD\t16\t/* Table 109 fixed fields */\n+\n+struct mt7925_nan_ulw_event {\n+\tu8 sched_id;\n+\tu8 seq_id;\n+\tu8 count_down;\n+\tu8 ulw_overwrite;\n+\t__le32 start_time;\n+\t__le32 duration;\n+\t__le32 period;\n+} __packed;\n+\n+/* ULW attribute laid out in NAN spec Table 109 field order */\n+struct mt7925_nan_ulw_attr {\n+\tu8 attr_id;\n+\t__le16 length;\n+\tu8 sched_id;\n+\tu8 seq_id;\n+\t__le32 start_time;\n+\t__le32 duration;\n+\t__le32 period;\n+\tu8 count_down;\n+\tu8 ulw_overwrite;\n+} __packed;\n+\n struct mt7925_nan_conf_dw {\n \tu8 config_2dot4g_dw_band;\n \t__le32 dw_2dot4g_interval_val;\n@@ -302,7 +353,7 @@ struct mt7925_nan_avail_ctrl_tlv {\n \t__le16 len;\n \t__le16 avail_ctrl;\n \tu8 seq_id;\n-\tu8 reserved[1];\n+\tu8 is_deferred;\n } __packed __aligned(4);\n \n struct mt7925_nan_ch_timeline {\n@@ -346,8 +397,7 @@ struct mt7925_nan_sched_update_peer_cap_tlv {\n \n struct mt7925_nan_sched_timeline {\n \tu8 map_id;\n-\tu8 local_map_id;\n-\tu8 reserved[2];\n+\tu8 reserved[3];\n \tunion {\n \t\t__le32 avail_map[NAN_TOTAL_DW];\n \t\tu8 avail_block[NAN_TOTAL_DW * 4];\n@@ -378,6 +428,15 @@ struct mt7925_nan_sched_update_crb_tlv {\n \tstruct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE];\n } __packed __aligned(4);\n \n+#define NAN_ULW_MAX_SIZE\t256\n+\n+struct mt7925_nan_update_ulw_tlv {\n+\t__le16 tag;\n+\t__le16 len;\n+\tu8 nmi_addr[ETH_ALEN];\n+\tu8 ulw_attr[NAN_ULW_MAX_SIZE];\n+} __packed __aligned(4);\n+\n struct mt7925_nan_sched_map_sta_rec_tlv {\n \t__le16 tag;\n \t__le16 len;\n@@ -390,6 +449,38 @@ struct mt7925_nan_sched_map_sta_rec_tlv {\n \tu8 reserved[2];\n } __packed __aligned(4);\n \n+/* Matches FW NAN_PHY_SETTING_T (enum fields are 4 bytes on ARM) */\n+struct mt7925_nan_phy_setting {\n+\tu8 phy_type_set;\n+\tu8 non_ht_basic_phy_type;\n+\tu8 use_short_preamble;\n+\tu8 use_short_slot_time;\n+\t__le16 operational_rate_set;\n+\t__le16 bss_basic_rate_set;\n+\t__le16 vht_basic_mcs_set;\n+\tu8 erp_protect_mode;\n+\tu8 ht_op_info1;\n+\t__le16 ht_op_info2;\n+\t__le16 ht_op_info3;\n+\t__le32 ht_protect_mode;\n+\t__le32 gf_operation_mode;\n+\t__le32 rifs_operation_mode;\n+} __packed;\n+\n+/* Matches FW NAN_SCHED_CMD_UPDATE_PHY_PARAM_T */\n+struct mt7925_nan_update_phy_setting_tlv {\n+\t__le16 tag;\n+\t__le16 len;\n+\tstruct mt7925_nan_phy_setting phy_2g;\n+\tstruct mt7925_nan_phy_setting phy_5g;\n+} __packed __aligned(4);\n+\n+int mt7925_nan_update_phy_setting(struct mt792x_dev *dev);\n+\n+struct ieee80211_chanctx_conf *\n+mt7925_nan_seed_link_sta(struct mt792x_dev *dev,\n+\t\t\t struct ieee80211_link_sta *link_sta);\n+\n int mt7925_nan_enable(struct ieee80211_vif *vif,\n \t\t struct mt792x_dev *dev,\n \t\t struct cfg80211_nan_conf *conf);\n@@ -403,8 +494,6 @@ int mt7925_nan_change_configure(struct ieee80211_vif *vif,\n \n void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb);\n \n-int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr);\n-\n void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,\n \t\t\t\t struct ieee80211_vif *vif);\n \ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c\nindex 02ef09dd797da..24585c992ff50 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c\n@@ -55,6 +55,7 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)\n \tcancel_delayed_work_sync(\u0026pm-\u003eps_work);\n \tcancel_delayed_work_sync(\u0026dev-\u003emlo_pm_work);\n \tcancel_work_sync(\u0026pm-\u003ewake_work);\n+\tcancel_work_sync(\u0026dev-\u003enan_deferred_work);\n \n \tmt7925_tx_token_put(dev);\n \t__mt792x_mcu_drv_pmctrl(dev);\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h\nindex 9efc251cb745f..9722d840c1af9 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt792x.h\n+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h\n@@ -342,6 +342,14 @@ struct mt792x_dev {\n \tstruct ieee80211_vif *nan_vif;\n \tconst struct ieee80211_iface_combination *iface_combinations;\n \tint n_iface_combinations;\n+\t/* deferred NAN MCU events run out of the atomic RX path on one shared\n+\t * work; see mt7925_nan_deferred_work() and enum mt7925_nan_deferred_event\n+\t */\n+\tstruct work_struct nan_deferred_work;\n+\t/* protects @nan_deferred_pending */\n+\tspinlock_t nan_deferred_lock;\n+\tunsigned long nan_deferred_pending;\n+\tu8 nan_started_cluster_id[ETH_ALEN];\n };\n \n static inline struct mt792x_bss_conf *\n"
} |
| 2/1 | 2026/08/24 22:58 | agent | patch-evaluator |
3mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"MT7925U",
"MT7925E"
],
"FocusSymbols": [
"mt7925_nan_deferred_work",
"mt7925_nan_update_phy_setting",
"mt7925_nan_seed_link_sta",
"mt7925_nan_enable",
"mt7925_nan_disable",
"mt7925_nan_mcu_event",
"mt7925_nan_local_sched_changed",
"mt792x_nan_set_peer_schedule",
"mt792x_nan_set_peer_rec",
"mt792x_nan_map_sta_rec"
],
"Reasoning": "The patch modifies NAN (Neighbor Awareness Networking) functionality in the MediaTek MT7925 Wi-Fi driver. It adds deferred work for NAN events, updates PHY settings, and refactors NAN enable/disable and peer scheduling logic. The driver supports USB (MT7925U) which can be emulated and fuzzed via syzkaller's USB gadget framework, making these changes reachable and worth fuzzing.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit d5bb2726534f601faa0c0ec8575f8d350eed3738
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 24 22:58:34 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
index cd22fcc021b1e..8c3049b66a857 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
@@ -270,6 +270,8 @@ int mt7925_register_device(struct mt792x_dev *dev)
INIT_WORK(&dev->reset_work, mt7925_mac_reset_work);
INIT_WORK(&dev->init_work, mt7925_init_work);
+ INIT_WORK(&dev->nan_deferred_work, mt7925_nan_deferred_work);
+ spin_lock_init(&dev->nan_deferred_lock);
INIT_WORK(&dev->phy.roc_work, mt7925_roc_work);
timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 84b55f008b3d3..051a0c8aed587 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -964,6 +964,21 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
+ /* NAN_DATA (NDI) peers skip association - fill link_sta caps
+ * from sband and push BSS_INFO with correct phymode + RLM.
+ */
+ if (vif->type == NL80211_IFTYPE_NAN_DATA) {
+ struct ieee80211_chanctx_conf *nan_ctx;
+
+ nan_ctx = mt7925_nan_seed_link_sta(dev, link_sta);
+ mconf->mt76.ctx = nan_ctx;
+
+ ret = mt7925_mcu_add_bss_info(&dev->phy, nan_ctx,
+ link_conf, link_sta, true);
+ if (ret)
+ goto out_pm;
+ }
+
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_link_sta *mlink_bc;
@@ -2587,26 +2602,18 @@ static int mt7925_start_nan(struct ieee80211_hw *hw,
cfg80211_chandef_create(&link_conf->chanreq.oper, chan,
NL80211_CHAN_NO_HT);
- err = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf,
- NULL, true);
+ err = mt7925_mcu_add_bss_info(&dev->phy, NULL,
+ link_conf, NULL, true);
if (err < 0)
goto out;
- dev->nan_vif = vif;
-
- err = mt7925_nan_set_nmi_addr(dev, vif->addr);
- if (err)
- goto rollback_bss;
-
err = mt7925_nan_enable(vif, dev, conf);
- if (err)
- goto rollback_bss;
-
- goto out;
+ if (err) {
+ mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false);
+ goto out;
+ }
-rollback_bss:
- dev->nan_vif = NULL;
- mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false);
+ err = mt7925_nan_update_phy_setting(dev);
out:
mt792x_mutex_release(dev);
@@ -2621,6 +2628,13 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err, ret;
+ /* Drop a deferred event queued just before stop so a stale cluster_id
+ * cannot leak into a restart; the work re-checks liveness anyway.
+ */
+ spin_lock_bh(&dev->nan_deferred_lock);
+ dev->nan_deferred_pending = 0;
+ spin_unlock_bh(&dev->nan_deferred_lock);
+
mt792x_mutex_acquire(dev);
err = mt7925_nan_disable(vif, dev);
@@ -2630,9 +2644,6 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
if (!err)
err = ret;
- if (dev->nan_vif == vif)
- dev->nan_vif = NULL;
-
mt792x_mutex_release(dev);
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index fa29c486a4553..1cfc209f9be5c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1914,11 +1914,9 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,
phy = (struct sta_rec_phy *)tlv;
if (mt7925_vif_is_nan(vif)) {
- enum nl80211_band band = chandef->chan ? chandef->chan->band
- : NL80211_BAND_2GHZ;
phy->phy_type = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_ERP;
phy->phy_type |= mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,
- band,
+ NL80211_BAND_5GHZ,
link_sta);
} else {
phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,
@@ -2003,7 +2001,11 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,
ra_info = (struct sta_rec_ra_info *)tlv;
if (mt7925_vif_is_nan(vif))
- band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ;
+ /* NAN is OFDM-only per spec; borrow the 5 GHz band lookup to
+ * avoid PHY_TYPE_BIT_HR_DSSS/CCK bits being added to phy_type.
+ * NAN interfaces have no chanctx, so chandef->chan is always NULL.
+ */
+ band = NL80211_BAND_5GHZ;
else
band = chandef->chan->band;
@@ -2847,7 +2849,7 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy,
bmc = (struct bss_rate_tlv *)tlv;
if (mt7925_vif_is_nan(vif))
- band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ;
+ band = NL80211_BAND_5GHZ;
else
band = chandef->chan->band;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 321e732347f2f..33782d9ba9ed4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -361,6 +361,7 @@ void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac,
void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
void mt7925_set_ipv6_ns_work(struct work_struct *work);
+void mt7925_nan_deferred_work(struct work_struct *work);
int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
index d260e803d056f..8a59f7b1aee25 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
@@ -32,8 +32,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
if (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan))
return;
- req->config_support_5g = 1;
- req->support_5g_val = 1;
req->config_5g_channel = 1;
if (chan->hw_value == NAN_5G_LOW_DISC_CHANNEL)
@@ -44,73 +42,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
req->channel_5g_val = cpu_to_le32(ch5g);
}
-static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (!conf->band_cfgs[NL80211_BAND_2GHZ].chan)
- return;
-
- req->config_2dot4g_support = 1;
- req->support_2dot4g_val = 1;
-}
-
-static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req,
- const u8 *cluster_id)
-{
- if (!cluster_id)
- return;
-
- req->cluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] << 8);
- req->cluster_low = cpu_to_le16((u16)cluster_id[3]);
-}
-
-static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) {
- req->config_dw.config_2dot4g_dw_band = 1;
- req->config_dw.dw_2dot4g_interval_val =
- cpu_to_le32(conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval);
- }
-
- if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) {
- req->config_dw.config_5g_dw_band = 1;
- req->config_dw.dw_5g_interval_val =
- cpu_to_le32(conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval);
- }
-}
-
-static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (conf->discovery_beacon_interval > 0) {
- req->config_2dot4g_beacons = true;
- req->beacon_2dot4g_val = conf->discovery_beacon_interval;
- }
-}
-
-static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) {
- req->config_2dot4g_rssi_close = 1;
- req->rssi_close_2dot4g_val =
- abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close);
- req->config_2dot4g_rssi_middle = 1;
- req->rssi_middle_2dot4g_val =
- abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle);
- }
-
- if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {
- req->config_5g_rssi_close = 1;
- req->rssi_close_5g_val =
- abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close);
- req->config_5g_rssi_middle = 1;
- req->rssi_middle_5g_val =
- abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle);
- }
-}
-
static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
@@ -144,101 +75,6 @@ mt7925_nan_update_conf(struct mt792x_vif *mvif,
memcpy(mvif->nan.conf.cluster_id, conf->cluster_id, ETH_ALEN);
}
-int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr)
-{
- struct mt76_dev *mdev;
- struct {
- u8 rsv[4];
- struct mt7925_nan_nmi_addr_tlv nmi_addr_tlv;
- } nmi_cmd = {
- .rsv = { 0 },
- .nmi_addr_tlv = {
- .tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS),
- .len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)),
- },
- };
- int ret;
-
- if (!dev || !addr)
- return -EINVAL;
-
- if (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) {
- dev_err(dev->mt76.dev, "NAN: invalid NMI address %pM\n", addr);
- return -EINVAL;
- }
-
- mdev = &dev->mt76;
- memcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN);
-
- ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nmi_cmd,
- sizeof(nmi_cmd), true);
-
- return ret;
-}
-
-int mt7925_nan_enable(struct ieee80211_vif *vif,
- struct mt792x_dev *dev,
- struct cfg80211_nan_conf *conf)
-{
- struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
- struct mt76_dev *mdev = &dev->mt76;
- struct {
- u8 rsv[4];
- struct mt7925_nan_enable_req_tlv nan_req_tlv;
- } nan_cmd = {
- .rsv = { 0 },
- .nan_req_tlv = {
- .tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST),
- .len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)),
- .config_random_factor_force = 0,
- .random_factor_force_val = 0,
- .config_hop_count_force = 0,
- .hop_count_force_val = 0,
- },
- };
- struct mt7925_nan_enable_req_tlv *p_nan_req_tlv = &nan_cmd.nan_req_tlv;
- int ret;
-
- if (!vif || !dev || !conf)
- return -EINVAL;
-
- p_nan_req_tlv->master_pref = conf->master_pref;
-
- mt7925_nan_set_2g_support(p_nan_req_tlv, conf);
- mt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf);
- mt7925_nan_set_cluster_id(p_nan_req_tlv, conf->cluster_id);
- mt7925_nan_set_dw_interval(p_nan_req_tlv, conf);
- mt7925_nan_set_disc_beacon(p_nan_req_tlv, conf);
- mt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf);
- mt7925_nan_set_scan_params(p_nan_req_tlv, conf);
-
- mt7925_nan_update_conf(mvif, conf);
-
- ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
-
- return ret;
-}
-
-int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
-{
- struct mt76_dev *mdev = &dev->mt76;
- struct {
- u8 rsv[4];
- struct tlv nan_dis_tlv;
- } nan_cmd = {
- .rsv = { 0 },
- .nan_dis_tlv = {
- .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
- .len = cpu_to_le16(sizeof(struct tlv)),
- },
- };
-
- if (!dev)
- return -EINVAL;
-
- return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
-}
-
static int
mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)
{
@@ -357,6 +193,213 @@ mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)
return 0;
}
+/* FW rate set bit definitions (matches FW wlan_def_cmm.h) */
+#define NAN_RATE_SET_BIT_1M BIT(0)
+#define NAN_RATE_SET_BIT_2M BIT(1)
+#define NAN_RATE_SET_BIT_5_5M BIT(2)
+#define NAN_RATE_SET_BIT_11M BIT(3)
+#define NAN_RATE_SET_BIT_6M BIT(6)
+#define NAN_RATE_SET_BIT_9M BIT(7)
+#define NAN_RATE_SET_BIT_12M BIT(8)
+#define NAN_RATE_SET_BIT_18M BIT(9)
+#define NAN_RATE_SET_BIT_24M BIT(10)
+#define NAN_RATE_SET_BIT_36M BIT(11)
+#define NAN_RATE_SET_BIT_48M BIT(12)
+#define NAN_RATE_SET_BIT_54M BIT(13)
+
+#define NAN_RATE_SET_ALL_A (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_9M | \
+ NAN_RATE_SET_BIT_12M | NAN_RATE_SET_BIT_18M | \
+ NAN_RATE_SET_BIT_24M | NAN_RATE_SET_BIT_36M | \
+ NAN_RATE_SET_BIT_48M | NAN_RATE_SET_BIT_54M)
+
+/* 5G basic: 6M+12M+24M (OFDM) */
+#define NAN_BASIC_RATE_SET_5G (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_12M | \
+ NAN_RATE_SET_BIT_24M)
+
+/* GF_MODE_DISALLOWED = 2, RIFS_MODE_DISALLOWED = 1 */
+#define NAN_GF_MODE_DISALLOWED 2
+#define NAN_RIFS_MODE_DISALLOWED 1
+
+int mt7925_nan_update_phy_setting(struct mt792x_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mphy;
+ struct ieee80211_supported_band *sband_5g;
+ struct mt7925_nan_phy_setting *phy;
+ struct {
+ u8 rsv[4];
+ struct mt7925_nan_update_phy_setting_tlv tlv;
+ } req = {};
+
+ sband_5g = mphy->hw->wiphy->bands[NL80211_BAND_5GHZ];
+
+ req.tlv.tag = cpu_to_le16(NAN_UNI_CMD_UPDATE_PHY_SETTING);
+ req.tlv.len = cpu_to_le16(sizeof(req.tlv));
+
+ /* 2G: ERP + HT (no CCK/HR_DSSS - NAN uses OFDM only) */
+ phy = &req.tlv.phy_2g;
+ phy->phy_type_set = PHY_TYPE_BIT_ERP | PHY_TYPE_BIT_HT;
+ phy->non_ht_basic_phy_type = PHY_TYPE_ERP_INDEX;
+ phy->use_short_preamble = 1;
+ phy->use_short_slot_time = 1;
+ phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);
+ phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);
+ phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);
+ phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);
+
+ /* 5G: OFDM + HT + VHT (NAN_MODE_11A) */
+ phy = &req.tlv.phy_5g;
+ phy->phy_type_set = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HT |
+ PHY_TYPE_BIT_VHT;
+ phy->non_ht_basic_phy_type = PHY_TYPE_OFDM_INDEX;
+ phy->use_short_preamble = 1;
+ phy->use_short_slot_time = 1;
+ phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);
+ phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);
+ phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);
+ phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);
+
+ /* VHT basic MCS set from sband capability */
+ if (sband_5g && sband_5g->vht_cap.vht_supported)
+ phy->vht_basic_mcs_set =
+ sband_5g->vht_cap.vht_mcs.rx_mcs_map;
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(NAN),
+ &req, sizeof(req), true);
+}
+
+struct ieee80211_chanctx_conf *
+mt7925_nan_seed_link_sta(struct mt792x_dev *dev,
+ struct ieee80211_link_sta *link_sta)
+{
+ struct ieee80211_supported_band *sband_2g, *sband_5g;
+ struct ieee80211_chanctx_conf *nan_ctx = NULL;
+ struct ieee80211_vif *nan_vif = dev->nan_vif;
+
+ /* Fill HT cap from 2G sband */
+ sband_2g = dev->mphy.hw->wiphy->bands[NL80211_BAND_2GHZ];
+ sband_5g = dev->mphy.hw->wiphy->bands[NL80211_BAND_5GHZ];
+ if (sband_2g)
+ link_sta->ht_cap = sband_2g->ht_cap;
+
+ link_sta->sta->wme = true;
+ link_sta->rx_nss = hweight8(dev->mphy.antenna_mask);
+
+ /* Get chanctx from NAN schedule.
+ * Prefer 5G committed slot for wider BW (VHT), fallback
+ * to first valid slot if no 5G data slot is scheduled.
+ */
+ if (nan_vif) {
+ struct ieee80211_nan_channel **slots =
+ nan_vif->cfg.nan_sched.schedule;
+ int i;
+
+ for (i = 0; i < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; i++) {
+ struct ieee80211_chanctx_conf *ctx;
+
+ if (!slots[i] || IS_ERR(slots[i]) ||
+ !slots[i]->chanctx_conf)
+ continue;
+
+ ctx = slots[i]->chanctx_conf;
+ if (!nan_ctx)
+ nan_ctx = ctx;
+ if (ctx->def.chan->band == NL80211_BAND_5GHZ) {
+ nan_ctx = ctx;
+ break;
+ }
+ }
+ }
+
+ /* Capability describes what the device can do and must not be
+ * filtered by the current schedule - firmware gates the VHT rate
+ * mode per the data schedule and re-derives it on schedule
+ * change, which only works if the caps are present up front.
+ */
+ if (sband_5g)
+ link_sta->vht_cap = sband_5g->vht_cap;
+
+ /* Bandwidth here is the capability ceiling, not the operating
+ * width - the per-slot operating bandwidth follows the current
+ * slot channel via the firmware RLM sync, so deriving it from
+ * the schedule at STA-add time would cap a later 5 GHz schedule
+ * at the bring-up width.
+ */
+ link_sta->bandwidth = IEEE80211_STA_RX_BW_80;
+
+ return nan_ctx;
+}
+
+int mt7925_nan_enable(struct ieee80211_vif *vif,
+ struct mt792x_dev *dev,
+ struct cfg80211_nan_conf *conf)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt7925_nan_common_hdr *hdr;
+ struct mt7925_nan_enable_req_tlv *req;
+ struct sk_buff *skb;
+
+ if (!vif || !dev || !conf)
+ return -EINVAL;
+
+ skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_ENABLE_MAX_SIZE);
+ if (!skb)
+ return -ENOMEM;
+
+ hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
+ memset(hdr, 0, sizeof(*hdr));
+
+ /* Set cluster id before joining cluster */
+ if (mt7925_nan_cluster_id_tlv(skb, conf->cluster_id)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ /* NAN enable request tlv */
+ req = (struct mt7925_nan_enable_req_tlv *)
+ mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_ENABLE_REQUEST,
+ sizeof(*req));
+ if (!req) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ req->master_pref = conf->master_pref;
+
+ mt7925_nan_set_5g_channel(dev, req, conf);
+ mt7925_nan_set_scan_params(req, conf);
+
+ if (mt7925_nan_dw_tlv(skb, conf) ||
+ mt7925_nan_sync_rssi_tlv(skb, conf)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ mt7925_nan_update_conf(mvif, conf);
+
+ return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
+}
+
+int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct {
+ u8 rsv[4];
+ struct tlv nan_dis_tlv;
+ } nan_cmd = {
+ .rsv = { 0 },
+ .nan_dis_tlv = {
+ .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
+ .len = cpu_to_le16(sizeof(struct tlv)),
+ },
+ };
+
+ if (!dev)
+ return -EINVAL;
+
+ return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
+}
+
int mt7925_nan_change_configure(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf)
@@ -473,8 +516,26 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n",
de_evt->event_type, de_evt->cluster_id);
- if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER)
+ if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER &&
+ de_evt->event_type != NAN_EVENT_ID_STARTED_CLUSTER)
+ return;
+
+ /* STARTED_CLUSTER fires during NAN_START, before nan.started is set and
+ * before the supplicant subscribes - defer past NAN_START via the work
+ * so ieee80211_nan_cluster_joined() actually reaches userspace.
+ */
+ if (de_evt->event_type == NAN_EVENT_ID_STARTED_CLUSTER) {
+ dev_dbg(dev->mt76.dev,
+ "nan: deferring STARTED_CLUSTER cluster=%pM\n",
+ cluster_id);
+ spin_lock_bh(&dev->nan_deferred_lock);
+ memcpy(dev->nan_started_cluster_id, cluster_id, ETH_ALEN);
+ set_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER,
+ &dev->nan_deferred_pending);
+ spin_unlock_bh(&dev->nan_deferred_lock);
+ ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
return;
+ }
if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) {
dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n");
@@ -487,7 +548,110 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n",
de_evt->own_nmi, de_evt->master_nmi);
- ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL);
+ /* joined an existing cluster, not a self-anchored new one */
+ ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, false, GFP_KERNEL);
+}
+
+/* Runs the deferred NAN MCU events in process context; takes wiphy_lock
+ * before nan_vif, which the NAN stop path frees under that mutex.
+ */
+void
+mt7925_nan_deferred_work(struct work_struct *work)
+{
+ struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
+ nan_deferred_work);
+ struct ieee80211_vif *vif;
+ unsigned long pending;
+ u8 cluster_id[ETH_ALEN];
+
+ spin_lock_bh(&dev->nan_deferred_lock);
+ pending = dev->nan_deferred_pending;
+ dev->nan_deferred_pending = 0;
+ memcpy(cluster_id, dev->nan_started_cluster_id, ETH_ALEN);
+ spin_unlock_bh(&dev->nan_deferred_lock);
+
+ if (!pending)
+ return;
+
+ wiphy_lock(dev->mt76.hw->wiphy);
+ vif = dev->nan_vif;
+ if (!vif || !ieee80211_vif_nan_started(vif))
+ goto out;
+
+ if (test_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, &pending))
+ ieee80211_nan_cluster_joined(vif, cluster_id, true, GFP_KERNEL);
+
+ if (test_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &pending))
+ ieee80211_nan_sched_update_done(vif);
+out:
+ wiphy_unlock(dev->mt76.hw->wiphy);
+}
+
+static void
+mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)
+{
+ struct mt7925_nan_ulw_event *evt;
+ struct mt7925_nan_ulw_attr attr;
+ struct wireless_dev *wdev;
+ u16 len;
+
+ if (!dev || !tlv)
+ return;
+
+ if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif))
+ return;
+
+ len = le16_to_cpu(tlv->len);
+ if (len < sizeof(*tlv) + sizeof(*evt)) {
+ dev_warn(dev->mt76.dev,
+ "nan: short ulw event tlv len=%u\n", len);
+ return;
+ }
+
+ evt = (struct mt7925_nan_ulw_event *)tlv->data;
+ wdev = ieee80211_vif_to_wdev(dev->nan_vif);
+ if (!wdev)
+ return;
+
+ dev_dbg(dev->mt76.dev,
+ "nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\n",
+ wdev, wdev->owner_nlportid,
+ evt->sched_id, evt->seq_id, le32_to_cpu(evt->duration));
+
+ /* Reorder the FW fields into NAN spec Table 109 attribute layout */
+ attr.attr_id = NAN_ULW_ATTR_ID;
+ attr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD);
+ attr.sched_id = evt->sched_id;
+ attr.seq_id = evt->seq_id;
+ attr.start_time = evt->start_time;
+ attr.duration = evt->duration;
+ attr.period = evt->period;
+ attr.count_down = evt->count_down;
+ attr.ulw_overwrite = evt->ulw_overwrite;
+
+ cfg80211_nan_ulw_update(wdev, (const u8 *)&attr, sizeof(attr),
+ GFP_KERNEL);
+}
+
+static void
+mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv)
+{
+ struct ieee80211_vif *vif;
+
+ if (!dev || !tlv)
+ return;
+
+ vif = dev->nan_vif;
+ if (!vif || !ieee80211_vif_nan_started(vif))
+ return;
+
+ /* Runs in the BH-disabled MCU-event RX path; the mac80211 helper needs
+ * the wiphy mutex and may sleep, so hand it to the work instead.
+ */
+ spin_lock_bh(&dev->nan_deferred_lock);
+ set_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &dev->nan_deferred_pending);
+ spin_unlock_bh(&dev->nan_deferred_lock);
+ ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
}
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
@@ -515,9 +679,15 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
case NAN_UNI_EVENT_ID_DE_EVENT_IND:
mt7925_nan_mcu_handle_de_event(dev, tlv);
break;
- case NAN_UNI_EVENT_REPORT_DW_END:
+ case NAN_UNI_EVENT_REPORT_DW_START:
mt7925_nan_handle_dw_ind(dev, tlv);
break;
+ case NAN_UNI_EVENT_ID_ULW_UPDATE:
+ mt7925_nan_handle_ulw_update(dev, tlv);
+ break;
+ case NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE:
+ mt7925_nan_handle_sched_update_done(dev, tlv);
+ break;
default:
break;
}
@@ -555,6 +725,7 @@ static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,
avail_ctrl_tlv->avail_ctrl =
cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);
avail_ctrl_tlv->seq_id = seq_id;
+ avail_ctrl_tlv->is_deferred = sched->deferred ? 1 : 0;
return 0;
}
@@ -584,9 +755,14 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
if (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) ==
slot_chan->chan->hw_value) {
- u32 map = le32_to_cpu(ch_list[j].avail_map[0]);
+ u32 dw;
- ch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i));
+ for (dw = 0; dw < NAN_TOTAL_DW; dw++) {
+ u32 map = le32_to_cpu(ch_list[j].avail_map[dw]);
+
+ ch_list[j].avail_map[dw] =
+ cpu_to_le32(map | BIT(i));
+ }
le32_add_cpu(&ch_list[j].num, 1);
is_found = true;
break;
@@ -594,12 +770,18 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
}
if (!is_found && num_channels < NAN_TIMELINE_MGMT_CHNL_LIST_NUM) {
+ u32 dw;
+
ch_list[num_channels].ch_info =
- cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
+ cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_CH_TYPE,
+ NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL) |
+ FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
slot->channel_entry[0]) |
FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH,
slot_chan->chan->hw_value));
- ch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i));
+ for (dw = 0; dw < NAN_TOTAL_DW; dw++)
+ ch_list[num_channels].avail_map[dw] =
+ cpu_to_le32(BIT(i));
le32_add_cpu(&ch_list[num_channels].num, 1);
ch_list[num_channels].is_valid++;
num_channels++;
@@ -647,15 +829,12 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
{
struct mt7925_nan_common_hdr *hdr;
struct mt76_dev *mdev;
- bool deferred;
struct sk_buff *skb;
- int ret = -ENOMEM;
if (!dev || !vif)
return;
mdev = &dev->mt76;
- deferred = vif->cfg.nan_sched.deferred;
mt792x_mutex_acquire(dev);
@@ -672,19 +851,9 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
goto out;
}
- ret = mt76_mcu_skb_send_msg(mdev, skb,
- MCU_UNI_CMD(NAN), true);
+ mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), false);
out:
mt792x_mutex_release(dev);
-
- if (deferred) {
- if (ret)
- dev_err(mdev->dev,
- "NAN: local schedule update failed: %d\n",
- ret);
-
- ieee80211_nan_sched_update_done(vif);
- }
}
static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
@@ -712,23 +881,6 @@ static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
return 0;
}
-static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif)
-{
- struct wiphy *wiphy;
- u8 bands = 0;
-
- if (!mvif || !mvif->phy)
- return BIT(NAN_SUPPORTED_BAND_ID_2P4G);
-
- wiphy = mvif->phy->mt76->hw->wiphy;
- if (wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))
- bands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G);
- if (wiphy->nan_supported_bands & BIT(NL80211_BAND_5GHZ))
- bands |= BIT(NAN_SUPPORTED_BAND_ID_5G);
-
- return bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G);
-}
-
static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
struct ieee80211_sta *sta,
struct mt792x_sta *msta)
@@ -755,8 +907,7 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
peer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv;
peer_cap_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
- peer_cap_tlv->supported_bands =
- mt7925_nan_get_supported_bands(msta->vif);
+ peer_cap_tlv->supported_bands = BIT(NAN_SUPPORTED_BAND_ID_2P4G);
peer_cap_tlv->max_chnl_switch_time = cpu_to_le16(sched->max_chan_switch);
for (i = 0; i < sched->n_channels; i++) {
@@ -785,52 +936,40 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
static void
mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv,
- struct ieee80211_vif *vif,
struct ieee80211_nan_peer_sched *sched)
{
- struct ieee80211_nan_sched_cfg *local_sched;
- u8 local_map_id;
u32 m, slot;
- if (!vif || !sched)
+ if (!sched)
return;
- local_sched = &vif->cfg.nan_sched;
- local_map_id = mt7925_nan_avail_attr_ctrl(local_sched) &
- NAN_AVAIL_CTRL_MAPID;
-
for (m = 0; m < CFG80211_NAN_MAX_PEER_MAPS &&
m < NAN_TIMELINE_MGMT_SIZE; m++) {
+ struct ieee80211_nan_peer_map *map = &sched->maps[m];
struct mt7925_nan_sched_timeline *tl =
&crb_tlv->comm_faw_timeline[m];
- struct ieee80211_nan_peer_map *map = &sched->maps[m];
- u32 avail_map = 0;
if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
continue;
tl->map_id = map->map_id;
- tl->local_map_id = local_map_id;
+ /*
+ * Convert peer schedule slots to FW avail_map bitmap.
+ * Each bit represents one time slot where the peer has
+ * committed availability. Fill all DW intervals the same.
+ */
for (slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS;
slot++) {
- struct ieee80211_nan_channel *local_ch;
- struct ieee80211_nan_channel *peer_ch;
-
- local_ch = local_sched->schedule[slot];
- peer_ch = map->slots[slot];
+ struct ieee80211_nan_channel *ch = map->slots[slot];
+ u32 dw;
- if (!local_ch || !local_ch->chanctx_conf ||
- !peer_ch || !peer_ch->chanctx_conf)
+ if (!ch || !ch->chanctx_conf)
continue;
- if (local_ch->chanctx_conf != peer_ch->chanctx_conf)
- continue;
-
- avail_map |= BIT(slot);
+ for (dw = 0; dw < NAN_TOTAL_DW; dw++)
+ tl->avail_map[dw] |= cpu_to_le32(BIT(slot));
}
-
- tl->avail_map[0] = cpu_to_le32(avail_map);
}
}
@@ -856,8 +995,38 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb,
crb_tlv->is_use_ranging = false;
crb_tlv->comm_ndc_ctrl.is_valid = false;
- mt7925_nan_fill_crb_committed(crb_tlv, msta->vif->phy->dev->nan_vif,
- sta->nan_sched);
+ mt7925_nan_fill_crb_committed(crb_tlv, sta->nan_sched);
+
+ return 0;
+}
+
+static int
+mt7925_nan_peer_ulw_tlv(struct sk_buff *skb,
+ struct ieee80211_sta *sta,
+ struct mt792x_sta *msta)
+{
+ struct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL;
+ struct ieee80211_nan_peer_sched *sched = NULL;
+ struct tlv *tlv = NULL;
+
+ if (!skb || !sta || !msta)
+ return -EINVAL;
+
+ sched = sta->nan_sched;
+ if (!sched || !sched->init_ulw || !sched->ulw_size)
+ return 0; /* No ULW to send, not an error */
+
+ if (sched->ulw_size > NAN_ULW_MAX_SIZE)
+ return -EINVAL;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW,
+ sizeof(struct mt7925_nan_update_ulw_tlv));
+ if (!tlv)
+ return -ENOMEM;
+
+ ulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv;
+ ether_addr_copy(ulw_tlv->nmi_addr, sta->addr);
+ memcpy(ulw_tlv->ulw_attr, sched->init_ulw, sched->ulw_size);
return 0;
}
@@ -914,6 +1083,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
goto free_skb;
}
+ ret = mt7925_nan_peer_ulw_tlv(skb, sta, msta);
+ if (ret)
+ goto free_skb;
+
ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
if (ret && idx_allocated)
goto clear_idx;
@@ -935,18 +1108,18 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
struct ieee80211_sta *sta)
{
+ struct mt7925_nan_sched_update_crb_tlv *crb_tlv;
struct mt7925_nan_common_hdr *hdr;
struct mt792x_sta *msta;
struct mt792x_nan *nan;
struct sk_buff *skb;
+ struct tlv *tlv;
int ret;
if (!mdev || !sta)
return -EINVAL;
- skb = mt76_mcu_msg_alloc(mdev, NULL,
- sizeof(struct mt7925_nan_common_hdr) +
- sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv));
+ skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE);
if (!skb)
return -ENOMEM;
@@ -961,6 +1134,25 @@ int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
return 0;
}
+ /* Send a zero-avail_map CRB TLV before deactivating the peer record so
+ * firmware clears the committed schedule slots for this peer. Without
+ * this, stale CRB entries linger and cause scheduling conflicts for
+ * subsequent NDP connections that reuse the same sch_idx.
+ */
+ tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB,
+ sizeof(struct mt7925_nan_sched_update_crb_tlv));
+ if (!tlv) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+ crb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv;
+ crb_tlv->sch_idx = msta->nan_sched.sch_idx;
+ crb_tlv->flags = NAN_CRB_USE_DATA_PATH;
+ crb_tlv->is_use_ranging = false;
+ crb_tlv->comm_ndc_ctrl.is_valid = false;
+ /* avail_map is zero-initialised by mt76_connac_mcu_add_tlv */
+
+ /* Deactivate peer record and release connection index */
if (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) {
dev_kfree_skb(skb);
return -ENOMEM;
@@ -990,13 +1182,11 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
struct sk_buff *skb;
int ndp_ctx_id = 0;
int ret = -ENOMEM;
- struct mt792x_dev *dev;
struct tlv *tlv;
if (!mdev || !vif || !sta)
return -EINVAL;
- dev = container_of(mdev, struct mt792x_dev, mt76);
msta = (struct mt792x_sta *)sta->drv_priv;
mvif = (struct mt792x_vif *)vif->drv_priv;
@@ -1012,33 +1202,6 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
memcpy(nmi_addr, nmi_sta->addr, ETH_ALEN);
nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
- if (!nmi_msta->nan_sched.idx_assigned) {
- if (!nmi_sta->nan_sched) {
- rcu_read_unlock();
- dev_err(mdev->dev,
- "NAN: peer schedule missing for NDI sta %pM\n",
- sta->addr);
- return -EAGAIN;
- }
-
- rcu_read_unlock();
- ret = mt792x_nan_set_peer_schedule(dev, nmi_sta);
- if (ret)
- return ret;
-
- rcu_read_lock();
- nmi_sta = rcu_dereference(sta->nmi);
- if (!nmi_sta) {
- rcu_read_unlock();
- dev_err(mdev->dev,
- "NAN: NMI sta not found for NDI sta %pM\n",
- sta->addr);
- return -EINVAL;
- }
-
- nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
- }
-
ndp_ctx_id = find_first_zero_bit(&nmi_msta->nan_sched.ndp_ctx_bitmap,
NAN_MAX_NDP_CXT);
if (ndp_ctx_id >= NAN_MAX_NDP_CXT) {
@@ -1073,7 +1236,7 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
memcpy(map_tlv->nmi_addr, nmi_addr, ETH_ALEN);
map_tlv->sta_rec_idx = msta->deflink.wcid.idx;
map_tlv->ndp_ctx_id = ndp_ctx_id;
- map_tlv->role_idx = cpu_to_le32(mvif->bss_conf.mt76.idx);
+ map_tlv->role_idx = NAN_BSS_INDEX_BAND0;
memcpy(map_tlv->ndi_addr, vif->addr, ETH_ALEN);
ret = mt76_mcu_skb_send_msg(mdev, skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
index f55730e25f462..d81d84a222d90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
@@ -28,6 +28,12 @@
#define NAN_MAX_CONN_CFG 8
#define NAN_MAX_NDP_CXT 4
+#define MT7925_NAN_ENABLE_MAX_SIZE \
+ (sizeof(struct mt7925_nan_common_hdr) + \
+ sizeof(struct mt7925_nan_enable_req_tlv) + \
+ sizeof(struct mt7925_nan_dw_interval_tlv) + \
+ sizeof(struct mt7925_nan_cluster_id_tlv) + \
+ sizeof(struct mt7925_nan_sync_rssi_tlv))
#define MT7925_NAN_CONF_MAX_SIZE \
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_master_preference_tlv) + \
@@ -44,7 +50,8 @@
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) + \
sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) + \
- sizeof(struct mt7925_nan_sched_update_crb_tlv))
+ sizeof(struct mt7925_nan_sched_update_crb_tlv) + \
+ sizeof(struct mt7925_nan_update_ulw_tlv))
/* NAN Availability Attribute */
#define NAN_AVAIL_ATTR_ID_OFFSET 0
@@ -65,6 +72,8 @@
#define UNII3_LOWER_BOUND 149
#define UNII3_UPPER_BOUND 165
+#define NAN_BSS_INDEX_BAND0 0
+
enum nan_uni_cmd_tag {
NAN_UNI_CMD_SET_MASTER_PREFERENCE = 0,
NAN_UNI_CMD_ENABLE_REQUEST = 7,
@@ -73,6 +82,8 @@ enum nan_uni_cmd_tag {
NAN_UNI_CMD_UPDATE_CRB = 10,
NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD = 12,
NAN_UNI_CMD_MAP_STA_RECORD = 13,
+ NAN_UNI_CMD_UPDATE_ULW = 16,
+ NAN_UNI_CMD_UPDATE_PHY_SETTING = 18,
NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL = 20,
NAN_UNI_CMD_UPDATE_PEER_CAPABILITY = 21,
NAN_UNI_CMD_CHANGE_NMI_ADDRESS = 24,
@@ -84,14 +95,25 @@ enum nan_uni_cmd_tag {
enum nan_uni_event_tag {
NAN_UNI_EVENT_ID_DE_EVENT_IND = 19,
+ NAN_UNI_EVENT_ID_ULW_UPDATE = 39,
+ NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE = 43,
+ NAN_UNI_EVENT_REPORT_DW_START = 59,
NAN_UNI_EVENT_REPORT_DW_END = 60,
};
enum nan_disc_event_type {
NAN_EVENT_ID_DISC_MAC_ADDR = 0,
+ NAN_EVENT_ID_STARTED_CLUSTER = 1,
NAN_EVENT_ID_JOINED_CLUSTER = 2,
};
+/* bit indices into mt792x_dev->nan_deferred_pending, set from the atomic
+ * MCU-event RX path and consumed by mt7925_nan_deferred_work()
+ */
+enum mt7925_nan_deferred_event {
+ MT7925_NAN_DEFERRED_STARTED_CLUSTER,
+ MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE,
+};
/* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */
enum nan_supported_bands {
NAN_SUPPORTED_BAND_ID_2P4G = 2,
@@ -108,12 +130,15 @@ enum nan_peer_supported_bands {
NAN_SUPPORTED_BN_NUM
};
+#define NAN_CH_CTRL_CH_TYPE BIT(0)
#define NAN_CH_CTRL_OP_CLASS GENMASK(15, 8)
#define NAN_CH_CTRL_PRIMARY_CH GENMASK(23, 16)
#define NAN_CRB_USE_DATA_PATH BIT(0)
#define NAN_CRB_AVAIL_6G_FORMAT GENMASK(2, 1)
+#define NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL 1
+
struct mt7925_nan_social_ch_scan_params {
u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS];
__le16 scan_period[NAN_MAX_SOCIAL_CHANNELS];
@@ -153,6 +178,32 @@ struct nan_rpt_dw_evt {
__le16 dw_num;
};
+#define NAN_ULW_ATTR_ID 0x17
+#define NAN_ULW_FIXED_PAYLOAD 16 /* Table 109 fixed fields */
+
+struct mt7925_nan_ulw_event {
+ u8 sched_id;
+ u8 seq_id;
+ u8 count_down;
+ u8 ulw_overwrite;
+ __le32 start_time;
+ __le32 duration;
+ __le32 period;
+} __packed;
+
+/* ULW attribute laid out in NAN spec Table 109 field order */
+struct mt7925_nan_ulw_attr {
+ u8 attr_id;
+ __le16 length;
+ u8 sched_id;
+ u8 seq_id;
+ __le32 start_time;
+ __le32 duration;
+ __le32 period;
+ u8 count_down;
+ u8 ulw_overwrite;
+} __packed;
+
struct mt7925_nan_conf_dw {
u8 config_2dot4g_dw_band;
__le32 dw_2dot4g_interval_val;
@@ -302,7 +353,7 @@ struct mt7925_nan_avail_ctrl_tlv {
__le16 len;
__le16 avail_ctrl;
u8 seq_id;
- u8 reserved[1];
+ u8 is_deferred;
} __packed __aligned(4);
struct mt7925_nan_ch_timeline {
@@ -346,8 +397,7 @@ struct mt7925_nan_sched_update_peer_cap_tlv {
struct mt7925_nan_sched_timeline {
u8 map_id;
- u8 local_map_id;
- u8 reserved[2];
+ u8 reserved[3];
union {
__le32 avail_map[NAN_TOTAL_DW];
u8 avail_block[NAN_TOTAL_DW * 4];
@@ -378,6 +428,15 @@ struct mt7925_nan_sched_update_crb_tlv {
struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE];
} __packed __aligned(4);
+#define NAN_ULW_MAX_SIZE 256
+
+struct mt7925_nan_update_ulw_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 nmi_addr[ETH_ALEN];
+ u8 ulw_attr[NAN_ULW_MAX_SIZE];
+} __packed __aligned(4);
+
struct mt7925_nan_sched_map_sta_rec_tlv {
__le16 tag;
__le16 len;
@@ -390,6 +449,38 @@ struct mt7925_nan_sched_map_sta_rec_tlv {
u8 reserved[2];
} __packed __aligned(4);
+/* Matches FW NAN_PHY_SETTING_T (enum fields are 4 bytes on ARM) */
+struct mt7925_nan_phy_setting {
+ u8 phy_type_set;
+ u8 non_ht_basic_phy_type;
+ u8 use_short_preamble;
+ u8 use_short_slot_time;
+ __le16 operational_rate_set;
+ __le16 bss_basic_rate_set;
+ __le16 vht_basic_mcs_set;
+ u8 erp_protect_mode;
+ u8 ht_op_info1;
+ __le16 ht_op_info2;
+ __le16 ht_op_info3;
+ __le32 ht_protect_mode;
+ __le32 gf_operation_mode;
+ __le32 rifs_operation_mode;
+} __packed;
+
+/* Matches FW NAN_SCHED_CMD_UPDATE_PHY_PARAM_T */
+struct mt7925_nan_update_phy_setting_tlv {
+ __le16 tag;
+ __le16 len;
+ struct mt7925_nan_phy_setting phy_2g;
+ struct mt7925_nan_phy_setting phy_5g;
+} __packed __aligned(4);
+
+int mt7925_nan_update_phy_setting(struct mt792x_dev *dev);
+
+struct ieee80211_chanctx_conf *
+mt7925_nan_seed_link_sta(struct mt792x_dev *dev,
+ struct ieee80211_link_sta *link_sta);
+
int mt7925_nan_enable(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf);
@@ -403,8 +494,6 @@ int mt7925_nan_change_configure(struct ieee80211_vif *vif,
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb);
-int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr);
-
void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index 02ef09dd797da..24585c992ff50 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -55,6 +55,7 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
cancel_delayed_work_sync(&pm->ps_work);
cancel_delayed_work_sync(&dev->mlo_pm_work);
cancel_work_sync(&pm->wake_work);
+ cancel_work_sync(&dev->nan_deferred_work);
mt7925_tx_token_put(dev);
__mt792x_mcu_drv_pmctrl(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 9efc251cb745f..9722d840c1af9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -342,6 +342,14 @@ struct mt792x_dev {
struct ieee80211_vif *nan_vif;
const struct ieee80211_iface_combination *iface_combinations;
int n_iface_combinations;
+ /* deferred NAN MCU events run out of the atomic RX path on one shared
+ * work; see mt7925_nan_deferred_work() and enum mt7925_nan_deferred_event
+ */
+ struct work_struct nan_deferred_work;
+ /* protects @nan_deferred_pending */
+ spinlock_t nan_deferred_lock;
+ unsigned long nan_deferred_pending;
+ u8 nan_started_cluster_id[ETH_ALEN];
};
static inline struct mt792x_bss_conf *
|
| 3/2 | 2026/08/24 22:58 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 21586 output: 37 thoughts: 515 Thoughts: **Analyzing the Reachability of a MediaTek MT7925 NAN Patch for Fuzzing** Okay, so I've got this patch affecting the NAN functionality within the `mt7925` MediaTek Wi-Fi driver. It's touching enablement, PHY settings, MCU events, and adds some `nan_deferred_work`. My immediate concern is, can I even *reach* this code in a fuzzing environment? Wi-Fi drivers, especially these hardware-specific ones like mt76, are notoriously picky about needing actual hardware – PCIe or USB. I quickly rule out `mac80211_hwsim` because, duh, that's just a *simulator*. We're dealing with a real hardware driver here. Now, the crucial question: is `mt7925` a PCIe or USB driver? Time to check the source. I'm going straight for `pci.c` and looking for a corresponding `usb.c` (or its absence, which would be telling). The diff indicates we're modifying `pci.c`. This strongly suggests PCIe. Typically, PCIe Wi-Fi drivers *demand* the presence of the physical device to even probe and execute, let alone to fuzz. Ah, but *does* syzkaller fuzz mt76? I know syzkaller can work with USB devices using `dummy_hcd` or `raw-gadget`, but PCIe is usually a different beast. Standard QEMU doesn't emulate these vendor-specific PCIe Wi-Fi cards. There's some PCI fuzzing support with vfio or other mechanisms, but they're not generally used for these. Then the instructions pop up. They explicitly say "Return WorthFuzzing=false if the patch...contains...code in vendor-specific PCIe...drivers...that require physical PCIe hardware cards not emulated in standard QEMU". And, *bingo*, MediaTek MT7925 is definitely a vendor-specific PCIe driver. Just to be thorough, I'm going to quickly check if `mt7925` even has a USB interface. `codesearch-dir-index` is the tool for this kind of quick check. Let's see if there's any hint of USB support within that directory. |
| 4/2 | 2026/08/24 22:58 | tool | codesearch-dir-index |
0mArgs:{
"Dir": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Files": [
"debugfs.c",
"init.c",
"mac.c",
"mac.h",
"main.c",
"mcu.c",
"mcu.h",
"mt7925.h",
"nan.c",
"nan.h",
"pci.c",
"pci_mac.c",
"pci_mcu.c",
"regd.c",
"regd.h",
"regs.h",
"testmode.c",
"usb.c"
],
"Subdirs": null
} |
| 5/2 | 2026/08/24 22:58 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 22762 output: 48 thoughts: 287 Thoughts: **Analyzing the Reachability of Kernel Code Through USB Fuzzing** Okay, so I see a `usb.c` file! That's interesting; the MT7925 clearly supports USB. Given my work with syzkaller, I know it can fuzz USB devices using the USB gadget framework and specifically the `dummy_hcd`. My primary concern now is whether the code modified in this patch is actually *reachable* via the USB driver. I note the patch touches `init.c`, `main.c`, `mcu.c`, `mt7925.h`, `nan.c`, `nan.h`, `pci.c`, and `mt792x.h`. Hold on… `pci.c` includes a modification to cancel the `nan_deferred_work`. Does that imply a similar action is needed in `usb.c`? The patch *didn't* modify `usb.c`, which is something to investigate further. My next step is to determine if `mt7925_nan_enable` and other related NAN functions are actually accessible. Reminding myself, NAN is a Wi-Fi feature, specifically Neighbor Awareness Networking, and is configured through `cfg80211` and `mac80211`. Now, if syzkaller's USB fuzzing probes the USB device, it registers a `wiphy` device. This is key. The implication then is that syzkaller can issue netlink commands to `cfg80211` to trigger various NAN operations. Therefore, the critical question becomes: Does `usb.c` call `mt7925_register_device`? That would be the connection. That is what I need to check. |
| 6/2 | 2026/08/24 22:58 | tool | grepper |
0mArgs:{
"Expression": "mt7925_register_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/init.c=190=static void mt7925_init_work(struct work_struct *work)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-242-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:243:int mt7925_register_device(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-244-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-331-}\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:332:EXPORT_SYMBOL_GPL(mt7925_register_device);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=277=int __mt7925_start(struct mt792x_phy *phy);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:278:int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-279-void mt7925_unregister_device(struct mt792x_dev *dev);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=529=static int mt7925_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-705-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:706:\tret = mt7925_register_device(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-707-\tif (ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=150=static int mt7925u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-251-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:252:\tret = mt7925_register_device(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-253-\tif (ret)\n"
} |
| 7/2 | 2026/08/24 22:58 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 24194 output: 43 thoughts: 103 Thoughts: **My Analysis of the mt7925 USB Driver's NAN Potential** Okay, so `mt7925_register_device` is definitely called by `mt7925u_probe` in `usb.c`. This means that fuzzing the device through its USB interface is a viable entry point. The crucial part is that when probed, it registers with mac80211, which gives us an existing framework to work with. Then, if we can trigger the right events, syzkaller should be able to leverage nl80211 to configure NAN. But here's the kicker, and the question that needs answering: does `mt7925` *actually* support NAN over USB? I need to verify that NAN is enabled for USB functionality. That’s the next thing to check. |
| 8/2 | 2026/08/24 22:58 | tool | grepper |
0mError:no matches Args: {
"Expression": "nan",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c"
}Results: {
"error": "no matches"
} |
| 9/2 | 2026/08/24 22:58 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 24531 output: 43 thoughts: 53 Thoughts: **Investigating NAN Initialization in MT7925 Driver** Okay, so I'm chasing down this NAN initialization, and the search in `usb.c` for "nan" came up empty. That's a bit odd. I know the MT7925 device uses NAN, so now I need to figure out where that setup occurs. Ah, right! `mt7925_register_device`… I recall that function. Let's dig into `init.c` and see what's happening within `mt7925_register_device`. Hopefully, it's a straightforward initialization and I can quickly ascertain the configuration parameters. |
| 10/2 | 2026/08/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "nan",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/init.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/init.c=133=static int mt7925_init_hardware(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-162-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:163:static int mt7925_init_nan_cap(struct mt76_dev *mdev)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-164-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-174-\tif (sband)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:175:\t\twiphy-\u003enan_capa.phy.ht = sband-\u003eht_cap;\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-176-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-178-\tif (sband)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:179:\t\twiphy-\u003enan_capa.phy.vht = sband-\u003evht_cap;\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-180-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-184-\tif (he_cap)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:185:\t\twiphy-\u003enan_capa.phy.he = *he_cap;\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-186-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c=190=static void mt7925_init_work(struct work_struct *work)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-209-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:210:\tdev-\u003emt76.init_wiphy = mt7925_init_nan_cap;\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-211-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c=243=int mt7925_register_device(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-272-\tINIT_WORK(\u0026dev-\u003einit_work, mt7925_init_work);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:273:\tINIT_WORK(\u0026dev-\u003enan_deferred_work, mt7925_nan_deferred_work);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:274:\tspin_lock_init(\u0026dev-\u003enan_deferred_lock);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-275-\n"
} |
| 11/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 25664 output: 48 thoughts: 278 Thoughts: **My Initial Thoughts on the MT7925 NAN Initialization** Okay, so `mt7925_init_nan_cap` is clearly the key function being used as the `init_wiphy` callback. That confirms NAN is enabled, universally, for this device, irrespective of whether it's a PCIe or USB interface. But, hold on a second... this patch also touches `drivers/net/wireless/mediatek/mt76/mt7925/pci.c`, specifically to cancel `nan_deferred_work`: ```c @@ -55,6 +55,7 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev) cancel_delayed_work_sync(&pm->ps_work); cancel_delayed_work_sync(&dev->mlo_pm_work); cancel_work_sync(&pm->wake_work); + cancel_work_sync(&dev->nan_deferred_work); mt7925_tx_token_put(dev); __mt792x_mcu_drv_pmctrl(dev); ``` That's fine for PCI. But this is where it gets interesting... it doesn't seem to touch the USB equivalent. Is this a potential bug? A race condition waiting to happen? I need to dig into the USB driver implementation. Let's immediately check `usb.c` to understand how the device is unregistered there. I need to understand how they handle this work in the USB version. |
| 12/2 | 2026/08/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "mt7925_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=278=int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:279:void mt7925_unregister_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-280-int mt7925_run_firmware(struct mt792x_dev *dev);\n"
} |
| 13/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 26517 output: 49 thoughts: 29 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Hmm, Let's Track Down This Function** Right, so I'm seeing `mt7925_unregister_device` called, and I know that's a key function in the MT7925 wireless driver. But hold on...it's declared in `mt7925.h`. Now, that's not unusual for an API function, but my immediate question is, where's the *implementation*? Where is that function actually *defined*? I need to go hunt down the source code for `mt7925_unregister_device` to understand its guts - the details that reveal how it actually works. This is essential for debugging, understanding driver behavior, or potentially modifying the function for a specific use-case. Time to start digging... |
| 14/2 | 2026/08/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "void mt7925_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=278=int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:279:void mt7925_unregister_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-280-int mt7925_run_firmware(struct mt792x_dev *dev);\n"
} |
| 15/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 26958 output: 49 thoughts: 18 Thoughts: Here's my thought process, as if I were considering this query: **Digging into the `mt7925_unregister_device` Function** Okay, so I need to find the definition of `mt7925_unregister_device`. That's the starting point. I'm going to head straight into the code. My guess is it’s a function related to deregistering or uninitializing a device, likely associated with the MediaTek MT7925 wireless chipset. Knowing that context, I'll be looking in the relevant driver source. Hopefully, I have access to the appropriate kernel sources and/or the MediaTek provided SDK. If not, I'll start with a web search, focusing on the kernel documentation or open source repositories like the Linux kernel tree itself or perhaps the relevant Mediatek Github repository (if one exists). The goal is the actual function signature and, most importantly, the function body. The name strongly suggests it's a critical part of the device lifecycle, probably handling resource cleanup and driver unbinding. I'll need to understand what resources are being released, any associated locks being taken/released, and what other functions are called from within `mt7925_unregister_device` to get a holistic view of its operation. Essentially, I'm looking to understand the full scope of what happens when this specific device is taken offline from a software perspective. |
| 16/2 | 2026/08/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "mt7925_unregister_device\\(",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=278=int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:279:void mt7925_unregister_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-280-int mt7925_run_firmware(struct mt792x_dev *dev);\n"
} |
| 17/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27498 output: 52 thoughts: 17 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Debugging Initiative: Undefined Behavior** Okay, hold on a second. Something's...off. It's flagging as undefined, and I haven't seen that before in this routine. I need to get to the bottom of this. Alright, I'm thinking, this definitely needs a direct look at the initialization procedure. Specifically, I'm going to jump into `init.c`. That should be the first place to check the potential sources for this issue. Let's see what's happening in there. |
| 18/2 | 2026/08/24 22:59 | tool | grepper |
0mError:no matches Args: {
"Expression": "void mt7925_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/init.c"
}Results: {
"error": "no matches"
} |
| 19/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27709 output: 43 thoughts: 13 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Investigating USB Unregistration** Okay, so we're talking USB device driver land, and something's gone awry with the unregistration process. My first instinct, given the context, is to zero in on the `usb.c` source file. It's the logical place to start digging for the core functions responsible for device unregistration within the USB subsystem. I need to refresh my memory on how the standard functions like `usb_deregister_dev()` (or similar) are implemented and what potential failure points might exist within that codepath. Essentially, my immediate goal is to understand the control flow related to unregistering a USB device. Gotta check for potential races, dangling pointers, or errors in the resource release within the unregister code. |
| 20/2 | 2026/08/24 22:59 | tool | grepper |
0mError:no matches Args: {
"Expression": "unregister",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c"
}Results: {
"error": "no matches"
} |
| 21/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27956 output: 50 thoughts: 12 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Unregistering USB Devices: Delving into `usb.c`** Okay, so I'm thinking about the unregistration process for USB devices, specifically how it's handled within `usb.c`. My immediate question is: what's the exact mechanism? I know there's a corresponding registration function, likely some `usb_register_device` or similar, but the unregistration side is always a bit less straightforward, usually involving a cascade of calls. I'm mentally running through the typical unregistration scenario: is it a direct call to a specific unregistration function? Or does it operate more like a deregistration process that requires cleanup of data structures and deallocation of resources? Does this utilize a callback system or polling, if the device is not "present?" What are the specific data structures being manipulated, and how are they tracked to ensure no dangling pointers or memory leaks occur during unregistration? I'm also wondering about the interaction with the USB host controller driver and the device driver. How does `usb.c` signal the unregistration event to these drivers, and what are the synchronization primitives (mutexes, spinlocks, etc.) used to prevent race conditions during this critical phase? Are there any specific error handling mechanisms in place to deal with unexpected device disconnects or unregistration failures? I need to refresh my memory on the internal data structures that track device state – likely things like URBs, endpoints, and interface handles. How are these handles released and freed? Does unregistering trigger an unmap operation? Are there any special considerations for composite devices, where multiple interfaces need to be unregistered independently? The devil is in the details, and I want to fully understand this. Time to dig into the source code! |
| 22/2 | 2026/08/24 22:59 | tool | grepper |
0mError:no matches Args: {
"Expression": "mt7925u_disconnect",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c"
}Results: {
"error": "no matches"
} |
| 23/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 28410 output: 49 thoughts: 12 Thoughts: Here's a summary of my initial thought process, as though I were considering a `usb.c` file: **Initial Assessment of `usb.c`** Okay, so we're diving into `usb.c`. My immediate thought is, "Alright, let's get a handle on the landscape." This file is the bedrock of USB functionality, so understanding its architecture is critical. I'm going to start by quickly scanning the file's structure. I'll look for the key data structures first: what are the USB descriptors? Where are the endpoint definitions? Are there any obvious state machine implementations or interrupt handlers defined? My expert intuition tells me to zero in on any core functions related to initialization, device enumeration, and data transfer. These are the usual suspects. I’ll keep an eye out for any potentially complex algorithms or hardware-specific interactions, as that's often where the real magic (and bugs) reside in these low-level drivers. I want to see how this implementation handles things like error conditions and power management too, because those are often overlooked. Overall, I need to understand this file's fundamental role in the USB ecosystem. |
| 24/2 | 2026/08/24 22:59 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 1,
"LineCount": 100
}Results: {
"Contents": " 1:\t// SPDX-License-Identifier: BSD-3-Clause-Clear\n 2:\t/* Copyright (C) 2023 MediaTek Inc. */\n 3:\t\n 4:\t#include \u003clinux/kernel.h\u003e\n 5:\t#include \u003clinux/module.h\u003e\n 6:\t#include \u003clinux/usb.h\u003e\n 7:\t\n 8:\t#include \"mt7925.h\"\n 9:\t#include \"mcu.h\"\n 10:\t#include \"mac.h\"\n 11:\t\n 12:\tstatic const struct usb_device_id mt7925u_device_table[] = {\n 13:\t\t{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x6639, 0xff, 0xff, 0xff),\n 14:\t\t\t.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },\n 15:\t\t{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7925, 0xff, 0xff, 0xff),\n 16:\t\t\t.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },\n 17:\t\t/* Netgear, Inc. A8500 */\n 18:\t\t{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9050, 0xff, 0xff, 0xff),\n 19:\t\t\t.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },\n 20:\t\t/* Netgear, Inc. A9000 */\n 21:\t\t{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9072, 0xff, 0xff, 0xff),\n 22:\t\t\t.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },\n 23:\t\t{ },\n 24:\t};\n 25:\t\n 26:\tstatic int\n 27:\tmt7925u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,\n 28:\t\t\t\t int cmd, int *seq)\n 29:\t{\n 30:\t\tstruct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);\n 31:\t\tu32 pad, ep;\n 32:\t\tint ret;\n 33:\t\n 34:\t\tret = mt7925_mcu_fill_message(mdev, skb, cmd, seq);\n 35:\t\tif (ret)\n 36:\t\t\treturn ret;\n 37:\t\n 38:\t\tmdev-\u003emcu.timeout = 3 * HZ;\n 39:\t\n 40:\t\tif (cmd != MCU_CMD(FW_SCATTER))\n 41:\t\t\tep = MT_EP_OUT_INBAND_CMD;\n 42:\t\telse\n 43:\t\t\tep = MT_EP_OUT_AC_BE;\n 44:\t\n 45:\t\tmt792x_skb_add_usb_sdio_hdr(dev, skb, 0);\n 46:\t\tpad = round_up(skb-\u003elen, 4) + 4 - skb-\u003elen;\n 47:\t\t__skb_put_zero(skb, pad);\n 48:\t\n 49:\t\tret = mt76u_bulk_msg(\u0026dev-\u003emt76, skb-\u003edata, skb-\u003elen, NULL,\n 50:\t\t\t\t 1000, ep);\n 51:\t\tdev_kfree_skb(skb);\n 52:\t\n 53:\t\treturn ret;\n 54:\t}\n 55:\t\n 56:\tstatic int mt7925u_mcu_init(struct mt792x_dev *dev)\n 57:\t{\n 58:\t\tstatic const struct mt76_mcu_ops mcu_ops = {\n 59:\t\t\t.headroom = MT_SDIO_HDR_SIZE +\n 60:\t\t\t\t sizeof(struct mt76_connac2_mcu_txd),\n 61:\t\t\t.tailroom = MT_USB_TAIL_SIZE,\n 62:\t\t\t.mcu_skb_send_msg = mt7925u_mcu_send_message,\n 63:\t\t\t.mcu_parse_response = mt7925_mcu_parse_response,\n 64:\t\t};\n 65:\t\tint ret;\n 66:\t\n 67:\t\tdev-\u003emt76.mcu_ops = \u0026mcu_ops;\n 68:\t\n 69:\t\tmt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\n 70:\t\tret = mt7925_run_firmware(dev);\n 71:\t\tif (ret)\n 72:\t\t\treturn ret;\n 73:\t\n 74:\t\tset_bit(MT76_STATE_MCU_RUNNING, \u0026dev-\u003emphy.state);\n 75:\t\tmt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\n 76:\t\n 77:\t\treturn 0;\n 78:\t}\n 79:\t\n 80:\tstatic int mt7925u_mac_reset(struct mt792x_dev *dev)\n 81:\t{\n 82:\t\tint err;\n 83:\t\n 84:\t\tif (atomic_read(\u0026dev-\u003emt76.bus_hung))\n 85:\t\t\treturn 0;\n 86:\t\n 87:\t\tmt792xu_reset_on_bus_error(dev);\n 88:\t\tif (atomic_read(\u0026dev-\u003emt76.bus_hung))\n 89:\t\t\treturn 0;\n 90:\t\n 91:\t\tmt76_txq_schedule_all(\u0026dev-\u003emphy);\n 92:\t\tmt76_worker_disable(\u0026dev-\u003emt76.tx_worker);\n 93:\t\n 94:\t\tset_bit(MT76_RESET, \u0026dev-\u003emphy.state);\n 95:\t\tset_bit(MT76_MCU_RESET, \u0026dev-\u003emphy.state);\n 96:\t\n 97:\t\twake_up(\u0026dev-\u003emt76.mcu.wait);\n 98:\t\tskb_queue_purge(\u0026dev-\u003emt76.mcu.res_q);\n 99:\t\n 100:\t\tmt76u_stop_rx(\u0026dev-\u003emt76);\n"
} |
| 25/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30440 output: 51 thoughts: 12 Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, geared toward an expert audience, and in the first person: **Diving Back into `usb.c`** Alright, time to get back to this `usb.c` file. I've been focusing on [mention a specific recent topic or function if you have it, otherwise skip] and now I want to get a broader view. I'm going to start from [mention starting point, e.g., the last section I looked at, or the top of the file, or a specific function I need to review]. The goal here is to refresh my memory of the larger architecture and how things are interconnected within this USB driver. I expect I'll spot opportunities for optimization or potential areas of concern that weren't immediately obvious when I was focused on a smaller piece of it. It's crucial, as always, to keep the bigger picture in mind. Let's see what we uncover. |
| 26/2 | 2026/08/24 22:59 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 101,
"LineCount": 100
}Results: {
"Contents": " 101:\t\tmt76u_stop_tx(\u0026dev-\u003emt76);\n 102:\t\n 103:\t\tmt792xu_wfsys_reset(dev);\n 104:\t\n 105:\t\tclear_bit(MT76_MCU_RESET, \u0026dev-\u003emphy.state);\n 106:\t\terr = mt76u_resume_rx(\u0026dev-\u003emt76);\n 107:\t\tif (err)\n 108:\t\t\tgoto out;\n 109:\t\n 110:\t\terr = mt792xu_mcu_power_on(dev);\n 111:\t\tif (err)\n 112:\t\t\tgoto out;\n 113:\t\n 114:\t\terr = mt792xu_dma_init(dev, false);\n 115:\t\tif (err)\n 116:\t\t\tgoto out;\n 117:\t\n 118:\t\tmt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);\n 119:\t\tmt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\n 120:\t\n 121:\t\terr = mt7925_run_firmware(dev);\n 122:\t\tif (err)\n 123:\t\t\tgoto out;\n 124:\t\n 125:\t\tmt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\n 126:\t\n 127:\t\terr = mt7925_mcu_set_eeprom(dev);\n 128:\t\tif (err)\n 129:\t\t\tgoto out;\n 130:\t\n 131:\t\terr = mt7925_mac_init(dev);\n 132:\t\tif (err)\n 133:\t\t\tgoto out;\n 134:\t\n 135:\t\tif (is_mt7927(\u0026dev-\u003emt76)) {\n 136:\t\t\terr = mt7925_mcu_set_dbdc(\u0026dev-\u003emphy, true);\n 137:\t\t\tif (err)\n 138:\t\t\t\tgoto out;\n 139:\t\t}\n 140:\t\n 141:\t\terr = __mt7925_start(\u0026dev-\u003ephy);\n 142:\tout:\n 143:\t\tclear_bit(MT76_RESET, \u0026dev-\u003emphy.state);\n 144:\t\n 145:\t\tmt76_worker_enable(\u0026dev-\u003emt76.tx_worker);\n 146:\t\n 147:\t\treturn err;\n 148:\t}\n 149:\t\n 150:\tstatic int mt7925u_probe(struct usb_interface *usb_intf,\n 151:\t\t\t\t const struct usb_device_id *id)\n 152:\t{\n 153:\t\tstatic const struct mt76_driver_ops drv_ops = {\n 154:\t\t\t.txwi_size = MT_SDIO_TXD_SIZE,\n 155:\t\t\t.drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ |\n 156:\t\t\t\t MT_DRV_AMSDU_OFFLOAD,\n 157:\t\t\t.survey_flags = SURVEY_INFO_TIME_TX |\n 158:\t\t\t\t\tSURVEY_INFO_TIME_RX |\n 159:\t\t\t\t\tSURVEY_INFO_TIME_BSS_RX,\n 160:\t\t\t.tx_prepare_skb = mt7925_usb_sdio_tx_prepare_skb,\n 161:\t\t\t.tx_complete_skb = mt7925_usb_sdio_tx_complete_skb,\n 162:\t\t\t.tx_status_data = mt7925_usb_sdio_tx_status_data,\n 163:\t\t\t.rx_skb = mt7925_queue_rx_skb,\n 164:\t\t\t.rx_check = mt7925_rx_check,\n 165:\t\t\t.sta_add = mt7925_mac_sta_add,\n 166:\t\t\t.sta_event = mt7925_mac_sta_event,\n 167:\t\t\t.sta_remove = mt7925_mac_sta_remove,\n 168:\t\t\t.update_survey = mt792x_update_channel,\n 169:\t\t};\n 170:\t\tstatic const struct mt792x_hif_ops hif_ops = {\n 171:\t\t\t.mcu_init = mt7925u_mcu_init,\n 172:\t\t\t.init_reset = mt792xu_init_reset,\n 173:\t\t\t.reset = mt7925u_mac_reset,\n 174:\t\t};\n 175:\t\tstatic struct mt76_bus_ops bus_ops = {\n 176:\t\t\t.rr = mt792xu_rr,\n 177:\t\t\t.wr = mt792xu_wr,\n 178:\t\t\t.rmw = mt792xu_rmw,\n 179:\t\t\t.read_copy = mt76u_read_copy,\n 180:\t\t\t.write_copy = mt792xu_copy,\n 181:\t\t\t.type = MT76_BUS_USB,\n 182:\t\t};\n 183:\t\tstruct usb_device *udev = interface_to_usbdev(usb_intf);\n 184:\t\tstruct ieee80211_ops *ops;\n 185:\t\tstruct ieee80211_hw *hw;\n 186:\t\tstruct mt792x_dev *dev;\n 187:\t\tstruct mt76_dev *mdev;\n 188:\t\tu8 features;\n 189:\t\tint ret;\n 190:\t\n 191:\t\tops = mt792x_get_mac80211_ops(\u0026usb_intf-\u003edev, \u0026mt7925_ops,\n 192:\t\t\t\t\t (void *)id-\u003edriver_info, \u0026features);\n 193:\t\tif (!ops)\n 194:\t\t\treturn -ENOMEM;\n 195:\t\n 196:\t\tops-\u003estop = mt792xu_stop;\n 197:\t\n 198:\t\tmdev = mt76_alloc_device(\u0026usb_intf-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\n 199:\t\tif (!mdev)\n 200:\t\t\treturn -ENOMEM;\n"
} |
| 27/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 32445 output: 51 thoughts: 24 Thoughts: Here's a summary of my thought process, as if I were analyzing that code: **Diving into the USB Driver's Disconnect Logic** Okay, so I'm digging into `usb.c` here. The goal is to understand the disconnect routine, specifically `mt7925u_disconnect`. Naturally, my first instinct is to see how this function fits into the bigger picture. I'm assuming there's likely some sort of USB device hotplug event handling going on within this driver. I want to see exactly what happens when the USB device connected to the mt7925u is disconnected. What resources are cleaned up? Are there any critical checks or sequencing I need to be aware of? I'm hoping to gain a solid grasp of how the driver gracefully handles the detachment, preventing any potential errors or resource leaks. Let's see how they've implemented the `mt7925u_disconnect` function. I'm expecting some kind of interrupt unregistering, freeing of allocated memory or mutex unlocking. Time to delve into the code! |
| 28/2 | 2026/08/24 22:59 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 201,
"LineCount": 100
}Results: {
"Contents": " 201:\t\n 202:\t\tdev = container_of(mdev, struct mt792x_dev, mt76);\n 203:\t\tdev-\u003efw_features = features;\n 204:\t\tdev-\u003ehif_ops = \u0026hif_ops;\n 205:\t\tmt792xu_reset_work_init(dev);\n 206:\t\n 207:\t\tusb_reset_device(udev);\n 208:\t\n 209:\t\tusb_set_intfdata(usb_intf, dev);\n 210:\t\n 211:\t\tret = __mt76u_init(mdev, usb_intf, \u0026bus_ops);\n 212:\t\tif (ret \u003c 0)\n 213:\t\t\tgoto error;\n 214:\t\n 215:\t\tmdev-\u003erev = (mt76_rr(dev, MT_HW_CHIPID) \u003c\u003c 16) |\n 216:\t\t\t (mt76_rr(dev, MT_HW_REV) \u0026 0xff);\n 217:\t\tdev_dbg(mdev-\u003edev, \"ASIC revision: %04x\\n\", mdev-\u003erev);\n 218:\t\n 219:\t\tif (mt76_chip(mdev) == 0x6639) {\n 220:\t\t\tdev_dbg(mdev-\u003edev,\n 221:\t\t\t\t\"MT7927 raw CHIPID=0x%04x, forcing chip=0x7927\\n\",\n 222:\t\t\t\tmt76_chip(mdev));\n 223:\t\t\tmdev-\u003erev = (0x7927 \u003c\u003c 16) | (mdev-\u003erev \u0026 0xff);\n 224:\t\t}\n 225:\t\n 226:\t\tif (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {\n 227:\t\t\tret = mt792xu_wfsys_reset(dev);\n 228:\t\t\tif (ret)\n 229:\t\t\t\tgoto error;\n 230:\t\t}\n 231:\t\n 232:\t\tret = mt792xu_mcu_power_on(dev);\n 233:\t\tif (ret)\n 234:\t\t\tgoto error;\n 235:\t\n 236:\t\tret = mt76u_alloc_mcu_queue(\u0026dev-\u003emt76);\n 237:\t\tif (ret)\n 238:\t\t\tgoto error;\n 239:\t\n 240:\t\tret = mt76u_alloc_queues(\u0026dev-\u003emt76);\n 241:\t\tif (ret)\n 242:\t\t\tgoto error;\n 243:\t\n 244:\t\tret = mt792xu_dma_init(dev, false);\n 245:\t\tif (ret)\n 246:\t\t\tgoto error;\n 247:\t\n 248:\t\thw = mt76_hw(dev);\n 249:\t\t/* check hw sg support in order to enable AMSDU */\n 250:\t\thw-\u003emax_tx_fragments = mdev-\u003eusb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;\n 251:\t\n 252:\t\tret = mt7925_register_device(dev);\n 253:\t\tif (ret)\n 254:\t\t\tgoto error;\n 255:\t\n 256:\t\treturn 0;\n 257:\t\n 258:\terror:\n 259:\t\tmt76u_queues_deinit(\u0026dev-\u003emt76);\n 260:\t\tmt792xu_reset_work_cleanup(dev);\n 261:\t\n 262:\t\tusb_set_intfdata(usb_intf, NULL);\n 263:\t\n 264:\t\tmt76_free_device(\u0026dev-\u003emt76);\n 265:\t\n 266:\t\treturn ret;\n 267:\t}\n 268:\t\n 269:\t#ifdef CONFIG_PM\n 270:\tstatic int mt7925u_suspend(struct usb_interface *intf, pm_message_t state)\n 271:\t{\n 272:\t\tstruct mt792x_dev *dev = usb_get_intfdata(intf);\n 273:\t\tstruct mt76_connac_pm *pm = \u0026dev-\u003epm;\n 274:\t\tint err, ret;\n 275:\t\n 276:\t\tpm-\u003esuspended = true;\n 277:\t\tdev-\u003ehif_resumed = false;\n 278:\t\tflush_work(\u0026dev-\u003ereset_work);\n 279:\t\tcancel_delayed_work_sync(\u0026dev-\u003emlo_pm_work);\n 280:\t\n 281:\t\tmt76_connac_mcu_set_hif_suspend(\u0026dev-\u003emt76, true, false);\n 282:\t\tret = wait_event_timeout(dev-\u003ewait,\n 283:\t\t\t\t\t dev-\u003ehif_idle, 3 * HZ);\n 284:\t\tif (!ret) {\n 285:\t\t\terr = -ETIMEDOUT;\n 286:\t\t\tgoto failed;\n 287:\t\t}\n 288:\t\n 289:\t\tmt76u_stop_rx(\u0026dev-\u003emt76);\n 290:\t\tmt76u_stop_tx(\u0026dev-\u003emt76);\n 291:\t\n 292:\t\treturn 0;\n 293:\t\n 294:\tfailed:\n 295:\t\tpm-\u003esuspended = false;\n 296:\t\n 297:\t\tif (err \u003c 0)\n 298:\t\t\tmt792x_reset(\u0026dev-\u003emt76);\n 299:\t\n 300:\t\treturn err;\n"
} |
| 29/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34307 output: 51 thoughts: 24 Thoughts: Here's my take on the thought process, as requested: **Diving Deeper into the Disconnect Logic** Okay, so I've spotted `mt7925u_disconnect` in `usb.c`. Now, my mind immediately jumps to a more comprehensive understanding. I need to get the full picture of how this disconnection is handled within the driver. This function is the key, but to really understand its implications, I need to read the rest of this file. What other functions does it call? What state transitions are involved? What resources are cleaned up? The specific context within `usb.c` is going to be incredibly valuable and what I am really after. I want to see how this disconnect fits into the larger framework. Let's dig in and see the details. |
| 30/2 | 2026/08/24 22:59 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 301,
"LineCount": 100
}Results: {
"Contents": " 301:\t}\n 302:\t\n 303:\tstatic int mt7925u_resume(struct usb_interface *intf)\n 304:\t{\n 305:\t\tstruct mt792x_dev *dev = usb_get_intfdata(intf);\n 306:\t\tstruct mt76_connac_pm *pm = \u0026dev-\u003epm;\n 307:\t\tbool reinit = true;\n 308:\t\tint err, i, ret;\n 309:\t\n 310:\t\tdev-\u003ehif_idle = false;\n 311:\t\tfor (i = 0; i \u003c 10; i++) {\n 312:\t\t\tu32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT);\n 313:\t\n 314:\t\t\tif (!(val \u0026 MT_WF_SW_SER_TRIGGER_SUSPEND)) {\n 315:\t\t\t\treinit = false;\n 316:\t\t\t\tbreak;\n 317:\t\t\t}\n 318:\t\t\tif (val \u0026 MT_WF_SW_SER_DONE_SUSPEND) {\n 319:\t\t\t\tmt76_wr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT, 0);\n 320:\t\t\t\tbreak;\n 321:\t\t\t}\n 322:\t\n 323:\t\t\tmsleep(20);\n 324:\t\t}\n 325:\t\n 326:\t\tif (reinit || mt792x_dma_need_reinit(dev)) {\n 327:\t\t\terr = mt792xu_dma_init(dev, true);\n 328:\t\t\tif (err)\n 329:\t\t\t\tgoto failed;\n 330:\t\t}\n 331:\t\n 332:\t\terr = mt76u_resume_rx(\u0026dev-\u003emt76);\n 333:\t\tif (err \u003c 0)\n 334:\t\t\tgoto failed;\n 335:\t\n 336:\t\tmt76_connac_mcu_set_hif_suspend(\u0026dev-\u003emt76, false, false);\n 337:\t\tret = wait_event_timeout(dev-\u003ewait,\n 338:\t\t\t\t\t dev-\u003ehif_resumed, 3 * HZ);\n 339:\t\tif (!ret)\n 340:\t\t\terr = -ETIMEDOUT;\n 341:\tfailed:\n 342:\t\tpm-\u003esuspended = false;\n 343:\t\n 344:\t\tif (err \u003c 0)\n 345:\t\t\tmt792x_reset(\u0026dev-\u003emt76);\n 346:\t\n 347:\t\treturn err;\n 348:\t}\n 349:\t#endif /* CONFIG_PM */\n 350:\t\n 351:\tMODULE_DEVICE_TABLE(usb, mt7925u_device_table);\n 352:\tMODULE_FIRMWARE(MT7925_FIRMWARE_WM);\n 353:\tMODULE_FIRMWARE(MT7925_ROM_PATCH);\n 354:\t\n 355:\tstatic struct usb_driver mt7925u_driver = {\n 356:\t\t.name\t\t= KBUILD_MODNAME,\n 357:\t\t.id_table\t= mt7925u_device_table,\n 358:\t\t.probe\t\t= mt7925u_probe,\n 359:\t\t.disconnect\t= mt792xu_disconnect,\n 360:\t#ifdef CONFIG_PM\n 361:\t\t.suspend\t= mt7925u_suspend,\n 362:\t\t.resume\t\t= mt7925u_resume,\n 363:\t\t.reset_resume\t= mt7925u_resume,\n 364:\t#endif /* CONFIG_PM */\n 365:\t\t.soft_unbind\t= 1,\n 366:\t\t.disable_hub_initiated_lpm = 1,\n 367:\t};\n 368:\tmodule_usb_driver(mt7925u_driver);\n 369:\t\n 370:\tMODULE_AUTHOR(\"Lorenzo Bianconi \u003clorenzo@kernel.org\u003e\");\n 371:\tMODULE_DESCRIPTION(\"MediaTek MT7925U (USB) wireless driver\");\n 372:\tMODULE_LICENSE(\"Dual BSD/GPL\");\n"
} |
| 31/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35710 output: 40 thoughts: 126 Thoughts: **Dissecting the MT792x Disconnect Sequence** Okay, so I see `mt792xu_disconnect` in play here. My initial thought is to trace the function definition. Given the naming convention, it's likely residing within a file associated with the MT792x USB driver, something like `mt792x/usb.c`, though that's just an educated guess based on past experience with these sorts of things. Hold on, I'm getting a little turned around. I just spotted that `mt7925_unregister_device` is being called from `mt7925e_unregister_device` in `pci.c`. The fact it's unregistering a device does suggest that it is a disconnection function. Aha! Now it's clicked. `mt792xu_disconnect` is a *generic* function designed to handle disconnects for all MT792x USB drivers, regardless of the specific variant. That makes the search a little easier, though it also points to how the function might be implemented to accommodate that. Time to zero in on the `mt792xu_disconnect` implementation and see how it works under the hood. |
| 32/2 | 2026/08/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "mt792xu_disconnect",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7921/usb.c=338=static struct usb_driver mt7921u_driver = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c-341-\t.probe\t\t= mt7921u_probe,\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c:342:\t.disconnect\t= mt792xu_disconnect,\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c-343-#ifdef CONFIG_PM\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=355=static struct usb_driver mt7925u_driver = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-358-\t.probe\t\t= mt7925u_probe,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:359:\t.disconnect\t= mt792xu_disconnect,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-360-#ifdef CONFIG_PM\n--\ndrivers/net/wireless/mediatek/mt76/mt792x.h=619=void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len);\ndrivers/net/wireless/mediatek/mt76/mt792x.h:620:void mt792xu_disconnect(struct usb_interface *usb_intf);\ndrivers/net/wireless/mediatek/mt76/mt792x.h-621-void mt792xu_stop(struct ieee80211_hw *hw, bool suspend);\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c=495=EXPORT_SYMBOL_GPL(mt792xu_stop);\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c-496-\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c:497:void mt792xu_disconnect(struct usb_interface *usb_intf)\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c-498-{\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c-526-}\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c:527:EXPORT_SYMBOL_GPL(mt792xu_disconnect);\ndrivers/net/wireless/mediatek/mt76/mt792x_usb.c-528-\n"
} |
| 33/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36877 output: 50 thoughts: 25 Thoughts: Here's my take on the thought process, as if I were the one thinking it: **Diving into the MT792X USB Disconnect Logic** Okay, time to get my hands dirty. I need to understand the disconnect process for the MT792X chipset over USB. Specifically, I'm heading into `mt792xu_disconnect` within the `mt792x_usb.c` file. This is where the core logic for handling the device being physically removed or otherwise disconnected is going to reside. I'm expecting to see the cleanup routines, any necessary hardware reset or disabling procedures, and perhaps some handling of pending transfers or state transitions. I'll be looking closely at how it interacts with the USB core, the device's registers, and any internal MT792X structures to ensure a clean and controlled teardown. It's critical this disconnect function does its job correctly to avoid any system instability or lingering resource issues after the device is gone. Let's see what we've got. |
| 34/2 | 2026/08/24 22:59 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt792x_usb.c",
"FirstLine": 497,
"LineCount": 35
}Results: {
"Contents": " 497:\tvoid mt792xu_disconnect(struct usb_interface *usb_intf)\n 498:\t{\n 499:\t\tstruct mt792x_dev *dev = usb_get_intfdata(usb_intf);\n 500:\t\n 501:\t\tif (!dev)\n 502:\t\t\treturn;\n 503:\t\n 504:\t\tset_bit(MT76_RESET, \u0026dev-\u003emphy.state);\n 505:\t\tset_bit(MT76_MCU_RESET, \u0026dev-\u003emphy.state);\n 506:\t\tclear_bit(MT76_STATE_RUNNING, \u0026dev-\u003emphy.state);\n 507:\t\twake_up(\u0026dev-\u003emt76.mcu.wait);\n 508:\t\tskb_queue_purge(\u0026dev-\u003emt76.mcu.res_q);\n 509:\t\n 510:\t\tcancel_work_sync(\u0026dev-\u003ereset_work);\n 511:\t\tcancel_work_sync(\u0026dev-\u003einit_work);\n 512:\t\tmt76_worker_disable(\u0026dev-\u003emt76.tx_worker);\n 513:\t\tmt792xu_reset_work_cleanup(dev);\n 514:\t\tif (!test_bit(MT76_STATE_INITIALIZED, \u0026dev-\u003emphy.state)) {\n 515:\t\t\tset_bit(MT76_REMOVED, \u0026dev-\u003emphy.state);\n 516:\t\t\treturn;\n 517:\t\t}\n 518:\t\n 519:\t\tmt76_unregister_device(\u0026dev-\u003emt76);\n 520:\t\tmt792xu_cleanup(dev);\n 521:\t\tset_bit(MT76_REMOVED, \u0026dev-\u003emphy.state);\n 522:\t\n 523:\t\tusb_set_intfdata(usb_intf, NULL);\n 524:\t\n 525:\t\tmt76_free_device(\u0026dev-\u003emt76);\n 526:\t}\n 527:\tEXPORT_SYMBOL_GPL(mt792xu_disconnect);\n 528:\t\n 529:\tMODULE_DESCRIPTION(\"MediaTek MT792x USB helpers\");\n 530:\tMODULE_LICENSE(\"Dual BSD/GPL\");\n 531:\tMODULE_AUTHOR(\"Lorenzo Bianconi \u003clorenzo@kernel.org\u003e\");\n"
} |
| 35/2 | 2026/08/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 37805 output: 49 thoughts: 111 Thoughts: **Debugging the Device Unregistration** Okay, so I'm looking into how this device gets unregistered and it seems like `mt792xu_disconnect` isn't using the specific `mt7925_unregister_device` function. Instead, it's calling the more generic `mt76_unregister_device`. Hmm, that's interesting. Now, I need to remind myself where `mt7925_unregister_device` *is* actually being used. Right, it looks like `mt7925_unregister_device` is only being called from the `pci.c` file, if my memory serves. Hold on a second, though... I'm seeing `mt7925_unregister_device` in `mt7925.h`, but I'm drawing a blank on its actual definition. Okay, time for another search to track down `void mt7925_unregister_device` and figure out where the heck it's implemented. |
| 36/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "void mt7925_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=278=int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:279:void mt7925_unregister_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-280-int mt7925_run_firmware(struct mt792x_dev *dev);\n"
} |
| 37/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 38356 output: 48 thoughts: 32 Thoughts: Okay, here's my take on those thoughts, framed as an expert in the field: **Refining the Search Strategy** Alright, that's frustrating. I know I just tried a search on this, and came up empty. Clearly, the initial query wasn't precise enough, or perhaps I'm looking at this from the wrong angle. My first instinct would be to go back and check the logs. But for the sake of efficiency, let's refine the search string immediately. Since I'm fairly certain of the function name - `mt7925_unregister_device` - let's cut away any extraneous cruft in the search terms. I'll drop the `void` part since that's likely already indexed as part of the function signature. This simplification should hopefully return more relevant results this time. |
| 38/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "mt7925_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=278=int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:279:void mt7925_unregister_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-280-int mt7925_run_firmware(struct mt792x_dev *dev);\n"
} |
| 39/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 38786 output: 51 thoughts: 263 Thoughts: **My Analysis of the Code Modification** Okay, so the change I'm looking at, `mt7925e_unregister_device`, is definitely rooted in `pci.c`, which makes sense given the function's name. This patch modifies `pci.c`, specifically adding a `cancel_work_sync` call for `dev->nan_deferred_work`. Interesting... Hang on a second. This `mt7925e_unregister_device` function is explicitly for the PCIe version. So, this implies that the USB version probably *doesn't* cancel `nan_deferred_work`. I need to confirm that distinction. I should verify that. Wait, that's odd, `mt7925_unregister_device` is declared in `mt7925.h` but the definition isn't right here. Where *is* it defined? I need to double-check `init.c`. There has to be a definition somewhere. |
| 40/2 | 2026/08/24 23:00 | tool | grepper |
0mError:no matches Args: {
"Expression": "mt7925_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/init.c"
}Results: {
"error": "no matches"
} |
| 41/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 39326 output: 53 thoughts: 46 Thoughts: **My Initial Thoughts on Function Location** Okay, hold on a second... `mt7925e_unregister_device` - I know that function, and I'm pretty sure it's related to PCI device unregistration. Let me just quickly confirm that. Right, so if I remember correctly, the typical place for PCI device management functions would be under `pci.c`. The most logical next step is to head over there and take a look for that specific function call, `mt7925e_unregister_device`, and see what the surrounding context is. It'll be much easier to understand how it's used if I can see its direct usage. |
| 42/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "mt7925e_unregister_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/pci.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/pci.c=36=static int mt7925e_init_reset(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-40-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:41:static void mt7925e_unregister_device(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-42-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=724=static void mt7925_pci_remove(struct pci_dev *pdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-729-\tset_bit(MT76_REMOVED, \u0026mdev-\u003ephy.state);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:730:\tmt7925e_unregister_device(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-731-\tdevm_free_irq(\u0026pdev-\u003edev, pdev-\u003eirq, dev);\n"
} |
| 43/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 39942 output: 39 thoughts: 1136 Thoughts: **Reaching and Fuzzing NAN Functions in MT7925 via USB** Okay, here's what I'm thinking. I've been looking at the `mt7925e_unregister_device` function, which is static in `pci.c`, but I need to consider the USB context. `usb.c` uses `mt792xu_disconnect` from `mt792x_usb.c`. My immediate concern is whether `mt792xu_disconnect` cancels the `nan_deferred_work` workqueue. It looks like it cancels `reset_work` and `init_work`, but not `nan_deferred_work`. And `nan_deferred_work` is specifically tied to the `mt7925` driver. This could potentially lead to a memory leak or a use-after-free scenario if `nan_deferred_work` is still running when the USB device is disconnected. Regardless of that specific issue, the key is that this code *is* reachable via USB. The patch I'm examining modifies a bunch of functions related to NAN (Neighbor Awareness Networking), specifically: `mt7925_nan_enable`, `mt7925_nan_disable`, `mt7925_nan_update_phy_setting`, `mt7925_nan_seed_link_sta`, `mt7925_nan_deferred_work`, and some others like `mt7925_nan_mcu_handle_de_event`, `mt7925_nan_handle_ulw_update`, and so on. These functions are accessible when the user configures NAN using netlink commands to the `wiphy` device that the USB driver creates. This is a very interesting attack surface. Since syzkaller can emulate USB devices and send these netlink commands, I'm confident that these functions are definitely reachable, and therefore, they are worth fuzzing. My primary focus should be the symbols that are either added or modified by this patch. So, I need to identify the key functions. Let's make a list: * `mt7925_nan_deferred_work` * `mt7925_nan_update_phy_setting` * `mt7925_nan_seed_link_sta` * `mt7925_nan_enable` * `mt7925_nan_disable` * `mt7925_nan_change_configure` (although not modified, it provides context) * `mt7925_nan_mcu_handle_de_event` * `mt7925_nan_handle_ulw_update` * `mt7925_nan_handle_sched_update_done` * `mt7925_nan_mcu_event` * `mt7925_nan_local_sched_changed` * `mt792x_nan_set_peer_schedule` * `mt792x_nan_set_peer_rec` * `mt792x_nan_map_sta_rec` Now, the next thing I need to do is check which of these symbols are exported and which are static because the non-static symbols are the primary candidates for external interaction and thus fuzzing. So, I checked each one: * `mt7925_nan_deferred_work` is non-static. * `mt7925_nan_update_phy_setting` is non-static. * `mt7925_nan_seed_link_sta` is non-static. * `mt7925_nan_enable` is non-static. * `mt7925_nan_disable` is non-static. * `mt7925_nan_mcu_event` is non-static. * `mt7925_nan_local_sched_changed` is non-static. * `mt792x_nan_set_peer_schedule` is non-static. * `mt792x_nan_set_peer_rec` is non-static. * `mt792x_nan_map_sta_rec` is non-static. Just to be absolutely sure, let's verify `mt7925_nan_enable`, since it's the gateway for many of those calls: Yes, it's non-static, defined in ` |
| 44/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "config MT7925",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/Kconfig-1-# SPDX-License-Identifier: BSD-3-Clause-Clear\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:2:config MT7925_COMMON\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-3-\ttristate\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-6-\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:7:config MT7925E\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-8-\ttristate \"MediaTek MT7925E (PCIe) support\"\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-18-\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:19:config MT7925U\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-20-\ttristate \"MediaTek MT7925U (USB) support\"\n"
} |
| 45/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 42462 output: 47 thoughts: 23 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing the MT7925U USB Configuration** Right, so `MT7925U` is clearly the configuration I'm working with for the USB interface. My immediate next step, as always, is to dive into the dependencies. I need to understand what other components, drivers, or system settings this config relies upon. I'll need to map out the interconnectedness. Are there any potential conflicts I should be aware of, or specific versions of supporting modules required for this to function optimally? Time to start tracing that dependency graph. |
| 46/2 | 2026/08/24 23:00 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/Kconfig",
"FirstLine": 1,
"LineCount": 30
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: BSD-3-Clause-Clear\n 2:\tconfig MT7925_COMMON\n 3:\t\ttristate\n 4:\t\tselect MT792x_LIB\n 5:\t\tselect WANT_DEV_COREDUMP\n 6:\t\n 7:\tconfig MT7925E\n 8:\t\ttristate \"MediaTek MT7925E (PCIe) support\"\n 9:\t\tselect MT7925_COMMON\n 10:\t\tdepends on MAC80211\n 11:\t\tdepends on PCI\n 12:\t\thelp\n 13:\t\t This adds support for MT7925-based wireless PCIe devices,\n 14:\t\t which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be\n 15:\t\t 2x2:2SS 4096-QAM, 160MHz channels.\n 16:\t\n 17:\t\t To compile this driver as a module, choose M here.\n 18:\t\n 19:\tconfig MT7925U\n 20:\t\ttristate \"MediaTek MT7925U (USB) support\"\n 21:\t\tselect MT792x_USB\n 22:\t\tselect MT7925_COMMON\n 23:\t\tdepends on MAC80211\n 24:\t\tdepends on USB\n 25:\t\thelp\n 26:\t\t This adds support for MT7925-based wireless USB devices,\n 27:\t\t which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be\n 28:\t\t 2x2:2SS 4096-QAM, 160MHz channels.\n 29:\t\n 30:\t\t To compile this driver as a module, choose M here.\n"
} |
| 47/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 43147 output: 55 thoughts: 379 Thoughts: **My Configuration Checklist for MT7925U Fuzzing** Okay, so I'm focusing on getting `MT7925U` right for USB fuzzing with syzkaller. I know it depends on `MAC80211` and `USB`, naturally. My initial thought was to simply include `MT7925U` in the `EnableConfigs`. But I should also throw in `MT7925E` for good measure, just to be comprehensive, though the USB side of things points me firmly toward `MT7925U` as the key target here. Wait, I need to remember that syzkaller *can* fuzz PCI devices, but USB is where syzkaller really shines in terms of both coverage and reliability, so I'll include both `MT7925U` *and* `MT7925E`. Also, I'll definitely want to ensure `USB` and `MAC80211` are correctly configured. But wait, `MAC80211` is part of the standard configuration. Fine, I'll just list `MT7925U` and `MT7925E`. Now, the symbol review. I need to zero in on these functions: `mt7925_nan_deferred_work`, `mt7925_nan_update_phy_setting`, `mt7925_nan_seed_link_sta`, `mt7925_nan_enable`, `mt7925_nan_disable`, `mt7925_nan_mcu_event`, `mt7925_nan_local_sched_changed`, `mt792x_nan_set_peer_schedule`, `mt792x_nan_set_peer_rec`, and `mt792x_nan_map_sta_rec`. Let me double check that `mt792x_nan_set_peer_schedule` is non-static. Gotta be absolutely sure those are accessible from the fuzzing harness. |
| 48/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "mt792x_nan_set_peer_schedule",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c=1004=mt7925_nan_peer_ulw_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-1033-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:1034:int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-1035-\t\t\t\t struct ieee80211_sta *sta)\n"
} |
| 49/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 44228 output: 55 thoughts: 27 Thoughts: Okay, here's my interpretation of those thoughts, framed as my own, given my expertise: **Examining the Dynamism** Alright, so the thing I'm working with is definitively non-static. We're dealing with a dynamic situation, which immediately shifts my thinking. That likely means memory allocation and deallocation, potentially race conditions, and definitely a more complex state management strategy than a purely static environment. That's a critical foundational understanding. Now, let me see... let's jog my memory – what about that specific function... `mt792x_nan_set_peer_rec`? I need to recall its role and how it interacts with the non-static elements. Is it responsible for updating, accessing, or perhaps even allocating/deallocating resources that are part of this dynamic landscape? Understanding the function's responsibility is key now, in this dynamic context. |
| 50/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "mt792x_nan_set_peer_rec",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c=1034=int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-1107-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:1108:int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-1109-\t\t\t struct ieee80211_sta *sta)\n"
} |
| 51/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 44694 output: 55 thoughts: 25 Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person: **Non-Static Considerations & Specific Function Review** Alright, the initial thought process is clear – we're explicitly moving away from static contexts. This implies a need for a more dynamic or context-aware approach, a shift that's likely prompted by the complexities of modern wireless networking. Now, the next logical step is to pinpoint a specific area to evaluate within that non-static paradigm. My mind immediately jumps to `mt792x_nan_map_sta_rec`. This function likely handles station record management within the mt792x chipset, specifically in relation to Network Allocation Vector (NAN) mapping. This means I need to carefully consider how this function would be impacted by the decision to remove a static context. The implications include: global state considerations, the need for increased synchronization mechanisms, potential impacts to concurrency, resource allocation, and memory footprint, among others. I need to understand if the change is a breaking change, an enhancement, or a refactoring effort. What is the goal here, and is this the right place to start? |
| 52/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "mt792x_nan_map_sta_rec",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c=1108=int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-1170-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:1171:int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-1172-\t\t\t struct ieee80211_vif *vif,\n"
} |
| 53/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 45212 output: 54 thoughts: 25 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing the Non-Static Event Handler** Alright, so the clue is *non-static*. That immediately brings up questions of scope and potential race conditions, especially when dealing with interrupts or asynchronous operations. We're obviously looking at some kind of event handling mechanism, likely in the context of the MT7925 wireless driver. Let's dig into this `mt7925_nan_mcu_event` function now. This suggests we're dealing with the Nano Network (NAN) Media Control Unit (MCU) event processing. I'll need to scrutinize the code within that handler carefully. I need to understand: * **How the event is triggered:** Is it hardware-generated, a software signal, or both? Knowing the source is key. * **What data it contains:** What information is being passed along with the event? This will tell me what the driver is trying to tell me. * **The context in which it's called:** Is it running in interrupt context, tasklet, workqueue, or something else? Timing is everything. * **The consequences of this event:** What actions are taken based on this event and what is the current state of the NAN component in the device? * **Possible interactions:** How does this event handler interract with the rest of the MT7925 driver? I need to see how the event is handled to fully understand the implications of this event being non-static. We need to find potential vulnerabilities. |
| 54/2 | 2026/08/24 23:00 | tool | grepper |
0mArgs:{
"Expression": "mt7925_nan_mcu_event",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c=637=mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-656-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:657:void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-658-{\n"
} |
| 55/2 | 2026/08/24 23:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 45820 output: 55 thoughts: 26 Thoughts: Here's my attempt at summarizing that thought process, tailored for an expert audience: **Non-Static Context in Scheduling** Okay, so the initial trigger confirms it: we're dealing with something non-static. The key here, and what immediately jumps to mind, is the `mt7925_nan_local_sched_changed` variable or function. This is the place to dig in. I need to understand how the scheduler is handling changes to its local environment. I'm assuming we're looking for where this non-static property is handled and how it impacts scheduling decisions within the `mt7925` driver. Need to verify what that entails and how it affects the overall flow. |
| 56/2 | 2026/08/24 23:01 | tool | grepper |
0mArgs:{
"Expression": "mt7925_nan_local_sched_changed",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c=794=static int mt7925_nan_avail_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-826-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:827:void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-828-\t\t\t\t struct ieee80211_vif *vif)\n"
} |
| 57/2 | 2026/08/24 23:01 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 46243 output: 53 thoughts: 24 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Non-Static Context and Configuration** Right, this definitely isn't static. We're looking at a dynamic scenario. My immediate thought is to delve into the `mt7925_nan_change_configure` function. That seems like the logical place to start dissecting the dynamic configuration changes. I need to understand how the system is behaving and that's the likely entry point. |
| 58/2 | 2026/08/24 23:01 | tool | grepper |
0mArgs:{
"Expression": "mt7925_nan_change_configure",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/nan.c=383=int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-402-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:403:int mt7925_nan_change_configure(struct ieee80211_vif *vif,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-404-\t\t\t\tstruct mt792x_dev *dev,\n"
} |
| 59/2 | 2026/08/24 23:01 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 46625 output: 284 thoughts: 3489 Thoughts: **Analysis of NAN (Neighbor Awareness Networking) Driver Modifications** Okay, here's what I've gathered. This patch focuses on enhancements and adjustments within the NAN functionality of the MT7925 Wi-Fi driver. While the initial scan didn't immediately show modifications, the deeper dive reveals several significant changes. First, several functions are new additions related to NAN: `mt7925_nan_deferred_work`, `mt7925_nan_update_phy_setting`, `mt7925_nan_seed_link_sta`, `mt7925_nan_enable`, and `mt7925_nan_disable`. These suggest improvements in how NAN operations are handled, potentially including PHY configuration, link establishment, and overall enable/disable behavior. Then, there are the modified functions. `mt7925_nan_mcu_event` shows updates to how the driver responds to events from the firmware, specifically adding handling for `NAN_UNI_EVENT_REPORT_DW_START`, `NAN_UNI_EVENT_ID_ULW_UPDATE`, and `NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE` events. This means the driver's event processing logic has expanded to manage these particular events. `mt7925_nan_local_sched_changed` has also been altered. It appears that the handling of local schedule updates has been streamlined, removing some of the deferral logic (specifically the `deferred` variable). The use of the `deferred` variable has been replaced to trigger the firmware to update the local schedule. `mt792x_nan_set_peer_schedule` has a new addition that will send a TLV with the UDW (Update Downstream). It seems that the firmware needs the updated downstream information for operation. The function `mt792x_nan_set_peer_rec` now includes a TLV (Type-Length-Value) to clear the committed schedule slots. This looks like a necessary step to prevent lingering stale entries in the scheduling. Finally, `mt792x_nan_map_sta_rec` has been modified. The changes seem to streamline the mapping of station records and clarify how NDP context IDs are handled. The role index is also clarified to use `NAN_BSS_INDEX_BAND0`. In summary, this patch is a definite upgrade to the NAN functionality. The changes make the driver handle new firmware events, update peer schedules, and modify how the station records map. The focus is on MT7925 devices, but these changes would apply to both MT7925E and MT7925U platforms. |
| 60/2 | 2026/08/24 23:01 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MT7925U",
"MT7925E"
],
"FocusSymbols": [
"mt7925_nan_deferred_work",
"mt7925_nan_update_phy_setting",
"mt7925_nan_seed_link_sta",
"mt7925_nan_enable",
"mt7925_nan_disable",
"mt7925_nan_mcu_event",
"mt7925_nan_local_sched_changed",
"mt792x_nan_set_peer_schedule",
"mt792x_nan_set_peer_rec",
"mt792x_nan_map_sta_rec"
],
"Reasoning": "The patch modifies NAN (Neighbor Awareness Networking) functionality in the MediaTek MT7925 Wi-Fi driver. It adds deferred work for NAN events, updates PHY settings, and refactors NAN enable/disable and peer scheduling logic. The driver supports USB (MT7925U) which can be emulated and fuzzed via syzkaller's USB gadget framework, making these changes reachable and worth fuzzing.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MT7925U",
"MT7925E"
],
"FocusSymbols": [
"mt7925_nan_deferred_work",
"mt7925_nan_update_phy_setting",
"mt7925_nan_seed_link_sta",
"mt7925_nan_enable",
"mt7925_nan_disable",
"mt7925_nan_mcu_event",
"mt7925_nan_local_sched_changed",
"mt792x_nan_set_peer_schedule",
"mt792x_nan_set_peer_rec",
"mt792x_nan_map_sta_rec"
],
"Reasoning": "The patch modifies NAN (Neighbor Awareness Networking) functionality in the MediaTek MT7925 Wi-Fi driver. It adds deferred work for NAN events, updates PHY settings, and refactors NAN enable/disable and peer scheduling logic. The driver supports USB (MT7925U) which can be emulated and fuzzed via syzkaller's USB gadget framework, making these changes reachable and worth fuzzing.",
"WorthFuzzing": true
} |
| 61/1 | 2026/08/24 23:01 | action | If |
3mArgs:{
"WorthFuzzing": true
}Results: null |
| 62/2 | 2026/08/24 23:01 | agent | kmsan-evaluator |
3mModel:best-expensive Args: null Results: {
"KMSANReasoning": "The patch modifies the mt7925 driver to add new features and fixes related to NAN (Neighbor Awareness Networking). It introduces new structures sent to the firmware (e.g., `mt7925_nan_update_phy_setting_tlv`, `mt7925_nan_update_ulw_tlv`, `mt7925_nan_sched_update_crb_tlv`) and one structure sent to user space (`mt7925_nan_ulw_attr` via `cfg80211_nan_ulw_update`). \n\nAll structures sent to the firmware are either explicitly zero-initialized (e.g., `req = {}` in `mt7925_nan_update_phy_setting`) or allocated using `mt76_connac_mcu_add_tlv`, which internally uses `skb_put_zero` to fully zero-initialize the TLV payload before specific fields are assigned. \n\nThe structure sent to user space (`mt7925_nan_ulw_attr`) is a `__packed` struct allocated on the stack in `mt7925_nan_handle_ulw_update`. All 9 of its fields are explicitly assigned before it is passed to `cfg80211_nan_ulw_update`, ensuring no uninitialized stack memory or padding bytes are leaked to user space.\n\nThe deferred work mechanism (`mt7925_nan_deferred_work`) uses `cluster_id` copied from `dev-\u003enan_started_cluster_id`. The `dev` structure is allocated with `kzalloc` (via `ieee80211_alloc_hw`), so `nan_started_cluster_id` is zero-initialized. It is only used if the `MT7925_NAN_DEFERRED_STARTED_CLUSTER` bit is set, which only happens after it has been populated with data from the firmware.\n\nSince all stack and heap structures introduced or modified by this patch are fully initialized or zeroed before being read, copied, or sent to user space/firmware, there is no risk of uninitialized memory usage or info-leaks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or memory corruption bugs. A dedicated KMSAN fuzzing session is not justified.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: For your convenience, here is the diff of the changes:
commit d5bb2726534f601faa0c0ec8575f8d350eed3738
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 24 22:58:34 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
index cd22fcc021b1e..8c3049b66a857 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
@@ -270,6 +270,8 @@ int mt7925_register_device(struct mt792x_dev *dev)
INIT_WORK(&dev->reset_work, mt7925_mac_reset_work);
INIT_WORK(&dev->init_work, mt7925_init_work);
+ INIT_WORK(&dev->nan_deferred_work, mt7925_nan_deferred_work);
+ spin_lock_init(&dev->nan_deferred_lock);
INIT_WORK(&dev->phy.roc_work, mt7925_roc_work);
timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 84b55f008b3d3..051a0c8aed587 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -964,6 +964,21 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
+ /* NAN_DATA (NDI) peers skip association - fill link_sta caps
+ * from sband and push BSS_INFO with correct phymode + RLM.
+ */
+ if (vif->type == NL80211_IFTYPE_NAN_DATA) {
+ struct ieee80211_chanctx_conf *nan_ctx;
+
+ nan_ctx = mt7925_nan_seed_link_sta(dev, link_sta);
+ mconf->mt76.ctx = nan_ctx;
+
+ ret = mt7925_mcu_add_bss_info(&dev->phy, nan_ctx,
+ link_conf, link_sta, true);
+ if (ret)
+ goto out_pm;
+ }
+
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_link_sta *mlink_bc;
@@ -2587,26 +2602,18 @@ static int mt7925_start_nan(struct ieee80211_hw *hw,
cfg80211_chandef_create(&link_conf->chanreq.oper, chan,
NL80211_CHAN_NO_HT);
- err = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf,
- NULL, true);
+ err = mt7925_mcu_add_bss_info(&dev->phy, NULL,
+ link_conf, NULL, true);
if (err < 0)
goto out;
- dev->nan_vif = vif;
-
- err = mt7925_nan_set_nmi_addr(dev, vif->addr);
- if (err)
- goto rollback_bss;
-
err = mt7925_nan_enable(vif, dev, conf);
- if (err)
- goto rollback_bss;
-
- goto out;
+ if (err) {
+ mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false);
+ goto out;
+ }
-rollback_bss:
- dev->nan_vif = NULL;
- mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false);
+ err = mt7925_nan_update_phy_setting(dev);
out:
mt792x_mutex_release(dev);
@@ -2621,6 +2628,13 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err, ret;
+ /* Drop a deferred event queued just before stop so a stale cluster_id
+ * cannot leak into a restart; the work re-checks liveness anyway.
+ */
+ spin_lock_bh(&dev->nan_deferred_lock);
+ dev->nan_deferred_pending = 0;
+ spin_unlock_bh(&dev->nan_deferred_lock);
+
mt792x_mutex_acquire(dev);
err = mt7925_nan_disable(vif, dev);
@@ -2630,9 +2644,6 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
if (!err)
err = ret;
- if (dev->nan_vif == vif)
- dev->nan_vif = NULL;
-
mt792x_mutex_release(dev);
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index fa29c486a4553..1cfc209f9be5c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1914,11 +1914,9 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,
phy = (struct sta_rec_phy *)tlv;
if (mt7925_vif_is_nan(vif)) {
- enum nl80211_band band = chandef->chan ? chandef->chan->band
- : NL80211_BAND_2GHZ;
phy->phy_type = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_ERP;
phy->phy_type |= mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,
- band,
+ NL80211_BAND_5GHZ,
link_sta);
} else {
phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,
@@ -2003,7 +2001,11 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,
ra_info = (struct sta_rec_ra_info *)tlv;
if (mt7925_vif_is_nan(vif))
- band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ;
+ /* NAN is OFDM-only per spec; borrow the 5 GHz band lookup to
+ * avoid PHY_TYPE_BIT_HR_DSSS/CCK bits being added to phy_type.
+ * NAN interfaces have no chanctx, so chandef->chan is always NULL.
+ */
+ band = NL80211_BAND_5GHZ;
else
band = chandef->chan->band;
@@ -2847,7 +2849,7 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy,
bmc = (struct bss_rate_tlv *)tlv;
if (mt7925_vif_is_nan(vif))
- band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ;
+ band = NL80211_BAND_5GHZ;
else
band = chandef->chan->band;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 321e732347f2f..33782d9ba9ed4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -361,6 +361,7 @@ void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac,
void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
void mt7925_set_ipv6_ns_work(struct work_struct *work);
+void mt7925_nan_deferred_work(struct work_struct *work);
int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
index d260e803d056f..8a59f7b1aee25 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
@@ -32,8 +32,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
if (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan))
return;
- req->config_support_5g = 1;
- req->support_5g_val = 1;
req->config_5g_channel = 1;
if (chan->hw_value == NAN_5G_LOW_DISC_CHANNEL)
@@ -44,73 +42,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
req->channel_5g_val = cpu_to_le32(ch5g);
}
-static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (!conf->band_cfgs[NL80211_BAND_2GHZ].chan)
- return;
-
- req->config_2dot4g_support = 1;
- req->support_2dot4g_val = 1;
-}
-
-static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req,
- const u8 *cluster_id)
-{
- if (!cluster_id)
- return;
-
- req->cluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] << 8);
- req->cluster_low = cpu_to_le16((u16)cluster_id[3]);
-}
-
-static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) {
- req->config_dw.config_2dot4g_dw_band = 1;
- req->config_dw.dw_2dot4g_interval_val =
- cpu_to_le32(conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval);
- }
-
- if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) {
- req->config_dw.config_5g_dw_band = 1;
- req->config_dw.dw_5g_interval_val =
- cpu_to_le32(conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval);
- }
-}
-
-static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (conf->discovery_beacon_interval > 0) {
- req->config_2dot4g_beacons = true;
- req->beacon_2dot4g_val = conf->discovery_beacon_interval;
- }
-}
-
-static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req,
- struct cfg80211_nan_conf *conf)
-{
- if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) {
- req->config_2dot4g_rssi_close = 1;
- req->rssi_close_2dot4g_val =
- abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close);
- req->config_2dot4g_rssi_middle = 1;
- req->rssi_middle_2dot4g_val =
- abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle);
- }
-
- if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {
- req->config_5g_rssi_close = 1;
- req->rssi_close_5g_val =
- abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close);
- req->config_5g_rssi_middle = 1;
- req->rssi_middle_5g_val =
- abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle);
- }
-}
-
static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
@@ -144,101 +75,6 @@ mt7925_nan_update_conf(struct mt792x_vif *mvif,
memcpy(mvif->nan.conf.cluster_id, conf->cluster_id, ETH_ALEN);
}
-int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr)
-{
- struct mt76_dev *mdev;
- struct {
- u8 rsv[4];
- struct mt7925_nan_nmi_addr_tlv nmi_addr_tlv;
- } nmi_cmd = {
- .rsv = { 0 },
- .nmi_addr_tlv = {
- .tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS),
- .len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)),
- },
- };
- int ret;
-
- if (!dev || !addr)
- return -EINVAL;
-
- if (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) {
- dev_err(dev->mt76.dev, "NAN: invalid NMI address %pM\n", addr);
- return -EINVAL;
- }
-
- mdev = &dev->mt76;
- memcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN);
-
- ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nmi_cmd,
- sizeof(nmi_cmd), true);
-
- return ret;
-}
-
-int mt7925_nan_enable(struct ieee80211_vif *vif,
- struct mt792x_dev *dev,
- struct cfg80211_nan_conf *conf)
-{
- struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
- struct mt76_dev *mdev = &dev->mt76;
- struct {
- u8 rsv[4];
- struct mt7925_nan_enable_req_tlv nan_req_tlv;
- } nan_cmd = {
- .rsv = { 0 },
- .nan_req_tlv = {
- .tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST),
- .len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)),
- .config_random_factor_force = 0,
- .random_factor_force_val = 0,
- .config_hop_count_force = 0,
- .hop_count_force_val = 0,
- },
- };
- struct mt7925_nan_enable_req_tlv *p_nan_req_tlv = &nan_cmd.nan_req_tlv;
- int ret;
-
- if (!vif || !dev || !conf)
- return -EINVAL;
-
- p_nan_req_tlv->master_pref = conf->master_pref;
-
- mt7925_nan_set_2g_support(p_nan_req_tlv, conf);
- mt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf);
- mt7925_nan_set_cluster_id(p_nan_req_tlv, conf->cluster_id);
- mt7925_nan_set_dw_interval(p_nan_req_tlv, conf);
- mt7925_nan_set_disc_beacon(p_nan_req_tlv, conf);
- mt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf);
- mt7925_nan_set_scan_params(p_nan_req_tlv, conf);
-
- mt7925_nan_update_conf(mvif, conf);
-
- ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
-
- return ret;
-}
-
-int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
-{
- struct mt76_dev *mdev = &dev->mt76;
- struct {
- u8 rsv[4];
- struct tlv nan_dis_tlv;
- } nan_cmd = {
- .rsv = { 0 },
- .nan_dis_tlv = {
- .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
- .len = cpu_to_le16(sizeof(struct tlv)),
- },
- };
-
- if (!dev)
- return -EINVAL;
-
- return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
-}
-
static int
mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)
{
@@ -357,6 +193,213 @@ mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)
return 0;
}
+/* FW rate set bit definitions (matches FW wlan_def_cmm.h) */
+#define NAN_RATE_SET_BIT_1M BIT(0)
+#define NAN_RATE_SET_BIT_2M BIT(1)
+#define NAN_RATE_SET_BIT_5_5M BIT(2)
+#define NAN_RATE_SET_BIT_11M BIT(3)
+#define NAN_RATE_SET_BIT_6M BIT(6)
+#define NAN_RATE_SET_BIT_9M BIT(7)
+#define NAN_RATE_SET_BIT_12M BIT(8)
+#define NAN_RATE_SET_BIT_18M BIT(9)
+#define NAN_RATE_SET_BIT_24M BIT(10)
+#define NAN_RATE_SET_BIT_36M BIT(11)
+#define NAN_RATE_SET_BIT_48M BIT(12)
+#define NAN_RATE_SET_BIT_54M BIT(13)
+
+#define NAN_RATE_SET_ALL_A (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_9M | \
+ NAN_RATE_SET_BIT_12M | NAN_RATE_SET_BIT_18M | \
+ NAN_RATE_SET_BIT_24M | NAN_RATE_SET_BIT_36M | \
+ NAN_RATE_SET_BIT_48M | NAN_RATE_SET_BIT_54M)
+
+/* 5G basic: 6M+12M+24M (OFDM) */
+#define NAN_BASIC_RATE_SET_5G (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_12M | \
+ NAN_RATE_SET_BIT_24M)
+
+/* GF_MODE_DISALLOWED = 2, RIFS_MODE_DISALLOWED = 1 */
+#define NAN_GF_MODE_DISALLOWED 2
+#define NAN_RIFS_MODE_DISALLOWED 1
+
+int mt7925_nan_update_phy_setting(struct mt792x_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mphy;
+ struct ieee80211_supported_band *sband_5g;
+ struct mt7925_nan_phy_setting *phy;
+ struct {
+ u8 rsv[4];
+ struct mt7925_nan_update_phy_setting_tlv tlv;
+ } req = {};
+
+ sband_5g = mphy->hw->wiphy->bands[NL80211_BAND_5GHZ];
+
+ req.tlv.tag = cpu_to_le16(NAN_UNI_CMD_UPDATE_PHY_SETTING);
+ req.tlv.len = cpu_to_le16(sizeof(req.tlv));
+
+ /* 2G: ERP + HT (no CCK/HR_DSSS - NAN uses OFDM only) */
+ phy = &req.tlv.phy_2g;
+ phy->phy_type_set = PHY_TYPE_BIT_ERP | PHY_TYPE_BIT_HT;
+ phy->non_ht_basic_phy_type = PHY_TYPE_ERP_INDEX;
+ phy->use_short_preamble = 1;
+ phy->use_short_slot_time = 1;
+ phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);
+ phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);
+ phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);
+ phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);
+
+ /* 5G: OFDM + HT + VHT (NAN_MODE_11A) */
+ phy = &req.tlv.phy_5g;
+ phy->phy_type_set = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HT |
+ PHY_TYPE_BIT_VHT;
+ phy->non_ht_basic_phy_type = PHY_TYPE_OFDM_INDEX;
+ phy->use_short_preamble = 1;
+ phy->use_short_slot_time = 1;
+ phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);
+ phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);
+ phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);
+ phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);
+
+ /* VHT basic MCS set from sband capability */
+ if (sband_5g && sband_5g->vht_cap.vht_supported)
+ phy->vht_basic_mcs_set =
+ sband_5g->vht_cap.vht_mcs.rx_mcs_map;
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(NAN),
+ &req, sizeof(req), true);
+}
+
+struct ieee80211_chanctx_conf *
+mt7925_nan_seed_link_sta(struct mt792x_dev *dev,
+ struct ieee80211_link_sta *link_sta)
+{
+ struct ieee80211_supported_band *sband_2g, *sband_5g;
+ struct ieee80211_chanctx_conf *nan_ctx = NULL;
+ struct ieee80211_vif *nan_vif = dev->nan_vif;
+
+ /* Fill HT cap from 2G sband */
+ sband_2g = dev->mphy.hw->wiphy->bands[NL80211_BAND_2GHZ];
+ sband_5g = dev->mphy.hw->wiphy->bands[NL80211_BAND_5GHZ];
+ if (sband_2g)
+ link_sta->ht_cap = sband_2g->ht_cap;
+
+ link_sta->sta->wme = true;
+ link_sta->rx_nss = hweight8(dev->mphy.antenna_mask);
+
+ /* Get chanctx from NAN schedule.
+ * Prefer 5G committed slot for wider BW (VHT), fallback
+ * to first valid slot if no 5G data slot is scheduled.
+ */
+ if (nan_vif) {
+ struct ieee80211_nan_channel **slots =
+ nan_vif->cfg.nan_sched.schedule;
+ int i;
+
+ for (i = 0; i < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; i++) {
+ struct ieee80211_chanctx_conf *ctx;
+
+ if (!slots[i] || IS_ERR(slots[i]) ||
+ !slots[i]->chanctx_conf)
+ continue;
+
+ ctx = slots[i]->chanctx_conf;
+ if (!nan_ctx)
+ nan_ctx = ctx;
+ if (ctx->def.chan->band == NL80211_BAND_5GHZ) {
+ nan_ctx = ctx;
+ break;
+ }
+ }
+ }
+
+ /* Capability describes what the device can do and must not be
+ * filtered by the current schedule - firmware gates the VHT rate
+ * mode per the data schedule and re-derives it on schedule
+ * change, which only works if the caps are present up front.
+ */
+ if (sband_5g)
+ link_sta->vht_cap = sband_5g->vht_cap;
+
+ /* Bandwidth here is the capability ceiling, not the operating
+ * width - the per-slot operating bandwidth follows the current
+ * slot channel via the firmware RLM sync, so deriving it from
+ * the schedule at STA-add time would cap a later 5 GHz schedule
+ * at the bring-up width.
+ */
+ link_sta->bandwidth = IEEE80211_STA_RX_BW_80;
+
+ return nan_ctx;
+}
+
+int mt7925_nan_enable(struct ieee80211_vif *vif,
+ struct mt792x_dev *dev,
+ struct cfg80211_nan_conf *conf)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt7925_nan_common_hdr *hdr;
+ struct mt7925_nan_enable_req_tlv *req;
+ struct sk_buff *skb;
+
+ if (!vif || !dev || !conf)
+ return -EINVAL;
+
+ skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_ENABLE_MAX_SIZE);
+ if (!skb)
+ return -ENOMEM;
+
+ hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
+ memset(hdr, 0, sizeof(*hdr));
+
+ /* Set cluster id before joining cluster */
+ if (mt7925_nan_cluster_id_tlv(skb, conf->cluster_id)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ /* NAN enable request tlv */
+ req = (struct mt7925_nan_enable_req_tlv *)
+ mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_ENABLE_REQUEST,
+ sizeof(*req));
+ if (!req) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ req->master_pref = conf->master_pref;
+
+ mt7925_nan_set_5g_channel(dev, req, conf);
+ mt7925_nan_set_scan_params(req, conf);
+
+ if (mt7925_nan_dw_tlv(skb, conf) ||
+ mt7925_nan_sync_rssi_tlv(skb, conf)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ mt7925_nan_update_conf(mvif, conf);
+
+ return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
+}
+
+int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct {
+ u8 rsv[4];
+ struct tlv nan_dis_tlv;
+ } nan_cmd = {
+ .rsv = { 0 },
+ .nan_dis_tlv = {
+ .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
+ .len = cpu_to_le16(sizeof(struct tlv)),
+ },
+ };
+
+ if (!dev)
+ return -EINVAL;
+
+ return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
+}
+
int mt7925_nan_change_configure(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf)
@@ -473,8 +516,26 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n",
de_evt->event_type, de_evt->cluster_id);
- if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER)
+ if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER &&
+ de_evt->event_type != NAN_EVENT_ID_STARTED_CLUSTER)
+ return;
+
+ /* STARTED_CLUSTER fires during NAN_START, before nan.started is set and
+ * before the supplicant subscribes - defer past NAN_START via the work
+ * so ieee80211_nan_cluster_joined() actually reaches userspace.
+ */
+ if (de_evt->event_type == NAN_EVENT_ID_STARTED_CLUSTER) {
+ dev_dbg(dev->mt76.dev,
+ "nan: deferring STARTED_CLUSTER cluster=%pM\n",
+ cluster_id);
+ spin_lock_bh(&dev->nan_deferred_lock);
+ memcpy(dev->nan_started_cluster_id, cluster_id, ETH_ALEN);
+ set_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER,
+ &dev->nan_deferred_pending);
+ spin_unlock_bh(&dev->nan_deferred_lock);
+ ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
return;
+ }
if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) {
dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n");
@@ -487,7 +548,110 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n",
de_evt->own_nmi, de_evt->master_nmi);
- ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL);
+ /* joined an existing cluster, not a self-anchored new one */
+ ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, false, GFP_KERNEL);
+}
+
+/* Runs the deferred NAN MCU events in process context; takes wiphy_lock
+ * before nan_vif, which the NAN stop path frees under that mutex.
+ */
+void
+mt7925_nan_deferred_work(struct work_struct *work)
+{
+ struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
+ nan_deferred_work);
+ struct ieee80211_vif *vif;
+ unsigned long pending;
+ u8 cluster_id[ETH_ALEN];
+
+ spin_lock_bh(&dev->nan_deferred_lock);
+ pending = dev->nan_deferred_pending;
+ dev->nan_deferred_pending = 0;
+ memcpy(cluster_id, dev->nan_started_cluster_id, ETH_ALEN);
+ spin_unlock_bh(&dev->nan_deferred_lock);
+
+ if (!pending)
+ return;
+
+ wiphy_lock(dev->mt76.hw->wiphy);
+ vif = dev->nan_vif;
+ if (!vif || !ieee80211_vif_nan_started(vif))
+ goto out;
+
+ if (test_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, &pending))
+ ieee80211_nan_cluster_joined(vif, cluster_id, true, GFP_KERNEL);
+
+ if (test_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &pending))
+ ieee80211_nan_sched_update_done(vif);
+out:
+ wiphy_unlock(dev->mt76.hw->wiphy);
+}
+
+static void
+mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)
+{
+ struct mt7925_nan_ulw_event *evt;
+ struct mt7925_nan_ulw_attr attr;
+ struct wireless_dev *wdev;
+ u16 len;
+
+ if (!dev || !tlv)
+ return;
+
+ if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif))
+ return;
+
+ len = le16_to_cpu(tlv->len);
+ if (len < sizeof(*tlv) + sizeof(*evt)) {
+ dev_warn(dev->mt76.dev,
+ "nan: short ulw event tlv len=%u\n", len);
+ return;
+ }
+
+ evt = (struct mt7925_nan_ulw_event *)tlv->data;
+ wdev = ieee80211_vif_to_wdev(dev->nan_vif);
+ if (!wdev)
+ return;
+
+ dev_dbg(dev->mt76.dev,
+ "nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\n",
+ wdev, wdev->owner_nlportid,
+ evt->sched_id, evt->seq_id, le32_to_cpu(evt->duration));
+
+ /* Reorder the FW fields into NAN spec Table 109 attribute layout */
+ attr.attr_id = NAN_ULW_ATTR_ID;
+ attr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD);
+ attr.sched_id = evt->sched_id;
+ attr.seq_id = evt->seq_id;
+ attr.start_time = evt->start_time;
+ attr.duration = evt->duration;
+ attr.period = evt->period;
+ attr.count_down = evt->count_down;
+ attr.ulw_overwrite = evt->ulw_overwrite;
+
+ cfg80211_nan_ulw_update(wdev, (const u8 *)&attr, sizeof(attr),
+ GFP_KERNEL);
+}
+
+static void
+mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv)
+{
+ struct ieee80211_vif *vif;
+
+ if (!dev || !tlv)
+ return;
+
+ vif = dev->nan_vif;
+ if (!vif || !ieee80211_vif_nan_started(vif))
+ return;
+
+ /* Runs in the BH-disabled MCU-event RX path; the mac80211 helper needs
+ * the wiphy mutex and may sleep, so hand it to the work instead.
+ */
+ spin_lock_bh(&dev->nan_deferred_lock);
+ set_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &dev->nan_deferred_pending);
+ spin_unlock_bh(&dev->nan_deferred_lock);
+ ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
}
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
@@ -515,9 +679,15 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
case NAN_UNI_EVENT_ID_DE_EVENT_IND:
mt7925_nan_mcu_handle_de_event(dev, tlv);
break;
- case NAN_UNI_EVENT_REPORT_DW_END:
+ case NAN_UNI_EVENT_REPORT_DW_START:
mt7925_nan_handle_dw_ind(dev, tlv);
break;
+ case NAN_UNI_EVENT_ID_ULW_UPDATE:
+ mt7925_nan_handle_ulw_update(dev, tlv);
+ break;
+ case NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE:
+ mt7925_nan_handle_sched_update_done(dev, tlv);
+ break;
default:
break;
}
@@ -555,6 +725,7 @@ static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,
avail_ctrl_tlv->avail_ctrl =
cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);
avail_ctrl_tlv->seq_id = seq_id;
+ avail_ctrl_tlv->is_deferred = sched->deferred ? 1 : 0;
return 0;
}
@@ -584,9 +755,14 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
if (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) ==
slot_chan->chan->hw_value) {
- u32 map = le32_to_cpu(ch_list[j].avail_map[0]);
+ u32 dw;
- ch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i));
+ for (dw = 0; dw < NAN_TOTAL_DW; dw++) {
+ u32 map = le32_to_cpu(ch_list[j].avail_map[dw]);
+
+ ch_list[j].avail_map[dw] =
+ cpu_to_le32(map | BIT(i));
+ }
le32_add_cpu(&ch_list[j].num, 1);
is_found = true;
break;
@@ -594,12 +770,18 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
}
if (!is_found && num_channels < NAN_TIMELINE_MGMT_CHNL_LIST_NUM) {
+ u32 dw;
+
ch_list[num_channels].ch_info =
- cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
+ cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_CH_TYPE,
+ NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL) |
+ FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
slot->channel_entry[0]) |
FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH,
slot_chan->chan->hw_value));
- ch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i));
+ for (dw = 0; dw < NAN_TOTAL_DW; dw++)
+ ch_list[num_channels].avail_map[dw] =
+ cpu_to_le32(BIT(i));
le32_add_cpu(&ch_list[num_channels].num, 1);
ch_list[num_channels].is_valid++;
num_channels++;
@@ -647,15 +829,12 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
{
struct mt7925_nan_common_hdr *hdr;
struct mt76_dev *mdev;
- bool deferred;
struct sk_buff *skb;
- int ret = -ENOMEM;
if (!dev || !vif)
return;
mdev = &dev->mt76;
- deferred = vif->cfg.nan_sched.deferred;
mt792x_mutex_acquire(dev);
@@ -672,19 +851,9 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
goto out;
}
- ret = mt76_mcu_skb_send_msg(mdev, skb,
- MCU_UNI_CMD(NAN), true);
+ mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), false);
out:
mt792x_mutex_release(dev);
-
- if (deferred) {
- if (ret)
- dev_err(mdev->dev,
- "NAN: local schedule update failed: %d\n",
- ret);
-
- ieee80211_nan_sched_update_done(vif);
- }
}
static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
@@ -712,23 +881,6 @@ static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
return 0;
}
-static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif)
-{
- struct wiphy *wiphy;
- u8 bands = 0;
-
- if (!mvif || !mvif->phy)
- return BIT(NAN_SUPPORTED_BAND_ID_2P4G);
-
- wiphy = mvif->phy->mt76->hw->wiphy;
- if (wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))
- bands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G);
- if (wiphy->nan_supported_bands & BIT(NL80211_BAND_5GHZ))
- bands |= BIT(NAN_SUPPORTED_BAND_ID_5G);
-
- return bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G);
-}
-
static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
struct ieee80211_sta *sta,
struct mt792x_sta *msta)
@@ -755,8 +907,7 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
peer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv;
peer_cap_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
- peer_cap_tlv->supported_bands =
- mt7925_nan_get_supported_bands(msta->vif);
+ peer_cap_tlv->supported_bands = BIT(NAN_SUPPORTED_BAND_ID_2P4G);
peer_cap_tlv->max_chnl_switch_time = cpu_to_le16(sched->max_chan_switch);
for (i = 0; i < sched->n_channels; i++) {
@@ -785,52 +936,40 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
static void
mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv,
- struct ieee80211_vif *vif,
struct ieee80211_nan_peer_sched *sched)
{
- struct ieee80211_nan_sched_cfg *local_sched;
- u8 local_map_id;
u32 m, slot;
- if (!vif || !sched)
+ if (!sched)
return;
- local_sched = &vif->cfg.nan_sched;
- local_map_id = mt7925_nan_avail_attr_ctrl(local_sched) &
- NAN_AVAIL_CTRL_MAPID;
-
for (m = 0; m < CFG80211_NAN_MAX_PEER_MAPS &&
m < NAN_TIMELINE_MGMT_SIZE; m++) {
+ struct ieee80211_nan_peer_map *map = &sched->maps[m];
struct mt7925_nan_sched_timeline *tl =
&crb_tlv->comm_faw_timeline[m];
- struct ieee80211_nan_peer_map *map = &sched->maps[m];
- u32 avail_map = 0;
if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
continue;
tl->map_id = map->map_id;
- tl->local_map_id = local_map_id;
+ /*
+ * Convert peer schedule slots to FW avail_map bitmap.
+ * Each bit represents one time slot where the peer has
+ * committed availability. Fill all DW intervals the same.
+ */
for (slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS;
slot++) {
- struct ieee80211_nan_channel *local_ch;
- struct ieee80211_nan_channel *peer_ch;
-
- local_ch = local_sched->schedule[slot];
- peer_ch = map->slots[slot];
+ struct ieee80211_nan_channel *ch = map->slots[slot];
+ u32 dw;
- if (!local_ch || !local_ch->chanctx_conf ||
- !peer_ch || !peer_ch->chanctx_conf)
+ if (!ch || !ch->chanctx_conf)
continue;
- if (local_ch->chanctx_conf != peer_ch->chanctx_conf)
- continue;
-
- avail_map |= BIT(slot);
+ for (dw = 0; dw < NAN_TOTAL_DW; dw++)
+ tl->avail_map[dw] |= cpu_to_le32(BIT(slot));
}
-
- tl->avail_map[0] = cpu_to_le32(avail_map);
}
}
@@ -856,8 +995,38 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb,
crb_tlv->is_use_ranging = false;
crb_tlv->comm_ndc_ctrl.is_valid = false;
- mt7925_nan_fill_crb_committed(crb_tlv, msta->vif->phy->dev->nan_vif,
- sta->nan_sched);
+ mt7925_nan_fill_crb_committed(crb_tlv, sta->nan_sched);
+
+ return 0;
+}
+
+static int
+mt7925_nan_peer_ulw_tlv(struct sk_buff *skb,
+ struct ieee80211_sta *sta,
+ struct mt792x_sta *msta)
+{
+ struct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL;
+ struct ieee80211_nan_peer_sched *sched = NULL;
+ struct tlv *tlv = NULL;
+
+ if (!skb || !sta || !msta)
+ return -EINVAL;
+
+ sched = sta->nan_sched;
+ if (!sched || !sched->init_ulw || !sched->ulw_size)
+ return 0; /* No ULW to send, not an error */
+
+ if (sched->ulw_size > NAN_ULW_MAX_SIZE)
+ return -EINVAL;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW,
+ sizeof(struct mt7925_nan_update_ulw_tlv));
+ if (!tlv)
+ return -ENOMEM;
+
+ ulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv;
+ ether_addr_copy(ulw_tlv->nmi_addr, sta->addr);
+ memcpy(ulw_tlv->ulw_attr, sched->init_ulw, sched->ulw_size);
return 0;
}
@@ -914,6 +1083,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
goto free_skb;
}
+ ret = mt7925_nan_peer_ulw_tlv(skb, sta, msta);
+ if (ret)
+ goto free_skb;
+
ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
if (ret && idx_allocated)
goto clear_idx;
@@ -935,18 +1108,18 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
struct ieee80211_sta *sta)
{
+ struct mt7925_nan_sched_update_crb_tlv *crb_tlv;
struct mt7925_nan_common_hdr *hdr;
struct mt792x_sta *msta;
struct mt792x_nan *nan;
struct sk_buff *skb;
+ struct tlv *tlv;
int ret;
if (!mdev || !sta)
return -EINVAL;
- skb = mt76_mcu_msg_alloc(mdev, NULL,
- sizeof(struct mt7925_nan_common_hdr) +
- sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv));
+ skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE);
if (!skb)
return -ENOMEM;
@@ -961,6 +1134,25 @@ int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
return 0;
}
+ /* Send a zero-avail_map CRB TLV before deactivating the peer record so
+ * firmware clears the committed schedule slots for this peer. Without
+ * this, stale CRB entries linger and cause scheduling conflicts for
+ * subsequent NDP connections that reuse the same sch_idx.
+ */
+ tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB,
+ sizeof(struct mt7925_nan_sched_update_crb_tlv));
+ if (!tlv) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+ crb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv;
+ crb_tlv->sch_idx = msta->nan_sched.sch_idx;
+ crb_tlv->flags = NAN_CRB_USE_DATA_PATH;
+ crb_tlv->is_use_ranging = false;
+ crb_tlv->comm_ndc_ctrl.is_valid = false;
+ /* avail_map is zero-initialised by mt76_connac_mcu_add_tlv */
+
+ /* Deactivate peer record and release connection index */
if (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) {
dev_kfree_skb(skb);
return -ENOMEM;
@@ -990,13 +1182,11 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
struct sk_buff *skb;
int ndp_ctx_id = 0;
int ret = -ENOMEM;
- struct mt792x_dev *dev;
struct tlv *tlv;
if (!mdev || !vif || !sta)
return -EINVAL;
- dev = container_of(mdev, struct mt792x_dev, mt76);
msta = (struct mt792x_sta *)sta->drv_priv;
mvif = (struct mt792x_vif *)vif->drv_priv;
@@ -1012,33 +1202,6 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
memcpy(nmi_addr, nmi_sta->addr, ETH_ALEN);
nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
- if (!nmi_msta->nan_sched.idx_assigned) {
- if (!nmi_sta->nan_sched) {
- rcu_read_unlock();
- dev_err(mdev->dev,
- "NAN: peer schedule missing for NDI sta %pM\n",
- sta->addr);
- return -EAGAIN;
- }
-
- rcu_read_unlock();
- ret = mt792x_nan_set_peer_schedule(dev, nmi_sta);
- if (ret)
- return ret;
-
- rcu_read_lock();
- nmi_sta = rcu_dereference(sta->nmi);
- if (!nmi_sta) {
- rcu_read_unlock();
- dev_err(mdev->dev,
- "NAN: NMI sta not found for NDI sta %pM\n",
- sta->addr);
- return -EINVAL;
- }
-
- nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
- }
-
ndp_ctx_id = find_first_zero_bit(&nmi_msta->nan_sched.ndp_ctx_bitmap,
NAN_MAX_NDP_CXT);
if (ndp_ctx_id >= NAN_MAX_NDP_CXT) {
@@ -1073,7 +1236,7 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
memcpy(map_tlv->nmi_addr, nmi_addr, ETH_ALEN);
map_tlv->sta_rec_idx = msta->deflink.wcid.idx;
map_tlv->ndp_ctx_id = ndp_ctx_id;
- map_tlv->role_idx = cpu_to_le32(mvif->bss_conf.mt76.idx);
+ map_tlv->role_idx = NAN_BSS_INDEX_BAND0;
memcpy(map_tlv->ndi_addr, vif->addr, ETH_ALEN);
ret = mt76_mcu_skb_send_msg(mdev, skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
index f55730e25f462..d81d84a222d90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
@@ -28,6 +28,12 @@
#define NAN_MAX_CONN_CFG 8
#define NAN_MAX_NDP_CXT 4
+#define MT7925_NAN_ENABLE_MAX_SIZE \
+ (sizeof(struct mt7925_nan_common_hdr) + \
+ sizeof(struct mt7925_nan_enable_req_tlv) + \
+ sizeof(struct mt7925_nan_dw_interval_tlv) + \
+ sizeof(struct mt7925_nan_cluster_id_tlv) + \
+ sizeof(struct mt7925_nan_sync_rssi_tlv))
#define MT7925_NAN_CONF_MAX_SIZE \
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_master_preference_tlv) + \
@@ -44,7 +50,8 @@
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) + \
sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) + \
- sizeof(struct mt7925_nan_sched_update_crb_tlv))
+ sizeof(struct mt7925_nan_sched_update_crb_tlv) + \
+ sizeof(struct mt7925_nan_update_ulw_tlv))
/* NAN Availability Attribute */
#define NAN_AVAIL_ATTR_ID_OFFSET 0
@@ -65,6 +72,8 @@
#define UNII3_LOWER_BOUND 149
#define UNII3_UPPER_BOUND 165
+#define NAN_BSS_INDEX_BAND0 0
+
enum nan_uni_cmd_tag {
NAN_UNI_CMD_SET_MASTER_PREFERENCE = 0,
NAN_UNI_CMD_ENABLE_REQUEST = 7,
@@ -73,6 +82,8 @@ enum nan_uni_cmd_tag {
NAN_UNI_CMD_UPDATE_CRB = 10,
NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD = 12,
NAN_UNI_CMD_MAP_STA_RECORD = 13,
+ NAN_UNI_CMD_UPDATE_ULW = 16,
+ NAN_UNI_CMD_UPDATE_PHY_SETTING = 18,
NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL = 20,
NAN_UNI_CMD_UPDATE_PEER_CAPABILITY = 21,
NAN_UNI_CMD_CHANGE_NMI_ADDRESS = 24,
@@ -84,14 +95,25 @@ enum nan_uni_cmd_tag {
enum nan_uni_event_tag {
NAN_UNI_EVENT_ID_DE_EVENT_IND = 19,
+ NAN_UNI_EVENT_ID_ULW_UPDATE = 39,
+ NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE = 43,
+ NAN_UNI_EVENT_REPORT_DW_START = 59,
NAN_UNI_EVENT_REPORT_DW_END = 60,
};
enum nan_disc_event_type {
NAN_EVENT_ID_DISC_MAC_ADDR = 0,
+ NAN_EVENT_ID_STARTED_CLUSTER = 1,
NAN_EVENT_ID_JOINED_CLUSTER = 2,
};
+/* bit indices into mt792x_dev->nan_deferred_pending, set from the atomic
+ * MCU-event RX path and consumed by mt7925_nan_deferred_work()
+ */
+enum mt7925_nan_deferred_event {
+ MT7925_NAN_DEFERRED_STARTED_CLUSTER,
+ MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE,
+};
/* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */
enum nan_supported_bands {
NAN_SUPPORTED_BAND_ID_2P4G = 2,
@@ -108,12 +130,15 @@ enum nan_peer_supported_bands {
NAN_SUPPORTED_BN_NUM
};
+#define NAN_CH_CTRL_CH_TYPE BIT(0)
#define NAN_CH_CTRL_OP_CLASS GENMASK(15, 8)
#define NAN_CH_CTRL_PRIMARY_CH GENMASK(23, 16)
#define NAN_CRB_USE_DATA_PATH BIT(0)
#define NAN_CRB_AVAIL_6G_FORMAT GENMASK(2, 1)
+#define NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL 1
+
struct mt7925_nan_social_ch_scan_params {
u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS];
__le16 scan_period[NAN_MAX_SOCIAL_CHANNELS];
@@ -153,6 +178,32 @@ struct nan_rpt_dw_evt {
__le16 dw_num;
};
+#define NAN_ULW_ATTR_ID 0x17
+#define NAN_ULW_FIXED_PAYLOAD 16 /* Table 109 fixed fields */
+
+struct mt7925_nan_ulw_event {
+ u8 sched_id;
+ u8 seq_id;
+ u8 count_down;
+ u8 ulw_overwrite;
+ __le32 start_time;
+ __le32 duration;
+ __le32 period;
+} __packed;
+
+/* ULW attribute laid out in NAN spec Table 109 field order */
+struct mt7925_nan_ulw_attr {
+ u8 attr_id;
+ __le16 length;
+ u8 sched_id;
+ u8 seq_id;
+ __le32 start_time;
+ __le32 duration;
+ __le32 period;
+ u8 count_down;
+ u8 ulw_overwrite;
+} __packed;
+
struct mt7925_nan_conf_dw {
u8 config_2dot4g_dw_band;
__le32 dw_2dot4g_interval_val;
@@ -302,7 +353,7 @@ struct mt7925_nan_avail_ctrl_tlv {
__le16 len;
__le16 avail_ctrl;
u8 seq_id;
- u8 reserved[1];
+ u8 is_deferred;
} __packed __aligned(4);
struct mt7925_nan_ch_timeline {
@@ -346,8 +397,7 @@ struct mt7925_nan_sched_update_peer_cap_tlv {
struct mt7925_nan_sched_timeline {
u8 map_id;
- u8 local_map_id;
- u8 reserved[2];
+ u8 reserved[3];
union {
__le32 avail_map[NAN_TOTAL_DW];
u8 avail_block[NAN_TOTAL_DW * 4];
@@ -378,6 +428,15 @@ struct mt7925_nan_sched_update_crb_tlv {
struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE];
} __packed __aligned(4);
+#define NAN_ULW_MAX_SIZE 256
+
+struct mt7925_nan_update_ulw_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 nmi_addr[ETH_ALEN];
+ u8 ulw_attr[NAN_ULW_MAX_SIZE];
+} __packed __aligned(4);
+
struct mt7925_nan_sched_map_sta_rec_tlv {
__le16 tag;
__le16 len;
@@ -390,6 +449,38 @@ struct mt7925_nan_sched_map_sta_rec_tlv {
u8 reserved[2];
} __packed __aligned(4);
+/* Matches FW NAN_PHY_SETTING_T (enum fields are 4 bytes on ARM) */
+struct mt7925_nan_phy_setting {
+ u8 phy_type_set;
+ u8 non_ht_basic_phy_type;
+ u8 use_short_preamble;
+ u8 use_short_slot_time;
+ __le16 operational_rate_set;
+ __le16 bss_basic_rate_set;
+ __le16 vht_basic_mcs_set;
+ u8 erp_protect_mode;
+ u8 ht_op_info1;
+ __le16 ht_op_info2;
+ __le16 ht_op_info3;
+ __le32 ht_protect_mode;
+ __le32 gf_operation_mode;
+ __le32 rifs_operation_mode;
+} __packed;
+
+/* Matches FW NAN_SCHED_CMD_UPDATE_PHY_PARAM_T */
+struct mt7925_nan_update_phy_setting_tlv {
+ __le16 tag;
+ __le16 len;
+ struct mt7925_nan_phy_setting phy_2g;
+ struct mt7925_nan_phy_setting phy_5g;
+} __packed __aligned(4);
+
+int mt7925_nan_update_phy_setting(struct mt792x_dev *dev);
+
+struct ieee80211_chanctx_conf *
+mt7925_nan_seed_link_sta(struct mt792x_dev *dev,
+ struct ieee80211_link_sta *link_sta);
+
int mt7925_nan_enable(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf);
@@ -403,8 +494,6 @@ int mt7925_nan_change_configure(struct ieee80211_vif *vif,
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb);
-int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr);
-
void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index 02ef09dd797da..24585c992ff50 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -55,6 +55,7 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
cancel_delayed_work_sync(&pm->ps_work);
cancel_delayed_work_sync(&dev->mlo_pm_work);
cancel_work_sync(&pm->wake_work);
+ cancel_work_sync(&dev->nan_deferred_work);
mt7925_tx_token_put(dev);
__mt792x_mcu_drv_pmctrl(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 9efc251cb745f..9722d840c1af9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -342,6 +342,14 @@ struct mt792x_dev {
struct ieee80211_vif *nan_vif;
const struct ieee80211_iface_combination *iface_combinations;
int n_iface_combinations;
+ /* deferred NAN MCU events run out of the atomic RX path on one shared
+ * work; see mt7925_nan_deferred_work() and enum mt7925_nan_deferred_event
+ */
+ struct work_struct nan_deferred_work;
+ /* protects @nan_deferred_pending */
+ spinlock_t nan_deferred_lock;
+ unsigned long nan_deferred_pending;
+ u8 nan_started_cluster_id[ETH_ALEN];
};
static inline struct mt792x_bss_conf *
|
| 63/3 | 2026/08/24 23:01 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 21583 output: 28 thoughts: 796 Thoughts: **Analyzing Potential Uninitialized Memory Risks in the `mt7925` Driver Patch Series**
Okay, so I need to figure out if this patch series for the `mt7925` driver warrants a dedicated KMSAN fuzzing session. The changes are all focused on NAN (Neighbor Awareness Networking) features and fixes, specifically within `drivers/net/wireless/mediatek/mt76/mt7925/`. Let's break down each modification to see if any introduce the risk of uninitialized memory usage.
First, `mt7925_register_device` adds initialization of `nan_deferred_work` with `INIT_WORK` and `nan_deferred_lock` with `spin_lock_init`. Nothing problematic there.
`mt7925_mac_link_sta_add` checks for `NL80211_IFTYPE_NAN_DATA` and calls `mt7925_nan_seed_link_sta` and `mt7925_mcu_add_bss_info`. No obvious uninitialized memory usage either.
`mt7925_start_nan` is simply modifying error handling and calling `mt7925_nan_update_phy_setting`. Okay, moving on. Similarly, `mt7925_stop_nan` just clears `nan_deferred_pending`.
The changes in `mt7925_mcu_sta_phy_tlv`, `mt7925_mcu_sta_rate_ctrl_tlv`, and `mt7925_mcu_bss_bmc_tlv` look to change the band logic for NAN. No red flags yet.
Now, `mt7925_nan_update_phy_setting`. This one creates a stack-allocated `req` struct that is *zero-initialized* (`= {}`). Excellent! This means there's no immediate uninitialized memory issue there.
`mt7925_nan_seed_link_sta` fills a `link_sta` structure based on some logic. Need to look more deeply at the function's logic, but no immediate uninitialized variable problems.
Finally, we're at `mt7925_nan_enable`. This function is interesting because it allocates an `skb` with `mt76_mcu_msg_alloc`, adds a header, and then a request using `mt76_connac_mcu_add_tlv`. Now, the crucial part is the `mt76_connac_mcu_add_tlv`. My gut feeling is that the TLV is initialized. However, I need to confirm this. I remember it's in `drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c`, and `mt76_connac_mcu_add_tlv` is where the memory initialization likely happens. Let me do a quick grep. Let's see...
|
| 64/3 | 2026/08/24 23:01 | tool | grepper |
0mArgs:{
"Expression": "mt76_connac_mcu_add_tlv"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 677 lines.\nUse more precise expression if possible.\n\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c=931=mt7615_mcu_sta_ba(struct mt7615_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c-947-\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c:948:\tsta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c-949-\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c=1153=mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c-1180-\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c:1181:\tsta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,\ndrivers/net/wireless/mediatek/mt76/mt7615/mcu.c-1182-\t\t\t\t\t sizeof(struct tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=372=void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-403-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:404:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-405-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=414=void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-423-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:424:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-425-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=482=void mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-490-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:491:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-492-\tuapsd = (struct sta_rec_uapsd *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=549=int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-561-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:562:\tsta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-563-\t\t\t\t\t sizeof(struct tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=650=mt76_connac_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-663-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:664:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-665-\tamsdu = (struct sta_rec_amsdu *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=677=mt76_connac_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-684-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:685:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-686-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=810=mt76_connac_mcu_sta_he_tlv_v2(struct sk_buff *skb, struct ieee80211_sta *sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-816-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:817:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-818-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=900=void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-919-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:920:\t\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-921-\t\tht = (struct sta_rec_ht *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-930-\t\tlen = is_connac2(dev) ? sizeof(*vht) : sizeof(*vht) - 4;\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:931:\t\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len);\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-932-\t\tvht = (struct sta_rec_vht *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-954-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:955:\t\t\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-956-\t\t\t\t\t\t sizeof(*he_6g_capa));\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-961-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:962:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-963-\tphy = (struct sta_rec_phy *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-972-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:973:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-974-\tra_info = (struct sta_rec_ra_info *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-989-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:990:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-991-\tstate = (struct sta_rec_state *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1094=int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1123-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1124:\tsta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1125-\t\t\t\t\t sizeof(struct tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1305=void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1311-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1312:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1313-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1337=int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1350-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1351:\tsta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1352-\t\t\t\t\t sizeof(struct tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=2766=mt76_connac_mcu_sta_key_tlv(struct mt76_connac_sta_key_conf *sta_key_conf,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-2774-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:2775:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-2776-\tsec = (struct sta_rec_sec *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=2863=void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif_link *mvif)\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-2872-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:2873:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-2874-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=2881=int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-2891-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:2892:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss));\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-2893-\tbss = (struct bss_info_basic *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h=1993=static inline struct tlv *\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h:1994:mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len)\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h-1995-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=547=mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-554-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:555:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-556-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=580=mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-586-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:587:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-588-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=606=mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-618-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:619:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-620-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=636=mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-642-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:643:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-644-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=653=mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy)\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-659-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:660:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-661-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=787=mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-799-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:800:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-801-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=930=mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-941-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:942:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-943-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=988=mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-995-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:996:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-997-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1003=mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1010-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1011:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1012-\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1020=mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1033-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1034:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1035-\tamsdu = (struct sta_rec_amsdu *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1059=mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1070-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1071:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1072-\twtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(\u0026dev-\u003emt76, \u0026msta-\u003ewcid,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1259=mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1288-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1289:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1290-\tbf = (struct sta_rec_bf *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1335=mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1350-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1351:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1352-\tbfee = (struct sta_rec_bfee *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1385=int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1401-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1402:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1403-\tra = (struct sta_rec_ra_fixed *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1430=int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1444-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1445:\tsta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1446-\t\t\t\t\t sizeof(struct tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1566=mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1578-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:1579:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-1580-\tra = (struct sta_rec_ra *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=1974=mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-2001-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:2002:\ttlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-2003-\tbcn = (struct bss_info_bcn *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=2057=int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-2078-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:2079:\ttlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-2080-\tbcn = (struct bss_info_bcn *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=4000=int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-4022-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:4023:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO,\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-4024-\t\t\t\t sizeof(*prot));\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c=4062=int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-4075-\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c:4076:\ttlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR,\ndrivers/net/wireless/mediatek/mt76/mt7915/mcu.c-4077-\t\t\t\t sizeof(*bss_color));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=732=mt7925_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-746-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:747:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-748-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1212=mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1219-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1220:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1221-\thdr_trans = (struct sta_rec_hdr_trans *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1264=int mt7925_mcu_set_tx(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1295-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1296:\t\ttlv = mt76_connac_mcu_add_tlv(skb, MCU_EDCA_AC_PARAM, sizeof(*e));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1297-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1320=mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1338-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1339:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1340-\tsec = (struct sta_rec_sec_uni *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1780=mt7925_mcu_sta_he_6g_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1788-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1789:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1790-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1796=mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1808-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1809:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1810-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1825=mt7925_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1832-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1833:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1834-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1840=mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1848-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1849:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1850-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1858=mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1872-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1873:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1874-\tamsdu = (struct sta_rec_amsdu *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1896=mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1912-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1913:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1914-\tphy = (struct sta_rec_phy *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1953=mt7925_mcu_sta_state_v2_tlv(struct mt76_phy *mphy, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1969-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1970:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1971-\tstate = (struct sta_rec_state_v2 *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1982=mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1999-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2000:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2001-\tra_info = (struct sta_rec_ra_info *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2028=mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2040-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2041:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2042-\teht_mld = (struct sta_rec_eht_mld *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2064=mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2092-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2093:\ttlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2094-\tmld = (struct sta_rec_mld *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2115=mt7925_mcu_sta_remove_tlv(struct sk_buff *skb)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2119-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2120:\ttlv = mt76_connac_mcu_add_tlv(skb, 0x25, sizeof(*rem));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2121-\trem = (struct sta_rec_remove *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2126=mt7925_mcu_sta_cmd(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2175-\t\tmt7925_mcu_sta_remove_tlv(skb);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2176:\t\tmt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2177-\t\t\t\t\tsizeof(struct tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2469=void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2486-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2487:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*req));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2488-\treq = (struct bss_rlm_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2569=void mt7925_mcu_bss_eht_tlv(struct sk_buff *skb, struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2578-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2579:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_EHT, sizeof(*req));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2580-\treq = (struct bss_eht_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2696=mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2714-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2715:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2716-\tbasic_req = (struct mt76_connac_bss_basic_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2785=mt7925_mcu_bss_sec_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2799-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2800:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2801-\tsec = (struct bss_sec_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2832=mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2846-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2847:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2848-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2867=mt7925_mcu_bss_mld_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2880-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2881:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2882-\tmld = (struct bss_mld_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2901=mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2905-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2906:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_QBSS, sizeof(*qos));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2907-\tqos = (struct mt76_connac_bss_qos_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2912=mt7925_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2920-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2921:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_11V_MBSSID,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2922-\t\t\t\t sizeof(*mbssid));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2931=mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2943-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2944:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2945-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2961=mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2966-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2967:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BSS_COLOR, sizeof(*color));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2968-\tcolor = (struct bss_info_uni_bss_color *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2977=mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2984-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2985:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2986-\tifs_time = (struct bss_ifs_time_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3134=int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3150-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3151:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_MBMC_SETTING, sizeof(*conf));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3152-\tconf = (struct mbmc_conf_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3165=mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3193-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3194:\t\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3195-\t\t\t\t\t alloc_len);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3217=int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3255-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3256:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_REQ, sizeof(*req));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3257-\treq = (struct scan_req_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3260-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3261:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID, sizeof(*ssid));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3262-\tssid = (struct scan_ssid_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3285-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3286:\t\t\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3287-\t\t\t\t\t\t sizeof(*bssid));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3296-\t} else {\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3297:\t\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, sizeof(*bssid));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3298-\t\tbssid = (struct scan_bssid_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3302-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3303:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3304-\tchan_info = (struct scan_chan_info_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3326-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3327:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_MISC, sizeof(*misc));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3328-\tmisc = (struct scan_misc_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3347=int mt7925_mcu_sched_scan_req(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3382-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3383:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SCHED_REQ, sizeof(*req));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3384-\treq = (struct scan_sched_req *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3393-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3394:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID, sizeof(*ssid));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3395-\tssid = (struct scan_ssid_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3404-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3405:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID_MATCH_SETS, sizeof(*match));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3406-\tmatch = (struct scan_sched_ssid_match_sets *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3415-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3416:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3417-\tchan_info = (struct scan_chan_info_tlv *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3447=mt7925_mcu_sched_scan_enable(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3467-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3468:\ttlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SCHED_ENABLE, sizeof(*req));\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3469-\treq = (struct scan_sched_enable *)tlv;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=79=mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-86-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:87:\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_MASTER_PREFERENCE,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-88-\t\t\t\t sizeof(struct mt7925_nan_master_preference_tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=103=mt7925_nan_dw_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-111-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:112:\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_DW_INTERVAL,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-113-\t\t\t\t sizeof(struct mt7925_nan_dw_interval_tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=141=mt7925_nan_cluster_id_tlv(struct sk_buff *skb, const u8 *cluster_id)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-148-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:149:\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_CLUSTER_ID,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-150-\t\t\t\t sizeof(struct mt7925_nan_cluster_id_tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=163=mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-170-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:171:\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_SYNC_RSSI,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-172-\t\t\t\t sizeof(struct mt7925_nan_sync_rssi_tlv));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=332=int mt7925_nan_enable(struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-359-\treq = (struct mt7925_nan_enable_req_tlv *)\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:360:\t\tmt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_ENABLE_REQUEST,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-361-\t\t\t\t\tsizeof(*req));\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=700=static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-711-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:712:\ttlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL,\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-713-\t\t\t\t sizeof(struct mt7925_nan_avail_ctrl_tlv));\n--\n\n"
} |
| 65/3 | 2026/08/24 23:01 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 39961 output: 58 thoughts: 61 Thoughts: Here's my summary, as if I were thinking it: **Digging into the MT76 Connection Handling** Okay, so I'm looking at how MT76 handles connection-related TLVs, specifically using `mt76_connac_mcu_add_tlv`. Right, so this function is responsible for adding Type-Length-Value (TLV) structures to the socket buffer, `skb`. Now, where is it defined? Let me just double check. Ah, yes, it's right here in `drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h`. Good, let's see what's going on under the hood and make sure this is as I would expect. |
| 66/3 | 2026/08/24 23:01 | tool | grepper |
0mArgs:{
"Expression": "mt76_connac_mcu_add_tlv",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h=1993=static inline struct tlv *\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h:1994:mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len)\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h-1995-{\n"
} |
| 67/3 | 2026/08/24 23:01 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 40384 output: 53 thoughts: 22 Thoughts: Okay, let's dive into this `mt76_connac_mcu_add_tlv` function. I need to understand how this piece works. I'm going to carefully read the implementation to get a solid grasp of its purpose, the data structures it manipulates, and how it fits into the broader connection management scheme within the mt76 driver for Connac hardware. I'll be looking for the specific Tag-Length-Value structures, how they're encoded, how they're added, and the context in which this function is typically called. This function is likely crucial for the lower levels of communication. My goal is to extract the functional essence: what data is being formatted and sent, and where it goes. |
| 68/3 | 2026/08/24 23:01 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h",
"FirstLine": 1990,
"LineCount": 20
}Results: {
"Contents": "1990:\tstruct tlv *mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag,\n1991:\t\t\t\t\t\t int len, void *sta_ntlv,\n1992:\t\t\t\t\t\t void *sta_wtbl);\n1993:\tstatic inline struct tlv *\n1994:\tmt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len)\n1995:\t{\n1996:\t\treturn mt76_connac_mcu_add_nested_tlv(skb, tag, len, skb-\u003edata, NULL);\n1997:\t}\n1998:\t\n1999:\tint mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy);\n2000:\tint mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif);\n2001:\tvoid mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,\n2002:\t\t\t\t\t struct ieee80211_bss_conf *link_conf,\n2003:\t\t\t\t\t struct ieee80211_link_sta *link_sta,\n2004:\t\t\t\t\t int state, bool newly);\n2005:\tvoid mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb,\n2006:\t\t\t\t\t struct ieee80211_vif *vif,\n2007:\t\t\t\t\t struct ieee80211_sta *sta, void *sta_wtbl,\n2008:\t\t\t\t\t void *wtbl_tlv);\n2009:\tvoid mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,\n"
} |
| 69/3 | 2026/08/24 23:01 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 41143 output: 60 thoughts: 49 Thoughts: Here's my summary, as if I were thinking these thoughts: **Diving into the MT76 Connac MCU Code** Okay, time to dig into this. I need to understand what's happening with these nested TLVs in the MT76 Connac MCU driver. Let's start by zeroing in on the `mt76_connac_mcu_add_nested_tlv` function, specifically within `drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c`. I know this driver intimately, so I suspect this function holds the key to the specific issue I'm debugging. Let's see what's being added, how the structure is handled, and hopefully identify the root cause of the problem. Time to get my hands dirty and start tracing the code. I anticipate a fair bit of pointer arithmetic and bitwise operations, so I'll be ready for those. This is going to be interesting. |
| 70/3 | 2026/08/24 23:02 | tool | grepper |
0mArgs:{
"Expression": "mt76_connac_mcu_add_nested_tlv",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=291=struct tlv *\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:292:mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-293-\t\t\t void *sta_ntlv, void *sta_wtbl)\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-315-}\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:316:EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_nested_tlv);\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-317-\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=514=void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-521-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:522:\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HDR_TRANS,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-523-\t\t\t\t\t sizeof(*htr),\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=595=void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-606-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:607:\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_GENERIC,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-608-\t\t\t\t\t sizeof(*generic),\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-630-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:631:\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx),\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-632-\t\t\t\t\t wtbl_tlv, sta_wtbl);\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-641-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:642:\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe),\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-643-\t\t\t\t\t wtbl_tlv, sta_wtbl);\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1002=void mt76_connac_mcu_wtbl_smps_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1008-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1009:\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps),\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1010-\t\t\t\t\t wtbl_tlv, sta_wtbl);\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1016=void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1024-\tif (sta-\u003edeflink.ht_cap.ht_supported || sta-\u003edeflink.he_6ghz_capa.capa) {\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1025:\t\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1026-\t\t\t\t\t\t wtbl_tlv, sta_wtbl);\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1047-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1048:\t\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_VHT,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1049-\t\t\t\t\t\t sizeof(*vht), wtbl_tlv,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1069-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1070:\t\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RAW_DATA,\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1071-\t\t\t\t\t\t sizeof(*raw), wtbl_tlv,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1149=void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1156-\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1157:\ttlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba),\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1158-\t\t\t\t\t wtbl_tlv, sta_wtbl);\n"
} |
| 71/3 | 2026/08/24 23:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 43319 output: 52 thoughts: 22 Thoughts: Here's a first-person summary, tailored as requested: **Diving into `mt76_connac_mcu_add_nested_tlv`** Alright, let's dissect `mt76_connac_mcu_add_nested_tlv`. Right off the bat, I know this function is going to be crucial for crafting and embedding nested Type-Length-Value structures within our MT76 Connac MCU's communication framework. My experience tells me this will be vital for a whole host of operations, ranging from firmware configuration to detailed command exchanges, potentially even handling complex data structures within those exchanges. I'm immediately looking for the parameter definitions; `tb` is probably the *target buffer*, a pointer to where the TLV data gets constructed. I'm expecting some kind of `TLV_HEADER` structure too – a structure with a *type* and *length* field at a minimum, and possibly some alignment bits. The nesting implies we'll have TLVs embedded *within* other TLVs, so understanding how the function calculates the size required and manages the offset manipulation is going to be key. My focus will shift to how the new TLV is created. The function call will probably have the type, length, and potentially a `data` parameter for the nested data. I'm assuming there's some kind of checks for buffer overflow, because that's always critical, especially when dealing with data being sent to and processed by another processor. I'll need to see how the function calculates the offset to find the position for nested TLV, and how it handles potential memory alignment issues. Also, I'm going to look for any signs of error checking or handling. If there's an issue with the buffer, invalid parameters, or data alignment issues. Finally, I'll be looking at how the function calculates the final TLV length, updates any parent TLVs that may be modified by nesting, and returns an indication of success or failure. Ideally, there are comments that give me context as to the function's purpose within the larger picture of Connac MCU communication. Time to roll up my sleeves and get into the code! |
| 72/3 | 2026/08/24 23:02 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c",
"FirstLine": 290,
"LineCount": 30
}Results: {
"Contents": " 290:\t\n 291:\tstruct tlv *\n 292:\tmt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len,\n 293:\t\t\t\t void *sta_ntlv, void *sta_wtbl)\n 294:\t{\n 295:\t\tstruct sta_ntlv_hdr *ntlv_hdr = sta_ntlv;\n 296:\t\tstruct tlv *sta_hdr = sta_wtbl;\n 297:\t\tstruct tlv *ptlv, tlv = {\n 298:\t\t\t.tag = cpu_to_le16(tag),\n 299:\t\t\t.len = cpu_to_le16(len),\n 300:\t\t};\n 301:\t\tu16 ntlv;\n 302:\t\n 303:\t\tptlv = skb_put_zero(skb, len);\n 304:\t\tmemcpy(ptlv, \u0026tlv, sizeof(tlv));\n 305:\t\n 306:\t\tntlv = le16_to_cpu(ntlv_hdr-\u003etlv_num);\n 307:\t\tntlv_hdr-\u003etlv_num = cpu_to_le16(ntlv + 1);\n 308:\t\n 309:\t\tif (sta_hdr) {\n 310:\t\t\tlen += le16_to_cpu(sta_hdr-\u003elen);\n 311:\t\t\tsta_hdr-\u003elen = cpu_to_le16(len);\n 312:\t\t}\n 313:\t\n 314:\t\treturn ptlv;\n 315:\t}\n 316:\tEXPORT_SYMBOL_GPL(mt76_connac_mcu_add_nested_tlv);\n 317:\t\n 318:\tstruct sk_buff *\n 319:\t__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif,\n"
} |
| 73/3 | 2026/08/24 23:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 44388 output: 27 thoughts: 1776 Thoughts: **Analysis of Zero-Initialization and Data Integrity in NAN Implementation** Okay, so I'm digging into this NAN implementation, specifically focusing on data initialization and potential issues with uninitialized memory. The first thing I see is the use of `skb_put_zero`, which is promising. That means the TLV payloads are fully zeroed out initially. This also means that `req` in `mt7925_nan_enable` is fully zeroed, which is a good baseline. Now, let's trace this through a few functions. In `mt7925_nan_update_ulw_tlv`, we have a TLV being created using `mt76_connac_mcu_add_tlv`. This, combined with the earlier `skb_put_zero` confirmation, means the entire `ulw_attr` field in the `mt7925_nan_update_ulw_tlv` struct *should* be zero-initialized, except for the parts we explicitly copy from `sched->init_ulw`. The important part here is the size check, `sched->ulw_size` is copied. Given that `ulw_attr` is 256 bytes large, the remaining bytes should remain zero, which aligns with the zero-initialization strategy. Next, I'm looking at `mt7925_nan_sched_update_crb_tlv` within `mt792x_nan_set_peer_rec`. Again, we're using `mt76_connac_mcu_add_tlv`. The comment explicitly states that the `avail_map` field is zero-initialized by the `mt76_connac_mcu_add_tlv` function. So far, so good – consistent behavior. Finally, I'm checking `mt7925_nan_handle_ulw_update`. Here, we're dealing with a `struct mt7925_nan_ulw_attr` allocated on the stack. The critical part is how this struct is populated, and its subsequent use in `cfg80211_nan_ulw_update`. I was initially concerned that there may be padding or uninitialized memory if the struct had any potential alignment issues. However, the use of `__packed` is important here, that means no padding. I meticulously examined each field assignment: `attr_id`, `length`, `sched_id`, `seq_id`, `start_time`, `duration`, `period`, `count_down`, and `ulw_overwrite` are all explicitly assigned, there are no gaps. The size of the struct is 19 bytes, determined by adding the sizes of the fields. So, because the struct is explicitly initialized and packed, I am certain there won't be any uninitialized bytes when passed to `cfg80211_nan_ulw_update`. Although the struct size (19 bytes) seems odd compared to `NAN_ULW_FIXED_PAYLOAD` (16 bytes), all fields *are* assigned, the struct is `__packed`, and the pointer and length are correctly passed to `cfg80211_nan_ulw_update`. Now I'll trace `cfg80211_nan_ulw_update` to be absolutely certain it handles the data correctly. |
| 74/3 | 2026/08/24 23:02 | tool | grepper |
0mArgs:{
"Expression": "cfg80211_nan_ulw_update"
}Results: {
"Output": "drivers/net/wireless/intel/iwlwifi/mld/nan.c=364=void iwl_mld_handle_nan_ulw_attr_notif(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c-386-\twdev = ieee80211_vif_to_wdev(mld-\u003enan_device_vif);\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c:387:\tcfg80211_nan_ulw_update(wdev, notif-\u003eattr, notif-\u003eattr_len, GFP_KERNEL);\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c-388-}\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=591=mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-631-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:632:\tcfg80211_nan_ulw_update(wdev, (const u8 *)\u0026attr, sizeof(attr),\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-633-\t\t\t\tGFP_KERNEL);\n--\ninclude/net/cfg80211.h=10844=void cfg80211_nan_cluster_joined(struct wireless_dev *wdev,\n--\ninclude/net/cfg80211.h-10848-/**\ninclude/net/cfg80211.h:10849: * cfg80211_nan_ulw_update - Notify user space about ULW update\ninclude/net/cfg80211.h-10850- * @wdev: Pointer to the wireless device structure\n--\ninclude/net/cfg80211.h-10858- */\ninclude/net/cfg80211.h:10859:void cfg80211_nan_ulw_update(struct wireless_dev *wdev,\ninclude/net/cfg80211.h-10860-\t\t\t const u8 *ulw, size_t ulw_len, gfp_t gfp);\n--\nnet/wireless/nl80211.c=23534=EXPORT_SYMBOL(cfg80211_nan_cluster_joined);\nnet/wireless/nl80211.c-23535-\nnet/wireless/nl80211.c:23536:void cfg80211_nan_ulw_update(struct wireless_dev *wdev,\nnet/wireless/nl80211.c-23537-\t\t\t const u8 *ulw, size_t ulw_len, gfp_t gfp)\n--\nnet/wireless/nl80211.c-23543-\nnet/wireless/nl80211.c:23544:\ttrace_cfg80211_nan_ulw_update(wiphy, wdev, ulw, ulw_len);\nnet/wireless/nl80211.c-23545-\n--\nnet/wireless/nl80211.c-23576-}\nnet/wireless/nl80211.c:23577:EXPORT_SYMBOL(cfg80211_nan_ulw_update);\nnet/wireless/nl80211.c-23578-\n--\nnet/wireless/trace.h=4353=TRACE_EVENT(cfg80211_nan_sched_update_done,\n--\nnet/wireless/trace.h-4369-\nnet/wireless/trace.h:4370:TRACE_EVENT(cfg80211_nan_ulw_update,\nnet/wireless/trace.h-4371-\tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,\n"
} |
| 75/3 | 2026/08/24 23:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 47994 output: 42 thoughts: 34 Thoughts: Here's a first-person summary, tailored for an expert audience, as requested: **Diving into the NAN ULW Update** Alright, let's pull up `net/wireless/nl80211.c` and specifically hone in on `cfg80211_nan_ulw_update`. I need to refresh my understanding of how the Upper Layer Wake-up (ULW) updates are handled in the NAN implementation. I'm primarily interested in the control plane aspects of this function. I'm assuming this function processes the incoming nl80211 message, which means it should handle the configuration for the NAN ULW, including the channel selection, the time window, the related parameters, etc. It should perform the necessary validations of the input. I expect there to be some interaction with the hardware through the cfg80211 API. I'll be looking for where the actual hardware commands are issued. I'll need to confirm if there is an update to the NAN configuration that has to be done to reflect the new ULW state, in terms of the wake-up triggers, the associated parameters, and all those other considerations. |
| 76/3 | 2026/08/24 23:02 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 23536,
"LineCount": 40
}Results: {
"Contents": "23536:\tvoid cfg80211_nan_ulw_update(struct wireless_dev *wdev,\n23537:\t\t\t\t const u8 *ulw, size_t ulw_len, gfp_t gfp)\n23538:\t{\n23539:\t\tstruct wiphy *wiphy = wdev-\u003ewiphy;\n23540:\t\tstruct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);\n23541:\t\tstruct sk_buff *msg;\n23542:\t\tvoid *hdr;\n23543:\t\n23544:\t\ttrace_cfg80211_nan_ulw_update(wiphy, wdev, ulw, ulw_len);\n23545:\t\n23546:\t\tif (!wdev-\u003eowner_nlportid)\n23547:\t\t\treturn;\n23548:\t\n23549:\t\t/* 32 for the wiphy idx, 64 for the wdev id, 100 for padding */\n23550:\t\tmsg = nlmsg_new(nla_total_size(sizeof(u32)) +\n23551:\t\t\t\tnla_total_size(ulw_len) +\n23552:\t\t\t\tnla_total_size(sizeof(u64)) + 100,\n23553:\t\t\t\tgfp);\n23554:\t\tif (!msg)\n23555:\t\t\treturn;\n23556:\t\n23557:\t\thdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_ULW_UPDATE);\n23558:\t\tif (!hdr)\n23559:\t\t\tgoto nla_put_failure;\n23560:\t\n23561:\t\tif (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev-\u003ewiphy_idx) ||\n23562:\t\t nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),\n23563:\t\t\t\t NL80211_ATTR_PAD) ||\n23564:\t\t (ulw \u0026\u0026 ulw_len \u0026\u0026\n23565:\t\t nla_put(msg, NL80211_ATTR_NAN_ULW, ulw_len, ulw)))\n23566:\t\t\tgoto nla_put_failure;\n23567:\t\n23568:\t\tgenlmsg_end(msg, hdr);\n23569:\t\n23570:\t\tgenlmsg_unicast(wiphy_net(wiphy), msg, wdev-\u003eowner_nlportid);\n23571:\t\n23572:\t\treturn;\n23573:\t\n23574:\t nla_put_failure:\n23575:\t\tnlmsg_free(msg);\n"
} |
| 77/3 | 2026/08/24 23:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 49114 output: 27 thoughts: 5240 Thoughts: **Uninitialized Memory Inspection in mt7925 NAN Driver** Okay, let's break this down systematically. My primary concern is ensuring that no uninitialized memory is being read or leaked, potentially leading to security vulnerabilities or unexpected behavior. I've examined several key functions within the mt7925 NAN driver related to User Location Wake (ULW) updates, scheduling, and general NAN operation. First, the `cfg80211_nan_ulw_update` function, specifically the `mt7925_nan_handle_ulw_update`, now that's where things get interesting. I scrutinized the `mt7925_nan_ulw_attr` struct, confirming its packed nature and that all its fields are explicitly assigned before being passed to user space. Therefore, no uninitialized bytes are present in the `attr` structure, which is sent to userspace via netlink message. Next, I looked into the deferred work function, `mt7925_nan_deferred_work`. Here, the `cluster_id` variable is copied from `dev->nan_started_cluster_id`. I confirmed that `dev->nan_started_cluster_id` is initialized in `mt7925_nan_mcu_handle_de_event` by a memcpy operation. I verified that if the deferred event hasn't started with `STARTED_CLUSTER` the `cluster_id` is not used. More importantly, I established that `struct mt792x_dev` is allocated with a function like `devm_kzalloc`, which zeroes the memory before use, so no uninitialized memory could be potentially used. The `mt7925_nan_update_phy_setting` function uses a zero-initialized structure, `req`, so that is also safe. The `mt7925_nan_seed_link_sta` function modifies the `link_sta` which is allocated by mac80211, it poses no issue. I then carefully looked at `mt7925_nan_fill_crb_committed`. The `crb_tlv` structure is allocated using `mt76_connac_mcu_add_tlv`, and I confirmed that function utilizes `skb_put_zero`, so `crb_tlv` is indeed zero-initialized. I also noted that the `avail_map` fields are updated using a bitwise OR operation from an initially zero state, avoiding any potential read-before-write issues. Similarly, in `mt7925_nan_slot_to_bitmap`, the `ch_list` array within `struct mt7925_nan_avail_ctrl_tlv` is allocated by `mt76_connac_mcu_add_tlv`, so it's also zero-initialized. Therefore, there's no risk of using uninitialized memory here, and the array access is handled correctly. Next, I verified the case `NAN_EVENT_ID_STARTED_CLUSTER` using the same logic for copying `cluster_id` from a TLV in `mt7925_nan_mcu_handle_de_event`. Furthermore, I have checked all other functions by tracing the memory allocation and initialization process. I've found a zero initialization for the allocations performed by `mt76_connac_mcu_add_tlv`. Those functions are `mt7925_nan_update_crb_tlv`, `mt7925_nan_peer_ulw_tlv` and `mt792x_nan_set_peer_rec`. In summary, I've reviewed several core functions and data structures. I am satisfied that there are no apparent uninitialized memory reads or leaks. All crucial data structures are either explicitly initialized or allocated in a way that ensures zero-initialization. This meticulous inspection provides confidence in the code's memory safety concerning uninitialized memory, which is essential for robustness and security. |
| 78/3 | 2026/08/24 23:03 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_kzalloc.*mt792x_dev"
}Results: {
"error": "no matches"
} |
| 79/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 55259 output: 24 thoughts: 19 Thoughts: Here's my summary, as if I were thinking these thoughts: **Digging into the MT7925 PCI Probe** Okay, so we've got an issue and I need to dive into the driver code for this MT7925 PCI device. My first instinct, given what we're looking at, is to start with the probing function. I'll need to locate and meticulously examine the `mt7925_pci_probe` function (or something with a similarly descriptive name, even `mt79xx_pci_probe`, if the naming convention is broad). This is where the initial device setup and initialization are likely happening. I need to understand the exact sequence of events during device detection and initialization to pinpoint where things might be going sideways. Let's see what we can find. |
| 80/3 | 2026/08/24 23:03 | tool | grepper |
0mArgs:{
"Expression": "mt7925_pci_probe"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/pci.c=515=static const struct mt792x_irq_map mt7928_irq_map = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-528-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:529:static int mt7925_pci_probe(struct pci_dev *pdev,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-530-\t\t\t const struct pci_device_id *id)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=915=static struct pci_driver mt7925_pci_driver = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-917-\t.id_table\t= mt7925_pci_device_table,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:918:\t.probe\t\t= mt7925_pci_probe,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-919-\t.remove\t\t= mt7925_pci_remove,\n"
} |
| 81/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 55856 output: 51 thoughts: 16 Thoughts: Okay, let's dive into this `mt7925_pci_probe` function. I see it's the PCI probe function for this particular WiFi chipset. As an expert in embedded systems and driver development, I know this is the entry point for initializing the device when the system detects it on the PCI bus. I'll be looking for several key things here: **My Initial Assessment of `mt7925_pci_probe`** First, I want to confirm it's correctly identifying the device using the `pci_device_id` table. That's crucial; we don't want the wrong driver attached! Then, I'll pay close attention to resource allocation. Is it requesting the necessary PCI BARs (Base Address Registers) for memory mapping and interrupt lines? It better be, and using the right flags, like `PCI_IORESOURCE_MEM`. I’m also looking for proper error handling; every potential failure point needs a graceful exit with appropriate cleanup (releasing allocated resources). I'll want to see how the driver handles device power management, if it attempts to enable the device's clock or reset logic. Next, I need to understand the driver's data structures. Are there any custom structs being allocated or initialized here? It's important to understand how the driver organizes its state for this device. I'll examine how it links into the common networking stack, probably using `net_device` and associated structures. I'll look for `alloc_netdev`, `register_netdev`, and other networking-related calls. I'll expect to see initialization of the device's MAC address and other configuration settings, probably read from the EEPROM or device-specific registers. I'll assess how it handles interrupts, and how it sets up any DMA (Direct Memory Access) channels to efficiently transfer data between the device and system memory. Finally, I'll look at the registration of device specific methods that would allow me to work with the interface. Overall, I'm expecting this probe function to be a well-structured, robust, and well-commented piece of code that carefully sets up the Mediatek 7925 device to function within the Linux kernel. Let's see if my expectations are met. |
| 82/3 | 2026/08/24 23:03 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/pci.c",
"FirstLine": 529,
"LineCount": 20
}Results: {
"Contents": " 529:\tstatic int mt7925_pci_probe(struct pci_dev *pdev,\n 530:\t\t\t\t const struct pci_device_id *id)\n 531:\t{\n 532:\t\tstatic const struct mt76_driver_ops drv_ops = {\n 533:\t\t\t/* txwi_size = txd size + txp size */\n 534:\t\t\t.txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_hw_txp),\n 535:\t\t\t.drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |\n 536:\t\t\t\t MT_DRV_AMSDU_OFFLOAD,\n 537:\t\t\t.survey_flags = SURVEY_INFO_TIME_TX |\n 538:\t\t\t\t\tSURVEY_INFO_TIME_RX |\n 539:\t\t\t\t\tSURVEY_INFO_TIME_BSS_RX,\n 540:\t\t\t.token_size = MT7925_TOKEN_SIZE,\n 541:\t\t\t.tx_prepare_skb = mt7925e_tx_prepare_skb,\n 542:\t\t\t.tx_complete_skb = mt76_connac_tx_complete_skb,\n 543:\t\t\t.rx_check = mt7925_rx_check,\n 544:\t\t\t.rx_skb = mt7925_queue_rx_skb,\n 545:\t\t\t.rx_poll_complete = mt792x_rx_poll_complete,\n 546:\t\t\t.sta_add = mt7925_mac_sta_add,\n 547:\t\t\t.sta_event = mt7925_mac_sta_event,\n 548:\t\t\t.sta_remove = mt7925_mac_sta_remove,\n"
} |
| 83/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 56888 output: 51 thoughts: 18 Thoughts: Okay, here's my interpretation of what's going through my mind as I approach the `mt7925_pci_probe` function, phrased as a first-person expert analysis: **Analyzing the mt7925_pci_probe Function** Right, let's dive into this `mt7925_pci_probe` function. The naming convention strongly suggests this is the PCI probe function for the MT7925 chipset. My initial thought is to quickly establish the *why* and *how*. This probe function, it's the gateway. It's the point where the kernel discovers and attempts to initialize a PCI device based on the MT7925 chipset. I'm expecting to see the standard PCI device registration dance, configuration, resource allocation, and then driver initialization steps. I'm immediately looking for any indication of compatibility handling. Does this function include any device ID checks to verify we are actually dealing with an MT7925 device? Are there any specific quirks or workarounds implemented for particular hardware revisions? This is crucial to avoid misidentification or incorrect initialization. I'll need to pay close attention to the PCI device's BARs (Base Address Registers) to see how the driver intends to map the hardware resources in memory. I anticipate it will access registers for the device, and I will anticipate any potential issues with DMA setup as this is networking. The next thing on my mind is how error handling is implemented. Are there robust checks throughout the function for things like resource allocation failures, hardware register access problems, or firmware loading errors? Proper error handling is essential for a stable and reliable driver. I also want to identify any power management considerations. This is a wireless device, so I'd anticipate routines to enable/disable power saving, handle wake-on-LAN functionality, or manage the radio's power states. Finally, I'll be looking for indications of how the driver is structured and how it interacts with the underlying wireless stack. Does it register itself with the appropriate networking subsystems (e.g., mac80211)? Are there any hints about the type of firmware required and how it's loaded? Any indication of how interrupt handling is set up is always a high-priority. Ultimately, I want to understand how this probe function sets the stage for the entire MT7925 wireless adapter's operation. I need to understand its role in the overall architecture. |
| 84/3 | 2026/08/24 23:03 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/pci.c",
"FirstLine": 549,
"LineCount": 40
}Results: {
"Contents": " 549:\t\t\t.update_survey = mt792x_update_channel,\n 550:\t\t};\n 551:\t\tstatic const struct mt792x_hif_ops mt7925_pcie_ops = {\n 552:\t\t\t.init_reset = mt7925e_init_reset,\n 553:\t\t\t.reset = mt7925e_mac_reset,\n 554:\t\t\t.mcu_init = mt7925e_mcu_init,\n 555:\t\t\t.drv_own = mt792xe_mcu_drv_pmctrl,\n 556:\t\t\t.fw_own = mt792xe_mcu_fw_pmctrl,\n 557:\t\t};\n 558:\t\tbool is_mt7927_hw, is_mt7928_hw;\n 559:\t\tstruct mt76_bus_ops *bus_ops;\n 560:\t\tstruct ieee80211_ops *ops;\n 561:\t\tstruct mt792x_dev *dev;\n 562:\t\tstruct mt76_dev *mdev;\n 563:\t\tu8 features;\n 564:\t\tint ret;\n 565:\t\tu16 cmd;\n 566:\t\n 567:\t\tret = pcim_enable_device(pdev);\n 568:\t\tif (ret)\n 569:\t\t\treturn ret;\n 570:\t\n 571:\t\tret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));\n 572:\t\tif (ret)\n 573:\t\t\treturn ret;\n 574:\t\n 575:\t\tpci_read_config_word(pdev, PCI_COMMAND, \u0026cmd);\n 576:\t\tif (!(cmd \u0026 PCI_COMMAND_MEMORY)) {\n 577:\t\t\tcmd |= PCI_COMMAND_MEMORY;\n 578:\t\t\tpci_write_config_word(pdev, PCI_COMMAND, cmd);\n 579:\t\t}\n 580:\t\tpci_set_master(pdev);\n 581:\t\n 582:\t\tret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);\n 583:\t\tif (ret \u003c 0)\n 584:\t\t\treturn ret;\n 585:\t\n 586:\t\tis_mt7927_hw = (pdev-\u003edevice == 0x6639 || pdev-\u003edevice == 0x7927 ||\n 587:\t\t\t\tpdev-\u003edevice == 0x0738);\n 588:\t\tis_mt7928_hw = (pdev-\u003edevice == 0x7928 || pdev-\u003edevice == 0x7935);\n"
} |
| 85/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 58216 output: 51 thoughts: 6 Thoughts: Okay, I'm ready to delve into this text. Let's see what we've got. I'll approach it with my usual critical eye, considering all the implications and nuances. I'm prepared to dissect the arguments, evaluate the evidence, and synthesize the information into a cohesive understanding. Let's get to it! |
| 86/3 | 2026/08/24 23:03 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/pci.c",
"FirstLine": 589,
"LineCount": 40
}Results: {
"Contents": " 589:\t\n 590:\t\tif (is_mt7928_hw)\n 591:\t\t\tret = dma_set_mask(\u0026pdev-\u003edev, DMA_BIT_MASK(34));\n 592:\t\telse\n 593:\t\t\tret = dma_set_mask(\u0026pdev-\u003edev, DMA_BIT_MASK(32));\n 594:\t\n 595:\t\tif (ret)\n 596:\t\t\tgoto err_free_pci_vec;\n 597:\t\n 598:\t\t/* MT7927: ASPM L1 causes unreliable WFDMA register access */\n 599:\t\tif (mt7925_disable_aspm || is_mt7927_hw)\n 600:\t\t\tmt76_pci_disable_aspm(pdev);\n 601:\t\n 602:\t\tops = mt792x_get_mac80211_ops(\u0026pdev-\u003edev, \u0026mt7925_ops,\n 603:\t\t\t\t\t (void *)id-\u003edriver_data, \u0026features);\n 604:\t\tif (!ops) {\n 605:\t\t\tret = -ENOMEM;\n 606:\t\t\tgoto err_free_pci_vec;\n 607:\t\t}\n 608:\t\n 609:\t\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\n 610:\t\tif (!mdev) {\n 611:\t\t\tret = -ENOMEM;\n 612:\t\t\tgoto err_free_pci_vec;\n 613:\t\t}\n 614:\t\n 615:\t\tpci_set_drvdata(pdev, mdev);\n 616:\t\n 617:\t\tdev = container_of(mdev, struct mt792x_dev, mt76);\n 618:\t\tdev-\u003efw_features = features;\n 619:\t\tdev-\u003ehif_ops = \u0026mt7925_pcie_ops;\n 620:\t\tdev-\u003epcie_reg = \u0026mt7925_pcie_reg;\n 621:\t\n 622:\t\tif (is_mt7928_hw) {\n 623:\t\t\tdev-\u003epcie_reg = \u0026mt7928_pcie_reg;\n 624:\t\t\tdev-\u003eirq_map = \u0026mt7928_irq_map;\n 625:\t\t\tmdev-\u003erev = 0x7928 \u003c\u003c 16;\n 626:\t\t} else if (is_mt7927_hw) {\n 627:\t\t\tdev-\u003eirq_map = \u0026mt7927_irq_map;\n 628:\t\t} else {\n"
} |
| 87/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 59072 output: 21 thoughts: 51 Thoughts: Here's my thought process, as it stands: **Diving into the MT76 Device Allocation** Okay, I need to understand how this MT76 wireless device is being allocated. I recall that `mt76_alloc_device` is the function responsible for that. Time to confirm and dissect the code flow. Let me open up `drivers/net/wireless/mediatek/mt76/mac80211.c` – that's where I expect to find the implementation of `mt76_alloc_device`. I want to see exactly what's going on, how the `mdev` structure gets initialized, and any potential issues or interesting aspects of this allocation process. Let's get to it. |
| 88/3 | 2026/08/24 23:03 | tool | grepper |
0mArgs:{
"Expression": "mt76_alloc_device"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mac80211.c=668=struct mt76_dev *\ndrivers/net/wireless/mediatek/mt76/mac80211.c:669:mt76_alloc_device(struct device *pdev, unsigned int size,\ndrivers/net/wireless/mediatek/mt76/mac80211.c-670-\t\t const struct ieee80211_ops *ops,\n--\ndrivers/net/wireless/mediatek/mt76/mac80211.c-745-}\ndrivers/net/wireless/mediatek/mt76/mac80211.c:746:EXPORT_SYMBOL_GPL(mt76_alloc_device);\ndrivers/net/wireless/mediatek/mt76/mac80211.c-747-\n--\ndrivers/net/wireless/mediatek/mt76/mt76.h=1307=__mt76_wcid_ptr(struct mt76_dev *dev, u16 idx)\n--\ndrivers/net/wireless/mediatek/mt76/mt76.h-1315-\ndrivers/net/wireless/mediatek/mt76/mt76.h:1316:struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size,\ndrivers/net/wireless/mediatek/mt76/mt76.h-1317-\t\t\t\t const struct ieee80211_ops *ops,\n--\ndrivers/net/wireless/mediatek/mt76/mt7603/pci.c=15=mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n--\ndrivers/net/wireless/mediatek/mt76/mt7603/pci.c-34-\ndrivers/net/wireless/mediatek/mt76/mt7603/pci.c:35:\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), \u0026mt7603_ops,\ndrivers/net/wireless/mediatek/mt76/mt7603/pci.c-36-\t\t\t\t \u0026mt7603_drv_ops);\n--\ndrivers/net/wireless/mediatek/mt76/mt7603/soc.c=10=mt76_wmac_probe(struct platform_device *pdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7603/soc.c-25-\ndrivers/net/wireless/mediatek/mt76/mt7603/soc.c:26:\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), \u0026mt7603_ops,\ndrivers/net/wireless/mediatek/mt76/mt7603/soc.c-27-\t\t\t\t \u0026mt7603_drv_ops);\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/mmio.c=166=int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/mmio.c-196-\ndrivers/net/wireless/mediatek/mt76/mt7615/mmio.c:197:\tmdev = mt76_alloc_device(pdev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7615/mmio.c-198-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/sdio.c=76=static int mt7663s_probe(struct sdio_func *func,\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/sdio.c-111-\ndrivers/net/wireless/mediatek/mt76/mt7615/sdio.c:112:\tmdev = mt76_alloc_device(\u0026func-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7615/sdio.c-113-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/usb.c=112=static int mt7663u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7615/usb.c-148-\ndrivers/net/wireless/mediatek/mt76/mt7615/usb.c:149:\tmdev = mt76_alloc_device(\u0026usb_intf-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7615/usb.c-150-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt76x0/pci.c=154=mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n--\ndrivers/net/wireless/mediatek/mt76/mt76x0/pci.c-191-\ndrivers/net/wireless/mediatek/mt76/mt76x0/pci.c:192:\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), \u0026mt76x0e_ops,\ndrivers/net/wireless/mediatek/mt76/mt76x0/pci.c-193-\t\t\t\t \u0026drv_ops);\n--\ndrivers/net/wireless/mediatek/mt76/mt76x0/usb.c=213=static int mt76x0u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt76x0/usb.c-235-\ndrivers/net/wireless/mediatek/mt76/mt76x0/usb.c:236:\tmdev = mt76_alloc_device(\u0026usb_intf-\u003edev, sizeof(*dev), \u0026mt76x0u_ops,\ndrivers/net/wireless/mediatek/mt76/mt76x0/usb.c-237-\t\t\t\t \u0026drv_ops);\n--\ndrivers/net/wireless/mediatek/mt76/mt76x2/pci.c=20=mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n--\ndrivers/net/wireless/mediatek/mt76/mt76x2/pci.c-55-\ndrivers/net/wireless/mediatek/mt76/mt76x2/pci.c:56:\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), \u0026mt76x2_ops,\ndrivers/net/wireless/mediatek/mt76/mt76x2/pci.c-57-\t\t\t\t \u0026drv_ops);\n--\ndrivers/net/wireless/mediatek/mt76/mt76x2/usb.c=32=static int mt76x2u_probe(struct usb_interface *intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt76x2/usb.c-53-\ndrivers/net/wireless/mediatek/mt76/mt76x2/usb.c:54:\tmdev = mt76_alloc_device(\u0026intf-\u003edev, sizeof(*dev), \u0026mt76x2u_ops,\ndrivers/net/wireless/mediatek/mt76/mt76x2/usb.c-55-\t\t\t\t \u0026drv_ops);\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mmio.c=917=struct mt7915_dev *mt7915_mmio_probe(struct device *pdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7915/mmio.c-944-\ndrivers/net/wireless/mediatek/mt76/mt7915/mmio.c:945:\tmdev = mt76_alloc_device(pdev, sizeof(*dev), \u0026mt7915_ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7915/mmio.c-946-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/pci.c=259=static int mt7921_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/pci.c-343-\ndrivers/net/wireless/mediatek/mt76/mt7921/pci.c:344:\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7921/pci.c-345-\tif (!mdev) {\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/sdio.c=90=static int mt7921s_probe(struct sdio_func *func,\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/sdio.c-137-\ndrivers/net/wireless/mediatek/mt76/mt7921/sdio.c:138:\tmdev = mt76_alloc_device(\u0026func-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7921/sdio.c-139-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c=150=static int mt7921u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c-197-\tops-\u003estop = mt792xu_stop;\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c:198:\tmdev = mt76_alloc_device(\u0026usb_intf-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7921/usb.c-199-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=529=static int mt7925_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-608-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:609:\tmdev = mt76_alloc_device(\u0026pdev-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-610-\tif (!mdev) {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=150=static int mt7925u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-197-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:198:\tmdev = mt76_alloc_device(\u0026usb_intf-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-199-\tif (!mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7996/mmio.c=832=struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7996/mmio.c-862-\ndrivers/net/wireless/mediatek/mt76/mt7996/mmio.c:863:\tmdev = mt76_alloc_device(pdev, sizeof(*dev), \u0026mt7996_ops, \u0026drv_ops);\ndrivers/net/wireless/mediatek/mt76/mt7996/mmio.c-864-\tif (!mdev)\n"
} |
| 89/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 62549 output: 49 thoughts: 37 Thoughts: Here's my summary, as if I were thinking these thoughts: **Diving into the MT76 Driver's Device Allocation** Okay, time to get my hands dirty. I need to understand how this MT76 driver handles device allocation. Specifically, I need to check out the `mt76_alloc_device` function. Let's head over to the `drivers/net/wireless/mediatek/mt76/mac80211.c` file. That's the logical place to start looking, given that `mac80211` is our wireless framework, and this is a Mediatek driver. I'm expecting this function to be the entry point for initializing the device's resources. I'll be looking for things like memory allocation, hardware reset sequences, interrupt registration, and potentially even clock enable operations. I'm keen to see the approach they've taken with this architecture, and hopefully how they handle things in the common MT76 abstraction layer, so I can see what I can learn. |
| 90/3 | 2026/08/24 23:03 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mac80211.c",
"FirstLine": 668,
"LineCount": 20
}Results: {
"Contents": " 668:\tstruct mt76_dev *\n 669:\tmt76_alloc_device(struct device *pdev, unsigned int size,\n 670:\t\t\t const struct ieee80211_ops *ops,\n 671:\t\t\t const struct mt76_driver_ops *drv_ops)\n 672:\t{\n 673:\t\tstruct ieee80211_hw *hw;\n 674:\t\tstruct mt76_phy *phy;\n 675:\t\tstruct mt76_dev *dev;\n 676:\t\tint i;\n 677:\t\n 678:\t\thw = ieee80211_alloc_hw(size, ops);\n 679:\t\tif (!hw)\n 680:\t\t\treturn NULL;\n 681:\t\n 682:\t\tdev = hw-\u003epriv;\n 683:\t\tdev-\u003ehw = hw;\n 684:\t\tdev-\u003edev = pdev;\n 685:\t\tdev-\u003einit_wiphy = NULL;\n 686:\t\tdev-\u003edrv = drv_ops;\n 687:\t\tdev-\u003edma_dev = pdev;\n"
} |
| 91/3 | 2026/08/24 23:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 63173 output: 28 thoughts: 86 Thoughts: **My Line of Inquiry** Okay, so I'm looking at how this driver is setting up the hardware interface. My initial thought is that `ieee80211_alloc_hw` is responsible for allocating the necessary structures. Specifically, it's taking care of the `hw` struct and, crucially, the `hw->priv` field, which I know, in this context, is referring to the device-specific data (`dev`, or `mt792x_dev` in this case). It's a standard practice. Now, I'm pretty sure I remember seeing `kzalloc` being used inside that function. Just a gut feeling, really. However, I want to be *certain*. The details of memory allocation are critical, especially when we're dealing with driver initialization. So, my next step is to verify that `kzalloc` is indeed the allocation mechanism used within `ieee80211_alloc_hw`. I need to confirm this before I move on to any further analysis. Let's dig into the code and see. |
| 92/3 | 2026/08/24 23:04 | tool | grepper |
0mError:no matches Args: {
"Expression": "kzalloc.*ieee80211_alloc_hw"
}Results: {
"error": "no matches"
} |
| 93/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 63529 output: 25 thoughts: 32 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into the 802.11 Hardware Allocation** Okay, time to get my hands dirty. I need to understand how the hardware is being allocated within the mac80211 framework. Specifically, I'm thinking about the process that starts with `ieee80211_alloc_hw`. I'm going to jump into `net/mac80211/main.c` and start my deep dive there. I want to see precisely how the struct `ieee80211_hw` gets instantiated, initialized, and how it's linked into the overall data structures. I'm looking for where the resource allocation happens, and any potential points where issues might arise. I'm particularly interested in how they're handling different hardware capabilities and chipsets and how this allocation handles that level of abstraction. Time to roll up my sleeves and dissect this function... |
| 94/3 | 2026/08/24 23:04 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_alloc_hw"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 619 lines.\nUse more precise expression if possible.\n\nDocumentation/driver-api/80211/mac80211.rst=30=references to other parts of the book.\n--\nDocumentation/driver-api/80211/mac80211.rst-38-\tieee80211_ops\nDocumentation/driver-api/80211/mac80211.rst:39:\tieee80211_alloc_hw\nDocumentation/driver-api/80211/mac80211.rst-40-\tieee80211_register_hw\n--\ndrivers/net/wireless/admtek/adm8211.c=1780=static int adm8211_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/admtek/adm8211.c-1832-\ndrivers/net/wireless/admtek/adm8211.c:1833:\tdev = ieee80211_alloc_hw(sizeof(*priv), \u0026adm8211_ops);\ndrivers/net/wireless/admtek/adm8211.c-1834-\tif (!dev) {\n--\ndrivers/net/wireless/ath/ar5523/ar5523.c=1590=static int ar5523_probe(struct usb_interface *intf,\n--\ndrivers/net/wireless/ath/ar5523/ar5523.c-1620-\ndrivers/net/wireless/ath/ar5523/ar5523.c:1621:\thw = ieee80211_alloc_hw(sizeof(*ar), \u0026ar5523_ops);\ndrivers/net/wireless/ath/ar5523/ar5523.c-1622-\tif (!hw)\n--\ndrivers/net/wireless/ath/ath10k/mac.c=9599=struct ath10k *ath10k_mac_create(size_t priv_size)\n--\ndrivers/net/wireless/ath/ath10k/mac.c-9608-\ndrivers/net/wireless/ath/ath10k/mac.c:9609:\thw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, ops);\ndrivers/net/wireless/ath/ath10k/mac.c-9610-\tif (!hw) {\n--\ndrivers/net/wireless/ath/ath11k/mac.c=10751=int ath11k_mac_allocate(struct ath11k_base *ab)\n--\ndrivers/net/wireless/ath/ath11k/mac.c-10763-\t\tpdev = \u0026ab-\u003epdevs[i];\ndrivers/net/wireless/ath/ath11k/mac.c:10764:\t\thw = ieee80211_alloc_hw(sizeof(struct ath11k), \u0026ath11k_ops);\ndrivers/net/wireless/ath/ath11k/mac.c-10765-\t\tif (!hw) {\n--\ndrivers/net/wireless/ath/ath12k/mac.c=15352=static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,\n--\ndrivers/net/wireless/ath/ath12k/mac.c-15363-\ndrivers/net/wireless/ath/ath12k/mac.c:15364:\thw = ieee80211_alloc_hw(struct_size(ah, radio, num_pdev_map),\ndrivers/net/wireless/ath/ath12k/mac.c-15365-\t\t\t\tpdev_map-\u003eab-\u003eath12k_ops);\n--\ndrivers/net/wireless/ath/ath5k/ahb.c=85=static int ath_ahb_probe(struct platform_device *pdev)\n--\ndrivers/net/wireless/ath/ath5k/ahb.c-121-\ndrivers/net/wireless/ath/ath5k/ahb.c:122:\thw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), \u0026ath5k_hw_ops);\ndrivers/net/wireless/ath/ath5k/ahb.c-123-\tif (hw == NULL) {\n--\ndrivers/net/wireless/ath/ath5k/pci.c=160=ath5k_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/ath/ath5k/pci.c-250-\t */\ndrivers/net/wireless/ath/ath5k/pci.c:251:\thw = ieee80211_alloc_hw(sizeof(*ah), \u0026ath5k_hw_ops);\ndrivers/net/wireless/ath/ath5k/pci.c-252-\tif (hw == NULL) {\n--\ndrivers/net/wireless/ath/ath9k/ahb.c=55=static int ath_ahb_probe(struct platform_device *pdev)\n--\ndrivers/net/wireless/ath/ath9k/ahb.c-76-\tath9k_fill_chanctx_ops();\ndrivers/net/wireless/ath/ath9k/ahb.c:77:\thw = ieee80211_alloc_hw(sizeof(struct ath_softc), \u0026ath9k_ops);\ndrivers/net/wireless/ath/ath9k/ahb.c-78-\tif (hw == NULL) {\n--\ndrivers/net/wireless/ath/ath9k/htc_drv_init.c=931=int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,\n--\ndrivers/net/wireless/ath/ath9k/htc_drv_init.c-938-\ndrivers/net/wireless/ath/ath9k/htc_drv_init.c:939:\thw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), \u0026ath9k_htc_ops);\ndrivers/net/wireless/ath/ath9k/htc_drv_init.c-940-\tif (!hw)\n--\ndrivers/net/wireless/ath/ath9k/pci.c=884=static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n--\ndrivers/net/wireless/ath/ath9k/pci.c-942-\tath9k_fill_chanctx_ops();\ndrivers/net/wireless/ath/ath9k/pci.c:943:\thw = ieee80211_alloc_hw(sizeof(struct ath_softc), \u0026ath9k_ops);\ndrivers/net/wireless/ath/ath9k/pci.c-944-\tif (!hw) {\n--\ndrivers/net/wireless/ath/carl9170/main.c=1747=void *carl9170_alloc(size_t priv_size)\n--\ndrivers/net/wireless/ath/carl9170/main.c-1763-\ndrivers/net/wireless/ath/carl9170/main.c:1764:\thw = ieee80211_alloc_hw(priv_size, \u0026carl9170_ops);\ndrivers/net/wireless/ath/carl9170/main.c-1765-\tif (!hw)\n--\ndrivers/net/wireless/ath/wcn36xx/main.c=1558=static int wcn36xx_probe(struct platform_device *pdev)\n--\ndrivers/net/wireless/ath/wcn36xx/main.c-1571-\tn_channels = wcn_band_2ghz.n_channels + wcn_band_5ghz.n_channels;\ndrivers/net/wireless/ath/wcn36xx/main.c:1572:\thw = ieee80211_alloc_hw(struct_size(wcn, chan_survey, n_channels), \u0026wcn36xx_ops);\ndrivers/net/wireless/ath/wcn36xx/main.c-1573-\tif (!hw) {\n--\ndrivers/net/wireless/atmel/at76c50x-usb.c=2196=static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)\n--\ndrivers/net/wireless/atmel/at76c50x-usb.c-2200-\ndrivers/net/wireless/atmel/at76c50x-usb.c:2201:\thw = ieee80211_alloc_hw(sizeof(struct at76_priv), \u0026at76_ops);\ndrivers/net/wireless/atmel/at76c50x-usb.c-2202-\tif (!hw) {\n--\ndrivers/net/wireless/broadcom/b43/main.c=5577=static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)\n--\ndrivers/net/wireless/broadcom/b43/main.c-5584-\ndrivers/net/wireless/broadcom/b43/main.c:5585:\thw = ieee80211_alloc_hw(sizeof(*wl), \u0026b43_hw_ops);\ndrivers/net/wireless/broadcom/b43/main.c-5586-\tif (!hw) {\n--\ndrivers/net/wireless/broadcom/b43legacy/main.c=3788=static int b43legacy_wireless_init(struct ssb_device *dev)\n--\ndrivers/net/wireless/broadcom/b43legacy/main.c-3797-\ndrivers/net/wireless/broadcom/b43legacy/main.c:3798:\thw = ieee80211_alloc_hw(sizeof(*wl), \u0026b43legacy_hw_ops);\ndrivers/net/wireless/broadcom/b43legacy/main.c-3799-\tif (!hw) {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c=1224=static int brcms_bcma_probe(struct bcma_device *pdev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1237-\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c:1238:\thw = ieee80211_alloc_hw(sizeof(struct brcms_info), \u0026brcms_ops);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1239-\tif (!hw) {\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c:1240:\t\tpr_err(\"%s: ieee80211_alloc_hw failed\\n\", __func__);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1241-\t\treturn -ENOMEM;\n--\ndrivers/net/wireless/intel/iwlegacy/3945-mac.c=3540=il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n--\ndrivers/net/wireless/intel/iwlegacy/3945-mac.c-3552-\ndrivers/net/wireless/intel/iwlegacy/3945-mac.c:3553:\thw = ieee80211_alloc_hw(sizeof(struct il_priv), \u0026il3945_mac_ops);\ndrivers/net/wireless/intel/iwlegacy/3945-mac.c-3554-\tif (!hw) {\n--\ndrivers/net/wireless/intel/iwlegacy/4965-mac.c=6479=il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n--\ndrivers/net/wireless/intel/iwlegacy/4965-mac.c-6491-\ndrivers/net/wireless/intel/iwlegacy/4965-mac.c:6492:\thw = ieee80211_alloc_hw(sizeof(struct il_priv), \u0026il4965_mac_ops);\ndrivers/net/wireless/intel/iwlegacy/4965-mac.c-6493-\tif (!hw) {\n--\ndrivers/net/wireless/intel/iwlwifi/dvm/mac80211.c=1609=struct ieee80211_hw *iwl_alloc_all(void)\n--\ndrivers/net/wireless/intel/iwlwifi/dvm/mac80211.c-1616-\ndrivers/net/wireless/intel/iwlwifi/dvm/mac80211.c:1617:\thw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +\ndrivers/net/wireless/intel/iwlwifi/dvm/mac80211.c-1618-\t\t\t\tsizeof(struct iwl_op_mode), \u0026iwlagn_hw_ops);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mld.c=396=iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mld.c-404-\t/* Allocate and initialize a new hardware device */\ndrivers/net/wireless/intel/iwlwifi/mld/mld.c:405:\thw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) +\ndrivers/net/wireless/intel/iwlwifi/mld/mld.c-406-\t\t\t\tsizeof(struct iwl_mld),\n--\ndrivers/net/wireless/intel/iwlwifi/mvm/ops.c=1198=iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,\n--\ndrivers/net/wireless/intel/iwlwifi/mvm/ops.c-1224-\t ********************************/\ndrivers/net/wireless/intel/iwlwifi/mvm/ops.c:1225:\thw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) +\ndrivers/net/wireless/intel/iwlwifi/mvm/ops.c-1226-\t\t\t\tsizeof(struct iwl_mvm),\n--\ndrivers/net/wireless/intersil/p54/main.c=736=struct ieee80211_hw *p54_init_common(size_t priv_data_len)\n--\ndrivers/net/wireless/intersil/p54/main.c-740-\ndrivers/net/wireless/intersil/p54/main.c:741:\tdev = ieee80211_alloc_hw(priv_data_len, \u0026p54_ops);\ndrivers/net/wireless/intersil/p54/main.c-742-\tif (!dev)\n--\ndrivers/net/wireless/marvell/libertas_tf/main.c=555=struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev,\n--\ndrivers/net/wireless/marvell/libertas_tf/main.c-562-\ndrivers/net/wireless/marvell/libertas_tf/main.c:563:\thw = ieee80211_alloc_hw(sizeof(struct lbtf_private), \u0026lbtf_ops);\ndrivers/net/wireless/marvell/libertas_tf/main.c-564-\tif (!hw)\n--\ndrivers/net/wireless/marvell/mwl8k.c=6268=static int mwl8k_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/marvell/mwl8k.c-6299-\ndrivers/net/wireless/marvell/mwl8k.c:6300:\thw = ieee80211_alloc_hw(sizeof(*priv), \u0026mwl8k_ops);\ndrivers/net/wireless/marvell/mwl8k.c-6301-\tif (hw == NULL) {\n--\ndrivers/net/wireless/mediatek/mt76/mac80211.c=518=mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,\n--\ndrivers/net/wireless/mediatek/mt76/mac80211.c-525-\tphy_size = ALIGN(sizeof(*phy), 8);\ndrivers/net/wireless/mediatek/mt76/mac80211.c:526:\thw = ieee80211_alloc_hw(size + phy_size, ops);\ndrivers/net/wireless/mediatek/mt76/mac80211.c-527-\tif (!hw)\n--\ndrivers/net/wireless/mediatek/mt76/mac80211.c=669=mt76_alloc_device(struct device *pdev, unsigned int size,\n--\ndrivers/net/wireless/mediatek/mt76/mac80211.c-677-\ndrivers/net/wireless/mediatek/mt76/mac80211.c:678:\thw = ieee80211_alloc_hw(size, ops);\ndrivers/net/wireless/mediatek/mt76/mac80211.c-679-\tif (!hw)\n--\ndrivers/net/wireless/mediatek/mt7601u/init.c=432=struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev)\n--\ndrivers/net/wireless/mediatek/mt7601u/init.c-436-\ndrivers/net/wireless/mediatek/mt7601u/init.c:437:\thw = ieee80211_alloc_hw(sizeof(*dev), \u0026mt7601u_ops);\ndrivers/net/wireless/mediatek/mt7601u/init.c-438-\tif (!hw)\n--\ndrivers/net/wireless/morsemicro/mm81x/mac.c=2416=struct mm81x *mm81x_mac_alloc(size_t priv_size, struct device *dev)\n--\ndrivers/net/wireless/morsemicro/mm81x/mac.c-2420-\ndrivers/net/wireless/morsemicro/mm81x/mac.c:2421:\thw = ieee80211_alloc_hw(sizeof(*mors) + priv_size, \u0026mm81x_ops);\ndrivers/net/wireless/morsemicro/mm81x/mac.c-2422-\tif (!hw) {\ndrivers/net/wireless/morsemicro/mm81x/mac.c:2423:\t\tdev_err(dev, \"ieee80211_alloc_hw failed\\r\\n\");\ndrivers/net/wireless/morsemicro/mm81x/mac.c-2424-\t\treturn NULL;\n--\ndrivers/net/wireless/purelifi/plfxlc/mac.c=702=struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf)\n--\ndrivers/net/wireless/purelifi/plfxlc/mac.c-706-\ndrivers/net/wireless/purelifi/plfxlc/mac.c:707:\thw = ieee80211_alloc_hw(sizeof(struct plfxlc_mac), \u0026plfxlc_ops);\ndrivers/net/wireless/purelifi/plfxlc/mac.c-708-\tif (!hw) {\n--\ndrivers/net/wireless/ralink/rt2x00/rt2800soc.c=263=static int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops)\n--\ndrivers/net/wireless/ralink/rt2x00/rt2800soc.c-293-\ndrivers/net/wireless/ralink/rt2x00/rt2800soc.c:294:\thw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops-\u003ehw);\ndrivers/net/wireless/ralink/rt2x00/rt2800soc.c-295-\tif (!hw)\n--\ndrivers/net/wireless/ralink/rt2x00/rt2x00pci.c=65=int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)\n--\ndrivers/net/wireless/ralink/rt2x00/rt2x00pci.c-94-\ndrivers/net/wireless/ralink/rt2x00/rt2x00pci.c:95:\thw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops-\u003ehw);\ndrivers/net/wireless/ralink/rt2x00/rt2x00pci.c-96-\tif (!hw) {\n--\ndrivers/net/wireless/ralink/rt2x00/rt2x00usb.c=797=int rt2x00usb_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/ralink/rt2x00/rt2x00usb.c-806-\ndrivers/net/wireless/ralink/rt2x00/rt2x00usb.c:807:\thw = ieee80211_alloc_hw(struct_size(rt2x00dev, anchor, 1), ops-\u003ehw);\ndrivers/net/wireless/ralink/rt2x00/rt2x00usb.c-808-\tif (!hw) {\n--\ndrivers/net/wireless/realtek/rtl818x/rtl8180/dev.c=1730=static int rtl8180_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/realtek/rtl818x/rtl8180/dev.c-1774-\ndrivers/net/wireless/realtek/rtl818x/rtl8180/dev.c:1775:\tdev = ieee80211_alloc_hw(sizeof(*priv), \u0026rtl8180_ops);\ndrivers/net/wireless/realtek/rtl818x/rtl8180/dev.c-1776-\tif (!dev) {\n--\ndrivers/net/wireless/realtek/rtl818x/rtl8187/dev.c=1442=static int rtl8187_probe(struct usb_interface *intf,\n--\ndrivers/net/wireless/realtek/rtl818x/rtl8187/dev.c-1455-\ndrivers/net/wireless/realtek/rtl818x/rtl8187/dev.c:1456:\tdev = ieee80211_alloc_hw(sizeof(*priv), \u0026rtl8187_ops);\ndrivers/net/wireless/realtek/rtl818x/rtl8187/dev.c-1457-\tif (!dev) {\n--\ndrivers/net/wireless/realtek/rtl8xxxu/core.c=7745=static int rtl8xxxu_probe(struct usb_interface *interface,\n--\ndrivers/net/wireless/realtek/rtl8xxxu/core.c-7812-\ndrivers/net/wireless/realtek/rtl8xxxu/core.c:7813:\thw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), \u0026rtl8xxxu_ops);\ndrivers/net/wireless/realtek/rtl8xxxu/core.c-7814-\tif (!hw)\n--\ndrivers/net/wireless/realtek/rtlwifi/pci.c=2088=int rtl_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/realtek/rtlwifi/pci.c-2128-\ndrivers/net/wireless/realtek/rtlwifi/pci.c:2129:\thw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) +\ndrivers/net/wireless/realtek/rtlwifi/pci.c-2130-\t\t\t\tsizeof(struct rtl_priv), \u0026rtl_ops);\n--\ndrivers/net/wireless/realtek/rtlwifi/usb.c=951=int rtl_usb_probe(struct usb_interface *intf,\n--\ndrivers/net/wireless/realtek/rtlwifi/usb.c-960-\ndrivers/net/wireless/realtek/rtlwifi/usb.c:961:\thw = ieee80211_alloc_hw(sizeof(struct rtl_priv) +\ndrivers/net/wireless/realtek/rtlwifi/usb.c-962-\t\t\t\tsizeof(struct rtl_usb_priv), \u0026rtl_ops);\n--\ndrivers/net/wireless/realtek/rtw88/pci.c=1795=int rtw_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/realtek/rtw88/pci.c-1805-\tdrv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_pci);\ndrivers/net/wireless/realtek/rtw88/pci.c:1806:\thw = ieee80211_alloc_hw(drv_data_size, \u0026rtw_ops);\ndrivers/net/wireless/realtek/rtw88/pci.c-1807-\tif (!hw) {\n--\ndrivers/net/wireless/realtek/rtw88/sdio.c=1325=int rtw_sdio_probe(struct sdio_func *sdio_func,\n--\ndrivers/net/wireless/realtek/rtw88/sdio.c-1333-\tdrv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_sdio);\ndrivers/net/wireless/realtek/rtw88/sdio.c:1334:\thw = ieee80211_alloc_hw(drv_data_size, \u0026rtw_ops);\ndrivers/net/wireless/realtek/rtw88/sdio.c-1335-\tif (!hw) {\n--\ndrivers/net/wireless/realtek/rtw88/usb.c=1263=int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)\n--\ndrivers/net/wireless/realtek/rtw88/usb.c-1271-\tdrv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb);\ndrivers/net/wireless/realtek/rtw88/usb.c:1272:\thw = ieee80211_alloc_hw(drv_data_size, \u0026rtw_ops);\ndrivers/net/wireless/realtek/rtw88/usb.c-1273-\tif (!hw)\n--\ndrivers/net/wireless/realtek/rtw89/core.c=7637=struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,\n--\ndrivers/net/wireless/realtek/rtw89/core.c-7679-\tdriver_data_size = sizeof(struct rtw89_dev) + bus_data_size;\ndrivers/net/wireless/realtek/rtw89/core.c:7680:\thw = ieee80211_alloc_hw(driver_data_size, ops);\ndrivers/net/wireless/realtek/rtw89/core.c-7681-\tif (!hw)\n--\ndrivers/net/wireless/rsi/rsi_91x_mac80211.c=2022=int rsi_mac80211_attach(struct rsi_common *common)\n--\ndrivers/net/wireless/rsi/rsi_91x_mac80211.c-2031-\ndrivers/net/wireless/rsi/rsi_91x_mac80211.c:2032:\thw = ieee80211_alloc_hw(sizeof(struct rsi_hw), \u0026mac80211_ops);\ndrivers/net/wireless/rsi/rsi_91x_mac80211.c-2033-\tif (!hw) {\n--\ndrivers/net/wireless/silabs/wfx/main.c=267=struct wfx_dev *wfx_init_common(struct device *dev, const struct wfx_platform_data *pdata,\n--\ndrivers/net/wireless/silabs/wfx/main.c-272-\ndrivers/net/wireless/silabs/wfx/main.c:273:\thw = ieee80211_alloc_hw(sizeof(struct wfx_dev), \u0026wfx_ops);\ndrivers/net/wireless/silabs/wfx/main.c-274-\tif (!hw)\n--\ndrivers/net/wireless/st/cw1200/main.c=257=static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,\n--\ndrivers/net/wireless/st/cw1200/main.c-263-\ndrivers/net/wireless/st/cw1200/main.c:264:\thw = ieee80211_alloc_hw(sizeof(struct cw1200_common), \u0026cw1200_ops);\ndrivers/net/wireless/st/cw1200/main.c-265-\tif (!hw)\n--\ndrivers/net/wireless/ti/wl1251/main.c=1582=struct ieee80211_hw *wl1251_alloc_hw(void)\n--\ndrivers/net/wireless/ti/wl1251/main.c-1587-\ndrivers/net/wireless/ti/wl1251/main.c:1588:\thw = ieee80211_alloc_hw(sizeof(*wl), \u0026wl1251_ops);\ndrivers/net/wireless/ti/wl1251/main.c-1589-\tif (!hw) {\n--\ndrivers/net/wireless/ti/wlcore/main.c=6351=struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,\n--\ndrivers/net/wireless/ti/wlcore/main.c-6357-\ndrivers/net/wireless/ti/wlcore/main.c:6358:\thw = ieee80211_alloc_hw(sizeof(*wl), \u0026wl1271_ops);\ndrivers/net/wireless/ti/wlcore/main.c-6359-\tif (!hw) {\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=5674=static int mac80211_hwsim_new_radio(struct genl_info *info,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5698-\t\tops = \u0026mac80211_hwsim_mchan_ops;\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5699:\thw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param-\u003ehwname);\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5700-\tif (!hw) {\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5701:\t\tpr_debug(\"mac80211_hwsim: ieee80211_alloc_hw failed\\n\");\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5702-\t\terr = -ENOMEM;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5705-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5706:\t/* ieee80211_alloc_hw_nm may have used a default name */\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5707-\tparam-\u003ehwname = wiphy_name(hw-\u003ewiphy);\n--\ndrivers/net/wireless/zydas/zd1211rw/zd_mac.c=1366=struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)\n--\ndrivers/net/wireless/zydas/zd1211rw/zd_mac.c-1370-\ndrivers/net/wireless/zydas/zd1211rw/zd_mac.c:1371:\thw = ieee80211_alloc_hw(sizeof(struct zd_mac), \u0026zd_ops);\ndrivers/net/wireless/zydas/zd1211rw/zd_mac.c-1372-\tif (!hw) {\n--\ninclude/net/mac80211.h=4742=struct ieee80211_ops {\n--\ninclude/net/mac80211.h-5144-/**\ninclude/net/mac80211.h:5145: * ieee80211_alloc_hw_nm - Allocate a new hardware device\ninclude/net/mac80211.h-5146- *\n--\ninclude/net/mac80211.h-5159- */\ninclude/net/mac80211.h:5160:struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,\ninclude/net/mac80211.h-5161-\t\t\t\t\t const struct ieee80211_ops *ops,\n--\ninclude/net/mac80211.h-5164-/**\ninclude/net/mac80211.h:5165: * ieee80211_alloc_hw - Allocate a new hardware device\ninclude/net/mac80211.h-5166- *\n--\ninclude/net/mac80211.h=5178=static inline\ninclude/net/mac80211.h:5179:struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,\ninclude/net/mac80211.h-5180-\t\t\t\t\tconst struct ieee80211_ops *ops)\ninclude/net/mac80211.h-5181-{\ninclude/net/mac80211.h:5182:\treturn ieee80211_alloc_hw_nm(priv_data_len, ops, NULL);\ninclude/net/mac80211.h-5183-}\n--\ninclude/net/mac80211.h-5191- *\ninclude/net/mac80211.h:5192: * @hw: the device to register as returned by ieee80211_alloc_hw()\ninclude/net/mac80211.h-5193- *\n--\ninclude/net/mac80211.h=5755=struct ieee80211_mutable_offsets {\n--\ninclude/net/mac80211.h-5764- * ieee80211_beacon_get_template - beacon template generation function\ninclude/net/mac80211.h:5765: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5766- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5785=ieee80211_beacon_get_template(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-5791- * ieee80211_beacon_get_template_ema_index - EMA beacon template generation\ninclude/net/mac80211.h:5792: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5793- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5820=struct ieee80211_ema_beacons {\n--\ninclude/net/mac80211.h-5829- * ieee80211_beacon_get_template_ema_list - EMA beacon template generation\ninclude/net/mac80211.h:5830: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5831- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5856=void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons);\n--\ninclude/net/mac80211.h-5859- * ieee80211_beacon_get_tim - beacon generation function\ninclude/net/mac80211.h:5860: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5861- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5882=struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-5888- * ieee80211_beacon_get - beacon generation function\ninclude/net/mac80211.h:5889: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5890- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5964=void ieee80211_color_change_finish(struct ieee80211_vif *vif, u8 link_id);\n--\ninclude/net/mac80211.h-5967- * ieee80211_proberesp_get - retrieve a Probe Response template\ninclude/net/mac80211.h:5968: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5969- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5978=struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-5982- * ieee80211_pspoll_get - retrieve a PS Poll template\ninclude/net/mac80211.h:5983: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-5984- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=5995=struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-5999- * ieee80211_nullfunc_get - retrieve a nullfunc template\ninclude/net/mac80211.h:6000: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6001- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6020=struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6025- * ieee80211_probereq_get - retrieve a Probe Request template\ninclude/net/mac80211.h:6026: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6027- * @src_addr: source MAC address\n--\ninclude/net/mac80211.h=6037=struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6043- * ieee80211_rts_get - RTS frame generation function\ninclude/net/mac80211.h:6044: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6045- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6056=void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,\n--\ninclude/net/mac80211.h-6062- * ieee80211_rts_duration - Get the duration field for an RTS frame\ninclude/net/mac80211.h:6063: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6064- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6074=__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6079- * ieee80211_ctstoself_get - CTS-to-self frame generation function\ninclude/net/mac80211.h:6080: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6081- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6092=void ieee80211_ctstoself_get(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6099- * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame\ninclude/net/mac80211.h:6100: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6101- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6111=__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6117- * ieee80211_generic_frame_duration - Calculate the duration field for a frame\ninclude/net/mac80211.h:6118: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6119- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6129=__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6136- * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames\ninclude/net/mac80211.h:6137: * @hw: pointer as obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6138- * @vif: \u0026struct ieee80211_vif pointer from the add_interface callback.\n--\ninclude/net/mac80211.h=6338=void ieee80211_key_replay(struct ieee80211_key_conf *keyconf);\n--\ninclude/net/mac80211.h-6341- * ieee80211_wake_queue - wake specific queue\ninclude/net/mac80211.h:6342: * @hw: pointer as obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6343- * @queue: queue number (counted from zero).\n--\ninclude/net/mac80211.h=6347=void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);\n--\ninclude/net/mac80211.h-6350- * ieee80211_stop_queue - stop specific queue\ninclude/net/mac80211.h:6351: * @hw: pointer as obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6352- * @queue: queue number (counted from zero).\n--\ninclude/net/mac80211.h=6356=void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);\n--\ninclude/net/mac80211.h-6359- * ieee80211_queue_stopped - test status of the queue\ninclude/net/mac80211.h:6360: * @hw: pointer as obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6361- * @queue: queue number (counted from zero).\n--\ninclude/net/mac80211.h=6368=int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue);\n--\ninclude/net/mac80211.h-6371- * ieee80211_stop_queues - stop all queues\ninclude/net/mac80211.h:6372: * @hw: pointer as obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6373- *\n--\ninclude/net/mac80211.h=6376=void ieee80211_stop_queues(struct ieee80211_hw *hw);\n--\ninclude/net/mac80211.h-6379- * ieee80211_wake_queues - wake all queues\ninclude/net/mac80211.h:6380: * @hw: pointer as obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6381- *\n--\ninclude/net/mac80211.h=6716=struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,\n--\ninclude/net/mac80211.h-6721- *\ninclude/net/mac80211.h:6722: * @hw: pointer as obtained from ieee80211_alloc_hw()\ninclude/net/mac80211.h-6723- * @addr: remote station's address\n--\ninclude/net/mac80211.h=6741=struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6746- * ieee80211_find_sta_by_link_addrs - find STA by link addresses\ninclude/net/mac80211.h:6747: * @hw: pointer as obtained from ieee80211_alloc_hw()\ninclude/net/mac80211.h-6748- * @addr: remote station's link address\n--\ninclude/net/mac80211.h=6876=void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,\n--\ninclude/net/mac80211.h-6881- *\ninclude/net/mac80211.h:6882: * @hw: pointer obtained from ieee80211_alloc_hw()\ninclude/net/mac80211.h-6883- * @txq: pointer obtained from station or virtual interface\n--\ninclude/net/mac80211.h=6889=ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq);\n--\ninclude/net/mac80211.h-6893- *\ninclude/net/mac80211.h:6894: * @hw: pointer obtained from ieee80211_alloc_hw()\ninclude/net/mac80211.h-6895- * @txq: pointer obtained from station or virtual interface\n--\ninclude/net/mac80211.h=6899=u32 ieee80211_txq_aql_pending(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6903- * ieee80211_iter_keys - iterate keys programmed into the device\ninclude/net/mac80211.h:6904: * @hw: pointer obtained from ieee80211_alloc_hw()\ninclude/net/mac80211.h-6905- * @vif: virtual interface to iterate, may be %NULL for all\n--\ninclude/net/mac80211.h=6920=void ieee80211_iter_keys(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6930- * ieee80211_iter_keys_rcu - iterate keys programmed into the device\ninclude/net/mac80211.h:6931: * @hw: pointer obtained from ieee80211_alloc_hw()\ninclude/net/mac80211.h-6932- * @vif: virtual interface to iterate, may be %NULL for all\n--\ninclude/net/mac80211.h=6944=void ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,\n--\ninclude/net/mac80211.h-6954- * ieee80211_iter_chan_contexts_atomic - iterate channel contexts\ninclude/net/mac80211.h:6955: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6956- * @iter: iterator function\n--\ninclude/net/mac80211.h=6972=void ieee80211_iter_chan_contexts_atomic(\n--\ninclude/net/mac80211.h-6980- * ieee80211_iter_chan_contexts_mtx - iterate channel contexts\ninclude/net/mac80211.h:6981: * @hw: pointer obtained from ieee80211_alloc_hw().\ninclude/net/mac80211.h-6982- * @iter: iterator function\n--\ninclude/net/mac80211.h=6997=void ieee80211_iter_chan_contexts_mtx(\n--\ninclude/net/mac80211.h-7005- * ieee80211_ap_probereq_get - retrieve a Probe Request template\n\n"
} |
| 95/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 77787 output: 27 thoughts: 32 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into the 802.11 Hardware Allocation** Okay, time to get my hands dirty. I need to understand how the hardware is being allocated within the mac80211 framework. Specifically, I'm thinking about the process that starts with `ieee80211_alloc_hw`. I'm going to jump into `net/mac80211/main.c` and start my deep dive there. I want to see precisely how the struct `ieee80211_hw` gets instantiated, initialized, and how it's linked into the overall data structures. I'm looking for where the resource allocation happens, and any potential points where issues might arise. I'm particularly interested in how they're handling different hardware capabilities and chipsets and how this allocation handles that level of abstraction. Time to roll up my sleeves and dissect this function... |
| 96/3 | 2026/08/24 23:04 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_alloc_hw_nm"
}Results: {
"Output": "drivers/net/wireless/virtual/mac80211_hwsim_main.c=5674=static int mac80211_hwsim_new_radio(struct genl_info *info,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5698-\t\tops = \u0026mac80211_hwsim_mchan_ops;\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5699:\thw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param-\u003ehwname);\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5700-\tif (!hw) {\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5705-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5706:\t/* ieee80211_alloc_hw_nm may have used a default name */\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5707-\tparam-\u003ehwname = wiphy_name(hw-\u003ewiphy);\n--\ninclude/net/mac80211.h=4742=struct ieee80211_ops {\n--\ninclude/net/mac80211.h-5144-/**\ninclude/net/mac80211.h:5145: * ieee80211_alloc_hw_nm - Allocate a new hardware device\ninclude/net/mac80211.h-5146- *\n--\ninclude/net/mac80211.h-5159- */\ninclude/net/mac80211.h:5160:struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,\ninclude/net/mac80211.h-5161-\t\t\t\t\t const struct ieee80211_ops *ops,\n--\ninclude/net/mac80211.h=5179=struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,\n--\ninclude/net/mac80211.h-5181-{\ninclude/net/mac80211.h:5182:\treturn ieee80211_alloc_hw_nm(priv_data_len, ops, NULL);\ninclude/net/mac80211.h-5183-}\n--\nnet/mac80211/main.c=775=static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {\n--\nnet/mac80211/main.c-792-\nnet/mac80211/main.c:793:struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,\nnet/mac80211/main.c-794-\t\t\t\t\t const struct ieee80211_ops *ops,\n--\nnet/mac80211/main.c-1050-}\nnet/mac80211/main.c:1051:EXPORT_SYMBOL(ieee80211_alloc_hw_nm);\nnet/mac80211/main.c-1052-\n"
} |
| 97/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 78981 output: 40 thoughts: 34 Thoughts: Here's my take on the process, considering I'm in the thick of this: **Analyzing `ieee80211_alloc_hw_nm`** Okay, I'm diving into `net/mac80211/main.c`. Specifically, I need to get a handle on `ieee80211_alloc_hw_nm`. This function, from the name alone, is clearly responsible for allocating the hardware structure within mac80211. I suspect this is the *new* method. So, I expect to see it handling the initial memory allocation for the `ieee80211_hw` struct (or perhaps a derivative), probably involving `kzalloc` or something similar to ensure a clean slate. I'm also anticipating it initializing some basic members of the structure – maybe setting up default values for key flags, pointers to other important data structures within mac80211, and pointers to default handler functions. I'll be looking to see how it interacts with any hardware-specific parameters that might be passed in. The "nm" likely means "new method," indicating this is a newer way of allocating and configuring the hardware structure, possibly intended to improve flexibility or address some older limitations. It's a key entry point, so I'm paying close attention to any error checking and cleanup mechanisms. The way it handles errors will give me an insight into the overall design philosophy regarding error handling in this module. I'm also curious about any potential locking mechanisms used during the allocation process, especially if it's operating within a multi-threaded context. This is going to give me a good baseline for how the mac80211 subsystem interacts with hardware. |
| 98/3 | 2026/08/24 23:04 | tool | read-file |
0mArgs:{
"File": "net/mac80211/main.c",
"FirstLine": 793,
"LineCount": 30
}Results: {
"Contents": " 793:\tstruct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,\n 794:\t\t\t\t\t\t const struct ieee80211_ops *ops,\n 795:\t\t\t\t\t\t const char *requested_name)\n 796:\t{\n 797:\t\tstruct ieee80211_local *local;\n 798:\t\tint priv_size, i;\n 799:\t\tstruct wiphy *wiphy;\n 800:\t\tbool emulate_chanctx;\n 801:\t\n 802:\t\tif (WARN_ON(!ops-\u003etx || !ops-\u003estart || !ops-\u003estop || !ops-\u003econfig ||\n 803:\t\t\t !ops-\u003eadd_interface || !ops-\u003eremove_interface ||\n 804:\t\t\t !ops-\u003econfigure_filter || !ops-\u003ewake_tx_queue))\n 805:\t\t\treturn NULL;\n 806:\t\n 807:\t\tif (WARN_ON(ops-\u003esta_state \u0026\u0026 (ops-\u003esta_add || ops-\u003esta_remove)))\n 808:\t\t\treturn NULL;\n 809:\t\n 810:\t\tif (WARN_ON(!!ops-\u003elink_info_changed != !!ops-\u003evif_cfg_changed ||\n 811:\t\t\t (ops-\u003elink_info_changed \u0026\u0026 ops-\u003ebss_info_changed)))\n 812:\t\t\treturn NULL;\n 813:\t\n 814:\t\t/* check all or no channel context operations exist */\n 815:\t\tif (ops-\u003eadd_chanctx == ieee80211_emulate_add_chanctx \u0026\u0026\n 816:\t\t ops-\u003eremove_chanctx == ieee80211_emulate_remove_chanctx \u0026\u0026\n 817:\t\t ops-\u003echange_chanctx == ieee80211_emulate_change_chanctx) {\n 818:\t\t\tif (WARN_ON(ops-\u003eassign_vif_chanctx ||\n 819:\t\t\t\t ops-\u003eunassign_vif_chanctx))\n 820:\t\t\t\treturn NULL;\n 821:\t\t\temulate_chanctx = true;\n 822:\t\t} else {\n"
} |
| 99/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 79994 output: 40 thoughts: 6 Thoughts: Okay, I'm ready. Let's see what we've got. Here's a summary: **Digging Deeper: The Urge to Understand** Alright, so the initial thought is clear: I need to delve further. It's that immediate, almost involuntary reaction I get when presented with something new, something that sparks my curiosity. My experience has taught me that initial surface impressions are rarely enough. There's always a hidden complexity, a nuance, a deeper layer of meaning waiting to be uncovered. Reading more, analyzing more, investigating more – that's the only way to truly grasp the subject at hand and assess its significance within the broader framework of my expertise. This urge, this compulsion to understand thoroughly, is fundamental to how I approach my work. |
| 100/3 | 2026/08/24 23:04 | tool | read-file |
0mArgs:{
"File": "net/mac80211/main.c",
"FirstLine": 823,
"LineCount": 40
}Results: {
"Contents": " 823:\t\t\tif (WARN_ON(ops-\u003eadd_chanctx == ieee80211_emulate_add_chanctx ||\n 824:\t\t\t\t ops-\u003eremove_chanctx == ieee80211_emulate_remove_chanctx ||\n 825:\t\t\t\t ops-\u003echange_chanctx == ieee80211_emulate_change_chanctx))\n 826:\t\t\t\treturn NULL;\n 827:\t\t\tif (WARN_ON(!ops-\u003eadd_chanctx ||\n 828:\t\t\t\t !ops-\u003eremove_chanctx ||\n 829:\t\t\t\t !ops-\u003echange_chanctx ||\n 830:\t\t\t\t !ops-\u003eassign_vif_chanctx ||\n 831:\t\t\t\t !ops-\u003eunassign_vif_chanctx))\n 832:\t\t\t\treturn NULL;\n 833:\t\t\temulate_chanctx = false;\n 834:\t\t}\n 835:\t\n 836:\t\t/* Ensure 32-byte alignment of our private data and hw private data.\n 837:\t\t * We use the wiphy priv data for both our ieee80211_local and for\n 838:\t\t * the driver's private data\n 839:\t\t *\n 840:\t\t * In memory it'll be like this:\n 841:\t\t *\n 842:\t\t * +-------------------------+\n 843:\t\t * | struct wiphy\t |\n 844:\t\t * +-------------------------+\n 845:\t\t * | struct ieee80211_local |\n 846:\t\t * +-------------------------+\n 847:\t\t * | driver's private data |\n 848:\t\t * +-------------------------+\n 849:\t\t *\n 850:\t\t */\n 851:\t\tpriv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;\n 852:\t\n 853:\t\twiphy = wiphy_new_nm(\u0026mac80211_config_ops, priv_size, requested_name);\n 854:\t\n 855:\t\tif (!wiphy)\n 856:\t\t\treturn NULL;\n 857:\t\n 858:\t\twiphy-\u003emgmt_stypes = ieee80211_default_mgmt_stypes;\n 859:\t\n 860:\t\twiphy-\u003eprivid = mac80211_wiphy_privid;\n 861:\t\n 862:\t\twiphy-\u003eflags |= WIPHY_FLAG_NETNS_OK |\n"
} |
| 101/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 80871 output: 20 thoughts: 33 Thoughts: Here's my summary, as if I were thinking these thoughts: **Analyzing the Wireless PHY Initialization** Okay, so I see `wiphy_new_nm` being invoked. That's the function we use to allocate a new wireless PHY (wiphy) structure and, if all goes well, initialize it for network manager. Right, let's dive into the core implementation in `net/wireless/core.c`. I need to understand what's happening internally during this allocation and setup phase. I want to see how the wiphy is structured, how it's linked into the system, and what the key steps are in its initialization workflow. I'm especially interested in how it interacts with the Network Manager context if I want to have a good understanding of the entire wireless subsystem. |
| 102/3 | 2026/08/24 23:04 | tool | grepper |
0mArgs:{
"Expression": "wiphy_new_nm"
}Results: {
"Output": "drivers/net/wireless/microchip/wilc1000/cfg80211.c=683=static int get_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n--\ndrivers/net/wireless/microchip/wilc1000/cfg80211.c-719-\ndrivers/net/wireless/microchip/wilc1000/cfg80211.c:720:/* wiphy_new_nm() will WARNON if not present */\ndrivers/net/wireless/microchip/wilc1000/cfg80211.c-721-static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,\n--\ninclude/net/cfg80211.h=6763=static inline const char *wiphy_name(const struct wiphy *wiphy)\n--\ninclude/net/cfg80211.h-6768-/**\ninclude/net/cfg80211.h:6769: * wiphy_new_nm - create a new wiphy for use with cfg80211\ninclude/net/cfg80211.h-6770- *\n--\ninclude/net/cfg80211.h-6781- */\ninclude/net/cfg80211.h:6782:struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,\ninclude/net/cfg80211.h-6783-\t\t\t const char *requested_name);\n--\ninclude/net/cfg80211.h=6797=static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,\n--\ninclude/net/cfg80211.h-6799-{\ninclude/net/cfg80211.h:6800:\treturn wiphy_new_nm(ops, sizeof_priv, NULL);\ninclude/net/cfg80211.h-6801-}\n--\nnet/mac80211/main.c=793=struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,\n--\nnet/mac80211/main.c-852-\nnet/mac80211/main.c:853:\twiphy = wiphy_new_nm(\u0026mac80211_config_ops, priv_size, requested_name);\nnet/mac80211/main.c-854-\n--\nnet/wireless/core.c=518=static void cfg80211_wiphy_work(struct work_struct *work)\n--\nnet/wireless/core.c-548-\nnet/wireless/core.c:549:struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,\nnet/wireless/core.c-550-\t\t\t const char *requested_name)\n--\nnet/wireless/core.c-702-}\nnet/wireless/core.c:703:EXPORT_SYMBOL(wiphy_new_nm);\nnet/wireless/core.c-704-\n--\nnet/wireless/tests/util.c=13=int t_wiphy_init(struct kunit_resource *resource, void *ctx)\n--\nnet/wireless/tests/util.c-22-\nnet/wireless/tests/util.c:23:\twiphy = wiphy_new_nm(ops, sizeof(*priv), \"kunit\");\nnet/wireless/tests/util.c-24-\tKUNIT_ASSERT_NOT_NULL(test, wiphy);\n"
} |
| 103/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 82052 output: 35 thoughts: 22 Thoughts: Here's my summary, as though I'm reading and processing the code: **Diving into wiphy_new_nm** Alright, let's crack open `net/wireless/core.c` and zero in on `wiphy_new_nm`. I know this is where new wireless PHY (wiphy) devices are likely created, and given my expertise, I'm expecting some pretty intricate memory management and device registration details. I need to understand how the system allocates and initializes a new wiphy structure, especially how it interacts with the Network Manager (NM) side of things. I'm looking for the allocation details - likely using `kzalloc` or similar, any setup of internal data structures related to NM and the wireless device itself. I'll expect to see how it handles errors during setup and the appropriate freeing if something goes wrong. This is the foundation; understanding this function will unlock how the rest of the wireless stack handles new devices, their capabilities, and integration with the userspace NM tools. I'm keen to see if this handles the registration directly or defers the NM-specific tasks. Let's see how they handle the NM's interaction with the device. |
| 104/3 | 2026/08/24 23:04 | tool | read-file |
0mArgs:{
"File": "net/wireless/core.c",
"FirstLine": 549,
"LineCount": 30
}Results: {
"Contents": " 549:\tstruct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,\n 550:\t\t\t\t const char *requested_name)\n 551:\t{\n 552:\t\tstatic atomic_t wiphy_counter = ATOMIC_INIT(0);\n 553:\t\n 554:\t\tstruct cfg80211_registered_device *rdev;\n 555:\t\tint alloc_size;\n 556:\t\n 557:\t\tWARN_ON(ops-\u003eadd_key \u0026\u0026 (!ops-\u003edel_key || !ops-\u003eset_default_key));\n 558:\t\tWARN_ON(ops-\u003eauth \u0026\u0026 (!ops-\u003eassoc || !ops-\u003edeauth || !ops-\u003edisassoc));\n 559:\t\tWARN_ON(ops-\u003econnect \u0026\u0026 !ops-\u003edisconnect);\n 560:\t\tWARN_ON(ops-\u003ejoin_ibss \u0026\u0026 !ops-\u003eleave_ibss);\n 561:\t\tWARN_ON(ops-\u003eadd_virtual_intf \u0026\u0026 !ops-\u003edel_virtual_intf);\n 562:\t\tWARN_ON(ops-\u003eadd_station \u0026\u0026 !ops-\u003edel_station);\n 563:\t\tWARN_ON(ops-\u003eadd_mpath \u0026\u0026 !ops-\u003edel_mpath);\n 564:\t\tWARN_ON(ops-\u003ejoin_mesh \u0026\u0026 !ops-\u003eleave_mesh);\n 565:\t\tWARN_ON(ops-\u003estart_p2p_device \u0026\u0026 !ops-\u003estop_p2p_device);\n 566:\t\tWARN_ON(ops-\u003estart_ap \u0026\u0026 !ops-\u003estop_ap);\n 567:\t\tWARN_ON(ops-\u003ejoin_ocb \u0026\u0026 !ops-\u003eleave_ocb);\n 568:\t\tWARN_ON(ops-\u003esuspend \u0026\u0026 !ops-\u003eresume);\n 569:\t\tWARN_ON(ops-\u003esched_scan_start \u0026\u0026 !ops-\u003esched_scan_stop);\n 570:\t\tWARN_ON(ops-\u003eremain_on_channel \u0026\u0026 !ops-\u003ecancel_remain_on_channel);\n 571:\t\tWARN_ON(ops-\u003etdls_channel_switch \u0026\u0026 !ops-\u003etdls_cancel_channel_switch);\n 572:\t\tWARN_ON(ops-\u003eadd_tx_ts \u0026\u0026 !ops-\u003edel_tx_ts);\n 573:\t\n 574:\t\talloc_size = sizeof(*rdev) + sizeof_priv;\n 575:\t\n 576:\t\trdev = kzalloc(alloc_size, GFP_KERNEL);\n 577:\t\tif (!rdev)\n 578:\t\t\treturn NULL;\n"
} |
| 105/3 | 2026/08/24 23:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 83016 output: 537 thoughts: 2959 Thoughts: **Uninitialized Memory Analysis - No KMSAN Issues Found**
Okay, let's break this down systematically. My initial thought was about `rdev` allocation – `kzalloc` is used, so that's good. `wiphy` and its private data, including `mt792x_dev`, are zero-initialized. This means `dev->nan_started_cluster_id` is guaranteed to start at zero. Even if it's copied and *not* used in specific scenarios (when `MT7925_NAN_DEFERRED_STARTED_CLUSTER` isn't set), it's still zero. Therefore, we're safe from any uninitialized read or potential information leak stemming from there. I quickly scan the patch for other possible issues.
Let's investigate the patch to see if I can find an issue. I checked the use of `req = {}` in `mt7925_nan_update_phy_setting`, which I confirmed zero-initializes the entire struct. I reviewed `mt7925_nan_enable`, and that's solid too because `hdr` is zeroed out via `memset`, and `req` is zero-initialized by `skb_put_zero` within the `mt76_connac_mcu_add_tlv` function. The `nan_cmd` struct in `mt7925_nan_disable` is also fine, being either fully or partially initialized with the remaining fields zero-initialized by the compiler. I removed the function `mt7925_nan_set_nmi_addr`, so that's not a concern. Zero-initialization via `mt76_connac_mcu_add_tlv` handles `mt7925_nan_update_crb_tlv`, `mt7925_nan_peer_ulw_tlv`, and other similar TLVs. `mt792x_nan_map_sta_rec` simply sets a member of an existing, allocated TLV.
The analysis is really about looking for *unassigned* memory. The use of `struct mt7925_nan_ulw_attr attr` in `mt7925_nan_handle_ulw_update` caught my eye, but I see that all the fields of `attr` are explicitly assigned, and no padding exists because of `__packed`. Also, this data is then passed to `cfg80211_nan_ulw_update`, which is a user-space interface. This means there's no way to leak uninitialized data. Double-checked the size and member count, and it's all good.
I go back and double-check, and I'm confident there are no other risky areas. `mt7925_nan_deferred_work` uses a copy of `dev->nan_started_cluster_id`, which is part of the `mt792x_dev` struct. But I checked if it's used correctly, zeroed or correctly set, depending on whether `MT7925_NAN_DEFERRED_STARTED_CLUSTER` is set or not, and I'm fine with it. It's either zero from `kzalloc`, or populated from an event. I checked `mt7925_nan_update_phy_setting` again, where the `req` struct is correctly zeroed. For `mt7925_nan_enable` I verified that it correctly zero-initializes several variables. In `mt7925_nan_peer_ulw_tlv`, `ulw_tlv` is zero-initialized by the `mt76_connac_mcu_add_tlv` and then data is copied into the TLV payload. I did the same check for `mt792x_nan_set_peer_rec`, where `crb_tlv` is initialized via `mt76_connac_mcu_add_tlv`.
In conclusion, I am certain there are no uninitialized memory access issues. All structures are either explicitly zero-initialized using a variety of techniques (e.g., `{}` for structs, `memset`, `skb_put_zero`, `kzalloc`), or have every field assigned before use. The patch is sound from a KMSAN perspective. Standard KASAN, LOCKDEP, and other bug detectors should be sufficient. I'll mark `NeedsKMSAN` as false and detail this detailed reasoning.
|
| 106/3 | 2026/08/24 23:05 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch modifies the mt7925 driver to add new features and fixes related to NAN (Neighbor Awareness Networking). It introduces new structures sent to the firmware (e.g., `mt7925_nan_update_phy_setting_tlv`, `mt7925_nan_update_ulw_tlv`, `mt7925_nan_sched_update_crb_tlv`) and one structure sent to user space (`mt7925_nan_ulw_attr` via `cfg80211_nan_ulw_update`). \n\nAll structures sent to the firmware are either explicitly zero-initialized (e.g., `req = {}` in `mt7925_nan_update_phy_setting`) or allocated using `mt76_connac_mcu_add_tlv`, which internally uses `skb_put_zero` to fully zero-initialize the TLV payload before specific fields are assigned. \n\nThe structure sent to user space (`mt7925_nan_ulw_attr`) is a `__packed` struct allocated on the stack in `mt7925_nan_handle_ulw_update`. All 9 of its fields are explicitly assigned before it is passed to `cfg80211_nan_ulw_update`, ensuring no uninitialized stack memory or padding bytes are leaked to user space.\n\nThe deferred work mechanism (`mt7925_nan_deferred_work`) uses `cluster_id` copied from `dev-\u003enan_started_cluster_id`. The `dev` structure is allocated with `kzalloc` (via `ieee80211_alloc_hw`), so `nan_started_cluster_id` is zero-initialized. It is only used if the `MT7925_NAN_DEFERRED_STARTED_CLUSTER` bit is set, which only happens after it has been populated with data from the firmware.\n\nSince all stack and heap structures introduced or modified by this patch are fully initialized or zeroed before being read, copied, or sent to user space/firmware, there is no risk of uninitialized memory usage or info-leaks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or memory corruption bugs. A dedicated KMSAN fuzzing session is not justified.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch modifies the mt7925 driver to add new features and fixes related to NAN (Neighbor Awareness Networking). It introduces new structures sent to the firmware (e.g., `mt7925_nan_update_phy_setting_tlv`, `mt7925_nan_update_ulw_tlv`, `mt7925_nan_sched_update_crb_tlv`) and one structure sent to user space (`mt7925_nan_ulw_attr` via `cfg80211_nan_ulw_update`). \n\nAll structures sent to the firmware are either explicitly zero-initialized (e.g., `req = {}` in `mt7925_nan_update_phy_setting`) or allocated using `mt76_connac_mcu_add_tlv`, which internally uses `skb_put_zero` to fully zero-initialize the TLV payload before specific fields are assigned. \n\nThe structure sent to user space (`mt7925_nan_ulw_attr`) is a `__packed` struct allocated on the stack in `mt7925_nan_handle_ulw_update`. All 9 of its fields are explicitly assigned before it is passed to `cfg80211_nan_ulw_update`, ensuring no uninitialized stack memory or padding bytes are leaked to user space.\n\nThe deferred work mechanism (`mt7925_nan_deferred_work`) uses `cluster_id` copied from `dev-\u003enan_started_cluster_id`. The `dev` structure is allocated with `kzalloc` (via `ieee80211_alloc_hw`), so `nan_started_cluster_id` is zero-initialized. It is only used if the `MT7925_NAN_DEFERRED_STARTED_CLUSTER` bit is set, which only happens after it has been populated with data from the firmware.\n\nSince all stack and heap structures introduced or modified by this patch are fully initialized or zeroed before being read, copied, or sent to user space/firmware, there is no risk of uninitialized memory usage or info-leaks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or memory corruption bugs. A dedicated KMSAN fuzzing session is not justified.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|