AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/01 06:17 flow patch-triage
8m Args:
null

Results:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB",
    "BRCMFMAC_PCIE",
    "CFG80211"
  ],
  "FocusSymbols": [
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa",
    "brcmf_netif_mon_rx"
  ],
  "Reasoning": "The patch adds support for V2 PMKSA cache operations in the brcmfmac driver, which is reachable via cfg80211 netlink commands when a Broadcom Wi-Fi device is present. Syzkaller can emulate such a device via its USB fuzzer, making this new logic reachable and testable. The patch also modifies radiotap header insertion in monitor mode and PCIe mailbox polling, which are functional changes.",
  "WorthFuzzing": true
}

1/1 2026/08/01 06:17 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 0fe167e456da1caf928269929533195a3fca312d\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Aug 1 06:17:53 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c\nindex 0b55d445895f2..7d7e5ececd229 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c\n@@ -3989,12 +3989,10 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,\n \n static __always_inline void brcmf_delay(u32 ms)\n {\n-\tif (ms \u003c 1000 / HZ) {\n-\t\tcond_resched();\n-\t\tmdelay(ms);\n-\t} else {\n+\tif (ms \u003c= 20)\n+\t\tusleep_range(ms * 1000, ms * 1000 + 1000);\n+\telse\n \t\tmsleep(ms);\n-\t}\n }\n \n static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],\n@@ -4364,6 +4362,104 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa,\n \treturn ret;\n }\n \n+/**\n+ * brcmf_pmksa_v2_op - update firmware PMKSA cache using the V2 list interface.\n+ *\n+ * V2 firmware (revision 12) uses a versioned flat list structure\n+ * (brcmf_pmk_list_v2_le) rather than the per-entry operation model of V3.\n+ * Each entry carries FILS-specific fields (raw PMK material, SSID, and\n+ * fils_cache_id) in addition to the basic BSSID + PMKID pair, enabling\n+ * FILS fast-roaming on devices that do not support V3.\n+ *\n+ * @cfg:   driver config structure holding the shadow V2 PMKSA list\n+ * @ifp:   interface pointer\n+ * @pmksa: the PMKSA to add/remove, or NULL for a flush\n+ * @alive: true = add (set time_left to no-expiry), false = remove/flush\n+ */\n+static s32\n+brcmf_pmksa_v2_op(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,\n+\t\t  struct cfg80211_pmksa *pmksa, bool alive)\n+{\n+\tstruct brcmf_pub *drvr = cfg-\u003epub;\n+\tstruct brcmf_pmk_list_v2_le *list = \u0026cfg-\u003epmk_list_v2;\n+\tstruct brcmf_pmksa_v2 *pmk = list-\u003epmk;\n+\tu32 npmk = le16_to_cpu(list-\u003elength);\n+\tu32 i;\n+\n+\t/* npmk here stores the count of valid entries, repurposing the\n+\t * length field of the shadow list as a counter.  We convert to\n+\t * the wire format (byte length) when sending to firmware.\n+\t */\n+\tif (!pmksa) {\n+\t\t/* Flush: zero the shadow list and push an empty V2 list. */\n+\t\tmemset(list, 0, sizeof(*list));\n+\t\tgoto send;\n+\t}\n+\n+\tif (alive) {\n+\t\t/* Set: search for existing BSSID match first. */\n+\t\tfor (i = 0; i \u003c npmk; i++)\n+\t\t\tif (!memcmp(pmksa-\u003ebssid, pmk[i].bssid, ETH_ALEN))\n+\t\t\t\tbreak;\n+\n+\t\tif (i \u003e= BRCMF_MAXPMKID) {\n+\t\t\tbphy_err(drvr, \"V2 PMKSA cache full (%d entries)\\n\",\n+\t\t\t\t npmk);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tmemset(\u0026pmk[i], 0, sizeof(pmk[i]));\n+\t\tpmk[i].length = cpu_to_le16(sizeof(struct brcmf_pmksa_v2));\n+\t\tif (pmksa-\u003ebssid)\n+\t\t\tmemcpy(pmk[i].bssid, pmksa-\u003ebssid, ETH_ALEN);\n+\t\tif (pmksa-\u003epmkid)\n+\t\t\tmemcpy(pmk[i].pmkid, pmksa-\u003epmkid, WLAN_PMKID_LEN);\n+\t\tif (pmksa-\u003epmk \u0026\u0026 pmksa-\u003epmk_len \u0026\u0026\n+\t\t    pmksa-\u003epmk_len \u003c= WLAN_PMK_LEN_SUITE_B_192) {\n+\t\t\tmemcpy(pmk[i].pmk, pmksa-\u003epmk, pmksa-\u003epmk_len);\n+\t\t\tpmk[i].pmk_len = cpu_to_le16(pmksa-\u003epmk_len);\n+\t\t}\n+\t\tif (pmksa-\u003essid \u0026\u0026 pmksa-\u003essid_len) {\n+\t\t\tmemcpy(pmk[i].ssid.SSID, pmksa-\u003essid, pmksa-\u003essid_len);\n+\t\t\tpmk[i].ssid.SSID_len = pmksa-\u003essid_len;\n+\t\t}\n+\t\tif (pmksa-\u003efils_cache_id)\n+\t\t\tpmk[i].fils_cache_id = *pmksa-\u003efils_cache_id;\n+\n+\t\tif (i == npmk)\n+\t\t\tnpmk++;\n+\t} else {\n+\t\t/* Delete: find by BSSID and compact the list. */\n+\t\tfor (i = 0; i \u003c npmk; i++)\n+\t\t\tif (!memcmp(pmksa-\u003ebssid, pmk[i].bssid, ETH_ALEN))\n+\t\t\t\tbreak;\n+\n+\t\tif (i \u003e= npmk) {\n+\t\t\tbphy_err(drvr, \"V2 PMKSA entry not found\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tfor (; i \u003c npmk - 1; i++)\n+\t\t\tmemcpy(\u0026pmk[i], \u0026pmk[i + 1], sizeof(pmk[i]));\n+\t\tmemset(\u0026pmk[npmk - 1], 0, sizeof(pmk[npmk - 1]));\n+\t\tnpmk--;\n+\t}\n+\n+\t/* Update shadow entry count (stored in length field). */\n+\tlist-\u003elength = cpu_to_le16(npmk);\n+\n+send:\n+\t/* Build the wire-format header and send the full list to firmware.\n+\t * version and length on the wire reflect the actual byte footprint.\n+\t */\n+\tlist-\u003eversion = cpu_to_le16(BRCMF_PMKSA_VER_2);\n+\tlist-\u003elength  = cpu_to_le16(offsetof(struct brcmf_pmk_list_v2_le, pmk) +\n+\t\t\t\t   npmk * sizeof(struct brcmf_pmksa_v2));\n+\n+\treturn brcmf_fil_iovar_data_set(ifp, \"pmkid_info\", list, sizeof(*list));\n+}\n+\n+\n static __used s32\n brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)\n {\n@@ -4402,8 +4498,8 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,\n \n \tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))\n \t\treturn brcmf_pmksa_v3_op(ifp, pmksa, true);\n-\n-\t/* TODO: implement PMKID_V2 */\n+\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\n+\t\treturn brcmf_pmksa_v2_op(cfg, ifp, pmksa, true);\n \n \tnpmk = le32_to_cpu(cfg-\u003epmk_list.npmk);\n \tfor (i = 0; i \u003c npmk; i++)\n@@ -4446,8 +4542,8 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,\n \n \tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))\n \t\treturn brcmf_pmksa_v3_op(ifp, pmksa, false);\n-\n-\t/* TODO: implement PMKID_V2 */\n+\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\n+\t\treturn brcmf_pmksa_v2_op(cfg, ifp, pmksa, false);\n \n \tnpmk = le32_to_cpu(cfg-\u003epmk_list.npmk);\n \tfor (i = 0; i \u003c npmk; i++)\n@@ -4487,8 +4583,8 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)\n \n \tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))\n \t\treturn brcmf_pmksa_v3_op(ifp, NULL, false);\n-\n-\t/* TODO: implement PMKID_V2 */\n+\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\n+\t\treturn brcmf_pmksa_v2_op(cfg, ifp, NULL, false);\n \n \tmemset(\u0026cfg-\u003epmk_list, 0, sizeof(cfg-\u003epmk_list));\n \terr = brcmf_update_pmklist(cfg, ifp);\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h\nindex 6ceb301429054..57167fde5ba15 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h\n@@ -344,7 +344,8 @@ struct brcmf_cfg80211_wowl {\n  * @bss_list: bss_list holding scanned ap information.\n  * @bss_info: bss information for cfg80211 layer.\n  * @conn_info: association info.\n- * @pmk_list: wpa2 pmk list.\n+ * @pmk_list: wpa2 pmk list (V1 firmware).\n+ * @pmk_list_v2: wpa2 pmk list for V2 firmware (FILS-capable, firmware rev 12).\n  * @scan_status: scan activity on the dongle.\n  * @pub: common driver information.\n  * @channel: current channel.\n@@ -376,6 +377,7 @@ struct brcmf_cfg80211_info {\n \tstruct wl_cfg80211_bss_info *bss_info;\n \tstruct brcmf_cfg80211_connect_info conn_info;\n \tstruct brcmf_pmk_list_le pmk_list;\n+\tstruct brcmf_pmk_list_v2_le pmk_list_v2;\n \tunsigned long scan_status;\n \tstruct brcmf_pub *pub;\n \tu32 channel;\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c\nindex ec170647800da..673f0000389cc 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c\n@@ -431,45 +431,51 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)\n \tnetif_rx(skb);\n }\n \n+struct brcmf_radiotap_info {\n+\tstruct ieee80211_radiotap_header hdr;\n+\ts8 dbm_antsignal;\n+} __packed;\n+\n void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)\n {\n \tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_RADIOTAP)) {\n-\t\t/* Do nothing */\n+\t\t/* Firmware already provided a full radiotap header; do nothing */\n \t} else if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR)) {\n \t\tstruct wlc_d11rxhdr *wlc_rxhdr = (struct wlc_d11rxhdr *)skb-\u003edata;\n-\t\tstruct ieee80211_radiotap_header *radiotap;\n+\t\tstruct brcmf_radiotap_info *rtap;\n \t\tunsigned int offset;\n \t\tu16 RxStatus1;\n+\t\ts8 rssi;\n \n \t\tRxStatus1 = le16_to_cpu(wlc_rxhdr-\u003erxhdr.RxStatus1);\n+\t\trssi = wlc_rxhdr-\u003erssi;\n \n \t\toffset = sizeof(struct wlc_d11rxhdr);\n-\t\t/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU\n-\t\t * subframes\n-\t\t */\n+\t\t/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */\n \t\tif (RxStatus1 \u0026 RXS_PBPRES)\n \t\t\toffset += 2;\n \t\toffset += D11_PHY_HDR_LEN;\n \n \t\tskb_pull(skb, offset);\n \n-\t\t/* TODO: use RX header to fill some radiotap data */\n-\t\tradiotap = skb_push(skb, sizeof(*radiotap));\n-\t\tmemset(radiotap, 0, sizeof(*radiotap));\n-\t\tradiotap-\u003eit_len = cpu_to_le16(sizeof(*radiotap));\n+\t\t/* Insert our radiotap header with RSSI data */\n+\t\trtap = skb_push(skb, sizeof(*rtap));\n+\t\tmemset(rtap, 0, sizeof(*rtap));\n+\t\trtap-\u003ehdr.it_len = cpu_to_le16(sizeof(*rtap));\n+\t\trtap-\u003ehdr.it_present = cpu_to_le32(1 \u003c\u003c IEEE80211_RADIOTAP_DBM_ANTSIGNAL);\n+\t\trtap-\u003edbm_antsignal = rssi;\n \n-\t\t/* TODO: 4 bytes with receive status? */\n-\t\tskb-\u003elen -= 4;\n+\t\t/* Strip the 4-byte receive status / FCS tail */\n+\t\tskb_trim(skb, skb-\u003elen - 4);\n \t} else {\n \t\tstruct ieee80211_radiotap_header *radiotap;\n \n-\t\t/* TODO: use RX status to fill some radiotap data */\n \t\tradiotap = skb_push(skb, sizeof(*radiotap));\n \t\tmemset(radiotap, 0, sizeof(*radiotap));\n \t\tradiotap-\u003eit_len = cpu_to_le16(sizeof(*radiotap));\n \n-\t\t/* TODO: 4 bytes with receive status? */\n-\t\tskb-\u003elen -= 4;\n+\t\t/* Strip the 4-byte receive status / FCS tail */\n+\t\tskb_trim(skb, skb-\u003elen - 4);\n \t}\n \n \tskb-\u003edev = ifp-\u003endev;\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c\nindex 35cbcea0abc9a..b9c518939f504 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c\n@@ -182,10 +182,8 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,\n \tstruct brcmf_bus *bus_if;\n \tstruct brcmf_pub *drvr;\n \tstruct brcmf_if *ifp;\n-\tbool currently_blocked;\n-\tint i;\n-\tu8 ifidx;\n \tunsigned long flags;\n+\tu8 ifidx;\n \n \tspin_lock_irqsave(\u0026flow-\u003eblock_lock, flags);\n \n@@ -194,23 +192,54 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,\n \t\tspin_unlock_irqrestore(\u0026flow-\u003eblock_lock, flags);\n \t\treturn;\n \t}\n-\tifidx = brcmf_flowring_ifidx_get(flow, flowid);\n \n-\tcurrently_blocked = false;\n-\tfor (i = 0; i \u003c flow-\u003enrofrings; i++) {\n-\t\tif ((flow-\u003erings[i]) \u0026\u0026 (i != flowid)) {\n-\t\t\tring = flow-\u003erings[i];\n-\t\t\tif ((ring-\u003estatus == RING_OPEN) \u0026\u0026\n-\t\t\t    (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {\n-\t\t\t\tif (ring-\u003eblocked) {\n-\t\t\t\t\tcurrently_blocked = true;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n+\tifidx = brcmf_flowring_ifidx_get(flow, flowid);\n+\tring-\u003eblocked = blocked;\n+\n+\t/*\n+\t * Maintain the per-interface blocked-ring counter.\n+\t *\n+\t * We use ring-\u003ecounted_in_blocked rather than checking\n+\t * ring-\u003estatus here.  A ring that became blocked while\n+\t * RING_OPEN has already been counted (counted_in_blocked=true).\n+\t * By the time we unblock it during teardown its status may have\n+\t * advanced to RING_CLOSING, so testing RING_OPEN would wrongly\n+\t * skip the atomic_dec and permanently leak the counter, leaving\n+\t * the netif queue stopped forever.\n+\t *\n+\t * Rule:\n+\t *   block transition  (unblocked→blocked): count only if RING_OPEN,\n+\t *                                          set counted_in_blocked.\n+\t *   unblock transition (blocked→unblocked): decrement only if we\n+\t *                                          previously counted it,\n+\t *                                          clear counted_in_blocked.\n+\t */\n+\tif (blocked) {\n+\t\tif (ring-\u003estatus == RING_OPEN) {\n+\t\t\tatomic_inc(\u0026flow-\u003eif_blocked_cnt[ifidx]);\n+\t\t\tring-\u003ecounted_in_blocked = true;\n \t\t}\n+\t} else {\n+\t\tif (ring-\u003ecounted_in_blocked) {\n+\t\t\tatomic_dec(\u0026flow-\u003eif_blocked_cnt[ifidx]);\n+\t\t\tring-\u003ecounted_in_blocked = false;\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * Only propagate a netif queue-stop/wake when the interface\n+\t * transitions between fully-clear and at-least-one-blocked.\n+\t * Reading the atomic is safe here: we hold block_lock, so no\n+\t * concurrent brcmf_flowring_block() call can race the update\n+\t * we just made above.\n+\t */\n+\tif (blocked \u0026\u0026 atomic_read(\u0026flow-\u003eif_blocked_cnt[ifidx]) != 1) {\n+\t\t/* Another ring was already blocked; no new queue-stop needed. */\n+\t\tspin_unlock_irqrestore(\u0026flow-\u003eblock_lock, flags);\n+\t\treturn;\n \t}\n-\tflow-\u003erings[flowid]-\u003eblocked = blocked;\n-\tif (currently_blocked) {\n+\tif (!blocked \u0026\u0026 atomic_read(\u0026flow-\u003eif_blocked_cnt[ifidx]) != 0) {\n+\t\t/* More rings still blocked; do not wake the queue yet. */\n \t\tspin_unlock_irqrestore(\u0026flow-\u003eblock_lock, flags);\n \t\treturn;\n \t}\n@@ -367,6 +396,8 @@ struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)\n \t\tspin_lock_init(\u0026flow-\u003eblock_lock);\n \t\tfor (i = 0; i \u003c ARRAY_SIZE(flow-\u003eaddr_mode); i++)\n \t\t\tflow-\u003eaddr_mode[i] = ADDR_INDIRECT;\n+\t\tfor (i = 0; i \u003c ARRAY_SIZE(flow-\u003eif_blocked_cnt); i++)\n+\t\t\tatomic_set(\u0026flow-\u003eif_blocked_cnt[i], 0);\n \t\tfor (i = 0; i \u003c ARRAY_SIZE(flow-\u003ehash); i++)\n \t\t\tflow-\u003ehash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;\n \t}\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h\nindex f3d511f9a3c9a..afdea8b3f8aa7 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h\n@@ -5,6 +5,8 @@\n #ifndef BRCMFMAC_FLOWRING_H\n #define BRCMFMAC_FLOWRING_H\n \n+#include \u003clinux/atomic.h\u003e\n+\n \n #define BRCMF_FLOWRING_HASHSIZE\t\t512\t\t/* has to be 2^x */\n #define BRCMF_FLOWRING_INVALID_ID\t0xFFFFFFFF\n@@ -26,6 +28,16 @@ enum ring_status {\n struct brcmf_flowring_ring {\n \tu16 hash_id;\n \tbool blocked;\n+\t/*\n+\t * True when this ring has been counted in the per-interface\n+\t * if_blocked_cnt[].  Set to true whenever the ring transitions\n+\t * unblocked→blocked while RING_OPEN; cleared on the matching\n+\t * blocked→unblocked transition.  Needed so that a ring that\n+\t * becomes blocked while RING_OPEN and is later moved to\n+\t * RING_CLOSING still correctly decrements the counter at\n+\t * teardown, even though its status is no longer RING_OPEN.\n+\t */\n+\tbool counted_in_blocked;\n \tenum ring_status status;\n \tstruct sk_buff_head skblist;\n };\n@@ -40,6 +52,12 @@ struct brcmf_flowring {\n \tstruct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];\n \tspinlock_t block_lock;\n \tenum proto_addr_mode addr_mode[BRCMF_MAX_IFS];\n+\t/* Per-interface count of currently blocked open rings.\n+\t * Maintained atomically so brcmf_flowring_block() can check\n+\t * whether any sibling ring is already blocked in O(1) without\n+\t * holding block_lock across an O(nrofrings) walk.\n+\t */\n+\tatomic_t if_blocked_cnt[BRCMF_MAX_IFS];\n \tu16 nrofrings;\n \tbool tdls_active;\n \tstruct brcmf_flowring_tdls_entry *tdls_entry;\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c\nindex a43f1a38b0e30..3c1ca355e8eec 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c\n@@ -1037,7 +1037,9 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)\n \t\t} else {\n \t\t\tbrcmf_dbg(TRACE, \"use existing\\n\");\n \t\t\tWARN_ON(entry-\u003emac_handle != mac_handle);\n-\t\t\t/* TODO: what should we do here: continue, reinit, .. */\n+\t\t\t/* Firmware re-sent ADD for the same MAC handle.\n+\t\t\t * No action required; it is a safe no-op.\n+\t\t\t */\n \t\t}\n \t}\n \treturn 0;\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c\nindex ba1ce1552e0f4..8db6167072da3 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c\n@@ -48,7 +48,19 @@\n #define MSGBUF_TYPE_LPBK_DMAXFER\t\t0x13\n #define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT\t\t0x14\n \n-#define NR_TX_PKTIDS\t\t\t\t2048\n+/*\n+ * NR_TX_PKTIDS: number of simultaneously in-flight TX packet IDs.\n+ * Each outstanding TX frame consumes one ID until the dongle returns\n+ * a TX-status completion.  The original 2048-entry pool exhausted under\n+ * ≥4 concurrent iperf3 streams on Wi-Fi 5/6 (802.11ac/ax) devices,\n+ * causing \"No PKTID available\" drops and TCP retransmits.  4096 gives\n+ * headroom for high-aggregation scenarios while still fitting in a\n+ * modest amount of host memory (~48 KB for the pktid table entries).\n+ *\n+ * NR_RX_PKTIDS: RX post buffers pre-allocated to the dongle.  1024 is\n+ * sufficient for current hardware RX ring depths; leave unchanged.\n+ */\n+#define NR_TX_PKTIDS\t\t\t\t4096\n #define NR_RX_PKTIDS\t\t\t\t1024\n \n #define BRCMF_IOCTL_REQ_PKTID\t\t\t0xFFFE\n@@ -64,8 +76,29 @@\n #define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK\t0x07\n #define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT\t5\n \n-#define BRCMF_MSGBUF_TX_FLUSH_CNT1\t\t32\n-#define BRCMF_MSGBUF_TX_FLUSH_CNT2\t\t96\n+/*\n+ * TX flush / doorbell-ring thresholds.\n+ *\n+ * CNT1 is the minimum number of frames to accumulate in the commonring\n+ * before the first intermediate write_complete() (doorbell ring) is\n+ * issued mid-batch.  CNT2 is the hard flush interval: after this many\n+ * frames have been written since the last flush, we unconditionally\n+ * ring the bell and reset the counter.\n+ *\n+ * Raising both from the original 32/96 to 64/128 doubles the average\n+ * number of TX descriptors committed per MMIO write, halving the PCIe\n+ * doorbell rate on sustained throughput workloads.  The tradeoff is a\n+ * marginally higher worst-case latency for the last frames in a burst,\n+ * which in practice is hidden by the time the dongle DMA engine drains\n+ * the previous batch.\n+ *\n+ * TRICKLE_TXWORKER_THRS governs how often brcmf_msgbuf_tx_queue_data()\n+ * forces a workqueue schedule when the queue depth is not a multiple of\n+ * this value.  Keeping it at half of CNT1 (32) preserves responsiveness\n+ * for low-rate flows (e.g. VoIP, ICMP) that never accumulate 64 frames.\n+ */\n+#define BRCMF_MSGBUF_TX_FLUSH_CNT1\t\t64\n+#define BRCMF_MSGBUF_TX_FLUSH_CNT2\t\t128\n \n #define BRCMF_MSGBUF_DELAY_TXWORKER_THRS\t96\n #define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS\t32\n@@ -787,10 +820,30 @@ static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,\n {\n \tstruct brcmf_commonring *commonring;\n \n-\tset_bit(flowid, msgbuf-\u003eflow_map);\n+\t/*\n+\t * If the bit was already set, a txflow_work item is already\n+\t * queued or running for this ring.  In that case the existing\n+\t * worker will drain our freshly enqueued frame when it runs,\n+\t * so we only need to schedule another work item when the\n+\t * force flag is set or the ring is below the delay threshold.\n+\t *\n+\t * If the bit was NOT set (test_and_set_bit returns false), no\n+\t * worker is pending for this ring at all.  We MUST schedule\n+\t * one unconditionally, otherwise the frame we just enqueued\n+\t * will sit in the flowring unsent until some unrelated event\n+\t * triggers the workqueue — causing silent TX stalls under\n+\t * high load when outstanding_tx \u003e= DELAY_TXWORKER_THRS.\n+\t */\n+\tif (!test_and_set_bit(flowid, msgbuf-\u003eflow_map)) {\n+\t\t/* Bit was clear: no worker pending, always schedule. */\n+\t\tqueue_work(msgbuf-\u003etxflow_wq, \u0026msgbuf-\u003etxflow_work);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Bit was already set: worker pending, apply coalescing heuristic. */\n \tcommonring = msgbuf-\u003eflowrings[flowid];\n-\tif ((force) || (atomic_read(\u0026commonring-\u003eoutstanding_tx) \u003c\n-\t\t\tBRCMF_MSGBUF_DELAY_TXWORKER_THRS))\n+\tif (force || (atomic_read(\u0026commonring-\u003eoutstanding_tx) \u003c\n+\t\t      BRCMF_MSGBUF_DELAY_TXWORKER_THRS))\n \t\tqueue_work(msgbuf-\u003etxflow_wq, \u0026msgbuf-\u003etxflow_work);\n \n \treturn 0;\n@@ -1621,11 +1674,11 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)\n \tdo {\n \t\tbrcmf_msgbuf_rxbuf_data_fill(msgbuf);\n \t\tif (msgbuf-\u003emax_rxbufpost != msgbuf-\u003erxbufpost)\n-\t\t\tmsleep(10);\n+\t\t\tusleep_range(1000, 2000);\n \t\telse\n \t\t\tbreak;\n \t\tcount++;\n-\t} while (count \u003c 10);\n+\t} while (count \u003c 100);\n \tbrcmf_msgbuf_rxbuf_event_post(msgbuf);\n \tbrcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);\n \ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c\nindex 13662aa4b4ea6..9338a5faa260a 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c\n@@ -268,6 +268,27 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {\n \n #define BRCMF_PCIE_MBDATA_TIMEOUT\t\tmsecs_to_jiffies(2000)\n \n+/*\n+ * H2D mailbox poll timing parameters.\n+ *\n+ * The dongle typically clears the H2D mailbox register within a few\n+ * hundred microseconds after the doorbell interrupt fires.  The\n+ * original code used msleep(10) * 100 iterations, meaning the\n+ * minimum observable latency was 10ms even when the dongle was fast.\n+ *\n+ * We instead start with a short sleep and double it each iteration\n+ * (exponential backoff) up to BRCMF_PCIE_MB_POLL_MAX_US, staying\n+ * within the same 1-second absolute timeout.\n+ *\n+ * MIN_US / INITIAL_MAX_US : usleep_range bounds for the first iteration.\n+ * MAX_US     : cap on the per-iteration sleep (µs).\n+ * TIMEOUT_US : total budget before giving up (1 second).\n+ */\n+#define BRCMF_PCIE_MB_POLL_MIN_US\t\t40\n+#define BRCMF_PCIE_MB_POLL_INITIAL_MAX_US\t50\n+#define BRCMF_PCIE_MB_POLL_MAX_US\t\t5000\n+#define BRCMF_PCIE_MB_POLL_TIMEOUT_US\t\t1000000\n+\n #define BRCMF_PCIE_CFGREG_STATUS_CMD\t\t0x4\n #define BRCMF_PCIE_CFGREG_PM_CSR\t\t0x4C\n #define BRCMF_PCIE_CFGREG_MSI_CAP\t\t0x58\n@@ -766,7 +787,8 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)\n \tstruct brcmf_core *core;\n \tu32 addr;\n \tu32 cur_htod_mb_data;\n-\tu32 i;\n+\tu32 elapsed_us = 0;\n+\tu32 sleep_us = BRCMF_PCIE_MB_POLL_INITIAL_MAX_US;\n \n \tshared = \u0026devinfo-\u003eshared;\n \taddr = shared-\u003ehtod_mb_data_addr;\n@@ -776,12 +798,40 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)\n \t\tbrcmf_dbg(PCIE, \"MB transaction is already pending 0x%04x\\n\",\n \t\t\t  cur_htod_mb_data);\n \n-\ti = 0;\n+\t/*\n+\t * Wait for the dongle to consume the previous H2D mailbox message.\n+\t *\n+\t * There is no interrupt that signals when the dongle clears this\n+\t * register, so polling is unavoidable.  The original code used\n+\t * msleep(10) per iteration, incurring at least 10ms of latency\n+\t * even when the dongle responded in microseconds.\n+\t *\n+\t * We use usleep_range() with exponential backoff instead:\n+\t *   - First iteration sleeps ~50µs (fast path for responsive dongle).\n+\t *   - Each subsequent iteration doubles the sleep, capped at 5ms,\n+\t *     so long waits still yield the CPU without busy-spinning.\n+\t *   - Total timeout matches the original 1-second limit.\n+\t *   - We bail early if the device has gone down so that a dead\n+\t *     dongle does not hold the caller for a full second.\n+\t */\n \twhile (cur_htod_mb_data != 0) {\n-\t\tmsleep(10);\n-\t\ti++;\n-\t\tif (i \u003e 100)\n+\t\tif (devinfo-\u003estate == BRCMFMAC_PCIE_STATE_DOWN) {\n+\t\t\tbrcmf_dbg(PCIE, \"Device down, aborting MB send\\n\");\n \t\t\treturn -EIO;\n+\t\t}\n+\n+\t\tif (elapsed_us \u003e= BRCMF_PCIE_MB_POLL_TIMEOUT_US) {\n+\t\t\tbrcmf_err(\"Timeout waiting for H2D MB slot after %u us\\n\",\n+\t\t\t\t  elapsed_us);\n+\t\t\treturn -EIO;\n+\t\t}\n+\n+\t\tusleep_range(BRCMF_PCIE_MB_POLL_MIN_US, sleep_us);\n+\t\telapsed_us += sleep_us;\n+\n+\t\t/* Exponential backoff, capped at BRCMF_PCIE_MB_POLL_MAX_US */\n+\t\tsleep_us = min(sleep_us * 2, (u32)BRCMF_PCIE_MB_POLL_MAX_US);\n+\n \t\tcur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);\n \t}\n \n@@ -1001,10 +1051,10 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)\n \tfree_irq(pdev-\u003eirq, devinfo);\n \tpci_disable_msi(pdev);\n \n-\tmsleep(50);\n+\tusleep_range(1000, 2000);\n \tcount = 0;\n-\twhile ((devinfo-\u003ein_irq) \u0026\u0026 (count \u003c 20)) {\n-\t\tmsleep(50);\n+\twhile ((devinfo-\u003ein_irq) \u0026\u0026 (count \u003c 1000)) {\n+\t\tusleep_range(1000, 2000);\n \t\tcount++;\n \t}\n \tif (devinfo-\u003ein_irq)\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c\nindex b725c64e5b5c6..4e414403d7471 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c\n@@ -1645,37 +1645,43 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)\n \n \t\trd_new.seq_num = rxseq;\n \t\trd_new.len = dlen;\n+\n+\t\t/*\n+\t\t * Claim the host once for the entire header-parsing phase.\n+\t\t *\n+\t\t * brcmf_sdio_hdparse() operates on data already in host\n+\t\t * memory, but may call brcmf_sdio_rxfail() on error, which\n+\t\t * writes SDIO Func1 registers and therefore requires the\n+\t\t * host to be claimed.\n+\t\t *\n+\t\t * skb_pull() and the num counter are pure host-memory\n+\t\t * operations; keep them outside the lock to minimise the\n+\t\t * hold time.  Both hdparse calls (superframe header and\n+\t\t * each subframe header) are grouped under a single claim/\n+\t\t * release, replacing the original N+1 separate pairs.\n+\t\t */\n \t\tsdio_claim_host(bus-\u003esdiodev-\u003efunc1);\n \t\terrcode = brcmf_sdio_hdparse(bus, pfirst-\u003edata, \u0026rd_new,\n \t\t\t\t\t     BRCMF_SDIO_FT_SUPER);\n-\t\tsdio_release_host(bus-\u003esdiodev-\u003efunc1);\n-\t\tbus-\u003ecur_read.len = rd_new.len_nxtfrm \u003c\u003c 4;\n-\n-\t\t/* Remove superframe header, remember offset */\n-\t\tskb_pull(pfirst, rd_new.dat_offset);\n-\t\tnum = 0;\n-\n-\t\t/* Validate all the subframe headers */\n-\t\tskb_queue_walk(\u0026bus-\u003eglom, pnext) {\n-\t\t\t/* leave when invalid subframe is found */\n-\t\t\tif (errcode)\n-\t\t\t\tbreak;\n \n-\t\t\trd_new.len = pnext-\u003elen;\n-\t\t\trd_new.seq_num = rxseq++;\n-\t\t\tsdio_claim_host(bus-\u003esdiodev-\u003efunc1);\n-\t\t\terrcode = brcmf_sdio_hdparse(bus, pnext-\u003edata, \u0026rd_new,\n-\t\t\t\t\t\t     BRCMF_SDIO_FT_SUB);\n-\t\t\tsdio_release_host(bus-\u003esdiodev-\u003efunc1);\n-\t\t\tbrcmf_dbg_hex_dump(BRCMF_GLOM_ON(),\n-\t\t\t\t\t   pnext-\u003edata, 32, \"subframe:\\n\");\n-\n-\t\t\tnum++;\n+\t\t/* Validate all the subframe headers while host is claimed */\n+\t\tif (!errcode) {\n+\t\t\tskb_queue_walk(\u0026bus-\u003eglom, pnext) {\n+\t\t\t\trd_new.len = pnext-\u003elen;\n+\t\t\t\trd_new.seq_num = rxseq++;\n+\t\t\t\terrcode = brcmf_sdio_hdparse(bus, pnext-\u003edata,\n+\t\t\t\t\t\t\t     \u0026rd_new,\n+\t\t\t\t\t\t\t     BRCMF_SDIO_FT_SUB);\n+\t\t\t\tbrcmf_dbg_hex_dump(BRCMF_GLOM_ON(),\n+\t\t\t\t\t\t   pnext-\u003edata, 32,\n+\t\t\t\t\t\t   \"subframe:\\n\");\n+\t\t\t\tif (errcode)\n+\t\t\t\t\tbreak;\n+\t\t\t}\n \t\t}\n \n \t\tif (errcode) {\n-\t\t\t/* Terminate frame on error */\n-\t\t\tsdio_claim_host(bus-\u003esdiodev-\u003efunc1);\n+\t\t\t/* Terminate frame on error, still holding the host */\n \t\t\tbrcmf_sdio_rxfail(bus, true, false);\n \t\t\tbus-\u003esdcnt.rxglomfail++;\n \t\t\tbrcmf_sdio_free_glom(bus);\n@@ -1683,6 +1689,14 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)\n \t\t\tbus-\u003ecur_read.len = 0;\n \t\t\treturn 0;\n \t\t}\n+\t\tsdio_release_host(bus-\u003esdiodev-\u003efunc1);\n+\n+\t\t/* Host released; now do the pure-memory bookkeeping */\n+\t\tbus-\u003ecur_read.len = rd_new.len_nxtfrm \u003c\u003c 4;\n+\n+\t\t/* Remove superframe header, remember offset */\n+\t\tskb_pull(pfirst, rd_new.dat_offset);\n+\t\tnum = 0;\n \n \t\t/* Basic SD framing looks ok - process each packet (header) */\n \ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c\nindex fc7a5dd2e5d86..3fd8bdbd35e58 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c\n@@ -516,12 +516,11 @@ int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,\n \t\t\treturn -ENOSPC;\n \n \t\t/*\n-\t\t * We aren't really out of space if the new frame is of\n-\t\t * a different priority, but we want the same behaviour\n-\t\t * so return -ENOSPC anyway.\n-\t\t *\n-\t\t * XXX: The old AMPDU code did this, but is it really\n-\t\t * necessary?\n+\t\t * IEEE 802.11n standard requires that all MPDUs within an\n+\t\t * A-MPDU belong to the same TID (Traffic Identifier).\n+\t\t * Since priority maps to TID, a different priority means\n+\t\t * we must close the current aggregate and start a new one,\n+\t\t * so we return -ENOSPC here.\n \t\t */\n \t\tfirst = skb_peek(\u0026session-\u003eskb_list);\n \t\tif (p-\u003epriority != first-\u003epriority)\n"
}

2/1 2026/08/01 06:17 agent patch-evaluator
8m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB",
    "BRCMFMAC_PCIE",
    "CFG80211"
  ],
  "FocusSymbols": [
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa",
    "brcmf_netif_mon_rx"
  ],
  "Reasoning": "The patch adds support for V2 PMKSA cache operations in the brcmfmac driver, which is reachable via cfg80211 netlink commands when a Broadcom Wi-Fi device is present. Syzkaller can emulate such a device via its USB fuzzer, making this new logic reachable and testable. The patch also modifies radiotap header insertion in monitor mode and PCIe mailbox polling, which are functional changes.",
  "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 0fe167e456da1caf928269929533195a3fca312d
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Aug 1 06:17:53 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0b55d445895f2..7d7e5ececd229 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -3989,12 +3989,10 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
 
 static __always_inline void brcmf_delay(u32 ms)
 {
-	if (ms < 1000 / HZ) {
-		cond_resched();
-		mdelay(ms);
-	} else {
+	if (ms <= 20)
+		usleep_range(ms * 1000, ms * 1000 + 1000);
+	else
 		msleep(ms);
-	}
 }
 
 static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
@@ -4364,6 +4362,104 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa,
 	return ret;
 }
 
+/**
+ * brcmf_pmksa_v2_op - update firmware PMKSA cache using the V2 list interface.
+ *
+ * V2 firmware (revision 12) uses a versioned flat list structure
+ * (brcmf_pmk_list_v2_le) rather than the per-entry operation model of V3.
+ * Each entry carries FILS-specific fields (raw PMK material, SSID, and
+ * fils_cache_id) in addition to the basic BSSID + PMKID pair, enabling
+ * FILS fast-roaming on devices that do not support V3.
+ *
+ * @cfg:   driver config structure holding the shadow V2 PMKSA list
+ * @ifp:   interface pointer
+ * @pmksa: the PMKSA to add/remove, or NULL for a flush
+ * @alive: true = add (set time_left to no-expiry), false = remove/flush
+ */
+static s32
+brcmf_pmksa_v2_op(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
+		  struct cfg80211_pmksa *pmksa, bool alive)
+{
+	struct brcmf_pub *drvr = cfg->pub;
+	struct brcmf_pmk_list_v2_le *list = &cfg->pmk_list_v2;
+	struct brcmf_pmksa_v2 *pmk = list->pmk;
+	u32 npmk = le16_to_cpu(list->length);
+	u32 i;
+
+	/* npmk here stores the count of valid entries, repurposing the
+	 * length field of the shadow list as a counter.  We convert to
+	 * the wire format (byte length) when sending to firmware.
+	 */
+	if (!pmksa) {
+		/* Flush: zero the shadow list and push an empty V2 list. */
+		memset(list, 0, sizeof(*list));
+		goto send;
+	}
+
+	if (alive) {
+		/* Set: search for existing BSSID match first. */
+		for (i = 0; i < npmk; i++)
+			if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
+				break;
+
+		if (i >= BRCMF_MAXPMKID) {
+			bphy_err(drvr, "V2 PMKSA cache full (%d entries)\n",
+				 npmk);
+			return -EINVAL;
+		}
+
+		memset(&pmk[i], 0, sizeof(pmk[i]));
+		pmk[i].length = cpu_to_le16(sizeof(struct brcmf_pmksa_v2));
+		if (pmksa->bssid)
+			memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
+		if (pmksa->pmkid)
+			memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
+		if (pmksa->pmk && pmksa->pmk_len &&
+		    pmksa->pmk_len <= WLAN_PMK_LEN_SUITE_B_192) {
+			memcpy(pmk[i].pmk, pmksa->pmk, pmksa->pmk_len);
+			pmk[i].pmk_len = cpu_to_le16(pmksa->pmk_len);
+		}
+		if (pmksa->ssid && pmksa->ssid_len) {
+			memcpy(pmk[i].ssid.SSID, pmksa->ssid, pmksa->ssid_len);
+			pmk[i].ssid.SSID_len = pmksa->ssid_len;
+		}
+		if (pmksa->fils_cache_id)
+			pmk[i].fils_cache_id = *pmksa->fils_cache_id;
+
+		if (i == npmk)
+			npmk++;
+	} else {
+		/* Delete: find by BSSID and compact the list. */
+		for (i = 0; i < npmk; i++)
+			if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
+				break;
+
+		if (i >= npmk) {
+			bphy_err(drvr, "V2 PMKSA entry not found\n");
+			return -EINVAL;
+		}
+
+		for (; i < npmk - 1; i++)
+			memcpy(&pmk[i], &pmk[i + 1], sizeof(pmk[i]));
+		memset(&pmk[npmk - 1], 0, sizeof(pmk[npmk - 1]));
+		npmk--;
+	}
+
+	/* Update shadow entry count (stored in length field). */
+	list->length = cpu_to_le16(npmk);
+
+send:
+	/* Build the wire-format header and send the full list to firmware.
+	 * version and length on the wire reflect the actual byte footprint.
+	 */
+	list->version = cpu_to_le16(BRCMF_PMKSA_VER_2);
+	list->length  = cpu_to_le16(offsetof(struct brcmf_pmk_list_v2_le, pmk) +
+				   npmk * sizeof(struct brcmf_pmksa_v2));
+
+	return brcmf_fil_iovar_data_set(ifp, "pmkid_info", list, sizeof(*list));
+}
+
+
 static __used s32
 brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
 {
@@ -4402,8 +4498,8 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
 
 	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
 		return brcmf_pmksa_v3_op(ifp, pmksa, true);
-
-	/* TODO: implement PMKID_V2 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))
+		return brcmf_pmksa_v2_op(cfg, ifp, pmksa, true);
 
 	npmk = le32_to_cpu(cfg->pmk_list.npmk);
 	for (i = 0; i < npmk; i++)
@@ -4446,8 +4542,8 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
 
 	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
 		return brcmf_pmksa_v3_op(ifp, pmksa, false);
-
-	/* TODO: implement PMKID_V2 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))
+		return brcmf_pmksa_v2_op(cfg, ifp, pmksa, false);
 
 	npmk = le32_to_cpu(cfg->pmk_list.npmk);
 	for (i = 0; i < npmk; i++)
@@ -4487,8 +4583,8 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
 
 	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
 		return brcmf_pmksa_v3_op(ifp, NULL, false);
-
-	/* TODO: implement PMKID_V2 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))
+		return brcmf_pmksa_v2_op(cfg, ifp, NULL, false);
 
 	memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
 	err = brcmf_update_pmklist(cfg, ifp);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 6ceb301429054..57167fde5ba15 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -344,7 +344,8 @@ struct brcmf_cfg80211_wowl {
  * @bss_list: bss_list holding scanned ap information.
  * @bss_info: bss information for cfg80211 layer.
  * @conn_info: association info.
- * @pmk_list: wpa2 pmk list.
+ * @pmk_list: wpa2 pmk list (V1 firmware).
+ * @pmk_list_v2: wpa2 pmk list for V2 firmware (FILS-capable, firmware rev 12).
  * @scan_status: scan activity on the dongle.
  * @pub: common driver information.
  * @channel: current channel.
@@ -376,6 +377,7 @@ struct brcmf_cfg80211_info {
 	struct wl_cfg80211_bss_info *bss_info;
 	struct brcmf_cfg80211_connect_info conn_info;
 	struct brcmf_pmk_list_le pmk_list;
+	struct brcmf_pmk_list_v2_le pmk_list_v2;
 	unsigned long scan_status;
 	struct brcmf_pub *pub;
 	u32 channel;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index ec170647800da..673f0000389cc 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -431,45 +431,51 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 	netif_rx(skb);
 }
 
+struct brcmf_radiotap_info {
+	struct ieee80211_radiotap_header hdr;
+	s8 dbm_antsignal;
+} __packed;
+
 void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 {
 	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_RADIOTAP)) {
-		/* Do nothing */
+		/* Firmware already provided a full radiotap header; do nothing */
 	} else if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR)) {
 		struct wlc_d11rxhdr *wlc_rxhdr = (struct wlc_d11rxhdr *)skb->data;
-		struct ieee80211_radiotap_header *radiotap;
+		struct brcmf_radiotap_info *rtap;
 		unsigned int offset;
 		u16 RxStatus1;
+		s8 rssi;
 
 		RxStatus1 = le16_to_cpu(wlc_rxhdr->rxhdr.RxStatus1);
+		rssi = wlc_rxhdr->rssi;
 
 		offset = sizeof(struct wlc_d11rxhdr);
-		/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU
-		 * subframes
-		 */
+		/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
 		if (RxStatus1 & RXS_PBPRES)
 			offset += 2;
 		offset += D11_PHY_HDR_LEN;
 
 		skb_pull(skb, offset);
 
-		/* TODO: use RX header to fill some radiotap data */
-		radiotap = skb_push(skb, sizeof(*radiotap));
-		memset(radiotap, 0, sizeof(*radiotap));
-		radiotap->it_len = cpu_to_le16(sizeof(*radiotap));
+		/* Insert our radiotap header with RSSI data */
+		rtap = skb_push(skb, sizeof(*rtap));
+		memset(rtap, 0, sizeof(*rtap));
+		rtap->hdr.it_len = cpu_to_le16(sizeof(*rtap));
+		rtap->hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
+		rtap->dbm_antsignal = rssi;
 
-		/* TODO: 4 bytes with receive status? */
-		skb->len -= 4;
+		/* Strip the 4-byte receive status / FCS tail */
+		skb_trim(skb, skb->len - 4);
 	} else {
 		struct ieee80211_radiotap_header *radiotap;
 
-		/* TODO: use RX status to fill some radiotap data */
 		radiotap = skb_push(skb, sizeof(*radiotap));
 		memset(radiotap, 0, sizeof(*radiotap));
 		radiotap->it_len = cpu_to_le16(sizeof(*radiotap));
 
-		/* TODO: 4 bytes with receive status? */
-		skb->len -= 4;
+		/* Strip the 4-byte receive status / FCS tail */
+		skb_trim(skb, skb->len - 4);
 	}
 
 	skb->dev = ifp->ndev;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
index 35cbcea0abc9a..b9c518939f504 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
@@ -182,10 +182,8 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
 	struct brcmf_bus *bus_if;
 	struct brcmf_pub *drvr;
 	struct brcmf_if *ifp;
-	bool currently_blocked;
-	int i;
-	u8 ifidx;
 	unsigned long flags;
+	u8 ifidx;
 
 	spin_lock_irqsave(&flow->block_lock, flags);
 
@@ -194,23 +192,54 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
 		spin_unlock_irqrestore(&flow->block_lock, flags);
 		return;
 	}
-	ifidx = brcmf_flowring_ifidx_get(flow, flowid);
 
-	currently_blocked = false;
-	for (i = 0; i < flow->nrofrings; i++) {
-		if ((flow->rings[i]) && (i != flowid)) {
-			ring = flow->rings[i];
-			if ((ring->status == RING_OPEN) &&
-			    (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
-				if (ring->blocked) {
-					currently_blocked = true;
-					break;
-				}
-			}
+	ifidx = brcmf_flowring_ifidx_get(flow, flowid);
+	ring->blocked = blocked;
+
+	/*
+	 * Maintain the per-interface blocked-ring counter.
+	 *
+	 * We use ring->counted_in_blocked rather than checking
+	 * ring->status here.  A ring that became blocked while
+	 * RING_OPEN has already been counted (counted_in_blocked=true).
+	 * By the time we unblock it during teardown its status may have
+	 * advanced to RING_CLOSING, so testing RING_OPEN would wrongly
+	 * skip the atomic_dec and permanently leak the counter, leaving
+	 * the netif queue stopped forever.
+	 *
+	 * Rule:
+	 *   block transition  (unblocked→blocked): count only if RING_OPEN,
+	 *                                          set counted_in_blocked.
+	 *   unblock transition (blocked→unblocked): decrement only if we
+	 *                                          previously counted it,
+	 *                                          clear counted_in_blocked.
+	 */
+	if (blocked) {
+		if (ring->status == RING_OPEN) {
+			atomic_inc(&flow->if_blocked_cnt[ifidx]);
+			ring->counted_in_blocked = true;
 		}
+	} else {
+		if (ring->counted_in_blocked) {
+			atomic_dec(&flow->if_blocked_cnt[ifidx]);
+			ring->counted_in_blocked = false;
+		}
+	}
+
+	/*
+	 * Only propagate a netif queue-stop/wake when the interface
+	 * transitions between fully-clear and at-least-one-blocked.
+	 * Reading the atomic is safe here: we hold block_lock, so no
+	 * concurrent brcmf_flowring_block() call can race the update
+	 * we just made above.
+	 */
+	if (blocked && atomic_read(&flow->if_blocked_cnt[ifidx]) != 1) {
+		/* Another ring was already blocked; no new queue-stop needed. */
+		spin_unlock_irqrestore(&flow->block_lock, flags);
+		return;
 	}
-	flow->rings[flowid]->blocked = blocked;
-	if (currently_blocked) {
+	if (!blocked && atomic_read(&flow->if_blocked_cnt[ifidx]) != 0) {
+		/* More rings still blocked; do not wake the queue yet. */
 		spin_unlock_irqrestore(&flow->block_lock, flags);
 		return;
 	}
@@ -367,6 +396,8 @@ struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
 		spin_lock_init(&flow->block_lock);
 		for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
 			flow->addr_mode[i] = ADDR_INDIRECT;
+		for (i = 0; i < ARRAY_SIZE(flow->if_blocked_cnt); i++)
+			atomic_set(&flow->if_blocked_cnt[i], 0);
 		for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
 			flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
 	}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
index f3d511f9a3c9a..afdea8b3f8aa7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
@@ -5,6 +5,8 @@
 #ifndef BRCMFMAC_FLOWRING_H
 #define BRCMFMAC_FLOWRING_H
 
+#include <linux/atomic.h>
+
 
 #define BRCMF_FLOWRING_HASHSIZE		512		/* has to be 2^x */
 #define BRCMF_FLOWRING_INVALID_ID	0xFFFFFFFF
@@ -26,6 +28,16 @@ enum ring_status {
 struct brcmf_flowring_ring {
 	u16 hash_id;
 	bool blocked;
+	/*
+	 * True when this ring has been counted in the per-interface
+	 * if_blocked_cnt[].  Set to true whenever the ring transitions
+	 * unblocked→blocked while RING_OPEN; cleared on the matching
+	 * blocked→unblocked transition.  Needed so that a ring that
+	 * becomes blocked while RING_OPEN and is later moved to
+	 * RING_CLOSING still correctly decrements the counter at
+	 * teardown, even though its status is no longer RING_OPEN.
+	 */
+	bool counted_in_blocked;
 	enum ring_status status;
 	struct sk_buff_head skblist;
 };
@@ -40,6 +52,12 @@ struct brcmf_flowring {
 	struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];
 	spinlock_t block_lock;
 	enum proto_addr_mode addr_mode[BRCMF_MAX_IFS];
+	/* Per-interface count of currently blocked open rings.
+	 * Maintained atomically so brcmf_flowring_block() can check
+	 * whether any sibling ring is already blocked in O(1) without
+	 * holding block_lock across an O(nrofrings) walk.
+	 */
+	atomic_t if_blocked_cnt[BRCMF_MAX_IFS];
 	u16 nrofrings;
 	bool tdls_active;
 	struct brcmf_flowring_tdls_entry *tdls_entry;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
index a43f1a38b0e30..3c1ca355e8eec 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -1037,7 +1037,9 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
 		} else {
 			brcmf_dbg(TRACE, "use existing\n");
 			WARN_ON(entry->mac_handle != mac_handle);
-			/* TODO: what should we do here: continue, reinit, .. */
+			/* Firmware re-sent ADD for the same MAC handle.
+			 * No action required; it is a safe no-op.
+			 */
 		}
 	}
 	return 0;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index ba1ce1552e0f4..8db6167072da3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -48,7 +48,19 @@
 #define MSGBUF_TYPE_LPBK_DMAXFER		0x13
 #define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT		0x14
 
-#define NR_TX_PKTIDS				2048
+/*
+ * NR_TX_PKTIDS: number of simultaneously in-flight TX packet IDs.
+ * Each outstanding TX frame consumes one ID until the dongle returns
+ * a TX-status completion.  The original 2048-entry pool exhausted under
+ * ≥4 concurrent iperf3 streams on Wi-Fi 5/6 (802.11ac/ax) devices,
+ * causing "No PKTID available" drops and TCP retransmits.  4096 gives
+ * headroom for high-aggregation scenarios while still fitting in a
+ * modest amount of host memory (~48 KB for the pktid table entries).
+ *
+ * NR_RX_PKTIDS: RX post buffers pre-allocated to the dongle.  1024 is
+ * sufficient for current hardware RX ring depths; leave unchanged.
+ */
+#define NR_TX_PKTIDS				4096
 #define NR_RX_PKTIDS				1024
 
 #define BRCMF_IOCTL_REQ_PKTID			0xFFFE
@@ -64,8 +76,29 @@
 #define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK	0x07
 #define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT	5
 
-#define BRCMF_MSGBUF_TX_FLUSH_CNT1		32
-#define BRCMF_MSGBUF_TX_FLUSH_CNT2		96
+/*
+ * TX flush / doorbell-ring thresholds.
+ *
+ * CNT1 is the minimum number of frames to accumulate in the commonring
+ * before the first intermediate write_complete() (doorbell ring) is
+ * issued mid-batch.  CNT2 is the hard flush interval: after this many
+ * frames have been written since the last flush, we unconditionally
+ * ring the bell and reset the counter.
+ *
+ * Raising both from the original 32/96 to 64/128 doubles the average
+ * number of TX descriptors committed per MMIO write, halving the PCIe
+ * doorbell rate on sustained throughput workloads.  The tradeoff is a
+ * marginally higher worst-case latency for the last frames in a burst,
+ * which in practice is hidden by the time the dongle DMA engine drains
+ * the previous batch.
+ *
+ * TRICKLE_TXWORKER_THRS governs how often brcmf_msgbuf_tx_queue_data()
+ * forces a workqueue schedule when the queue depth is not a multiple of
+ * this value.  Keeping it at half of CNT1 (32) preserves responsiveness
+ * for low-rate flows (e.g. VoIP, ICMP) that never accumulate 64 frames.
+ */
+#define BRCMF_MSGBUF_TX_FLUSH_CNT1		64
+#define BRCMF_MSGBUF_TX_FLUSH_CNT2		128
 
 #define BRCMF_MSGBUF_DELAY_TXWORKER_THRS	96
 #define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS	32
@@ -787,10 +820,30 @@ static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,
 {
 	struct brcmf_commonring *commonring;
 
-	set_bit(flowid, msgbuf->flow_map);
+	/*
+	 * If the bit was already set, a txflow_work item is already
+	 * queued or running for this ring.  In that case the existing
+	 * worker will drain our freshly enqueued frame when it runs,
+	 * so we only need to schedule another work item when the
+	 * force flag is set or the ring is below the delay threshold.
+	 *
+	 * If the bit was NOT set (test_and_set_bit returns false), no
+	 * worker is pending for this ring at all.  We MUST schedule
+	 * one unconditionally, otherwise the frame we just enqueued
+	 * will sit in the flowring unsent until some unrelated event
+	 * triggers the workqueue — causing silent TX stalls under
+	 * high load when outstanding_tx >= DELAY_TXWORKER_THRS.
+	 */
+	if (!test_and_set_bit(flowid, msgbuf->flow_map)) {
+		/* Bit was clear: no worker pending, always schedule. */
+		queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
+		return 0;
+	}
+
+	/* Bit was already set: worker pending, apply coalescing heuristic. */
 	commonring = msgbuf->flowrings[flowid];
-	if ((force) || (atomic_read(&commonring->outstanding_tx) <
-			BRCMF_MSGBUF_DELAY_TXWORKER_THRS))
+	if (force || (atomic_read(&commonring->outstanding_tx) <
+		      BRCMF_MSGBUF_DELAY_TXWORKER_THRS))
 		queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
 
 	return 0;
@@ -1621,11 +1674,11 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
 	do {
 		brcmf_msgbuf_rxbuf_data_fill(msgbuf);
 		if (msgbuf->max_rxbufpost != msgbuf->rxbufpost)
-			msleep(10);
+			usleep_range(1000, 2000);
 		else
 			break;
 		count++;
-	} while (count < 10);
+	} while (count < 100);
 	brcmf_msgbuf_rxbuf_event_post(msgbuf);
 	brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 13662aa4b4ea6..9338a5faa260a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -268,6 +268,27 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
 
 #define BRCMF_PCIE_MBDATA_TIMEOUT		msecs_to_jiffies(2000)
 
+/*
+ * H2D mailbox poll timing parameters.
+ *
+ * The dongle typically clears the H2D mailbox register within a few
+ * hundred microseconds after the doorbell interrupt fires.  The
+ * original code used msleep(10) * 100 iterations, meaning the
+ * minimum observable latency was 10ms even when the dongle was fast.
+ *
+ * We instead start with a short sleep and double it each iteration
+ * (exponential backoff) up to BRCMF_PCIE_MB_POLL_MAX_US, staying
+ * within the same 1-second absolute timeout.
+ *
+ * MIN_US / INITIAL_MAX_US : usleep_range bounds for the first iteration.
+ * MAX_US     : cap on the per-iteration sleep (µs).
+ * TIMEOUT_US : total budget before giving up (1 second).
+ */
+#define BRCMF_PCIE_MB_POLL_MIN_US		40
+#define BRCMF_PCIE_MB_POLL_INITIAL_MAX_US	50
+#define BRCMF_PCIE_MB_POLL_MAX_US		5000
+#define BRCMF_PCIE_MB_POLL_TIMEOUT_US		1000000
+
 #define BRCMF_PCIE_CFGREG_STATUS_CMD		0x4
 #define BRCMF_PCIE_CFGREG_PM_CSR		0x4C
 #define BRCMF_PCIE_CFGREG_MSI_CAP		0x58
@@ -766,7 +787,8 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
 	struct brcmf_core *core;
 	u32 addr;
 	u32 cur_htod_mb_data;
-	u32 i;
+	u32 elapsed_us = 0;
+	u32 sleep_us = BRCMF_PCIE_MB_POLL_INITIAL_MAX_US;
 
 	shared = &devinfo->shared;
 	addr = shared->htod_mb_data_addr;
@@ -776,12 +798,40 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
 		brcmf_dbg(PCIE, "MB transaction is already pending 0x%04x\n",
 			  cur_htod_mb_data);
 
-	i = 0;
+	/*
+	 * Wait for the dongle to consume the previous H2D mailbox message.
+	 *
+	 * There is no interrupt that signals when the dongle clears this
+	 * register, so polling is unavoidable.  The original code used
+	 * msleep(10) per iteration, incurring at least 10ms of latency
+	 * even when the dongle responded in microseconds.
+	 *
+	 * We use usleep_range() with exponential backoff instead:
+	 *   - First iteration sleeps ~50µs (fast path for responsive dongle).
+	 *   - Each subsequent iteration doubles the sleep, capped at 5ms,
+	 *     so long waits still yield the CPU without busy-spinning.
+	 *   - Total timeout matches the original 1-second limit.
+	 *   - We bail early if the device has gone down so that a dead
+	 *     dongle does not hold the caller for a full second.
+	 */
 	while (cur_htod_mb_data != 0) {
-		msleep(10);
-		i++;
-		if (i > 100)
+		if (devinfo->state == BRCMFMAC_PCIE_STATE_DOWN) {
+			brcmf_dbg(PCIE, "Device down, aborting MB send\n");
 			return -EIO;
+		}
+
+		if (elapsed_us >= BRCMF_PCIE_MB_POLL_TIMEOUT_US) {
+			brcmf_err("Timeout waiting for H2D MB slot after %u us\n",
+				  elapsed_us);
+			return -EIO;
+		}
+
+		usleep_range(BRCMF_PCIE_MB_POLL_MIN_US, sleep_us);
+		elapsed_us += sleep_us;
+
+		/* Exponential backoff, capped at BRCMF_PCIE_MB_POLL_MAX_US */
+		sleep_us = min(sleep_us * 2, (u32)BRCMF_PCIE_MB_POLL_MAX_US);
+
 		cur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
 	}
 
@@ -1001,10 +1051,10 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)
 	free_irq(pdev->irq, devinfo);
 	pci_disable_msi(pdev);
 
-	msleep(50);
+	usleep_range(1000, 2000);
 	count = 0;
-	while ((devinfo->in_irq) && (count < 20)) {
-		msleep(50);
+	while ((devinfo->in_irq) && (count < 1000)) {
+		usleep_range(1000, 2000);
 		count++;
 	}
 	if (devinfo->in_irq)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index b725c64e5b5c6..4e414403d7471 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -1645,37 +1645,43 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
 		rd_new.seq_num = rxseq;
 		rd_new.len = dlen;
+
+		/*
+		 * Claim the host once for the entire header-parsing phase.
+		 *
+		 * brcmf_sdio_hdparse() operates on data already in host
+		 * memory, but may call brcmf_sdio_rxfail() on error, which
+		 * writes SDIO Func1 registers and therefore requires the
+		 * host to be claimed.
+		 *
+		 * skb_pull() and the num counter are pure host-memory
+		 * operations; keep them outside the lock to minimise the
+		 * hold time.  Both hdparse calls (superframe header and
+		 * each subframe header) are grouped under a single claim/
+		 * release, replacing the original N+1 separate pairs.
+		 */
 		sdio_claim_host(bus->sdiodev->func1);
 		errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
 					     BRCMF_SDIO_FT_SUPER);
-		sdio_release_host(bus->sdiodev->func1);
-		bus->cur_read.len = rd_new.len_nxtfrm << 4;
-
-		/* Remove superframe header, remember offset */
-		skb_pull(pfirst, rd_new.dat_offset);
-		num = 0;
-
-		/* Validate all the subframe headers */
-		skb_queue_walk(&bus->glom, pnext) {
-			/* leave when invalid subframe is found */
-			if (errcode)
-				break;
 
-			rd_new.len = pnext->len;
-			rd_new.seq_num = rxseq++;
-			sdio_claim_host(bus->sdiodev->func1);
-			errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
-						     BRCMF_SDIO_FT_SUB);
-			sdio_release_host(bus->sdiodev->func1);
-			brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
-					   pnext->data, 32, "subframe:\n");
-
-			num++;
+		/* Validate all the subframe headers while host is claimed */
+		if (!errcode) {
+			skb_queue_walk(&bus->glom, pnext) {
+				rd_new.len = pnext->len;
+				rd_new.seq_num = rxseq++;
+				errcode = brcmf_sdio_hdparse(bus, pnext->data,
+							     &rd_new,
+							     BRCMF_SDIO_FT_SUB);
+				brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
+						   pnext->data, 32,
+						   "subframe:\n");
+				if (errcode)
+					break;
+			}
 		}
 
 		if (errcode) {
-			/* Terminate frame on error */
-			sdio_claim_host(bus->sdiodev->func1);
+			/* Terminate frame on error, still holding the host */
 			brcmf_sdio_rxfail(bus, true, false);
 			bus->sdcnt.rxglomfail++;
 			brcmf_sdio_free_glom(bus);
@@ -1683,6 +1689,14 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			bus->cur_read.len = 0;
 			return 0;
 		}
+		sdio_release_host(bus->sdiodev->func1);
+
+		/* Host released; now do the pure-memory bookkeeping */
+		bus->cur_read.len = rd_new.len_nxtfrm << 4;
+
+		/* Remove superframe header, remember offset */
+		skb_pull(pfirst, rd_new.dat_offset);
+		num = 0;
 
 		/* Basic SD framing looks ok - process each packet (header) */
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
index fc7a5dd2e5d86..3fd8bdbd35e58 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
@@ -516,12 +516,11 @@ int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
 			return -ENOSPC;
 
 		/*
-		 * We aren't really out of space if the new frame is of
-		 * a different priority, but we want the same behaviour
-		 * so return -ENOSPC anyway.
-		 *
-		 * XXX: The old AMPDU code did this, but is it really
-		 * necessary?
+		 * IEEE 802.11n standard requires that all MPDUs within an
+		 * A-MPDU belong to the same TID (Traffic Identifier).
+		 * Since priority maps to TID, a different priority means
+		 * we must close the current aggregate and start a new one,
+		 * so we return -ENOSPC here.
 		 */
 		first = skb_peek(&session->skb_list);
 		if (p->priority != first->priority)

3/2 2026/08/01 06:17 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13314
							output: 21
							thoughts: 1354
						

Thoughts:
**Analyzing the brcmfmac Patch Series for Fuzzing Potential**

Okay, so I've got this patch series for the `brcmfmac` and `brcmsmac` drivers in the Linux kernel. First glance, there's quite a bit happening across various files, specifically: `cfg80211.c`, `cfg80211.h`, `core.c`, `flowring.c`, `fwsignal.c`, `msgbuf.c`, `pcie.c`, `sdio.c`, and `ampdu.c`. The changes range from subtle timing adjustments (`brcmf_delay` now using `usleep_range`, for instance) to more involved additions like `brcmf_pmksa_v2_op` for PMKSA cache version 2. There are also tweaks to flow control, message buffer handling, and SDIO/PCIE interaction.

I need to quickly assess this for fuzzing opportunities. The prompt flags "vendor-specific PCIe switch, SmartNIC, or GPU drivers" as a no-go for fuzzing if they require specific physical hardware.  But, `brcmfmac` is a Wi-Fi driver, so it typically communicates with physical Wi-Fi hardware. But, *brcmfmac* also supports USB! That's key. USB devices can be readily emulated. USB gadget, dummy_hcd, or syzkaller's USB fuzzing (vhci).

Let me confirm the USB support. There's a `drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c` file. Bingo. So, syzkaller could be used to fuzz this driver.

Now, let's break down the implications of the patches. It looks like the changes in `cfg80211.c` are related to PMKSA cache management, which might affect different communication interfaces. The changes in `core.c` affect the monitor mode's RSSI data. `flowring.c` manages flow control. `msgbuf.c` deals with message buffer size. `pcie.c` uses `usleep_range`. `sdio.c` is related to SDIO communication.

The question then is whether all these modified code paths are reachable through the USB interface. If code in `cfg80211.c`, `core.c`, `flowring.c`, `msgbuf.c`, `pcie.c`, and `sdio.c` is reachable via USB, then we have a good fuzzing target, because we can emulate the USB Wi-Fi dongle. Now I will use `grepper` to see if those files are used by the USB implementation of the driver. If so, then *WorthFuzzing=true*.



4/2 2026/08/01 06:18 tool grepper
0m Args:
{
  "Expression": "brcmf_usb_probe"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1165=static const struct brcmf_bus_ops brcmf_usb_bus_ops = {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1175-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1176:static void brcmf_usb_probe_phase2(struct device *dev, int ret,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1177-\t\t\t\t   struct brcmf_fw_request *fwreq)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1224=brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1243-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1244:static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1245-\t\t\t      enum brcmf_fwvendor fwvid)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1307-\t/* request firmware here */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1308:\tret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1309-\tif (ret) {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1341=static int\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1342:brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1343-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1442-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1443:\tret = brcmf_usb_probe_cb(devinfo, id-\u003edriver_info);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1444-\tif (ret)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1511=static int brcmf_usb_reset_resume(struct usb_interface *intf)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1523-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1524:\tret = brcmf_fw_get_firmwares(\u0026usb-\u003edev, fwreq, brcmf_usb_probe_phase2);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1525-\tif (ret \u003c 0)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1565=static struct usb_driver brcmf_usbdrvr = {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1566-\t.name = KBUILD_MODNAME,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1567:\t.probe = brcmf_usb_probe,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1568-\t.disconnect = brcmf_usb_disconnect,\n"
}

5/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16446
							output: 29
							thoughts: 141
						

Thoughts:
**Fuzzing the `brcmfmac` Driver via USB: Initial Assessment**

Okay, so I'm thinking about fuzzing the `brcmfmac` driver, specifically via USB. My initial thought is to identify a reachable entry point that might be susceptible. Let's start by looking at `brcmf_pmksa_v2_op`. I want to see if we can trigger something interesting there.

It looks like `brcmf_pmksa_v2_op` is called from `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, and `brcmf_cfg80211_flush_pmksa`. Right, these all seem to be `cfg80211` callbacks. That suggests an interface we might be able to leverage.

Now, let's zoom in on `brcmf_cfg80211_set_pmksa`. That's the one I'm most interested in for now. Let's see if we can manipulate the inputs to that to lead us to what we want.



6/2 2026/08/01 06:18 tool grepper
0m Args:
{
  "Expression": "brcmf_cfg80211_set_pmksa"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4481=static s32\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4482:brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4483-\t\t\t struct cfg80211_pmksa *pmksa)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=6078=static struct cfg80211_ops brcmf_cfg80211_ops = {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-6099-\t.resume = brcmf_cfg80211_resume,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:6100:\t.set_pmksa = brcmf_cfg80211_set_pmksa,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-6101-\t.del_pmksa = brcmf_cfg80211_del_pmksa,\n"
}

7/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 17278
							output: 24
							thoughts: 32
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Analyzing the Relevant Code**

Alright, so the discussion centers on `cfg80211_ops` callbacks. No surprises there; that's the core of the mac80211 interface, and a common area of focus for anyone working with wireless drivers. I immediately think through all the usual suspects: association, authentication, regulatory domain handling, the works. I'm mentally checking if we're looking at a specific callback function for a specific problem. Is it something related to rate control, hardware configuration, or perhaps power management within the driver?

But then my mind shifts to a specific function I'm curious about. What about `brcmf_netif_mon_rx`? That throws a different light on things. This implies we're dealing with monitoring mode functionality for a Broadcom driver, or something that's Broadcom-specific. We must be looking at packet reception in promiscuous mode or monitor mode. That narrows down the possibilities and suggests a potential area for investigating a potential issue, perhaps packet injection, or sniffing. My thinking jumps from the general `cfg80211_ops` to something much more specific.



8/2 2026/08/01 06:18 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=434=struct brcmf_radiotap_info {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-438-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:439:void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-440-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h=220=void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h:221:void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h-222-void brcmf_net_detach(struct net_device *ndev, bool locked);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1200=brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1240-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1241:\t\tbrcmf_netif_mon_rx(ifp, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1242-\t\treturn;\n"
}

9/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 18132
							output: 26
							thoughts: 53
						

Thoughts:
Okay, here's my interpretation of those thoughts, presented as my own mental process, given my expertise:

**Diving into the BRCMF Driver Architecture**

Alright, let's see, I'm tracking this `brcmf_netif_mon_rx` function... and it looks like it's being called from `brcmf_msgbuf_process_rx_complete`. Okay, that makes sense. Standard receive path processing. Now, a little flag goes up. I'm wondering about `msgbuf.c`. I need to make sure I get the context right. That file is key to understanding how data is handled, and I need to recall exactly how it's used with PCIe. Does it handle data being received from the network through PCIe? Yes, that's right. But what about USB? Does the USB stack *also* leverage `msgbuf.c` for its communication? I need to check that. The message buffer architecture is often shared, but I need to confirm the specifics of how it's employed across different underlying transport layers, so I don't confuse the data flow later. This detail could significantly impact how I interpret the overall system behavior.



10/2 2026/08/01 06:18 tool grepper
0m Args:
{
  "Expression": "brcmf_msgbuf_process_rx_complete"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1199=static void\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1200:brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1201-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1341=static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1380-\t\tbrcmf_dbg(MSGBUF, \"MSGBUF_TYPE_RX_CMPLT\\n\");\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1381:\t\tbrcmf_msgbuf_process_rx_complete(msgbuf, buf);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1382-\t\tbreak;\n"
}

11/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 18815
							output: 47
							thoughts: 19
						

Thoughts:
Here's a summary of my thought process:

**Investigating brcmfmac USB and msgbuf.c**

Okay, so I'm digging into `brcmfmac` and its USB implementation. My initial question is whether or not `msgbuf.c` plays a role in it. It's a key question because `msgbuf.c` often handles message buffering and queuing, which is a common pattern for USB communication, especially with complex drivers. If it *is* used, I can leverage my existing knowledge of `msgbuf.c` structures, functions, and potential bottlenecks to get a much faster understanding of how the USB interface operates. If it's *not* used, I'll have to investigate alternative buffering mechanisms or direct message handling within the `brcmfmac` USB code, which might point to a less conventional approach, but potentially one that's optimized for performance. Either way, figuring this out is the crucial first step.



12/2 2026/08/01 06:18 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "msgbuf",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c"
}

Results:
{
  "error": "no matches"
}

13/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 19098
							output: 47
							thoughts: 10
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person:

**Navigating the USB Driver Landscape**

Hmm, so I'm thinking about the USB stack... and I'm trying to recall the lower-level driver components. Is it possible that the code related to USB's *bulk complete data context* - `bcdc.c` - is, in fact, relevant here? It's a fuzzy memory, but I'm mentally parsing the possibilities and considering if this is the correct place to focus. Need to double-check which modules are responsible for managing data transfers and if that component provides the framework I need.



14/2 2026/08/01 06:18 tool grepper
0m Args:
{
  "Expression": "bcdc",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-20-#include \"common.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:21:#include \"bcdc.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-22-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=485=static void brcmf_usb_tx_complete(struct urb *urb)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-494-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:495:\tbrcmf_proto_bcdc_txcomplete(devinfo-\u003edev, req-\u003eskb, urb-\u003estatus == 0);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-496-\treq-\u003eskb = NULL;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-500-\t\tdevinfo-\u003etx_flowblock) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:501:\t\tbrcmf_proto_bcdc_txflowblock(devinfo-\u003edev, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-502-\t\tdevinfo-\u003etx_flowblock = false;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=608=static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-652-\t    !devinfo-\u003etx_flowblock) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:653:\t\tbrcmf_proto_bcdc_txflowblock(dev, true);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-654-\t\tdevinfo-\u003etx_flowblock = true;\n"
}

15/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 19924
							output: 47
							thoughts: 68
						

Thoughts:
Okay, let me break this down.

**Network Interface Controller Driver Investigation**

Alright, so I'm digging into how our network interface controllers are implemented, specifically how the drivers are structured. It looks like both USB and SDIO are leaning on `bcdc.c`. That's interesting, suggesting a shared core for these interface types. Then I see PCIe is utilizing `msgbuf.c` which, on its face, seems to handle a very different type of communication. Ah, but wait a minute, I'm noting that `flowring.c` is being used by both `msgbuf.c` and `pcie.c`. That's immediately sparking a question: is there any chance that `flowring.c` is also used *indirectly* by USB? The shared use of `bcdc.c` and a potential path to `flowring.c` has got me thinking about deeper architectural commonalities than are immediately apparent. I need to investigate the dependency chain further.



16/2 2026/08/01 06:18 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "flowring",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c"
}

Results:
{
  "error": "no matches"
}

17/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 20262
							output: 48
							thoughts: 16
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:

**Investigating Code Dependencies: flowring.c and bcdc.c**

Alright, let's see... *flowring.c*. I'm working on something that touches the data flow, and I need to understand this module's role. Hmm, I have a feeling `bcdc.c` might be the place to look for that interaction. The way I've structured my analysis usually goes like this - I'm trying to figure out if `flowring.c` is actually *used* by `bcdc.c`. It's a common dependency pattern, but I need to confirm it specifically in this case. I’ll start by digging into `bcdc.c` and looking for function calls, includes, or any references to `flowring.c`'s symbols or data structures. I want to trace the data flow and understand how these two modules relate. Perhaps I'll use grep, ctags, or my IDE's built-in dependency analysis to quickly see if the inclusion exists. If it does, then the work is that much easier. If not, then I'll need to expand my search.



18/2 2026/08/01 06:18 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "flowring",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c"
}

Results:
{
  "error": "no matches"
}

19/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 20610
							output: 24
							thoughts: 159
						

Thoughts:
**Analyzing the Broadcom WiFi Driver Call Graph**

Okay, so I'm looking at these driver files, and it's quickly becoming clear how things are structured. It looks like `flowring.c`, `msgbuf.c`, and `pcie.c` are all pretty specifically tied to the PCIe implementation. But hang on... I see `brcmf_pmksa_v2_op`, which seems like it might be a lower-level function dealing with PMKSA, and that's *actually* defined in `cfg80211.c`. That's the generic wireless configuration library, so it's probably shared across different hardware platforms. And then there's `brcmf_netif_mon_rx` which is also defined in a generic file, `core.c`.

Now things are getting interesting. The thing I need to confirm is that `brcmf_netif_mon_rx` can be called from multiple places: the PCIe-specific `msgbuf.c`, and also from `bcdc.c` which, if I recall, deals with USB and SDIO interfaces. But is that right? Does `bcdc.c` *really* call `brcmf_netif_mon_rx`? Or is it USB-specific `usb.c` or SDIO-specific `sdio.c` that's calling it? I'll need to double check those source files to verify the call graph. Let's see...



20/2 2026/08/01 06:18 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=434=struct brcmf_radiotap_info {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-438-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:439:void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-440-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h=220=void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h:221:void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h-222-void brcmf_net_detach(struct net_device *ndev, bool locked);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1200=brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1240-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1241:\t\tbrcmf_netif_mon_rx(ifp, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1242-\t\treturn;\n"
}

21/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 21649
							output: 26
							thoughts: 127
						

Thoughts:
**PCIe Focus and SDIO Uncertainties**

Okay, so I'm looking at this `brcmf_netif_mon_rx` function and the code clearly shows that it's only called from `msgbuf.c`. Alright, that's pretty definitive - it looks like `brcmf_netif_mon_rx` is specifically related to PCIe. But what about SDIO? I was pretty sure it’s in `sdio.c`, isn't it?

The standard QEMU setup doesn't emulate SDIO, so I need to think this through. Hang on, I seem to recall some fuzzing work with syzkaller... maybe there's some SDIO stuff in there? No, I'm pretty sure it doesn't have it. Or does it? It's been a while. I should probably double-check. The best way would be to look for SDIO pseudo-syscalls. That's the key.



22/2 2026/08/01 06:18 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "sdio",
  "PathPrefix": "sys/linux/"
}

Results:
{
  "error": "no matches"
}

23/2 2026/08/01 06:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 22024
							output: 27
							thoughts: 610
						

Thoughts:
**Analyzing the Potential Reachability of `brcmf_cfg80211_set_pmksa` via Syzkaller**

Okay, first off, I can't just use `grepper` on `sys/linux/` because those aren't kernel tree paths. And the prompt is telling me to use `read-syz-spec` or `syz-grepper` which, for some reason, aren't in the available tool list! But I get it, I can't search for syzkaller specs with this. Anyway, I don't actually need to, I know syzkaller hits USB and `mac80211_hwsim` already.

Right, `brcmfmac`...that's a fullmac driver, so it goes through `cfg80211`, not `mac80211`. Syzkaller hits `cfg80211` through netlink (`nl80211`). So, theoretically, if a `brcmfmac` device is present, I can reach `brcmf_cfg80211_set_pmksa` via nl80211. Crucially, can the fuzzing environment have a `brcmfmac` device?

Aha! USB! Syzkaller has a USB fuzzer and can emulate it. The USB route is my best bet. Now I need to confirm whether the `brcmfmac` USB driver actually registers with `cfg80211`. Let's see... `brcmf_usb_probe` looks promising. And yes, it's there. That then calls `brcmf_usb_probe_cb`, which, in turn, goes through `brcmf_attach`, `brcmf_cfg80211_attach`, and eventually `wiphy_new` and `wiphy_register`. So, when syzkaller emulates a Broadcom USB Wi-Fi dongle, `brcmf_usb_probe` *should* be triggered, creating a `wiphy`. Then, syzkaller can hit that `wiphy` with nl80211 commands, which should land on `brcmf_cfg80211_set_pmksa`.

But, wait... `brcmf_cfg80211_set_pmksa` calls `brcmf_pmksa_v2_op` only if `BRCMF_FEAT_PMKID_V2` is enabled. Time to check where that flag is set.



24/2 2026/08/01 06:19 tool grepper
0m Args:
{
  "Expression": "BRCMF_FEAT_PMKID_V2"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4482=brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4500-\t\treturn brcmf_pmksa_v3_op(ifp, pmksa, true);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4501:\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4502-\t\treturn brcmf_pmksa_v2_op(cfg, ifp, pmksa, true);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4527=brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4544-\t\treturn brcmf_pmksa_v3_op(ifp, pmksa, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4545:\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4546-\t\treturn brcmf_pmksa_v2_op(cfg, ifp, pmksa, false);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4574=brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4585-\t\treturn brcmf_pmksa_v3_op(ifp, NULL, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4586:\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4587-\t\treturn brcmf_pmksa_v2_op(cfg, ifp, NULL, false);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c=137=static const struct brcmf_feat_wlcfeat brcmf_feat_wlcfeat_map[] = {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c:138:\t{ 12, 0, BIT(BRCMF_FEAT_PMKID_V2) },\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-139-\t{ 13, 0, BIT(BRCMF_FEAT_PMKID_V3) },\n"
}

25/2 2026/08/01 06:19 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 24175
							output: 44
							thoughts: 215
						

Thoughts:
**Analyzing the Implications of Feature Enablement in Broadcom WiFi Drivers**

Okay, so I see that `BRCMF_FEAT_PMKID_V2` is getting set up based on what the firmware says it supports, which is determined by this `brcmf_feat_wlcfeat_map` thing. That makes sense, pretty standard feature flag handling. The exciting part is that the Syzkaller USB fuzzer is capable of tricking the system into *believing* the firmware supports this feature (feature 12), therefore enabling `BRCMF_FEAT_PMKID_V2`. This means that code path involving `brcmf_pmksa_v2_op` becomes accessible and therefore fuzzable. This is good news, fuzzable is exploitable.

But hold on, let me quickly pivot here... what about the `brcmsmac` driver? This patch also touches `drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c`. Okay, let's take a look at what this `brcmsmac` is all about. Ah, right. It's the mac80211 driver for those older Broadcom PCIe cards – specifically the BCM4313, BCM43224, BCM43225 chips. Now, am I remembering correctly that this is PCIe *only*? That detail could be important when considering the attack surface. Need to quickly confirm this fact.



26/2 2026/08/01 06:19 tool grepper
0m Args:
{
  "Expression": "module_init",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c=1318=static DECLARE_WORK(brcms_driver_work, brcms_driver_init);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1319-\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c:1320:static int __init brcms_module_init(void)\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1321-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c=1336=static void __exit brcms_module_exit(void)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1342-\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c:1343:module_init(brcms_module_init);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1344-module_exit(brcms_module_exit);\n"
}

27/2 2026/08/01 06:19 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 25145
							output: 47
							thoughts: 12
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Diving into `brcms_module_init`**

Okay, time to dig into this. "Let's check `brcms_module_init`." That's the starting point, the entry function for the Broadcom wireless driver, right? So, I'm thinking, this is where it all begins. Where the driver gets loaded, memory is allocated, hardware is initialized, and interrupts are set up. I need to understand what's happening at the ground level, before any higher-level abstractions kick in. From there I'll be able to trace exactly how the driver handles this specific chip. This is always the best place to start when working on a new platform or troubleshooting an initialization issue.



28/2 2026/08/01 06:19 tool grepper
0m Args:
{
  "Expression": "brcms_module_init",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c=1318=static DECLARE_WORK(brcms_driver_work, brcms_driver_init);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1319-\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c:1320:static int __init brcms_module_init(void)\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1321-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c=1336=static void __exit brcms_module_exit(void)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1342-\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c:1343:module_init(brcms_module_init);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c-1344-module_exit(brcms_module_exit);\n"
}

29/2 2026/08/01 06:19 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 25760
							output: 60
							thoughts: 12
						

Thoughts:
Okay, let's dive into this. Here's my take on `brcms_module_init`, from an expert's perspective:

**Initial Assessment: brcms_module_init**

Alright, let's get into the guts of this initialization routine, `brcms_module_init`. Immediately, I'm already anticipating a few things based on the name. This is likely the first point of entry for the Broadcom wireless driver, so I'm expecting to see a lot of foundational setup. Thinking back to past experiences, I'm looking for memory allocations, device registration, and perhaps some early hardware probing or initialization. I'll need to keep an eye out for potential race conditions during driver loading, too, as I've seen those bite before. Let's see how they've handled that.



30/2 2026/08/01 06:19 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c",
  "FirstLine": 1315,
  "LineCount": 30
}

Results:
{
  "Contents": "1315:\t\t\tpr_err(\"%s: register returned %d\\n\", __func__, error);\n1316:\t}\n1317:\t\n1318:\tstatic DECLARE_WORK(brcms_driver_work, brcms_driver_init);\n1319:\t\n1320:\tstatic int __init brcms_module_init(void)\n1321:\t{\n1322:\t\tbrcms_debugfs_init();\n1323:\t\tif (!schedule_work(\u0026brcms_driver_work))\n1324:\t\t\treturn -EBUSY;\n1325:\t\n1326:\t\treturn 0;\n1327:\t}\n1328:\t\n1329:\t/*\n1330:\t * This function unloads the brcmsmac driver from the system.\n1331:\t *\n1332:\t * This function unconditionally unloads the brcmsmac driver module from the\n1333:\t * system.\n1334:\t *\n1335:\t */\n1336:\tstatic void __exit brcms_module_exit(void)\n1337:\t{\n1338:\t\tcancel_work_sync(\u0026brcms_driver_work);\n1339:\t\tbcma_driver_unregister(\u0026brcms_bcma_driver);\n1340:\t\tbrcms_debugfs_exit();\n1341:\t}\n1342:\t\n1343:\tmodule_init(brcms_module_init);\n1344:\tmodule_exit(brcms_module_exit);\n"
}

31/2 2026/08/01 06:19 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 26422
							output: 44
							thoughts: 1359
						

Thoughts:
**Reaching a Verdict on Fuzzing Worthiness**

Okay, so I'm looking at this patch and my initial thought is the `bcma_driver` registration. BCMA is Broadcom's internal bus, typically PCIe or SoC. The fact that `brcmsmac` is a PCIe/SoC driver raises a red flag right away because standard QEMU might not emulate the necessary PCIe device. I need to be careful; the prompt states to return `WorthFuzzing=false` if the patch targets vendor-specific PCIe switch/SmartNIC/GPU drivers which are unlikely to be emulated in standard QEMU.

But wait, the bulk of the changes appear to be in `brcmfmac`, and that has USB support, and syzkaller *does* fuzz that. The `brcmsmac` change looks like a comment update, a small update on `ampdu.c`! So, the real focus is on `brcmfmac`.

Now, let's dissect the `brcmfmac` changes.
1.  `brcmf_delay` is modified to use `usleep_range` or `msleep` instead of `mdelay`. That's a functional change; it's a sleep operation, not a busy wait. This is reachable, obviously.
2.  `brcmf_pmksa_v2_op` is added and called from a few existing functions. This is interesting. It's a new feature, V2 PMKSA cache support. This is reachable via nl80211, which syzkaller can use via USB.
3.  `brcmf_netif_mon_rx` is in `core.c`, but it's only called from `msgbuf.c` (PCIe only). Hmm, is `msgbuf.c` reachable? It seems only if we have a PCIe device present. Can syzkaller emulate Broadcom PCIe devices? Usually not, unless it's a generic PCI device, or QEMU has specific emulation. QEMU doesn't emulate the Broadcom Wi-Fi PCIe cards.
    Similarly, `brcmf_flowring_block` (in `flowring.c`), `brcmf_msgbuf_schedule_txdata` (in `msgbuf.c`), and `brcmf_pcie_send_mb_data` (in `pcie.c`) are all PCIe-only. `brcmf_sdio_rxglom` (in `sdio.c`) is SDIO only, which is not what we are looking for.

So, in a standard QEMU setup with USB fuzzing, the only reachable functional changes are `brcmf_delay` and `brcmf_pmksa_v2_op`.

Let's confirm that `brcmf_pmksa_v2_op` *is* reachable via USB. It is. `brcmf_cfg80211_set_pmksa` is a `cfg80211_ops` callback and called from `nl80211_set_pmksa`. This is reachable from userspace via netlink, which syzkaller uses. This requires a `wiphy` device. The `brcmfmac` USB driver *does* register a `wiphy` during probe! So, syzkaller's USB fuzzer can emulate a `brcmfmac` USB device, and then send `NL80211_CMD_SET_PMKSA` to this `wiphy`. That will call `brcmf_cfg80211_set_pmksa`. If the emulated USB device *reports* `BRCMF_FEAT_PMKID_V2` in its firmware features, then `brcmf_pmksa_v2_op` *will* be called. This is definitely reachable, and it's worth fuzzing!

I need to confirm the configuration requirements for `brcmfmac` USB.



32/2 2026/08/01 06:19 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "config BRCMFMAC",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/Kconfig"
}

Results:
{
  "error": "no matches"
}

33/2 2026/08/01 06:19 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 28710
							output: 19
							thoughts: 14
						

Thoughts:
Okay, here's my attempt at summarizing that thought process, tailored for an expert audience:

**Hunting Down the brcmfmac Kconfig**

Right, let's get down to brass tacks. I need to get my hands on the `Kconfig` file for `brcmfmac`. No messing around here. This isn't a casual exploration; I need to understand its configuration options, dependencies, and any associated symbols. I'm after a deep dive to either modify or integrate the driver. Time to track down the most reliable source for the base configuration file. Let's start the search.



34/2 2026/08/01 06:19 tool grepper
0m Args:
{
  "Expression": "config BRCMFMAC"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig:1:config BRCMFMAC\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-2-\ttristate \"Broadcom FullMAC WLAN driver\"\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-10-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig:11:config BRCMFMAC_PROTO_BCDC\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-12-\tbool\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-13-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig:14:config BRCMFMAC_PROTO_MSGBUF\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-15-\tbool\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-16-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig:17:config BRCMFMAC_SDIO\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-18-\tbool \"SDIO bus interface support for FullMAC driver\"\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-28-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig:29:config BRCMFMAC_USB\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-30-\tbool \"USB bus interface support for FullMAC driver\"\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-39-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig:40:config BRCMFMAC_PCIE\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig-41-\tbool \"PCIE bus interface support for FullMAC driver\"\n"
}

35/2 2026/08/01 06:19 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 29484
							output: 50
							thoughts: 30
						

Thoughts:
Okay, here's my interpretation of that thought process, assuming I'm a seasoned kernel developer:

**Delving into the brcmfmac Kconfig**

Alright, time to dive into the `drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig` file. I'm assuming this is going to be the heart of the configuration options for the brcmfmac wireless driver. Given the path, I'm expecting to see all the build-time configurations, dependencies, and any device-specific settings defined here. This Kconfig file will be critical for understanding how the driver is parameterized, what features are enabled or disabled, and how it interacts with the rest of the kernel build system. I’m thinking I will find options for various Broadcom Wi-Fi chipsets, power management settings, debug flags, and maybe even firmware selection. I need to understand this to properly configure the driver for the target platform I'm working with and see what sort of flexibility this driver offers me. Let’s get to it and see what's actually in there. I'm hoping it's well-structured and documented, because these Broadcom drivers can sometimes be a bit dense.



36/2 2026/08/01 06:19 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig",
  "FirstLine": 1,
  "LineCount": 45
}

Results:
{
  "Contents": "   1:\tconfig BRCMFMAC\n   2:\t\ttristate \"Broadcom FullMAC WLAN driver\"\n   3:\t\tdepends on CFG80211\n   4:\t\tselect BRCMUTIL\n   5:\t\thelp\n   6:\t\t  This module adds support for wireless adapters based on Broadcom\n   7:\t\t  FullMAC chipsets. It has to work with at least one of the bus\n   8:\t\t  interface support. If you choose to build a module, it'll be called\n   9:\t\t  brcmfmac.ko.\n  10:\t\n  11:\tconfig BRCMFMAC_PROTO_BCDC\n  12:\t\tbool\n  13:\t\n  14:\tconfig BRCMFMAC_PROTO_MSGBUF\n  15:\t\tbool\n  16:\t\n  17:\tconfig BRCMFMAC_SDIO\n  18:\t\tbool \"SDIO bus interface support for FullMAC driver\"\n  19:\t\tdepends on (MMC = y || MMC = BRCMFMAC)\n  20:\t\tdepends on BRCMFMAC\n  21:\t\tselect BRCMFMAC_PROTO_BCDC\n  22:\t\tselect FW_LOADER\n  23:\t\tdefault y\n  24:\t\thelp\n  25:\t\t  This option enables the SDIO bus interface support for Broadcom\n  26:\t\t  IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to\n  27:\t\t  use the driver for a SDIO wireless card.\n  28:\t\n  29:\tconfig BRCMFMAC_USB\n  30:\t\tbool \"USB bus interface support for FullMAC driver\"\n  31:\t\tdepends on (USB = y || USB = BRCMFMAC)\n  32:\t\tdepends on BRCMFMAC\n  33:\t\tselect BRCMFMAC_PROTO_BCDC\n  34:\t\tselect FW_LOADER\n  35:\t\thelp\n  36:\t\t  This option enables the USB bus interface support for Broadcom\n  37:\t\t  IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to\n  38:\t\t  use the driver for an USB wireless card.\n  39:\t\n  40:\tconfig BRCMFMAC_PCIE\n  41:\t\tbool \"PCIE bus interface support for FullMAC driver\"\n  42:\t\tdepends on BRCMFMAC\n  43:\t\tdepends on PCI\n  44:\t\tselect BRCMFMAC_PROTO_MSGBUF\n  45:\t\tselect FW_LOADER\n"
}

37/2 2026/08/01 06:19 llm patch-evaluator
5m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 30449
							output: 47
							thoughts: 693
						

Thoughts:
**My Analysis of the BRCMFMAC Driver Configuration and Functionality**

Okay, so I'm diving into this driver configuration and need to make sure everything is set up correctly. First, I need to enable `BRCMFMAC` and `BRCMFMAC_USB`. That seems straightforward. I'll also add `CFG80211`, `USB`, and `MAC80211`, even though `MAC80211` might not be strictly required for `brcmfmac`. Always good to have for consistency, though.

Hmm, wait. `BRCMFMAC_USB` has a dependency check. It looks like it should be `USB = y || USB = BRCMFMAC`. Just to be safe, I'll double check that. Yes, confirmed. I'll make sure `BRCMFMAC` and `BRCMFMAC_USB` are enabled.

Next, I'm taking a closer look at `brcmf_pmksa_v2_op`. Let's refresh our memory. Ah, yes, it's defined in `cfg80211.c`, and it's responsible for handling PMKSA (Pairwise Master Key Security Association) version 2 operations. It's used in this context. It first checks if the pointer to the pmksa is null. If it is null it goes to `send` after zeroing the shadow list and pushing an empty version 2 list. If not, it does the below. It then builds a wire-format header and sends the list to the firmware. The version and length are on the wire.

Then I see it uses the following:

```c
	list->version = cpu_to_le16(BRCMF_PMKSA_VER_2);
	list->length  = cpu_to_le16(offsetof(struct brcmf_pmk_list_v2_le, pmk) +
				   npmk * sizeof(struct brcmf_pmksa_v2));

	return brcmf_fil_iovar_data_set(ifp, "pmkid_info", list, sizeof(*list));
```

Okay, so this is a functional change, and it's reachable through nl80211, right? Yes, confirmed. It uses iovar to set "pmkid_info". The patch also introduces a minor modification to `brcmf_delay` in `cfg80211.c`. It's a small change with the `usleep_range` function call. However, `brcmf_pmksa_v2_op` itself seems like a significant addition.

Let me quickly scan for any other potentially reachable functions. `brcmf_netif_mon_rx`, `brcmf_flowring_block`, `brcmf_msgbuf_schedule_txdata`, and `brcmf_pcie_send_mb_data` all seem to be PCIe-specific. The `brcmf_sdio_rxglom` seems to be SDIO-specific.

Wait, that's interesting... I just want to double check my understanding of `brcmf_flowring_block`. Is that really PCIe-only? I should verify whether `flowring.c` is actually compiled and included for USB configurations too. This could be a blind spot I need to address.



38/2 2026/08/01 06:25 tool grepper
0m Args:
{
  "Expression": "flowring.o",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile=32=brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \\\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile-33-\t\tcommonring.o \\\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile:34:\t\tflowring.o \\\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile-35-\t\tmsgbuf.o\n"
}

39/2 2026/08/01 06:25 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 32087
							output: 24
							thoughts: 234
						

Thoughts:
**Analyzing the Reachability of `flowring.o` and Related Code Paths**

Okay, so it's clear that `flowring.o` is *definitely* only compiled when `CONFIG_BRCMFMAC_PROTO_MSGBUF` is enabled. And, that `CONFIG_BRCMFMAC_PROTO_MSGBUF` gets selected via `CONFIG_BRCMFMAC_PCIE`. Therefore, `flowring.c` is exclusively tied to PCIe, no surprises there.

Now, what about `brcmf_sdio_rxglom`? Hmm, that's tucked away in `sdio.c`, meaning it's only compiled with `CONFIG_BRCMFMAC_SDIO` enabled. Given Syzkaller's current lack of SDIO emulation, that path is clearly not relevant for fuzzing, at least not directly.

So, if we're ignoring SDIO, that narrows the attack surface. From what I see, the only reachable areas, initially, are within `cfg80211.c` and potentially `core.c`, but only if `brcmf_netif_mon_rx` is called. Ah, but that function, `brcmf_netif_mon_rx`, *is* in `core.c`, which is always compiled. However, I need to verify its call sites. If the primary call site is from `msgbuf.c` that would constrain it to PCIe use as well. Let me double-check the code for any other call locations just to be absolutely certain. We can't afford to overlook anything, however small.



40/2 2026/08/01 06:25 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=434=struct brcmf_radiotap_info {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-438-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:439:void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-440-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h=220=void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h:221:void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h-222-void brcmf_net_detach(struct net_device *ndev, bool locked);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1200=brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1240-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1241:\t\tbrcmf_netif_mon_rx(ifp, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1242-\t\treturn;\n"
}

41/2 2026/08/01 06:25 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 33230
							output: 29
							thoughts: 1032
						

Thoughts:
**Analyzing the Relevant Code for Fuzzing**

Okay, so I'm looking at `msgbuf.c` and trying to identify the best entry points for fuzzing based on the patch. Based on the code, these functions are reachable: `brcmf_pmksa_v2_op`, `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, and `brcmf_cfg80211_flush_pmksa`.

`brcmf_cfg80211_set_pmksa` is interesting because, while it's not entirely new, it's been modified to call the new `brcmf_pmksa_v2_op`. Initially, `brcmf_pmksa_v2_op` seemed like the key function to focus on. However, it's a static helper function.

The prompt directs us to prioritize non-static, non-inlined API entrypoints. Let's check the static status of the functions. `brcmf_pmksa_v2_op` is indeed static, so it's not an ideal candidate. `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, and `brcmf_cfg80211_flush_pmksa` are also static.

Wait a minute, although they are static, they are assigned to `cfg80211_ops`, making them API entry points. That makes them better choices than `brcmf_pmksa_v2_op`.

I also noticed `brcmf_netif_mon_rx` which is non-static, but it is reached via PCIe. The prompt states we don't want to include PCIe-specific code that requires hardware, but since the patch also includes USB-reachable code (related to `brcmf_pmksa_v2_op`), the patch is worth fuzzing. I'll focus on the functions reachable through standard means.

Therefore, for `FocusSymbols`, I'll list `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, and `brcmf_cfg80211_flush_pmksa` as the most promising targets, despite their static nature. Their assignment to `cfg80211_ops` makes them entry points. I should also check `cfg80211.c` for `brcmf_cfg80211_set_pmksa` . It's good to be cautious and check for inlining, but these `cfg80211` callbacks are most likely my targets.



42/2 2026/08/01 06:25 tool grepper
0m Args:
{
  "Expression": "brcmf_cfg80211_set_pmksa"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4481=static s32\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4482:brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4483-\t\t\t struct cfg80211_pmksa *pmksa)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=6078=static struct cfg80211_ops brcmf_cfg80211_ops = {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-6099-\t.resume = brcmf_cfg80211_resume,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:6100:\t.set_pmksa = brcmf_cfg80211_set_pmksa,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-6101-\t.del_pmksa = brcmf_cfg80211_del_pmksa,\n"
}

43/2 2026/08/01 06:25 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 35315
							output: 26
							thoughts: 254
						

Thoughts:
**My Analysis of Potential Entry Points**

Okay, these seem like the likely candidates – the ones that could serve as entry points into the system. Let me just quickly confirm a few things to be sure.

Right, what about `brcmf_netif_mon_rx`? It's not static, so I should definitely include it as a possibility, just to be thorough. Now, how about `brcmf_flowring_block`? That one *is* static, so I can probably exclude it for now. And `brcmf_msgbuf_schedule_txdata`? Also static, so it's off the list. Then there's `brcmf_pcie_send_mb_data`. Non-static again, so that's a keeper. And finally, `brcmf_sdio_rxglom`, which is static, so I'll leave it.

Alright, so taking all of that into account, I believe the best focus symbols for this analysis are:

*   `brcmf_cfg80211_set_pmksa`
*   `brcmf_cfg80211_del_pmksa`
*   `brcmf_cfg80211_flush_pmksa`
*   `brcmf_netif_mon_rx`
*   `brcmf_pcie_send_mb_data`

Hang on, let me quickly double-check where `brcmf_pcie_send_mb_data` resides. Ah, yes, it's defined in `pcie.c`. Good, and let me just make sure it's *still* non-static...



44/2 2026/08/01 06:25 tool grepper
0m Args:
{
  "Expression": "brcmf_pcie_send_mb_data"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c=783=static int\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c:784:brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-785-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c=850=static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-867-\t\tbrcmf_dbg(PCIE, \"D2H_MB_DATA: DEEP SLEEP REQ\\n\");\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c:868:\t\tbrcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_DS_ACK);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-869-\t\tbrcmf_dbg(PCIE, \"D2H_MB_DATA: sent DEEP SLEEP ACK\\n\");\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c=2676=static int brcmf_pcie_pm_enter_D3(struct device *dev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2689-\tdevinfo-\u003embdata_completed = false;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c:2690:\tbrcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2691-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c=2706=static int brcmf_pcie_pm_leave_D3(struct device *dev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2721-\t\tbrcmf_dbg(PCIE, \"Try to wakeup device....\\n\");\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c:2722:\t\tif (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2723-\t\t\tgoto cleanup;\n"
}

45/2 2026/08/01 06:25 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 36773
							output: 222
							thoughts: 1202
						

Thoughts:
**Refining the Syzkaller Configuration for Broadcom Wi-Fi Driver Coverage**

Okay, so I'm focusing on enhancing Syzkaller's fuzzing coverage for this `brcmfmac` driver patch. I've been thinking through the best approach to configure Syzkaller to effectively test the changes.

Initially, I identified some functions of interest. I started with `brcmf_cfg80211_set_pmksa` because it's the entry point for the new V2 PMKSA logic. I included its related functions `brcmf_cfg80211_del_pmksa` and `brcmf_cfg80211_flush_pmksa` as well because they are also involved in the PMKSA cache operations. I also noted `brcmf_netif_mon_rx` because it looked like a non-static, modified function related to radiotap header modifications in monitor mode.

Based on these initial observations, I decided to check which configs would enable the relevant functionality, starting with `BRCMFMAC`, and `BRCMFMAC_USB`. Because `BRCMFMAC_USB` depends on `USB`, I confirmed `USB` should also be enabled. Then, I observed that `BRCMFMAC` has a dependency on `CFG80211`, so that should be enabled too. Since Syzkaller can emulate the Broadcom device via its USB fuzzer, I'm confident that this approach would be suitable.

However, I also realized that the patch touches PCIe mailbox polling. To ensure comprehensive coverage, I'll also enable `BRCMFMAC_PCIE` as well. For good measure, I could also enable `BRCMFMAC_SDIO` but Syzkaller doesn't fuzz SDIO, so I decided not to enable it. I'll stick to listing `BRCMFMAC`, `BRCMFMAC_USB`, and `BRCMFMAC_PCIE` as enabled configs.

Let's double check my analysis to ensure that `brcmf_cfg80211_set_pmksa` is truly worth listing. After reviewing the patch's reasoning, my understanding is this patch introduces V2 PMKSA cache operations to the driver that are reachable via `cfg80211` netlink commands and that Syzkaller can emulate this. This also includes the modification to radiotap header insertion in monitor mode and PCIe mailbox polling. The focus will be on the added V2 PMKSA cache logic and the functional changes.

I've examined the `set-results` parameters to ensure that they are correctly stated: `WorthFuzzing` is true. The focus symbols initially are: `["brcmf_cfg80211_set_pmksa", "brcmf_cfg80211_del_pmksa", "brcmf_cfg80211_flush_pmksa", "brcmf_netif_mon_rx"]`. The `EnableConfigs` are correctly listed as `["BRCMFMAC", "BRCMFMAC_USB", "BRCMFMAC_PCIE", "CFG80211"]`.

I've gone through the code again, considering static versus non-static functions. `brcmf_cfg80211_set_pmksa` is static, but it's an API entry point, so it is worthwhile to include it in the focus. Also, based on my previous analysis, I confirmed `brcmf_netif_mon_rx` is non-static and modified, making it a good candidate for fuzzing.

I've also observed the following during my code review:
*   `brcmf_flowring_attach` is modified and it initializes `if_blocked_cnt`
*   `brcmf_proto_msgbuf_attach` is non-static, so I can also include it

My final `FocusSymbols` are: `["brcmf_cfg80211_set_pmksa", "brcmf_cfg80211_del_pmksa", "brcmf_cfg80211_flush_pmksa", "brcmf_netif_mon_rx", "brcmf_flowring_attach", "brcmf_proto_msgbuf_attach"]`.

The configs are: `BRCMFMAC`, `BRCMFMAC_USB`, `BRCMFMAC_PCIE`, `CFG80211`.

It looks like this is a good, refined setup for Syzkaller to begin fuzzing the relevant parts of this patch, ensuring coverage of the new PMKSA logic and functional changes.


46/2 2026/08/01 06:26 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB",
    "BRCMFMAC_PCIE",
    "CFG80211"
  ],
  "FocusSymbols": [
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa",
    "brcmf_netif_mon_rx"
  ],
  "Reasoning": "The patch adds support for V2 PMKSA cache operations in the brcmfmac driver, which is reachable via cfg80211 netlink commands when a Broadcom Wi-Fi device is present. Syzkaller can emulate such a device via its USB fuzzer, making this new logic reachable and testable. The patch also modifies radiotap header insertion in monitor mode and PCIe mailbox polling, which are functional changes.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB",
    "BRCMFMAC_PCIE",
    "CFG80211"
  ],
  "FocusSymbols": [
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa",
    "brcmf_netif_mon_rx"
  ],
  "Reasoning": "The patch adds support for V2 PMKSA cache operations in the brcmfmac driver, which is reachable via cfg80211 netlink commands when a Broadcom Wi-Fi device is present. Syzkaller can emulate such a device via its USB fuzzer, making this new logic reachable and testable. The patch also modifies radiotap header insertion in monitor mode and PCIe mailbox polling, which are functional changes.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)