AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/02 00:46 flow patch-triage
6m Args:
null

Results:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB"
  ],
  "FocusSymbols": [
    "brcmf_pmksa_v2_op",
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa"
  ],
  "Reasoning": "The patch modifies several components of the Broadcom Wi-Fi drivers. Changes to PCIe (msgbuf.c, flowring.c, pcie.c) and SDIO (sdio.c) are unreachable in standard virtualized environments as they require physical hardware. However, the brcmfmac driver supports USB, which can be emulated by syzkaller. The patch adds `brcmf_pmksa_v2_op` in the shared cfg80211.c to handle V2 PMKSA cache updates. This is reachable via cfg80211 netlink commands (e.g., NL80211_CMD_SET_PMKSA) if the emulated USB device reports a firmware version \u003e= 12. Therefore, this functional change is fuzzable.",
  "WorthFuzzing": true
}

1/1 2026/08/02 00:46 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 45369e14392e1f94284469c3866db7e21cdbc4ae\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sun Aug 2 00:46:16 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..2375c2f9d97a2 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,109 @@ 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/* Write the updated entry count back to shadow BEFORE we overwrite\n+\t * list-\u003elength with the wire-format byte length at send:.  If we\n+\t * don't do this here, the next call will read a byte-length back\n+\t * as an entry count and silently corrupt the list.\n+\t */\n+\tlist-\u003elength = cpu_to_le16(npmk);\n+\n+send:\n+\t/* Build the wire-format byte length and send the full list to firmware.\n+\t * Read npmk back from the shadow (handles the flush path where npmk=0).\n+\t */\n+\tnpmk = le16_to_cpu(list-\u003elength);\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 +4503,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 +4547,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 +4588,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..eefc437dd0550 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,55 @@ 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-\n-\t\t/* TODO: 4 bytes with receive status? */\n-\t\tskb-\u003elen -= 4;\n+\t\t/* Insert our radiotap header with RSSI data */\n+\t\tif (skb_cow_head(skb, sizeof(*rtap)))\n+\t\t\tgoto drop;\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/* 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\tif (skb_cow_head(skb, sizeof(*radiotap)))\n+\t\t\tgoto drop;\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;\n@@ -478,6 +488,10 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)\n \tskb-\u003eprotocol = htons(ETH_P_802_2);\n \n \tbrcmf_netif_rx(ifp, skb);\n+\treturn;\n+\n+drop:\n+\tbrcmu_pkt_buf_free_skb(skb);\n }\n \n static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,\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/02 00:46 agent patch-evaluator
6m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB"
  ],
  "FocusSymbols": [
    "brcmf_pmksa_v2_op",
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa"
  ],
  "Reasoning": "The patch modifies several components of the Broadcom Wi-Fi drivers. Changes to PCIe (msgbuf.c, flowring.c, pcie.c) and SDIO (sdio.c) are unreachable in standard virtualized environments as they require physical hardware. However, the brcmfmac driver supports USB, which can be emulated by syzkaller. The patch adds `brcmf_pmksa_v2_op` in the shared cfg80211.c to handle V2 PMKSA cache updates. This is reachable via cfg80211 netlink commands (e.g., NL80211_CMD_SET_PMKSA) if the emulated USB device reports a firmware version \u003e= 12. Therefore, this functional change is fuzzable.",
  "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 45369e14392e1f94284469c3866db7e21cdbc4ae
Author: syz-cluster <triage@syzkaller.com>
Date:   Sun Aug 2 00:46:16 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..2375c2f9d97a2 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,109 @@ 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--;
+	}
+
+	/* Write the updated entry count back to shadow BEFORE we overwrite
+	 * list->length with the wire-format byte length at send:.  If we
+	 * don't do this here, the next call will read a byte-length back
+	 * as an entry count and silently corrupt the list.
+	 */
+	list->length = cpu_to_le16(npmk);
+
+send:
+	/* Build the wire-format byte length and send the full list to firmware.
+	 * Read npmk back from the shadow (handles the flush path where npmk=0).
+	 */
+	npmk = le16_to_cpu(list->length);
+	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 +4503,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 +4547,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 +4588,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..eefc437dd0550 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -431,45 +431,55 @@ 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));
-
-		/* TODO: 4 bytes with receive status? */
-		skb->len -= 4;
+		/* Insert our radiotap header with RSSI data */
+		if (skb_cow_head(skb, sizeof(*rtap)))
+			goto drop;
+		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;
+
+		/* 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 */
+		if (skb_cow_head(skb, sizeof(*radiotap)))
+			goto drop;
 		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;
@@ -478,6 +488,10 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 	skb->protocol = htons(ETH_P_802_2);
 
 	brcmf_netif_rx(ifp, skb);
+	return;
+
+drop:
+	brcmu_pkt_buf_free_skb(skb);
 }
 
 static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
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/02 00:46 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13606
							output: 48
							thoughts: 1106
						

Thoughts:
**Fuzzing Feasibility Analysis for brcmfmac/brcmsmac Kernel Patches**

Okay, so I have a patch series applied to the kernel targeting the `brcmfmac` and `brcmsmac` drivers within the Broadcom 80211 wireless stack. My immediate concern is whether these changes introduce new functional behavior that necessitates fuzzing. Let's break it down:

First, examining the changes in `brcmfmac/cfg80211.c`, I see a shift from `mdelay`/`msleep` to `usleep_range`, which is common. The addition of `brcmf_pmksa_v2_op` and its integration into PMKSA operations is noteworthy, especially if `BRCMF_FEAT_PMKID_V2` is enabled. That adds a new code path. This also touches the header in `cfg80211.h`.

In `brcmfmac/core.c`, the handling of `BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR` to insert a radiotap header is a significant addition, specifically related to monitor mode. This introduces new data processing and control flow, which definitely warrants a closer look.

`brcmfmac/flowring.c` introduces an atomic counter to track blocked rings, that seems like a performance optimization, though I'll see how it can be attacked.

The changes in `brcmfmac/msgbuf.c` are interesting. Increasing `NR_TX_PKTIDS` and altering the `msleep` calls, along with the modification to `brcmf_msgbuf_schedule_txdata`, are likely related to packet transmission and buffer management. This is definitely a potential attack surface.

The `brcmfmac/pcie.c` changes, particularly the `usleep_range` backoff in `brcmf_pcie_send_mb_data` and the sleep changes in `brcmf_pcie_release_irq`, suggests optimization and error handling. This may be of interest for PCIe-specific fuzzing. The changes to `sdio.c` look like a basic locking reordering, so probably nothing to worry about. The change in `ampdu.c` is only a comment.

The critical question now is, are these changes fuzzable in a practical environment? Broadcom drivers are typically tied to physical hardware (PCIe, SDIO, USB). But wait, `brcmfmac` supports USB. Can we emulate a USB device? Syzkaller has `syz_usb_connect`! That’s a game changer. Let me check if `brcmfmac` has a USB driver... Yes, `drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c`.

Okay, the patch touches `cfg80211.c`, `core.c`, `flowring.c`, `msgbuf.c`, `pcie.c`, and `sdio.c`. `cfg80211.c`, `core.c`, `flowring.c`, and `msgbuf.c` are core parts of `brcmfmac` and *could* be reachable through USB, SDIO, or PCIe. In particular, `msgbuf.c` is used by PCIe. And `flowring.c` is used by PCIe and possibly others. Time to check how the `brcmfmac` USB driver interacts with `flowring` and `msgbuf` - that could be the key to triggering these changes through a virtualized environment.



4/2 2026/08/02 00:46 tool grepper
0m Args:
{
  "Expression": "brcmf_flowring",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-27-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:28:static const u8 brcmf_flowring_prio2fifo[] = {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-29-\t0,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c=42=static bool\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:43:brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN])\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-44-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:45:\tstruct brcmf_flowring_tdls_entry *search;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-46-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-58-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:59:u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-60-\t\t\t  u8 prio, u8 ifidx)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-61-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:62:\tstruct brcmf_flowring_hash *hash;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-63-\tu16 hash_idx;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-69-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:70:\tfifo = brcmf_flowring_prio2fifo[prio];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-71-\tsta = (flow-\u003eaddr_mode[ifidx] == ADDR_INDIRECT);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-77-\tif ((sta) \u0026\u0026 (flow-\u003etdls_active) \u0026\u0026\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:78:\t    (brcmf_flowring_is_tdls_mac(flow, da))) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-79-\t\tsta = false;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-102-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:103:u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-104-\t\t\t  u8 prio, u8 ifidx)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-105-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:106:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:107:\tstruct brcmf_flowring_hash *hash;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-108-\tu16 hash_idx;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-114-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:115:\tfifo = brcmf_flowring_prio2fifo[prio];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-116-\tsta = (flow-\u003eaddr_mode[ifidx] == ADDR_INDIRECT);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-122-\tif ((sta) \u0026\u0026 (flow-\u003etdls_active) \u0026\u0026\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:123:\t    (brcmf_flowring_is_tdls_mac(flow, da))) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-124-\t\tsta = false;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-167-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:168:u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-169-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:170:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-171-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-177-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:178:static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-179-\t\t\t\t bool blocked)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-180-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:181:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-182-\tstruct brcmf_bus *bus_if;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-195-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:196:\tifidx = brcmf_flowring_ifidx_get(flow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-197-\tring-\u003eblocked = blocked;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-232-\t * Reading the atomic is safe here: we hold block_lock, so no\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:233:\t * concurrent brcmf_flowring_block() call can race the update\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-234-\t * we just made above.\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-255-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:256:void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-257-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-258-\tstruct brcmf_bus *bus_if = dev_get_drvdata(flow-\u003edev);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:259:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-260-\tstruct brcmf_if *ifp;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-268-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:269:\tifidx = brcmf_flowring_ifidx_get(flow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-270-\tifp = brcmf_get_ifp(bus_if-\u003edrvr, ifidx);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-271-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:272:\tbrcmf_flowring_block(flow, flowid, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-273-\thash_idx = ring-\u003ehash_id;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-287-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:288:u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-289-\t\t\t   struct sk_buff *skb)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-290-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:291:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-292-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-298-\t    (skb_queue_len(\u0026ring-\u003eskblist) \u003e BRCMF_FLOWRING_HIGH)) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:299:\t\tbrcmf_flowring_block(flow, flowid, true);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-300-\t\tbrcmf_dbg(MSGBUF, \"Flowcontrol: BLOCK for ring %d\\n\", flowid);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-307-\t\tif (skb_queue_len(\u0026ring-\u003eskblist) \u003c BRCMF_FLOWRING_LOW)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:308:\t\t\tbrcmf_flowring_block(flow, flowid, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-309-\t}\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-313-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:314:struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-315-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:316:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-317-\tstruct sk_buff *skb;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-326-\t    (skb_queue_len(\u0026ring-\u003eskblist) \u003c BRCMF_FLOWRING_LOW)) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:327:\t\tbrcmf_flowring_block(flow, flowid, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-328-\t\tbrcmf_dbg(MSGBUF, \"Flowcontrol: OPEN for ring %d\\n\", flowid);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-334-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:335:void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-336-\t\t\t     struct sk_buff *skb)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-337-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:338:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-339-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-345-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:346:u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-347-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:348:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-349-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-360-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:361:void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-362-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:363:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-364-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-374-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:375:u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-376-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:377:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-378-\tu16 hash_idx;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-386-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:387:struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-388-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:389:\tstruct brcmf_flowring *flow;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-390-\tu32 i;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-408-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:409:void brcmf_flowring_detach(struct brcmf_flowring *flow)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-410-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-412-\tstruct brcmf_pub *drvr = bus_if-\u003edrvr;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:413:\tstruct brcmf_flowring_tdls_entry *search;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:414:\tstruct brcmf_flowring_tdls_entry *remove;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-415-\tu16 flowid;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-431-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:432:void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-433-\t\t\t\t\tenum proto_addr_mode addr_mode)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-453-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:454:void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-455-\t\t\t\tu8 peer[ETH_ALEN])\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-458-\tstruct brcmf_pub *drvr = bus_if-\u003edrvr;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:459:\tstruct brcmf_flowring_hash *hash;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:460:\tstruct brcmf_flowring_tdls_entry *prev;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:461:\tstruct brcmf_flowring_tdls_entry *search;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-462-\tu32 i;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-500-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:501:void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-502-\t\t\t\t  u8 peer[ETH_ALEN])\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-503-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:504:\tstruct brcmf_flowring_tdls_entry *tdls_entry;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c:505:\tstruct brcmf_flowring_tdls_entry *search;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c-506-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-14-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:15:struct brcmf_flowring_hash {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-16-\tu8 mac[ETH_ALEN];\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h=22=enum ring_status {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-27-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:28:struct brcmf_flowring_ring {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-29-\tu16 hash_id;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-44-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:45:struct brcmf_flowring_tdls_entry {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-46-\tu8 mac[ETH_ALEN];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:47:\tstruct brcmf_flowring_tdls_entry *next;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-48-};\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-49-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:50:struct brcmf_flowring {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-51-\tstruct device *dev;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:52:\tstruct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-53-\tspinlock_t block_lock;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-55-\t/* Per-interface count of currently blocked open rings.\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:56:\t * Maintained atomically so brcmf_flowring_block() can check\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-57-\t * whether any sibling ring is already blocked in O(1) without\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-62-\tbool tdls_active;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:63:\tstruct brcmf_flowring_tdls_entry *tdls_entry;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:64:\tstruct brcmf_flowring_ring *rings[] __counted_by(nrofrings);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-65-};\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-67-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:68:u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-69-\t\t\t  u8 prio, u8 ifidx);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:70:u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-71-\t\t\t  u8 prio, u8 ifidx);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:72:void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:73:void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:74:u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:75:u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-76-\t\t\t   struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:77:struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:78:void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-79-\t\t\t     struct sk_buff *skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:80:u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:81:u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:82:struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:83:void brcmf_flowring_detach(struct brcmf_flowring *flow);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:84:void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-85-\t\t\t\t\tenum proto_addr_mode addr_mode);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:86:void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-87-\t\t\t\tu8 peer[ETH_ALEN]);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h:88:void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h-89-\t\t\t\t  u8 peer[ETH_ALEN]);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=262=struct brcmf_msgbuf {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-298-\tstruct brcmf_msgbuf_pktids *rx_pktids;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:299:\tstruct brcmf_flowring *flow;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-300-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=581=brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-592-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:593:\tbrcmf_flowring_delete(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-594-}\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=616=brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-635-\t\tbphy_err(drvr, \"dma_alloc_coherent failed\\n\");\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:636:\t\tbrcmf_flowring_delete(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-637-\t\treturn BRCMF_FLOWRING_INVALID_ID;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-657-\tcreate-\u003emsg.request_id = 0;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:658:\tcreate-\u003etid = brcmf_flowring_tid(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-659-\tcreate-\u003eflow_ring_id = cpu_to_le16(flowid +\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=698=static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-709-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:710:\tflowid = brcmf_flowring_create(msgbuf-\u003eflow, eh-\u003eh_dest,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-711-\t\t\t\t       skb-\u003epriority, ifidx);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=731=static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-732-{\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:733:\tstruct brcmf_flowring *flow = msgbuf-\u003eflow;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-734-\tstruct brcmf_pub *drvr = msgbuf-\u003edrvr;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-750-\tcount = BRCMF_MSGBUF_TX_FLUSH_CNT2 - BRCMF_MSGBUF_TX_FLUSH_CNT1;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:751:\twhile (brcmf_flowring_qlen(flow, flowid)) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:752:\t\tskb = brcmf_flowring_dequeue(flow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-753-\t\tif (skb == NULL) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-754-\t\t\tbphy_err(drvr, \"No SKB, but qlen %d\\n\",\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:755:\t\t\t\t brcmf_flowring_qlen(flow, flowid));\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-756-\t\t\tbreak;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-761-\t\t\t\t\t     \u0026physaddr, \u0026pktid)) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:762:\t\t\tbrcmf_flowring_reinsert(flow, flowid, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-763-\t\t\tbphy_err(drvr, \"No PKTID available !!\\n\");\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-769-\t\t\t\t\t       msgbuf-\u003etx_pktids, pktid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:770:\t\t\tbrcmf_flowring_reinsert(flow, flowid, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-771-\t\t\tbreak;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-778-\t\ttx_msghdr-\u003emsg.request_id = cpu_to_le32(pktid + 1);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:779:\t\ttx_msghdr-\u003emsg.ifidx = brcmf_flowring_ifidx_get(flow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-780-\t\ttx_msghdr-\u003eflags = BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=853=static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-856-\tstruct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr-\u003eproto-\u003epd;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:857:\tstruct brcmf_flowring *flow = msgbuf-\u003eflow;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-858-\tstruct ethhdr *eh = (struct ethhdr *)(skb-\u003edata);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-862-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:863:\tflowid = brcmf_flowring_lookup(flow, eh-\u003eh_dest, skb-\u003epriority, ifidx);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-864-\tif (flowid == BRCMF_FLOWRING_INVALID_ID) {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-868-\t\t} else {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:869:\t\t\tbrcmf_flowring_enqueue(flow, flowid, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-870-\t\t\treturn 0;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-872-\t}\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:873:\tqueue_count = brcmf_flowring_enqueue(flow, flowid, skb);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-874-\tforce = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=882=brcmf_msgbuf_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-886-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:887:\tbrcmf_flowring_configure_addr_mode(msgbuf-\u003eflow, ifidx, addr_mode);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-888-}\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=892=brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-895-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:896:\tbrcmf_flowring_delete_peer(msgbuf-\u003eflow, ifidx, peer);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-897-}\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=901=brcmf_msgbuf_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-904-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:905:\tbrcmf_flowring_add_tdls_peer(msgbuf-\u003eflow, ifidx, peer);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-906-}\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1286=brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1307-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1308:\tbrcmf_flowring_open(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1309-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1315=brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1330-\t\tbphy_err(drvr, \"Flowring deletion failed, code %d\\n\", status);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1331:\t\tbrcmf_flowring_delete(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1332-\t\treturn;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1422=int brcmf_proto_msgbuf_rx_trigger(struct device *dev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1442-\t\tcommonring = msgbuf-\u003eflowrings[flowid];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1443:\t\tqlen = brcmf_flowring_qlen(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1444-\t\tif ((qlen \u003e BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) ||\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1454=void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1459-\tstruct brcmf_commonring *commonring_del = msgbuf-\u003eflowrings[flowid];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1460:\tstruct brcmf_flowring *flow = msgbuf-\u003eflow;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1461-\tvoid *ret_ptr;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1499-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1500:\tifidx = brcmf_flowring_ifidx_get(msgbuf-\u003eflow, flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1501-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1522=static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1528-\tu16 i;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1529:\tstruct brcmf_flowring_ring *ring;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1530:\tstruct brcmf_flowring_hash *hash;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1531-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1580=int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1663-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1664:\tmsgbuf-\u003eflow = brcmf_flowring_attach(drvr-\u003ebus_if-\u003edev,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1665-\t\t\t\t\t     if_msgbuf-\u003emax_flowrings);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1710=void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1730-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1731:\t\tbrcmf_flowring_detach(msgbuf-\u003eflow);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1732-\t\tdma_free_coherent(drvr-\u003ebus_if-\u003edev,\n"
}

5/2 2026/08/02 00:46 llm patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 28199
							output: 47
							thoughts: 69
						

Thoughts:
**Investigating `msgbuf.c` Usage**

Okay, so `msgbuf.c` is definitely tied to the PCIe driver, that's my starting point. Now, to get a better handle on the context, I need to see *how* it's being used within that driver family. My next step is to examine the `brcmfmac` directory. Specifically, I'll drill down into `drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c` – that's a natural candidate given the initial hint. I'll also glance at `usb.c` while I'm at it, just to see if there's any cross-pollination or overlap in how these Broadcom wireless drivers are structured. It's not the most likely place to find a connection, but it's worth a quick look to rule it out – I should have a clear answer on whether `usb.c` interacts with `msgbuf.c`.



6/2 2026/08/02 00:47 tool grepper
0m Error:
no matches

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

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

7/2 2026/08/02 00:47 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 28546
							output: 48
							thoughts: 269
						

Thoughts:
**Analyzing the Patch's Worth for Fuzzing**

Okay, so this patch touches `msgbuf.c` and `flowring.c`. Those files scream "PCIe" to me, right? But then I remember `brcmfmac`. Now, the prompt specifically says to return `WorthFuzzing=false` for vendor-specific PCIe drivers like `mlxsw`, `qed`, `amdgpu`, etc. – drivers that *need* actual hardware not emulated in QEMU. Is `brcmfmac` one of those?

Hang on a second… isn't `brcmfmac` a Wi-Fi driver? Yeah, it is. And Syzkaller has `mac80211_hwsim` for Wi-Fi. But `brcmfmac` is a FullMAC driver, which complicates things a bit. Does Syzkaller fuzz *this* specific driver? I'm not entirely sure.

Then I remember Syzkaller's USB fuzzing capabilities, which *could* potentially cover the USB side of `brcmfmac`. That said, the fact that the patch also touches `flowring.c` and `msgbuf.c` – which are pretty much PCIe specific – throws a wrench in the works.

Wait… does `sdio.c` utilize `msgbuf.c`? That would change things if this is used by SDIO as well. It's time to dig deeper and actually check the cross-references.



8/2 2026/08/02 00:47 tool grepper
0m Error:
no matches

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

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

9/2 2026/08/02 00:47 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 29195
							output: 49
							thoughts: 316
						

Thoughts:
**Analyzing the Reachability of Driver Functions via USB**

Okay, so I'm looking at this patch and immediately, my expert eye goes to the driver landscape. I see changes in `msgbuf.c` and `flowring.c`, which I know are pretty much PCIe-specific. But then there's `cfg80211.c`, and that's where things get interesting. That one's shared across multiple interfaces – USB, SDIO, and PCIe, making it a potential target. This patch specifically modifies `brcmf_pmksa_v2_op` in `cfg80211.c`, which is concerning as it is a central function. It also touches `brcmf_netif_mon_rx` in `core.c` and `brcmf_sdio_rxglom` in `sdio.c`.

Now, the million-dollar question: Can syzkaller even touch these SDIO drivers effectively? I know it doesn't have a dedicated generic SDIO fuzzer. That said, I need to investigate if there's a possible path. Hang on, the prompt says the code paths should be accessible in a virtualized environment. That's a good filter. It explicitly mentions the difficulty in reaching code paths that rely on very specific, emulated hardware like USB gadget or mac80211_hwsim.

So, the next obvious step is to figure out if `brcmfmac` is even reachable via USB. Luckily, I know there's a USB driver for it, so there's a good chance. Let's dig deeper. The real test is whether the functions being modified, `brcmf_pmksa_v2_op` and `brcmf_netif_mon_rx`, are indeed reachable via USB.

Alright, so I need to trace the call paths. I recall that `brcmf_netif_mon_rx` is called from `brcmf_rx_frame` in `core.c`. The question becomes whether `brcmf_rx_frame` is called by the USB driver. If so, that's my entry point for fuzzing these crucial functions.



10/2 2026/08/02 00:47 tool grepper
0m Args:
{
  "Expression": "brcmf_rx_frame",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h=279=static inline void brcmf_bus_remove(struct brcmf_bus *bus)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-293-/* Receive frame for delivery to OS.  Callee disposes of rxp. */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h:294:void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-295-\t\t    bool inirq);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=497=static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-515-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:516:void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-517-\t\t    bool inirq)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c=1514=static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-1731-\t\t\telse\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:1732:\t\t\t\tbrcmf_rx_frame(bus-\u003esdiodev-\u003edev, pfirst,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-1733-\t\t\t\t\t       false, false);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c=1870=static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-2065-\t\telse\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:2066:\t\t\tbrcmf_rx_frame(bus-\u003esdiodev-\u003edev, pkt,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-2067-\t\t\t\t       false, false);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=507=static void brcmf_usb_rx_complete(struct urb *urb)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-527-\t\tskb_put(skb, urb-\u003eactual_length);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:528:\t\tbrcmf_rx_frame(devinfo-\u003edev, skb, true, true);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-529-\t\tbrcmf_usb_rx_refill(devinfo, req);\n"
}

11/2 2026/08/02 00:47 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 31014
							output: 55
							thoughts: 90
						

Thoughts:
Okay, here's my interpretation of that thought process, from an expert's perspective:

**Diving into the BRCMF Rx Path**

Right, so I'm tracing the data flow in this BRCMF driver. My initial understanding, confirmed by my code reading, is that `brcmf_rx_frame` is indeed the entry point that's called when data is received over USB, as `usb.c` clearly indicates. Interesting. Now, if the network interface is operating in monitor mode, `brcmf_netif_mon_rx` seems to get invoked from within `brcmf_rx_frame`, which makes perfect sense. I remember that interaction. But it's always good to double-check these assumptions...Just to be thorough, I'm going to quickly verify that `brcmf_netif_mon_rx` is *actually* called from `brcmf_rx_frame`. Time to jump into `core.c` and confirm that's the function's origin. Shouldn't take long.



12/2 2026/08/02 00:47 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c"
}

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"
}

13/2 2026/08/02 00:47 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 31564
							output: 52
							thoughts: 20
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach this task, as if these were my internal thoughts:

**Investigating the `brcmf_netif_mon_rx` Callers**

Alright, the next logical step here is to pinpoint exactly *where* `brcmf_netif_mon_rx` is being invoked. Understanding its call graph is crucial for comprehending its role in the broader system architecture. I need to trace its usage – identify all the functions that directly or indirectly call this specific function. This will give me a better grasp of the context in which it operates. Knowing the callers will expose the input parameters and any setup that is happening before the function is called. With this information, I can analyze potential issues, understand the flow, and quickly assess any areas of interest. This should be a quick and easy task to gather this information. Let's start digging.



14/2 2026/08/02 00:47 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

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"
}

15/2 2026/08/02 00:47 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 32366
							output: 55
							thoughts: 393
						

Thoughts:
**My Analysis of Potential Attack Vectors**

Okay, so `brcmf_netif_mon_rx` is called from `msgbuf.c`. Wait a minute, `msgbuf.c` is specifically tied to PCIe. That's a limited vector. Does anything else call that function? Nope, just `msgbuf.c`. So that's probably a dead end for USB.

Let's switch gears and look at `brcmf_pmksa_v2_op`, found in `cfg80211.c`. Crucially, can `cfg80211.c` be reached through USB? Yes, it's the generic cfg80211 interface for `brcmfmac`, so that's a much more promising target.

The next question is how to trigger `brcmf_pmksa_v2_op`. It appears it is called through `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, and `brcmf_cfg80211_flush_pmksa`. These are standard cfg80211 operations, which is good. Could Syzkaller hit these ops? I think so, yes, via netlink commands to cfg80211, like `NL80211_CMD_SET_PMKSA`.

But hold on, does the `brcmfmac` USB driver register these ops? Thankfully, yes, `brcmfmac` registers a `wiphy` with these ops.

A critical point, though, is that `brcmf_pmksa_v2_op` is only actually called if `brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2)` evaluates to true. So, I need to check where `BRCMF_FEAT_PMKID_V2` is set to see if this is even feasible to exploit on a USB system.



16/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "BRCMF_FEAT_PMKID_V2",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4487=brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4505-\t\treturn brcmf_pmksa_v3_op(ifp, pmksa, true);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4506:\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4507-\t\treturn brcmf_pmksa_v2_op(cfg, ifp, pmksa, true);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4532=brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4549-\t\treturn brcmf_pmksa_v3_op(ifp, pmksa, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4550:\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4551-\t\treturn brcmf_pmksa_v2_op(cfg, ifp, pmksa, false);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4579=brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4590-\t\treturn brcmf_pmksa_v3_op(ifp, NULL, false);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4591:\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4592-\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"
}

17/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 34213
							output: 54
							thoughts: 422
						

Thoughts:
**Analyzing the Feasibility of Fuzzing BRCMF with Syzkaller**

Okay, so I'm looking at this `BRCMF_FEAT_PMKID_V2` feature. It looks like it's enabled based on the firmware features map (`brcmf_feat_wlcfeat_map`). The question is, can Syzkaller, with its firmware emulation capabilities, actually set this feature for us?

Now, Syzkaller *can* emulate a USB device using `syz_usb_connect`. But the critical piece here is that `brcmfmac` relies on downloading firmware to the device and then communicating with it. So, does `brcmfmac` even *work* within Syzkaller's setup, given its dependence on firmware?

Hold on... Syzkaller typically uses `mac80211_hwsim` for Wi-Fi fuzzing, right? It avoids `brcmfmac` because `brcmfmac` is a FullMAC driver. That means it's tightly coupled with Broadcom's specific firmware and hardware responses. Which, of course, is a massive headache.

Ah, but I remember, Syzkaller has a USB fuzzer which can emulate *any* USB device. That's key. If Syzkaller emulates a Broadcom USB Wi-Fi dongle, the `brcmfmac` driver *should* probe it. It will trigger the driver to attempt to load firmware through the `brcmf_usb_probe_cb` -> `brcmf_fw_alloc_request` -> `request_firmware` sequence.

The problem, though, is what happens if firmware loading fails? The probe *fails*, and the driver won't initialize the cfg80211 interface. That's a showstopper. But Syzkaller images typically *do* have `linux-firmware` installed, right? So, there's a chance the firmware *will* be available.

If the firmware is present, the driver will try to send it to the emulated USB device. Then, the driver is going to expect the emulated device to actually *boot* and respond to commands, like those in the `brcmf_c_preinit_dcmds` series. Since our emulated USB device is just a dumb fuzzer, it'll either timeout or spew garbage responses.

The real question is... Will it successfully initialize the `wiphy` and register it with cfg80211? That's the core question, isn't it? I need to dig into `brcmf_usb_probe_cb` and the overall initialization flow to understand the critical points and potential failure modes. Let's see what happens.



18/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_usb_probe_cb",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c"
}

Results:
{
  "Output": "drivers/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=1342=brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)\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"
}

19/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 35668
							output: 51
							thoughts: 18
						

Thoughts:
Okay, let's dive into this `brcmf_usb_probe_cb` function. I need to understand its role in the USB device probing process, specifically within the Broadcom Wi-Fi driver framework. I know this is a critical point in device initialization – this function is likely responsible for detecting a compatible device, potentially allocating resources, and setting up the initial communication link. I'll need to figure out what data structures it interacts with, what checks it performs (device IDs, configuration), and what steps it takes to get the device ready for further driver operations. It's the gateway for our USB-connected Wi-Fi devices.



20/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_usb_probe_cb",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/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=1342=brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)\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"
}

21/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 36260
							output: 55
							thoughts: 21
						

Thoughts:
Here's my summary, as though I'm reading and processing the code:

**Diving into brcmf_usb_probe_cb**

Okay, let's get into the details of `brcmf_usb_probe_cb`, shall we? Looks like this is the callback function we're using in `usb.c`... It's the critical entry point for our USB device probe handling, and I need to fully understand its function. I expect it's going to involve resource allocation, device initialization, driver binding, and quite a bit of error handling, given the potential complexities of USB interactions. I'll need to pay close attention to the data structures it manipulates, especially those related to the USB device context and any internal driver states. I'm anticipating some intricate interactions with the USB core, and I'll need to ensure the correct protocols and endpoints are being set up. Time to dig in and see exactly how they've handled this driver's initialization.



22/2 2026/08/02 00:48 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c",
  "FirstLine": 1244,
  "LineCount": 100
}

Results:
{
  "Contents": "1244:\tstatic int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,\n1245:\t\t\t\t      enum brcmf_fwvendor fwvid)\n1246:\t{\n1247:\t\tstruct brcmf_bus *bus;\n1248:\t\tstruct brcmf_usbdev *bus_pub;\n1249:\t\tstruct device *dev = devinfo-\u003edev;\n1250:\t\tstruct brcmf_fw_request *fwreq;\n1251:\t\tint ret;\n1252:\t\n1253:\t\tbrcmf_dbg(USB, \"Enter\\n\");\n1254:\t\tbus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);\n1255:\t\tif (!bus_pub)\n1256:\t\t\treturn -ENODEV;\n1257:\t\n1258:\t\tbus = kzalloc_obj(*bus, GFP_ATOMIC);\n1259:\t\tif (!bus) {\n1260:\t\t\tret = -ENOMEM;\n1261:\t\t\tgoto fail;\n1262:\t\t}\n1263:\t\n1264:\t\tbus-\u003edev = dev;\n1265:\t\tbus_pub-\u003ebus = bus;\n1266:\t\tbus-\u003ebus_priv.usb = bus_pub;\n1267:\t\tdev_set_drvdata(dev, bus);\n1268:\t\tbus-\u003eops = \u0026brcmf_usb_bus_ops;\n1269:\t\tbus-\u003eproto_type = BRCMF_PROTO_BCDC;\n1270:\t\tbus-\u003efwvid = fwvid;\n1271:\t\tbus-\u003ealways_use_fws_queue = true;\n1272:\t#ifdef CONFIG_PM\n1273:\t\tbus-\u003ewowl_supported = true;\n1274:\t#endif\n1275:\t\n1276:\t\tdevinfo-\u003esettings = brcmf_get_module_param(bus-\u003edev, BRCMF_BUSTYPE_USB,\n1277:\t\t\t\t\t\t\t   bus_pub-\u003edevid,\n1278:\t\t\t\t\t\t\t   bus_pub-\u003echiprev);\n1279:\t\tif (!devinfo-\u003esettings) {\n1280:\t\t\tret = -ENOMEM;\n1281:\t\t\tgoto fail;\n1282:\t\t}\n1283:\t\tret = PTR_ERR_OR_ZERO(devinfo-\u003esettings);\n1284:\t\tif (ret \u003c 0)\n1285:\t\t\tgoto fail;\n1286:\t\n1287:\t\tif (!brcmf_usb_dlneeded(devinfo)) {\n1288:\t\t\tret = brcmf_alloc(devinfo-\u003edev, devinfo-\u003esettings);\n1289:\t\t\tif (ret)\n1290:\t\t\t\tgoto fail;\n1291:\t\t\tret = brcmf_attach(devinfo-\u003edev);\n1292:\t\t\tif (ret)\n1293:\t\t\t\tgoto fail;\n1294:\t\t\t/* we are done */\n1295:\t\t\tcomplete(\u0026devinfo-\u003edev_init_done);\n1296:\t\t\treturn 0;\n1297:\t\t}\n1298:\t\tbus-\u003echip = bus_pub-\u003edevid;\n1299:\t\tbus-\u003echiprev = bus_pub-\u003echiprev;\n1300:\t\n1301:\t\tfwreq = brcmf_usb_prepare_fw_request(devinfo);\n1302:\t\tif (!fwreq) {\n1303:\t\t\tret = -ENOMEM;\n1304:\t\t\tgoto fail;\n1305:\t\t}\n1306:\t\n1307:\t\t/* request firmware here */\n1308:\t\tret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);\n1309:\t\tif (ret) {\n1310:\t\t\tbrcmf_err(\"firmware request failed: %d\\n\", ret);\n1311:\t\t\tkfree(fwreq);\n1312:\t\t\tgoto fail;\n1313:\t\t}\n1314:\t\n1315:\t\treturn 0;\n1316:\t\n1317:\tfail:\n1318:\t\t/* Release resources in reverse order */\n1319:\t\tbrcmf_free(devinfo-\u003edev);\n1320:\t\tkfree(bus);\n1321:\t\tbrcmf_usb_detach(devinfo);\n1322:\t\treturn ret;\n1323:\t}\n1324:\t\n1325:\tstatic void\n1326:\tbrcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)\n1327:\t{\n1328:\t\tif (!devinfo)\n1329:\t\t\treturn;\n1330:\t\tbrcmf_dbg(USB, \"Enter, bus_pub %p\\n\", devinfo);\n1331:\t\n1332:\t\tbrcmf_detach(devinfo-\u003edev);\n1333:\t\tbrcmf_free(devinfo-\u003edev);\n1334:\t\tkfree(devinfo-\u003ebus_pub.bus);\n1335:\t\tbrcmf_usb_detach(devinfo);\n1336:\t}\n1337:\t\n1338:\t/* Forward declaration for usb_match_id() call */\n1339:\tstatic const struct usb_device_id brcmf_usb_devid_table[];\n1340:\t\n1341:\tstatic int\n1342:\tbrcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)\n1343:\t{\n"
}

23/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 38034
							output: 55
							thoughts: 62
						

Thoughts:
Okay, let's break this down.

**Diving into the BRCMF USB Probe Process**

Right, so `brcmf_usb_probe_cb` is the entry point, and it kicks things off by calling `brcmf_fw_get_firmwares`.  That function is responsible for the asynchronous firmware loading, which is key.  It seems the system is designed to handle a potentially slow firmware retrieval, which makes sense.  And, critically, once that's done, it calls `brcmf_usb_probe_phase2`. Okay, time to understand how the system is put together. Let's dig into `brcmf_usb_probe_phase2` and see what it's doing with that freshly loaded firmware.



24/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_usb_probe_phase2",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c"
}

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=1244=static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,\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=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"
}

25/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 38903
							output: 54
							thoughts: 16
						

Thoughts:
Okay, let's dive into this `brcmf_usb_probe_phase2` function. I need to understand what this second phase of USB probing entails in the Broadcom Wi-Fi driver. I'm assuming, given the naming, that `brcmf_usb_probe_phase1` handled some initial setup or detection. Now, phase 2 must be where the real work of initializing the device happens. My expectation is that this involves:

**USB Device Initialization: Diving into brcmf_usb_probe_phase2**

*   First, I'd expect some kind of resource allocation. Likely, memory for internal data structures related to the device's state. Is there a `struct brcmf_usbdev` or similar? It's probably being initialized here.
*   Next, I anticipate some interaction with the USB core. Setting up endpoints for data transfer (bulk, interrupt, control), configuring USB descriptors, and likely claiming the USB interface that corresponds to the Wi-Fi device. This is where I'll see the driver taking ownership of the USB resources.
*   There's almost certainly going to be some form of device communication setup. This could involve sending initial control messages to the Broadcom chip, setting up hardware registers, or preparing the chip for subsequent communication with the host. This step is where firmware loading might take place, if it's not handled earlier.
*   I'll be looking for interrupt handling setup, if the device uses interrupts to signal readiness or events. The driver needs to register interrupt handlers with the USB core.
*   Finally, I'll be searching for any device-specific initialization. Maybe there's a hardware initialization sequence for the Broadcom chip, or some form of power-up routine. There could be some sort of a check to ensure the connection.
*   I'd also expect to see some error handling. USB is complex, so things can go wrong. I'll be looking for error checks after each USB operation, and any error recovery routines that are in place.

I need to understand how the driver is translating higher-level Wi-Fi concepts (like scanning, association, data transfer) into the USB-specific operations within this function. Let's see how it's done.



26/2 2026/08/02 00:48 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c",
  "FirstLine": 1176,
  "LineCount": 50
}

Results:
{
  "Contents": "1176:\tstatic void brcmf_usb_probe_phase2(struct device *dev, int ret,\n1177:\t\t\t\t\t   struct brcmf_fw_request *fwreq)\n1178:\t{\n1179:\t\tstruct brcmf_bus *bus = dev_get_drvdata(dev);\n1180:\t\tstruct brcmf_usbdev_info *devinfo = bus-\u003ebus_priv.usb-\u003edevinfo;\n1181:\t\tconst struct firmware *fw;\n1182:\t\n1183:\t\tif (ret)\n1184:\t\t\tgoto error;\n1185:\t\n1186:\t\tbrcmf_dbg(USB, \"Start fw downloading\\n\");\n1187:\t\n1188:\t\tfw = fwreq-\u003eitems[BRCMF_USB_FW_CODE].binary;\n1189:\t\tkfree(fwreq);\n1190:\t\n1191:\t\tret = check_file(fw-\u003edata);\n1192:\t\tif (ret \u003c 0) {\n1193:\t\t\tbrcmf_err(\"invalid firmware\\n\");\n1194:\t\t\trelease_firmware(fw);\n1195:\t\t\tgoto error;\n1196:\t\t}\n1197:\t\n1198:\t\tdevinfo-\u003eimage = fw-\u003edata;\n1199:\t\tdevinfo-\u003eimage_len = fw-\u003esize;\n1200:\t\n1201:\t\tret = brcmf_usb_fw_download(devinfo);\n1202:\t\trelease_firmware(fw);\n1203:\t\tif (ret)\n1204:\t\t\tgoto error;\n1205:\t\n1206:\t\tret = brcmf_alloc(devinfo-\u003edev, devinfo-\u003esettings);\n1207:\t\tif (ret)\n1208:\t\t\tgoto error;\n1209:\t\n1210:\t\t/* Attach to the common driver interface */\n1211:\t\tret = brcmf_attach(devinfo-\u003edev);\n1212:\t\tif (ret)\n1213:\t\t\tgoto error;\n1214:\t\n1215:\t\tcomplete(\u0026devinfo-\u003edev_init_done);\n1216:\t\treturn;\n1217:\terror:\n1218:\t\tbrcmf_dbg(TRACE, \"failed: dev=%s, err=%d\\n\", dev_name(dev), ret);\n1219:\t\tcomplete(\u0026devinfo-\u003edev_init_done);\n1220:\t\tdevice_release_driver(dev);\n1221:\t}\n1222:\t\n1223:\tstatic struct brcmf_fw_request *\n1224:\tbrcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)\n1225:\t{\n"
}

27/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 40186
							output: 54
							thoughts: 57
						

Thoughts:
Okay, here's my interpretation of this sequence, focusing on my own thought process as an expert:

**Investigating the USB Firmware Download Sequence**

Right, so we're looking at a USB-based Broadcom Wi-Fi driver initialization. It looks like the core function here is `brcmf_usb_fw_download(devinfo)`. If that succeeds, the driver then moves on to allocate memory with `brcmf_alloc` and attach itself, likely initializing the hardware interaction via `brcmf_attach`.

My first inclination is to drill down into `brcmf_usb_fw_download`. That's where the critical firmware loading should be happening, and where any initial setup or error conditions would be most apparent. I need to understand what that function is doing, what its preconditions are, and how it handles potential failures. Is it checking for valid firmware images? Is it handling USB transfers correctly? Does it account for different Broadcom chipset revisions? What are the potential error paths? These are all the questions that I need to ask right away. Knowing the details of the download process is the crucial first step.



28/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_usb_fw_download",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1028=static int\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1029:brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1030-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1176=static void brcmf_usb_probe_phase2(struct device *dev, int ret,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1200-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1201:\tret = brcmf_usb_fw_download(devinfo);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1202-\trelease_firmware(fw);\n"
}

29/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 40845
							output: 54
							thoughts: 15
						

Thoughts:
Okay, let's dive into this `brcmf_usb_fw_download` code. I'm already anticipating some of the usual suspects here – the intricate dance of USB device initialization, firmware loading, and potential error handling. I'm going to be looking for the standard protocol interactions, the specific commands being sent to the Broadcom chipset over USB. My immediate concerns will be around the size limitations, buffering, and how the firmware image is parsed and transmitted. I'll need to pay close attention to the error codes and what the function does to recover, or if it just bails out. This is where I can start thinking about potential vulnerabilities: what happens if the firmware is corrupt or if malicious data is sent? How robust is the integrity check, and does it validate the firmware in memory? I need to understand the sequencing; is the download atomic? Or does it break down in a way I could exploit? I will also analyze any relevant configuration parameters passed to this function, and whether these inputs are validated appropriately. This is going to be good.



30/2 2026/08/02 00:48 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c",
  "FirstLine": 1028,
  "LineCount": 50
}

Results:
{
  "Contents": "1028:\tstatic int\n1029:\tbrcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)\n1030:\t{\n1031:\t\tint err;\n1032:\t\tstruct usb_interface *intf;\n1033:\t\n1034:\t\tbrcmf_dbg(USB, \"Enter\\n\");\n1035:\t\tif (!devinfo) {\n1036:\t\t\terr = -ENODEV;\n1037:\t\t\tgoto out;\n1038:\t\t}\n1039:\t\n1040:\t\tif (!devinfo-\u003eimage) {\n1041:\t\t\tbrcmf_err(\"No firmware!\\n\");\n1042:\t\t\terr = -ENOENT;\n1043:\t\t\tgoto out;\n1044:\t\t}\n1045:\t\n1046:\t\tintf = to_usb_interface(devinfo-\u003edev);\n1047:\t\terr = usb_autopm_get_interface(intf);\n1048:\t\tif (err)\n1049:\t\t\tgoto out;\n1050:\t\n1051:\t\terr = brcmf_usb_dlstart(devinfo,\n1052:\t\t\t(u8 *)devinfo-\u003eimage, devinfo-\u003eimage_len);\n1053:\t\tif (err == 0)\n1054:\t\t\terr = brcmf_usb_dlrun(devinfo);\n1055:\t\n1056:\t\tusb_autopm_put_interface(intf);\n1057:\tout:\n1058:\t\treturn err;\n1059:\t}\n1060:\t\n1061:\t\n1062:\tstatic void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)\n1063:\t{\n1064:\t\tbrcmf_dbg(USB, \"Enter, devinfo %p\\n\", devinfo);\n1065:\t\n1066:\t\t/* free the URBS */\n1067:\t\tbrcmf_usb_free_q(\u0026devinfo-\u003erx_freeq);\n1068:\t\tbrcmf_usb_free_q(\u0026devinfo-\u003etx_freeq);\n1069:\t\n1070:\t\tusb_free_urb(devinfo-\u003ectl_urb);\n1071:\t\tusb_free_urb(devinfo-\u003ebulk_urb);\n1072:\t\n1073:\t\tkfree(devinfo-\u003etx_reqs);\n1074:\t\tkfree(devinfo-\u003erx_reqs);\n1075:\t\n1076:\t\tif (devinfo-\u003esettings)\n1077:\t\t\tbrcmf_release_module_param(devinfo-\u003esettings);\n"
}

31/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 41853
							output: 47
							thoughts: 94
						

Thoughts:
Here's my take on this – considering my expertise, I'm thinking about the implications for fuzzing this driver.

**Firmware Download and Device Attachment: A Fuzzing Perspective**

Okay, so `brcmf_usb_dlstart` and `brcmf_usb_dlrun` are the key functions here – they're responsible for transferring the firmware over USB to the target device. This is the initial setup phase. The interesting part, from a fuzzing perspective, is what happens when we use a tool like syzkaller to emulate that device.

If syzkaller is successfully emulating the device, it's designed to either handle (or reject) these USB requests, the URBs. Now, if it *accepts* those URBs, my understanding is that both `brcmf_usb_dlstart` and `brcmf_usb_dlrun` will return a 0, a success code. This is the crucial point for a fuzzer: a "success" here could be deceptive. It might *appear* successful, but the emulation might not be perfect. The firmware could be partially or incorrectly processed on the emulated side, which could allow a later crash.

Then, importantly, `brcmf_attach` is called. So, the successful firmware download is supposed to lead to attaching the driver to the "device". This makes me wonder: can we trigger bugs in the attachment process if the firmware download was somehow... corrupted or malformed, even if the functions *report* success? This is where the vulnerabilities might hide. We need to focus not just on ensuring a zero return, but also the state of the emulated device. The emulator needs to be as realistic as possible to expose the most bugs. The driver might assume a certain firmware state after the download, and if that assumption is wrong, we're likely to have a bug. Therefore, I need to look closely at the emulator's USB handling.



32/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_attach",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h=299=int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-300-/* Indication from bus module regarding presence/insertion of dongle. */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h:301:int brcmf_attach(struct device *dev);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-302-/* Indication from bus module regarding removal/absence of dongle */\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h-18- * (module) initiliazation takes place. The device specific settings is part\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h:19: * of the drvr struct and should be initialized on every brcmf_attach.\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h-20- */\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=1315=int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1343-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:1344:int brcmf_attach(struct device *dev)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1345-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c=2185=static void brcmf_pcie_setup(struct device *dev, int ret,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2265-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c:2266:\tret = brcmf_attach(\u0026devinfo-\u003epdev-\u003edev);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2267-\tif (ret)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c=4223=static void brcmf_sdio_firmware_callback(struct device *dev, int err,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-4413-\t/* Attach to the common layer, reserve hdr space */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:4414:\terr = brcmf_attach(sdiod-\u003edev);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-4415-\tif (err != 0) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:4416:\t\tbrcmf_err(\"brcmf_attach failed\\n\");\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c-4417-\t\tgoto free;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1176=static void brcmf_usb_probe_phase2(struct device *dev, int ret,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1210-\t/* Attach to the common driver interface */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1211:\tret = brcmf_attach(devinfo-\u003edev);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1212-\tif (ret)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1244=static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1290-\t\t\tgoto fail;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1291:\t\tret = brcmf_attach(devinfo-\u003edev);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1292-\t\tif (ret)\n"
}

33/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 43718
							output: 54
							thoughts: 17
						

Thoughts:
Okay, let's dive into this. Here's my take on those instructions, as if they're my mental process:

**Diving into the `brcmf_attach` Function**

Alright, time to get my hands dirty. I need to understand this piece of the puzzle, and the place to start is the `brcmf_attach` function. Specifically, it's in `core.c`. Let's get to the code and see what makes this tick. I'm expecting this to be the point where a new Broadcom Wi-Fi driver instance gets… well, attached! I'm hoping I can easily see how all of the internal structures are initialized and hooked up. Time to see what's happening under the hood. I suspect that there should be some sort of device initialization happening as part of the procedure.



34/2 2026/08/02 00:48 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c",
  "FirstLine": 1344,
  "LineCount": 50
}

Results:
{
  "Contents": "1344:\tint brcmf_attach(struct device *dev)\n1345:\t{\n1346:\t\tstruct brcmf_bus *bus_if = dev_get_drvdata(dev);\n1347:\t\tstruct brcmf_pub *drvr = bus_if-\u003edrvr;\n1348:\t\tint ret = 0;\n1349:\t\tint i;\n1350:\t\n1351:\t\tbrcmf_dbg(TRACE, \"Enter\\n\");\n1352:\t\n1353:\t\tfor (i = 0; i \u003c ARRAY_SIZE(drvr-\u003eif2bss); i++)\n1354:\t\t\tdrvr-\u003eif2bss[i] = BRCMF_BSSIDX_INVALID;\n1355:\t\n1356:\t\tmutex_init(\u0026drvr-\u003eproto_block);\n1357:\t\n1358:\t\t/* Link to bus module */\n1359:\t\tdrvr-\u003ehdrlen = 0;\n1360:\t\n1361:\t\tret = brcmf_fwvid_attach(drvr);\n1362:\t\tif (ret != 0) {\n1363:\t\t\tbphy_err(drvr, \"brcmf_fwvid_attach failed\\n\");\n1364:\t\t\tgoto fail;\n1365:\t\t}\n1366:\t\n1367:\t\t/* Attach and link in the protocol */\n1368:\t\tret = brcmf_proto_attach(drvr);\n1369:\t\tif (ret != 0) {\n1370:\t\t\tbphy_err(drvr, \"brcmf_prot_attach failed\\n\");\n1371:\t\t\tgoto fail;\n1372:\t\t}\n1373:\t\n1374:\t\t/* attach firmware event handler */\n1375:\t\tret = brcmf_fweh_attach(drvr);\n1376:\t\tif (ret != 0) {\n1377:\t\t\tbphy_err(drvr, \"brcmf_fweh_attach failed\\n\");\n1378:\t\t\tgoto fail;\n1379:\t\t}\n1380:\t\n1381:\t\t/* Attach to events important for core code */\n1382:\t\tbrcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,\n1383:\t\t\t\t    brcmf_psm_watchdog_notify);\n1384:\t\n1385:\t\tbrcmf_fwvid_get_cfg80211_ops(drvr);\n1386:\t\n1387:\t\tret = brcmf_bus_started(drvr, drvr-\u003eops);\n1388:\t\tif (ret != 0) {\n1389:\t\t\tbphy_err(drvr, \"dongle is not responding: err=%d\\n\", ret);\n1390:\t\t\tgoto fail;\n1391:\t\t}\n1392:\t\n1393:\t\treturn 0;\n"
}

35/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 44748
							output: 49
							thoughts: 22
						

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

**Analyzing the brcmf_bus_started Call**

Okay, so `brcmf_bus_started` is firing up. My first instinct is to dig in and understand its function. This likely represents the initial stage of bus initialization for a Broadcom Wi-Fi device, which is a critical point. I'll need to immediately look at what the function does, and more importantly, how it relates to the broader system architecture. Is this a synchronous operation? What resources does it acquire? Are there any potential race conditions I should be immediately aware of? Understanding the sequence of events here is paramount to grasping the overall bring-up procedure. I need to quickly identify its interactions with the core bus driver, and any potential side effects on power management. Time to dive into the code...



36/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_bus_started",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c=68=MODULE_PARM_DESC(iapp, \"Enable partial support for the obsoleted Inter-Access Point Protocol\");\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-70-#ifdef DEBUG\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c:71:/* always succeed brcmf_bus_started() */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-72-static int brcmf_ignore_probe_fail;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=1209=static const struct file_operations bus_reset_fops = {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1213-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:1214:static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1215-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=1344=int brcmf_attach(struct device *dev)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1386-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:1387:\tret = brcmf_bus_started(drvr, drvr-\u003eops);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1388-\tif (ret != 0) {\n"
}

37/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 45534
							output: 54
							thoughts: 19
						

Thoughts:
Here's a first-person summary, assuming I'm an expert and this is my thought process:

**Diving into the BRCMF Bus Startup**

Alright, time to dig into the Broadcom Wi-Fi driver, specifically the bus startup sequence. I need to get a clear picture of what's happening when a BRCMF-based device comes online. Let's start with `brcmf_bus_started` in `core.c`. That function name itself is a good sign; it likely marks a crucial point, the culmination of some setup phase. I want to understand how the core driver interfaces with the bus itself, whether it's SDIO, PCIe, or something else. I'll be looking for how it handles initialization, device detection, resource allocation, and, of course, the actual activation of the hardware. The goal here is to grasp the fundamental mechanics so I can troubleshoot any bus-related issues efficiently. Knowing this flow is key to debugging.



38/2 2026/08/02 00:48 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c",
  "FirstLine": 1214,
  "LineCount": 50
}

Results:
{
  "Contents": "1214:\tstatic int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)\n1215:\t{\n1216:\t\tint ret = -1;\n1217:\t\tstruct brcmf_bus *bus_if = drvr-\u003ebus_if;\n1218:\t\tstruct brcmf_if *ifp;\n1219:\t\tstruct brcmf_if *p2p_ifp;\n1220:\t\n1221:\t\tbrcmf_dbg(TRACE, \"\\n\");\n1222:\t\n1223:\t\t/* add primary networking interface */\n1224:\t\tifp = brcmf_add_if(drvr, 0, 0, false, \"wlan%d\",\n1225:\t\t\t\t   is_valid_ether_addr(drvr-\u003esettings-\u003emac) ? drvr-\u003esettings-\u003emac : NULL);\n1226:\t\tif (IS_ERR(ifp))\n1227:\t\t\treturn PTR_ERR(ifp);\n1228:\t\n1229:\t\tp2p_ifp = NULL;\n1230:\t\n1231:\t\t/* signal bus ready */\n1232:\t\tbrcmf_bus_change_state(bus_if, BRCMF_BUS_UP);\n1233:\t\n1234:\t\t/* do bus specific preinit here */\n1235:\t\tret = brcmf_bus_preinit(bus_if);\n1236:\t\tif (ret \u003c 0)\n1237:\t\t\tgoto fail;\n1238:\t\n1239:\t\t/* Bus is ready, do any initialization */\n1240:\t\tret = brcmf_c_preinit_dcmds(ifp);\n1241:\t\tif (ret \u003c 0)\n1242:\t\t\tgoto fail;\n1243:\t\n1244:\t\tbrcmf_feat_attach(drvr);\n1245:\t\n1246:\t\tret = brcmf_proto_init_done(drvr);\n1247:\t\tif (ret \u003c 0)\n1248:\t\t\tgoto fail;\n1249:\t\n1250:\t\tbrcmf_proto_add_if(drvr, ifp);\n1251:\t\n1252:\t\tdrvr-\u003econfig = brcmf_cfg80211_attach(drvr, ops,\n1253:\t\t\t\t\t\t     drvr-\u003esettings-\u003ep2p_enable);\n1254:\t\tif (drvr-\u003econfig == NULL) {\n1255:\t\t\tret = -ENOMEM;\n1256:\t\t\tgoto fail;\n1257:\t\t}\n1258:\t\n1259:\t\tret = brcmf_net_attach(ifp, false);\n1260:\t\n1261:\t\tif ((!ret) \u0026\u0026 (drvr-\u003esettings-\u003ep2p_enable)) {\n1262:\t\t\tp2p_ifp = drvr-\u003eiflist[1];\n1263:\t\t\tif (p2p_ifp)\n"
}

39/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 46616
							output: 51
							thoughts: 104
						

Thoughts:
**Analyzing the `brcmf_c_preinit_dcmds` Function Call**

Okay, so `brcmf_c_preinit_dcmds(ifp)` is getting called. My initial assessment is that this is where things get interesting. Given my understanding of how syzkaller operates, if it's emulating the device, it's very likely the dongle commands, or `dcmds`, will simply be received and either ignored or responded to with meaningless data. No real firmware running here. That's the first thing to consider, given the context.

Now, if `brcmf_c_preinit_dcmds` fails, it returns a value less than zero, and we branch to `fail`. That's standard error handling. My immediate thought is, "Okay, is `brcmf_ignore_probe_fail` used here?". It's crucial to understand how that variable, or its equivalent, is handled to truly understand the fail path. This is key to determine whether we continue or exit. I need to check the code to see what that is doing. I'll focus on the failure path now.



40/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_ignore_probe_fail",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c=68=MODULE_PARM_DESC(iapp, \"Enable partial support for the obsoleted Inter-Access Point Protocol\");\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-71-/* always succeed brcmf_bus_started() */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c:72:static int brcmf_ignore_probe_fail;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c:73:module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-74-MODULE_PARM_DESC(ignore_probe_fail, \"always succeed probe for debugging\");\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c=512=struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-533-#ifdef DEBUG\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c:534:\tsettings-\u003eignore_probe_fail = !!brcmf_ignore_probe_fail;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-535-#endif\n"
}

41/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 47449
							output: 53
							thoughts: 154
						

Thoughts:
**Analyzing a Potential Syzkaller Fuzzing Vector**

Okay, hold on a second. I'm looking at this `brcmf_ignore_probe_fail` function and it's only compiled in when `DEBUG` is defined. That's a red flag. I don't typically see `DEBUG` defined in the syzkaller kernels, so this path is likely dead. But wait, I need to consider a different route!

I see `brcmf_c_preinit_dcmds`. This function is sending commands to the Broadcom device. If the device doesn't respond correctly, there's a timeout, which is interesting from a fuzzing perspective. The question is, can syzkaller's USB fuzzer generate *valid* responses to these `dcmds`? Syzkaller's USB fuzzer gives us the power to provide completely arbitrary responses to USB requests.

However, `brcmf_c_preinit_dcmds` isn't sending a single command; it's sending *multiple* commands, and expects very specific responses. Now I'm getting somewhere... that creates more of a challenge. I need to take a closer look at `brcmf_c_preinit_dcmds` and understand the expected sequence of communication.



42/2 2026/08/02 00:48 tool grepper
0m Args:
{
  "Expression": "brcmf_c_preinit_dcmds",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c=248=static int brcmf_c_process_cal_blob(struct brcmf_if *ifp)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-264-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c:265:int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c-266-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h=69=void brcmf_release_module_param(struct brcmf_mp_device *module_param);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h-71-/* Sets dongle media info (drv_version, mac address). */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h:72:int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h-73-int brcmf_c_set_cur_etheraddr(struct brcmf_if *ifp, const u8 *addr);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=1214=static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1239-\t/* Bus is ready, do any initialization */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:1240:\tret = brcmf_c_preinit_dcmds(ifp);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1241-\tif (ret \u003c 0)\n"
}

43/2 2026/08/02 00:48 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 48533
							output: 53
							thoughts: 17
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Analyzing `brcmf_c_preinit_dcmds`**

Alright, let's dive into `brcmf_c_preinit_dcmds`. My initial thought is likely to be about context. Where does this function sit within the broader Broadcom WiFi driver architecture? Is it a core initialization routine, a helper function called during driver loading, or perhaps something triggered by a specific event? The name itself suggests pre-initialization, so I'm already anticipating tasks like possibly setting up communication channels, configuring hardware registers in a basic state, or potentially loading firmware or microcode. I'm immediately trying to remember what the expected hardware configuration is in that case, and if the function is compatible with any given hardware.

I'm probably going to be mentally formulating a series of questions: Does this deal with the SDIO, PCIe, or USB interface layers? What's the typical flow of control *before* this function is called, and *after* it completes? I'll probably start visualizing the call stack, anticipating what other functions might call this one, and which functions it might call in turn.

My next step will likely involve thinking of areas of potential trouble. Are there any known errata related to this specific pre-init stage? What are the common failure modes, and what are the logging mechanisms in place to diagnose problems? I'm probably also mentally checking for potential race conditions or synchronization issues, especially if this function interacts with hardware registers or shared memory. I'll need to remember if there are any known timing constraints for this particular function.

If I'm debugging or tracing an issue, I'll be forming a hypothesis about what this function is *supposed* to be doing, and how the observed behavior deviates from that expected behavior. I'm going to start mentally stepping through the code, focusing on the most critical sections, or anything that seems unusual.



44/2 2026/08/02 00:49 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c",
  "FirstLine": 265,
  "LineCount": 50
}

Results:
{
  "Contents": " 265:\tint brcmf_c_preinit_dcmds(struct brcmf_if *ifp)\n 266:\t{\n 267:\t\tstruct brcmf_pub *drvr = ifp-\u003edrvr;\n 268:\t\tstruct brcmf_fweh_info *fweh = drvr-\u003efweh;\n 269:\t\tu8 buf[BRCMF_DCMD_SMLEN];\n 270:\t\tstruct brcmf_bus *bus;\n 271:\t\tstruct brcmf_rev_info_le revinfo;\n 272:\t\tstruct brcmf_rev_info *ri;\n 273:\t\tchar *clmver;\n 274:\t\tchar *ptr;\n 275:\t\ts32 err;\n 276:\t\n 277:\t\tif (is_valid_ether_addr(ifp-\u003emac_addr)) {\n 278:\t\t\t/* set mac address */\n 279:\t\t\terr = brcmf_c_set_cur_etheraddr(ifp, ifp-\u003emac_addr);\n 280:\t\t\tif (err \u003c 0)\n 281:\t\t\t\tgoto done;\n 282:\t\t} else {\n 283:\t\t\t/* retrieve mac address */\n 284:\t\t\terr = brcmf_fil_iovar_data_get(ifp, \"cur_etheraddr\", ifp-\u003emac_addr,\n 285:\t\t\t\t\t\t       sizeof(ifp-\u003emac_addr));\n 286:\t\t\tif (err \u003c 0) {\n 287:\t\t\t\tbphy_err(drvr, \"Retrieving cur_etheraddr failed, %d\\n\", err);\n 288:\t\t\t\tgoto done;\n 289:\t\t\t}\n 290:\t\n 291:\t\t\tif (ether_addr_equal_unaligned(ifp-\u003emac_addr, brcmf_default_mac_address)) {\n 292:\t\t\t\tbphy_err(drvr, \"Default MAC is used, replacing with random MAC to avoid conflicts\\n\");\n 293:\t\t\t\teth_random_addr(ifp-\u003emac_addr);\n 294:\t\t\t\tifp-\u003endev-\u003eaddr_assign_type = NET_ADDR_RANDOM;\n 295:\t\t\t\terr = brcmf_c_set_cur_etheraddr(ifp, ifp-\u003emac_addr);\n 296:\t\t\t\tif (err \u003c 0)\n 297:\t\t\t\t\tgoto done;\n 298:\t\t\t}\n 299:\t\t}\n 300:\t\n 301:\t\tmemcpy(ifp-\u003edrvr-\u003emac, ifp-\u003emac_addr, sizeof(ifp-\u003edrvr-\u003emac));\n 302:\t\tmemcpy(ifp-\u003edrvr-\u003ewiphy-\u003eperm_addr, ifp-\u003edrvr-\u003emac, ETH_ALEN);\n 303:\t\n 304:\t\tbus = ifp-\u003edrvr-\u003ebus_if;\n 305:\t\tri = \u0026ifp-\u003edrvr-\u003erevinfo;\n 306:\t\n 307:\t\terr = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,\n 308:\t\t\t\t\t     \u0026revinfo, sizeof(revinfo));\n 309:\t\tif (err \u003c 0) {\n 310:\t\t\tbphy_err(drvr, \"retrieving revision info failed, %d\\n\", err);\n 311:\t\t\tstrscpy(ri-\u003echipname, \"UNKNOWN\", sizeof(ri-\u003echipname));\n 312:\t\t} else {\n 313:\t\t\tri-\u003evendorid = le32_to_cpu(revinfo.vendorid);\n 314:\t\t\tri-\u003edeviceid = le32_to_cpu(revinfo.deviceid);\n"
}

45/2 2026/08/02 00:49 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 49981
							output: 53
							thoughts: 55
						

Thoughts:
Okay, here's my interpretation of this code snippet, presented as my own thought process:

**Diving into the Firmware Interaction**

Alright, so I see it's kicking things off with the `BRCMF_C_GET_REVINFO` command. Standard operating procedure, usually the first thing you grab when you're probing a Broadcom Wi-Fi device. Beyond that, it's clearly sending other commands too, without specifying. Gotta find the call to `brcmf_fil_iovar_data_get`. Hmm, a critical function here, that implies we are setting up a state and grabbing some valuable info.

Now, the interesting part is the `if` statement. If `brcmf_fil_iovar_data_get` fails, that's a problem. Immediately, we jump to `done`. I need to understand what's happening in the `done` section. Failure here could indicate a communication problem with the firmware, an unsupported iovar, an invalid parameter, or some other critical issue. Let me quickly examine what the `done` path entails to pinpoint the potential impact of this failure. What are the cleanup steps? Are there any error messages? It's all about diagnostics.



46/2 2026/08/02 00:49 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c",
  "FirstLine": 315,
  "LineCount": 50
}

Results:
{
  "Contents": " 315:\t\t\tri-\u003eradiorev = le32_to_cpu(revinfo.radiorev);\n 316:\t\t\tri-\u003ecorerev = le32_to_cpu(revinfo.corerev);\n 317:\t\t\tri-\u003eboardid = le32_to_cpu(revinfo.boardid);\n 318:\t\t\tri-\u003eboardvendor = le32_to_cpu(revinfo.boardvendor);\n 319:\t\t\tri-\u003eboardrev = le32_to_cpu(revinfo.boardrev);\n 320:\t\t\tri-\u003edriverrev = le32_to_cpu(revinfo.driverrev);\n 321:\t\t\tri-\u003eucoderev = le32_to_cpu(revinfo.ucoderev);\n 322:\t\t\tri-\u003ebus = le32_to_cpu(revinfo.bus);\n 323:\t\t\tri-\u003ephytype = le32_to_cpu(revinfo.phytype);\n 324:\t\t\tri-\u003ephyrev = le32_to_cpu(revinfo.phyrev);\n 325:\t\t\tri-\u003eanarev = le32_to_cpu(revinfo.anarev);\n 326:\t\t\tri-\u003echippkg = le32_to_cpu(revinfo.chippkg);\n 327:\t\t\tri-\u003envramrev = le32_to_cpu(revinfo.nvramrev);\n 328:\t\n 329:\t\t\t/* use revinfo if not known yet */\n 330:\t\t\tif (!bus-\u003echip) {\n 331:\t\t\t\tbus-\u003echip = le32_to_cpu(revinfo.chipnum);\n 332:\t\t\t\tbus-\u003echiprev = le32_to_cpu(revinfo.chiprev);\n 333:\t\t\t}\n 334:\t\t}\n 335:\t\tri-\u003eresult = err;\n 336:\t\n 337:\t\tif (bus-\u003echip)\n 338:\t\t\tbrcmf_chip_name(bus-\u003echip, bus-\u003echiprev,\n 339:\t\t\t\t\tri-\u003echipname, sizeof(ri-\u003echipname));\n 340:\t\n 341:\t\t/* Do any CLM downloading */\n 342:\t\terr = brcmf_c_process_clm_blob(ifp);\n 343:\t\tif (err \u003c 0) {\n 344:\t\t\tbphy_err(drvr, \"download CLM blob file failed, %d\\n\", err);\n 345:\t\t\tgoto done;\n 346:\t\t}\n 347:\t\n 348:\t\t/* Do TxCap downloading, if needed */\n 349:\t\terr = brcmf_c_process_txcap_blob(ifp);\n 350:\t\tif (err \u003c 0) {\n 351:\t\t\tbphy_err(drvr, \"download TxCap blob file failed, %d\\n\", err);\n 352:\t\t\tgoto done;\n 353:\t\t}\n 354:\t\n 355:\t\t/* Download external calibration blob, if available */\n 356:\t\terr = brcmf_c_process_cal_blob(ifp);\n 357:\t\tif (err \u003c 0) {\n 358:\t\t\tbphy_err(drvr, \"download calibration blob file failed, %d\\n\", err);\n 359:\t\t\tgoto done;\n 360:\t\t}\n 361:\t\n 362:\t\t/* query for 'ver' to get version info from firmware */\n 363:\t\tmemset(buf, 0, sizeof(buf));\n 364:\t\terr = brcmf_fil_iovar_data_get(ifp, \"ver\", buf, sizeof(buf));\n"
}

47/2 2026/08/02 00:49 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 51297
							output: 53
							thoughts: 10
						

Thoughts:
Okay, I'm ready to dive into this. Let's see how this goes.

**Analyzing the Function's Context**

Alright, I need to understand this function fully. I've got the initial snippet, but that's not enough to draw any firm conclusions. Before I can properly assess its performance, efficiency, or potential issues, I absolutely have to see the *rest* of the function. What are the inputs, the other internal calculations, and crucially, what's the ultimate output? Understanding the complete picture is paramount here. This fragment alone gives me a very limited perspective, and I'm itching to get the whole context. I need to see the entire implementation to start forming meaningful insights.



48/2 2026/08/02 00:49 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c",
  "FirstLine": 365,
  "LineCount": 50
}

Results:
{
  "Contents": " 365:\t\tif (err \u003c 0) {\n 366:\t\t\tbphy_err(drvr, \"Retrieving version information failed, %d\\n\",\n 367:\t\t\t\t err);\n 368:\t\t\tgoto done;\n 369:\t\t}\n 370:\t\tbuf[sizeof(buf) - 1] = '\\0';\n 371:\t\tptr = (char *)buf;\n 372:\t\tstrsep(\u0026ptr, \"\\n\");\n 373:\t\n 374:\t\t/* Print fw version info */\n 375:\t\tbrcmf_info(\"Firmware: %s %s\\n\", ri-\u003echipname, buf);\n 376:\t\n 377:\t\t/* locate firmware version number for ethtool */\n 378:\t\tptr = strrchr(buf, ' ');\n 379:\t\tif (!ptr) {\n 380:\t\t\tbphy_err(drvr, \"Retrieving version number failed\");\n 381:\t\t\tgoto done;\n 382:\t\t}\n 383:\t\tstrscpy(ifp-\u003edrvr-\u003efwver, ptr + 1, sizeof(ifp-\u003edrvr-\u003efwver));\n 384:\t\n 385:\t\t/* Query for 'clmver' to get CLM version info from firmware */\n 386:\t\tmemset(buf, 0, sizeof(buf));\n 387:\t\terr = brcmf_fil_iovar_data_get(ifp, \"clmver\", buf, sizeof(buf));\n 388:\t\tif (err) {\n 389:\t\t\tbrcmf_dbg(TRACE, \"retrieving clmver failed, %d\\n\", err);\n 390:\t\t} else {\n 391:\t\t\tbuf[sizeof(buf) - 1] = '\\0';\n 392:\t\t\tclmver = (char *)buf;\n 393:\t\n 394:\t\t\t/* Replace all newline/linefeed characters with space\n 395:\t\t\t * character\n 396:\t\t\t */\n 397:\t\t\tstrreplace(clmver, '\\n', ' ');\n 398:\t\n 399:\t\t\t/* store CLM version for adding it to revinfo debugfs file */\n 400:\t\t\tmemcpy(ifp-\u003edrvr-\u003eclmver, clmver, sizeof(ifp-\u003edrvr-\u003eclmver));\n 401:\t\n 402:\t\t\tbrcmf_dbg(INFO, \"CLM version = %s\\n\", clmver);\n 403:\t\t}\n 404:\t\n 405:\t\t/* set mpc */\n 406:\t\terr = brcmf_fil_iovar_int_set(ifp, \"mpc\", 1);\n 407:\t\tif (err) {\n 408:\t\t\tbphy_err(drvr, \"failed setting mpc\\n\");\n 409:\t\t\tgoto done;\n 410:\t\t}\n 411:\t\n 412:\t\tbrcmf_c_set_joinpref_default(ifp);\n 413:\t\n 414:\t\t/* Setup event_msgs, enable E_IF */\n"
}

49/2 2026/08/02 00:49 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 52321
							output: 53
							thoughts: 7
						

Thoughts:
Okay, I'm ready. Here's my summary, presented as my internal thought process, assuming I'm an expert in this field:

**Internal Reflection on Function Completion**

Alright, that's done. I've reached the end of the function, and now I need to solidify my understanding of the execution path. Let me mentally walk through it one more time. The core logic hinges on the interplay of [mention key concepts from the text, e.g., "the conditional statement and the iterative loop," or "the data structures used and the recursive calls"]. Did I handle all the edge cases I anticipated? Did I appropriately consider what happens when [mention potential inputs or scenarios from the text]?

I'm particularly interested in whether my assumptions about [mention a specific assumption from the function, e.g., "memory allocation"] were correct, given the function's [mention the function's overall goal]. Could any optimizations have been made? Perhaps by [mention potential optimization strategies, if you can infer them based on the text, e.g., "rearranging the order of operations" or "employing a different algorithm for a specific stage"].

I also need to verify that the function's output aligns with the established specifications. The [mention the type of output, e.g., "return value"] should be correctly formatted. The function's internal behaviour should be aligned with the parameters and their characteristics. Overall, is it truly robust? Does it scale well? I'll probably want to test that further.

The time complexity is still top of mind; based on the structure, it appears to be [mention your assessment of the time complexity, e.g., "O(n log n) due to the sorting step" or "O(1)"] if the function is not dependent on specific parameters.

Finally, I need to check the function's side effects. I assume that it should not have modified global state or produced unnecessary output. That is what I had intended, anyway.

Now, I'm at the end. That should be a clean and solid result.



50/2 2026/08/02 00:49 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c",
  "FirstLine": 415,
  "LineCount": 50
}

Results:
{
  "Contents": " 415:\t\terr = brcmf_fil_iovar_data_get(ifp, \"event_msgs\", fweh-\u003eevent_mask,\n 416:\t\t\t\t\t       fweh-\u003eevent_mask_len);\n 417:\t\tif (err) {\n 418:\t\t\tbphy_err(drvr, \"Get event_msgs error (%d)\\n\", err);\n 419:\t\t\tgoto done;\n 420:\t\t}\n 421:\t\t/*\n 422:\t\t * BRCMF_E_IF can safely be used to set the appropriate bit\n 423:\t\t * in the event_mask as the firmware event code is guaranteed\n 424:\t\t * to match the value of BRCMF_E_IF because it is old cruft\n 425:\t\t * that all vendors have.\n 426:\t\t */\n 427:\t\tsetbit(fweh-\u003eevent_mask, BRCMF_E_IF);\n 428:\t\terr = brcmf_fil_iovar_data_set(ifp, \"event_msgs\", fweh-\u003eevent_mask,\n 429:\t\t\t\t\t       fweh-\u003eevent_mask_len);\n 430:\t\tif (err) {\n 431:\t\t\tbphy_err(drvr, \"Set event_msgs error (%d)\\n\", err);\n 432:\t\t\tgoto done;\n 433:\t\t}\n 434:\t\n 435:\t\t/* Setup default scan channel time */\n 436:\t\terr = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,\n 437:\t\t\t\t\t    BRCMF_DEFAULT_SCAN_CHANNEL_TIME);\n 438:\t\tif (err) {\n 439:\t\t\tbphy_err(drvr, \"BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\\n\",\n 440:\t\t\t\t err);\n 441:\t\t\tgoto done;\n 442:\t\t}\n 443:\t\n 444:\t\t/* Setup default scan unassoc time */\n 445:\t\terr = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,\n 446:\t\t\t\t\t    BRCMF_DEFAULT_SCAN_UNASSOC_TIME);\n 447:\t\tif (err) {\n 448:\t\t\tbphy_err(drvr, \"BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\\n\",\n 449:\t\t\t\t err);\n 450:\t\t\tgoto done;\n 451:\t\t}\n 452:\t\n 453:\t\t/* Enable tx beamforming, errors can be ignored (not supported) */\n 454:\t\t(void)brcmf_fil_iovar_int_set(ifp, \"txbf\", 1);\n 455:\tdone:\n 456:\t\treturn err;\n 457:\t}\n 458:\t\n 459:\t#ifndef CONFIG_BRCM_TRACING\n 460:\tvoid __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...)\n 461:\t{\n 462:\t\tstruct va_format vaf;\n 463:\t\tva_list args;\n 464:\t\n"
}

51/2 2026/08/02 00:49 llm patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 53678
							output: 49
							thoughts: 126
						

Thoughts:
Here's my analysis of what's going on:

**Analysis of `brcmf_c_preinit_dcmds` and its Implications**

Okay, so `brcmf_c_preinit_dcmds` returns an error code, `err`. That's the key. If the USB fuzzer in syzkaller just responds with zeros for every request, then `err` will be zero. Which initially looks like a good sign, a success. But I need to dig deeper. Wait a second, `brcmf_fil_iovar_data_get` is called later, and that reads data directly from the device. If the fuzzer is sending all zeros, then the data read by this function is going to be all zeros too. That could cause all sorts of problems down the line, corrupting internal structures, passing invalid values as parameters to other functions.

If `brcmf_c_preinit_dcmds` returns success (i.e., `err` is 0), the execution flow proceeds to `brcmf_bus_started`. That's where things get interesting, because that's where `brcmf_feat_attach` is called. So, the key is the data that's read by `brcmf_fil_iovar_data_get`.



52/2 2026/08/02 00:50 tool grepper
0m Args:
{
  "Expression": "brcmf_feat_attach",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c=1214=static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1243-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:1244:\tbrcmf_feat_attach(drvr);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c-1245-\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c=259=static int brcmf_feat_fwcap_debugfs_read(struct seq_file *seq, void *data)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-288-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c:289:void brcmf_feat_attach(struct brcmf_pub *drvr)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-290-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h=90=enum brcmf_feat_quirk {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h-96-/**\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h:97: * brcmf_feat_attach() - determine features and quirks.\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h-98- *\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h-100- */\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h:101:void brcmf_feat_attach(struct brcmf_pub *drvr);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h-102-\n"
}

53/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 54763
							output: 53
							thoughts: 13
						

Thoughts:
Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of embedded system development:

**Analyzing `brcmf_feat_attach`**

Alright, time to dive into `brcmf_feat_attach`. I immediately recognize this as a critical function within the Broadcom wireless firmware, probably related to feature initialization or attachment during the driver's setup phase. I need to understand its role in the bigger picture, particularly how it interacts with the hardware and the rest of the driver's architecture. I expect this function deals with device capabilities, feature flags, and potentially sets up the necessary data structures for different wireless functionalities. My instinct says I should be looking for interactions with hardware registers, power management logic, and perhaps even firmware image loading or validation. Let's see what secrets this function holds.



54/2 2026/08/02 00:50 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c",
  "FirstLine": 289,
  "LineCount": 50
}

Results:
{
  "Contents": " 289:\tvoid brcmf_feat_attach(struct brcmf_pub *drvr)\n 290:\t{\n 291:\t\tstruct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);\n 292:\t\tstruct brcmf_pno_macaddr_le pfn_mac;\n 293:\t\tstruct brcmf_gscan_config gscan_cfg;\n 294:\t\tu32 wowl_cap;\n 295:\t\ts32 err;\n 296:\t\n 297:\t\tbrcmf_feat_firmware_capabilities(ifp);\n 298:\t\tmemset(\u0026gscan_cfg, 0, sizeof(gscan_cfg));\n 299:\t\tif (drvr-\u003ebus_if-\u003echip != BRCM_CC_43430_CHIP_ID \u0026\u0026\n 300:\t\t    drvr-\u003ebus_if-\u003echip != BRCM_CC_4345_CHIP_ID \u0026\u0026\n 301:\t\t    drvr-\u003ebus_if-\u003echip != BRCM_CC_43454_CHIP_ID \u0026\u0026\n 302:\t\t    drvr-\u003ebus_if-\u003echip != CY_CC_43439_CHIP_ID)\n 303:\t\t\tbrcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,\n 304:\t\t\t\t\t\t  \"pfn_gscan_cfg\",\n 305:\t\t\t\t\t\t  \u0026gscan_cfg, sizeof(gscan_cfg));\n 306:\t\tbrcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, \"pfn\");\n 307:\t\tif (drvr-\u003ebus_if-\u003ewowl_supported)\n 308:\t\t\tbrcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, \"wowl\");\n 309:\t\tif (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {\n 310:\t\t\terr = brcmf_fil_iovar_int_get(ifp, \"wowl_cap\", \u0026wowl_cap);\n 311:\t\t\tif (!err) {\n 312:\t\t\t\tifp-\u003edrvr-\u003efeat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);\n 313:\t\t\t\tif (wowl_cap \u0026 BRCMF_WOWL_PFN_FOUND)\n 314:\t\t\t\t\tifp-\u003edrvr-\u003efeat_flags |=\n 315:\t\t\t\t\t\tBIT(BRCMF_FEAT_WOWL_ND);\n 316:\t\t\t\tif (wowl_cap \u0026 BRCMF_WOWL_GTK_FAILURE)\n 317:\t\t\t\t\tifp-\u003edrvr-\u003efeat_flags |=\n 318:\t\t\t\t\t\tBIT(BRCMF_FEAT_WOWL_GTK);\n 319:\t\t\t}\n 320:\t\t}\n 321:\t\t/* MBSS does not work for all chips */\n 322:\t\tswitch (drvr-\u003ebus_if-\u003echip) {\n 323:\t\tcase BRCM_CC_4330_CHIP_ID:\n 324:\t\tcase BRCM_CC_43362_CHIP_ID:\n 325:\t\t\tifp-\u003edrvr-\u003efeat_flags \u0026= ~BIT(BRCMF_FEAT_MBSS);\n 326:\t\t\tbreak;\n 327:\t\tdefault:\n 328:\t\t\tbreak;\n 329:\t\t}\n 330:\t\tbrcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, \"rsdb_mode\");\n 331:\t\tbrcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, \"tdls_enable\");\n 332:\t\tbrcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, \"mfp\");\n 333:\t\tbrcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_DUMP_OBSS, \"dump_obss\");\n 334:\t\n 335:\t\tpfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;\n 336:\t\terr = brcmf_fil_iovar_data_get(ifp, \"pfn_macaddr\", \u0026pfn_mac,\n 337:\t\t\t\t\t       sizeof(pfn_mac));\n 338:\t\tif (!err)\n"
}

55/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 56168
							output: 52
							thoughts: 23
						

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

**Diving into `brcmf_feat_firmware_capabilities`**

Okay, so I see a call to `brcmf_feat_firmware_capabilities`. My immediate instinct is to dissect what's happening. I need to understand this function. It's obviously significant enough to be called, so let's start by figuring out precisely what its purpose is. What data does it handle? What are the inputs? What are the outputs? I'll probably be looking at how it interfaces with the firmware, and what specific capabilities it's attempting to discover or enable. This feels like a core piece of the initialization or feature discovery process, and understanding its role is key to grasping the broader system behavior.



56/2 2026/08/02 00:50 tool grepper
0m Args:
{
  "Expression": "brcmf_feat_firmware_capabilities",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c=206=static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-227-#define MAX_CAPS_BUFFER_SIZE\t768\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c:228:static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-229-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c=289=void brcmf_feat_attach(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-296-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c:297:\tbrcmf_feat_firmware_capabilities(ifp);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-298-\tmemset(\u0026gscan_cfg, 0, sizeof(gscan_cfg));\n"
}

57/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 56784
							output: 53
							thoughts: 16
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Analyzing Firmware Capabilities**

Alright, time to dive into `brcmf_feat_firmware_capabilities`. I need to understand what this module is all about. Based on the name, it's pretty clear that this is where the code that deals with determining the features supported by the firmware is located. Given the naming convention, it's likely dealing with Broadcom's WiFi firmware. I'm going to quickly skim the header file for definitions and data structures first. I'm looking for the essential elements: are we talking about a simple bitfield, a more complex structure, or maybe even an opaque blob that requires specific functions to interpret? I need to get a high-level sense of how these capabilities are represented before I dig into any of the parsing or interpretation logic. Then I'll focus on how the firmware capabilities are being read, how the data is being stored internally, and how the driver subsequently uses this information. I'll expect to see this information being used to determine the features the driver enables. I am also going to be looking for potential security vulnerabilities that may have been overlooked or patched.



58/2 2026/08/02 00:50 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c",
  "FirstLine": 228,
  "LineCount": 50
}

Results:
{
  "Contents": " 228:\tstatic void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)\n 229:\t{\n 230:\t\tstruct brcmf_pub *drvr = ifp-\u003edrvr;\n 231:\t\tchar caps[MAX_CAPS_BUFFER_SIZE];\n 232:\t\tenum brcmf_feat_id id;\n 233:\t\tint i, err;\n 234:\t\n 235:\t\terr = brcmf_fil_iovar_data_get(ifp, \"cap\", caps, sizeof(caps));\n 236:\t\tif (err) {\n 237:\t\t\tbphy_err(drvr, \"could not get firmware cap (%d)\\n\", err);\n 238:\t\t\treturn;\n 239:\t\t}\n 240:\t\n 241:\t\tbrcmf_dbg(INFO, \"[ %s]\\n\", caps);\n 242:\t\n 243:\t\tfor (i = 0; i \u003c ARRAY_SIZE(brcmf_fwcap_map); i++) {\n 244:\t\t\tif (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) {\n 245:\t\t\t\tid = brcmf_fwcap_map[i].feature;\n 246:\t\t\t\tbrcmf_dbg(INFO, \"enabling feature: %s\\n\",\n 247:\t\t\t\t\t  brcmf_feat_names[id]);\n 248:\t\t\t\tifp-\u003edrvr-\u003efeat_flags |= BIT(id);\n 249:\t\t\t}\n 250:\t\t}\n 251:\t}\n 252:\t\n 253:\t/**\n 254:\t * brcmf_feat_fwcap_debugfs_read() - expose firmware capabilities to debugfs.\n 255:\t *\n 256:\t * @seq: sequence for debugfs entry.\n 257:\t * @data: raw data pointer.\n 258:\t */\n 259:\tstatic int brcmf_feat_fwcap_debugfs_read(struct seq_file *seq, void *data)\n 260:\t{\n 261:\t\tstruct brcmf_bus *bus_if = dev_get_drvdata(seq-\u003eprivate);\n 262:\t\tstruct brcmf_pub *drvr = bus_if-\u003edrvr;\n 263:\t\tstruct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);\n 264:\t\tchar caps[MAX_CAPS_BUFFER_SIZE + 1] = { };\n 265:\t\tchar *tmp;\n 266:\t\tint err;\n 267:\t\n 268:\t\terr = brcmf_fil_iovar_data_get(ifp, \"cap\", caps, sizeof(caps));\n 269:\t\tif (err) {\n 270:\t\t\tbphy_err(drvr, \"could not get firmware cap (%d)\\n\", err);\n 271:\t\t\treturn err;\n 272:\t\t}\n 273:\t\n 274:\t\t/* Put every capability in a new line */\n 275:\t\tfor (tmp = caps; *tmp; tmp++) {\n 276:\t\t\tif (*tmp == ' ')\n 277:\t\t\t\t*tmp = '\\n';\n"
}

59/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 57978
							output: 53
							thoughts: 65
						

Thoughts:
Okay, let's break this down.

**Decoding Firmware Capabilities**

Right, so I'm digging into how the system determines the capabilities of this Broadcom Wi-Fi device. I see that the function `brcmf_feat_firmware_capabilities` is the one reading the "cap" data directly from the device. Seems straightforward enough at first glance. But, hold on a second...

I need to circle back to `BRCMF_FEAT_PMKID_V2`. I remember seeing that feature flagged, and I need to understand how it's handled in relation to the general capability reading. 

The next logical step, before I dig further, is to go back and check the `brcmf_feat_wlcfeat_map` data structure. I've encountered this one previously, so it should be a key part of the mapping between device features and their internal representations. That mapping will give me the best view of the feature enablement process. I need to refresh my understanding of how those maps relate to what `brcmf_feat_firmware_capabilities` is doing.



60/2 2026/08/02 00:50 tool grepper
0m Args:
{
  "Expression": "brcmf_feat_wlcfeat_map",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c=131=struct brcmf_feat_wlcfeat {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-136-\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) },\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c=142=static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-158-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c:159:\tfor (i = 0; i \u003c ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c:160:\t\te = \u0026brcmf_feat_wlcfeat_map[i];\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c-161-\t\tif (major \u003e e-\u003emin_ver_major ||\n"
}

61/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 58776
							output: 53
							thoughts: 19
						

Thoughts:
Okay, here's my interpretation of that thought process, assuming I'm well-versed in the subject matter:

**Diving into `brcmf_feat_wlc_version_overrides`**

Alright, time to dig into this specific file: `brcmf_feat_wlc_version_overrides`. I immediately recognize this as part of the Broadcom wireless driver, likely related to feature negotiation or compatibility based on the version of the Broadcom Wireless LAN Controller (WLC) firmware. I'm expecting to find conditional logic here – perhaps a series of macros, lookups, or function pointers – that allows the driver to adapt its behavior depending on the capabilities or revision level of the WLC it's interacting with. This could range from enabling specific features only available on newer firmware versions, to implementing workarounds for known bugs or limitations in older versions. I'll be looking closely at the data structures and control flow to understand how these overrides are implemented and managed. Specific areas of focus will be version checks, function pointer tables, and any feature flag definitions. I'll need to understand how the driver determines the WLC version, and what actions it takes based on that determination. This is likely a critical area for maintaining compatibility and maximizing the functionality of the wireless interface across a range of WLC firmware releases.



62/2 2026/08/02 00:50 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c",
  "FirstLine": 142,
  "LineCount": 50
}

Results:
{
  "Contents": " 142:\tstatic void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv)\n 143:\t{\n 144:\t\tstruct brcmf_if *ifp = brcmf_get_ifp(drv, 0);\n 145:\t\tconst struct brcmf_feat_wlcfeat *e;\n 146:\t\tstruct brcmf_wlc_version_le ver;\n 147:\t\tu32 feat_flags = 0;\n 148:\t\tint i, err, major, minor;\n 149:\t\n 150:\t\terr = brcmf_fil_iovar_data_get(ifp, \"wlc_ver\", \u0026ver, sizeof(ver));\n 151:\t\tif (err)\n 152:\t\t\treturn;\n 153:\t\n 154:\t\tmajor = le16_to_cpu(ver.wlc_ver_major);\n 155:\t\tminor = le16_to_cpu(ver.wlc_ver_minor);\n 156:\t\n 157:\t\tbrcmf_dbg(INFO, \"WLC version: %d.%d\\n\", major, minor);\n 158:\t\n 159:\t\tfor (i = 0; i \u003c ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) {\n 160:\t\t\te = \u0026brcmf_feat_wlcfeat_map[i];\n 161:\t\t\tif (major \u003e e-\u003emin_ver_major ||\n 162:\t\t\t    (major == e-\u003emin_ver_major \u0026\u0026\n 163:\t\t\t     minor \u003e= e-\u003emin_ver_minor)) {\n 164:\t\t\t\tfeat_flags |= e-\u003efeat_flags;\n 165:\t\t\t}\n 166:\t\t}\n 167:\t\n 168:\t\tif (!feat_flags)\n 169:\t\t\treturn;\n 170:\t\n 171:\t\tfor (i = 0; i \u003c BRCMF_FEAT_LAST; i++)\n 172:\t\t\tif (feat_flags \u0026 BIT(i))\n 173:\t\t\t\tbrcmf_dbg(INFO, \"enabling firmware feature: %s\\n\",\n 174:\t\t\t\t\t  brcmf_feat_names[i]);\n 175:\t\tdrv-\u003efeat_flags |= feat_flags;\n 176:\t}\n 177:\t\n 178:\t/**\n 179:\t * brcmf_feat_iovar_int_get() - determine feature through iovar query.\n 180:\t *\n 181:\t * @ifp: interface to query.\n 182:\t * @id: feature id.\n 183:\t * @name: iovar name.\n 184:\t */\n 185:\tstatic void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,\n 186:\t\t\t\t\t     enum brcmf_feat_id id, char *name)\n 187:\t{\n 188:\t\tu32 data;\n 189:\t\tint err;\n 190:\t\n 191:\t\t/* we need to know firmware error */\n"
}

63/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 59961
							output: 53
							thoughts: 571
						

Thoughts:
**Analyzing the Feasibility of Reaching `brcmf_pmksa_v2_op` via Syzkaller USB Fuzzing**

Okay, let's break this down. My understanding is that `BRCMF_FEAT_PMKID_V2` is contingent on the firmware's response to `wlc_ver`. Specifically, if the major version reported in that response is 12 or greater, the feature is enabled. The question is, can I, with syzkaller's USB fuzzer, manipulate this `wlc_ver` response to trigger the activation of this feature? If I can, then I can potentially reach the `brcmf_pmksa_v2_op` function through cfg80211 operations.

My first thought was, can syzkaller's USB fuzzer even initialize the `brcmfmac` driver? The driver initiates by sending multiple commands; `BRCMF_C_GET_REVINFO`, `ver`, `clmver`, `mpc`, `event_msgs`, `BRCMF_C_SET_SCAN_CHANNEL_TIME`, `BRCMF_C_SET_SCAN_UNASSOC_TIME`, `txbf`, `cap`, and `wlc_ver`. Initially, I thought that if the fuzzer simply returned 0 for all of these, the driver might proceed. However, I have to account for error handling in functions such as `brcmf_c_preinit_dcmds` that can check the error value (`err`). If my fuzzer returns 0, the error check will see 0.

Then I realized that `brcmf_feat_wlc_version_overrides` reads the `wlc_ver` response. If my fuzzer responds with 0, then the `major` and `minor` version numbers will also be 0. Thus, since I need `major >= 12` to enable `BRCMF_FEAT_PMKID_V2`, this approach would fail.

A crucial point I need to consider is whether the fuzzer can return *non-zero* data. The good news is, I know that syzkaller's USB fuzzer can indeed return arbitrary data for both USB control and bulk transfers. I can use the `syz_usb_connect` call to describe the USB device, and then syzkaller lets me inject any data I want in response to USB Request Blocks (URBs).

Therefore, it's theoretically possible to craft a `wlc_ver` response where the major version is 12 or greater. Consequently, I can activate `BRCMF_FEAT_PMKID_V2` and reach `brcmf_pmksa_v2_op`.

I have to consider other aspects though, like `brcmf_netif_mon_rx`, which is called within `brcmf_rx_frame` if the interface is in monitor mode. It seems like the critical path is `brcmf_rx_frame` so I will focus on that.



64/2 2026/08/02 00:50 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c",
  "FirstLine": 516,
  "LineCount": 50
}

Results:
{
  "Contents": " 516:\tvoid brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event,\n 517:\t\t\t    bool inirq)\n 518:\t{\n 519:\t\tstruct brcmf_if *ifp;\n 520:\t\tstruct brcmf_bus *bus_if = dev_get_drvdata(dev);\n 521:\t\tstruct brcmf_pub *drvr = bus_if-\u003edrvr;\n 522:\t\n 523:\t\tbrcmf_dbg(DATA, \"Enter: %s: rxp=%p\\n\", dev_name(dev), skb);\n 524:\t\n 525:\t\tif (brcmf_rx_hdrpull(drvr, skb, \u0026ifp))\n 526:\t\t\treturn;\n 527:\t\n 528:\t\tif (brcmf_proto_is_reorder_skb(skb)) {\n 529:\t\t\tbrcmf_proto_rxreorder(ifp, skb);\n 530:\t\t} else {\n 531:\t\t\t/* Process special event packets */\n 532:\t\t\tif (handle_event) {\n 533:\t\t\t\tgfp_t gfp = inirq ? GFP_ATOMIC : GFP_KERNEL;\n 534:\t\n 535:\t\t\t\tbrcmf_fweh_process_skb(ifp-\u003edrvr, skb,\n 536:\t\t\t\t\t\t       BCMILCP_SUBTYPE_VENDOR_LONG, gfp);\n 537:\t\t\t}\n 538:\t\t\tbrcmf_netif_rx(ifp, skb);\n 539:\t\t}\n 540:\t}\n 541:\t\n 542:\tvoid brcmf_rx_event(struct device *dev, struct sk_buff *skb)\n 543:\t{\n 544:\t\tstruct brcmf_if *ifp;\n 545:\t\tstruct brcmf_bus *bus_if = dev_get_drvdata(dev);\n 546:\t\tstruct brcmf_pub *drvr = bus_if-\u003edrvr;\n 547:\t\n 548:\t\tbrcmf_dbg(EVENT, \"Enter: %s: rxp=%p\\n\", dev_name(dev), skb);\n 549:\t\n 550:\t\tif (brcmf_rx_hdrpull(drvr, skb, \u0026ifp))\n 551:\t\t\treturn;\n 552:\t\n 553:\t\tbrcmf_fweh_process_skb(ifp-\u003edrvr, skb, 0, GFP_KERNEL);\n 554:\t\tbrcmu_pkt_buf_free_skb(skb);\n 555:\t}\n 556:\t\n 557:\tvoid brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)\n 558:\t{\n 559:\t\tstruct ethhdr *eh;\n 560:\t\tu16 type;\n 561:\t\n 562:\t\tif (!ifp) {\n 563:\t\t\tbrcmu_pkt_buf_free_skb(txp);\n 564:\t\t\treturn;\n 565:\t\t}\n"
}

65/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 62107
							output: 52
							thoughts: 74
						

Thoughts:
**Investigating the BRCM WiFi Driver Receive Path**

Okay, hold on a second. I was under the impression that `brcmf_rx_frame` was calling `brcmf_netif_mon_rx`, but that doesn't seem right. Looking back at the code, it looks like it's actually calling `brcmf_netif_rx`. That's a key distinction. Now, where is `brcmf_netif_mon_rx` actually being invoked? I thought I had identified its call site earlier within `msgbuf.c`. Let me double-check that location again and ensure that my prior analysis was correct. I need to be sure about this.



66/2 2026/08/02 00:50 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

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"
}

67/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 62919
							output: 52
							thoughts: 73
						

Thoughts:
Here's my summary, as the expert:

**Narrowing Down the `brcmf_netif_mon_rx` Callers**

Okay, so I'm focusing on the call to `brcmf_netif_mon_rx`. From what I've traced, it *seems* like it's exclusively called from `msgbuf.c`. That's a strong clue. And, if my memory serves me correctly, `msgbuf.c` is *primarily* associated with the PCIe driver architecture. But hold on a second... is there any chance the USB driver, particularly in its specific implementation or edge cases, utilizes `msgbuf.c` as well? I need to verify that assumption before I proceed. Let me double-check the potential attachment points by looking at the calls to `brcmf_proto_msgbuf_attach`. That should clarify this line of thought.



68/2 2026/08/02 00:50 tool grepper
0m Args:
{
  "Expression": "brcmf_proto_msgbuf_attach",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c=1575=static void brcmf_msgbuf_debugfs_create(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1579-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c:1580:int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c-1581-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h=32=void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h:33:int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h-34-void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h-35-#else\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h:36:static inline int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h-37-{\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c=20=int brcmf_proto_attach(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-35-\t} else if (drvr-\u003ebus_if-\u003eproto_type == BRCMF_PROTO_MSGBUF) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c:36:\t\tif (brcmf_proto_msgbuf_attach(drvr))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-37-\t\t\tgoto fail;\n"
}

69/2 2026/08/02 00:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 63904
							output: 45
							thoughts: 55
						

Thoughts:
Okay, here's my interpretation of that thought process, assuming I'm an expert in this area and thinking this through:

**Investigating brcmf_proto_msgbuf_attach and its Context**

Right, so `brcmf_proto_msgbuf_attach` gets called from `brcmf_proto_attach`. The conditional is based on `proto_type`, specifically when `proto_type` is set to `BRCMF_PROTO_MSGBUF`. My immediate next step is crystal clear: I need to trace back and understand how and where `proto_type` is actually set. That's the key variable here. Knowing its origin is crucial to understanding the path that leads to `brcmf_proto_msgbuf_attach` being called, and why. I need to figure out where and how `proto_type` is being assigned a value so that I can understand the bigger picture.



70/2 2026/08/02 00:51 tool grepper
0m Args:
{
  "Expression": "proto_type",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c=1040=static int brcmf_ops_sdio_probe(struct sdio_func *func,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c-1085-\tbus_if-\u003ebus_priv.sdio = sdiodev;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c:1086:\tbus_if-\u003eproto_type = BRCMF_PROTO_BCDC;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c-1087-\tbus_if-\u003efwvid = id-\u003edriver_data;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h=141=struct brcmf_bus_stats {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-149- * @bus_priv: pointer to private bus device.\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h:150: * @proto_type: protocol type, bcdc or msgbuf\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-151- * @dev: device pointer of bus device.\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h=165=struct brcmf_bus {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-170-\t} bus_priv;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h:171:\tenum brcmf_bus_protocol_type proto_type;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-172-\tstruct device *dev;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c=2489=brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2564-\tbus-\u003eops = \u0026brcmf_pcie_bus_ops;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c:2565:\tbus-\u003eproto_type = BRCMF_PROTO_MSGBUF;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c-2566-\tbus-\u003echip = devinfo-\u003ecoreid;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c=20=int brcmf_proto_attach(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-31-\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c:32:\tif (drvr-\u003ebus_if-\u003eproto_type == BRCMF_PROTO_BCDC) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-33-\t\tif (brcmf_proto_bcdc_attach(drvr))\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-34-\t\t\tgoto fail;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c:35:\t} else if (drvr-\u003ebus_if-\u003eproto_type == BRCMF_PROTO_MSGBUF) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-36-\t\tif (brcmf_proto_msgbuf_attach(drvr))\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-39-\t\tbphy_err(drvr, \"Unsupported proto type %d\\n\",\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c:40:\t\t\t drvr-\u003ebus_if-\u003eproto_type);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-41-\t\tgoto fail;\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c=59=void brcmf_proto_detach(struct brcmf_pub *drvr)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-63-\tif (drvr-\u003eproto) {\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c:64:\t\tif (drvr-\u003ebus_if-\u003eproto_type == BRCMF_PROTO_BCDC)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-65-\t\t\tbrcmf_proto_bcdc_detach(drvr);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c:66:\t\telse if (drvr-\u003ebus_if-\u003eproto_type == BRCMF_PROTO_MSGBUF)\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c-67-\t\t\tbrcmf_proto_msgbuf_detach(drvr);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c=1244=static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1268-\tbus-\u003eops = \u0026brcmf_usb_bus_ops;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c:1269:\tbus-\u003eproto_type = BRCMF_PROTO_BCDC;\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c-1270-\tbus-\u003efwvid = fwvid;\n"
}

71/2 2026/08/02 00:51 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 65901
							output: 52
							thoughts: 799
						

Thoughts:
**Reaching brcmf_pmksa_v2_op for Fuzzing**

Okay, so I'm focusing on these Broadcom Wi-Fi driver changes and need to figure out which are actually fuzzable. First, it looks like `BRCMF_PROTO_MSGBUF` is strictly PCIe, meaning `msgbuf.c` and `flowring.c` are out, given that syzkaller doesn't emulate the PCIe Broadcom cards. Those are dead ends. But what about `brcmf_pmksa_v2_op` in `cfg80211.c`? That seems more promising. I need to figure out if it's reachable via USB.

The crucial point here is that it requires initialization and a `wlc_ver` of 12 or greater. Is this a functional change? Yes, it supports V2 PMKSA cache updates, so potentially interesting. Is it worth the effort? If reachable through USB, absolutely.

Wait, let me think. The prompt mentioned unreachable code paths in virtualized environments like GCE or QEMU, even with hardware emulation. Can syzkaller's USB fuzzer *actually* initialize `brcmfmac`?

Okay, let's break this down. The driver needs firmware. The USB fuzzer triggers `brcmf_usb_probe`, which requests the firmware. If the firmware is present (as it usually is in syzkaller images), it gets loaded, sent to the USB device, and the fuzzer accepts the URBs. Then comes `brcmf_attach`. That then calls `brcmf_bus_started`, which in turn calls `brcmf_c_preinit_dcmds`. Inside `brcmf_c_preinit_dcmds`, the code sends commands like `BRCMF_C_GET_REVINFO` through `brcmf_fil_iovar_data_get` using BCDC protocol over USB.

The fuzzer can supply arbitrary data back to these USB bulk transfers. If it provides something reasonable (or even just zeros, if the driver isn't super strict), the initialization might work. Hang on, does `brcmf_c_preinit_dcmds` check for errors? Yes, it does. `brcmf_fil_iovar_data_get` sends a command and waits for a reply. If the fuzzer provides a BCDC header and some data, then `brcmf_fil_iovar_data_get` will return 0 which is success! So, yes, it seems I *can* successfully initialize the driver!

That means the fuzzer could then provide a `wlc_ver` of >= 12, enabling `BRCMF_FEAT_PMKID_V2`. Then, through netlink, I can send `NL80211_CMD_SET_PMKSA`, which calls `brcmf_cfg80211_set_pmksa`, which *then* calls `brcmf_pmksa_v2_op`. Brilliant! So, `brcmf_pmksa_v2_op` IS reachable and worth fuzzing.

Now, what about that other change I saw in `brcmsmac/ampdu.c`? Gotta investigate that one... let's check the diff.



72/2 2026/08/02 00:51 tool grepper
0m Args:
{
  "Expression": "brcms_c_ampdu_add_frame",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c=469=void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c-484- */\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c:485:int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c-486-\t\t\t    struct sk_buff *p)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.h=40=void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.h-41-\t\t\t\t struct brcms_c_info *wlc);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.h:42:int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.h-43-\t\t\t    struct sk_buff *p);\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c=1343=static void prep_ampdu_frame(struct dma_info *di, struct sk_buff *p)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c-1347-\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c:1348:\tret = brcms_c_ampdu_add_frame(session, p);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c-1349-\tif (ret == -ENOSPC) {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c-1354-\t\tampdu_finalize(di);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c:1355:\t\tret = brcms_c_ampdu_add_frame(session, p);\ndrivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c-1356-\t}\n"
}

73/2 2026/08/02 00:51 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 68177
							output: 42
							thoughts: 518
						

Thoughts:
**Analyzing Recent Changes and Fuzzing Potential**

Okay, so I've been reviewing this diff and here's the breakdown of my thinking: the comment update in `brcmsmac/ampdu.c` is just that - a comment. No functional change to worry about, and it's a clarification really.

Moving on, `brcmf_sdio_rxglom` in `sdio.c` looks interesting but unfortunately, it doesn't seem directly fuzzable. My understanding is that Syzkaller, while powerful, doesn't have an SDIO fuzzer. It's got USB, PCI (with limitations on vendor-specific physical cards), and vhci for Bluetooth, but not SDIO, which means this code path is likely unreachable for fuzzing.

Now, that brings me to `brcmf_delay` in `cfg80211.c`. It's a functional change, a straightforward alteration of a delay function, really. Nothing terribly complex, even though it's a change to the existing code.

Therefore, the most interesting and potentially fuzz-worthy target I've found so far is `brcmf_pmksa_v2_op`. This is where I'll focus my efforts. To determine reachability, I need to confirm its existence within the `brcmfmac` driver, and determine the configuration dependencies. Let's dig into Kconfig and see what's what.



74/2 2026/08/02 00:51 tool grepper
0m Args:
{
  "Expression": "config BRCMFMAC",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/"
}

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"
}

75/2 2026/08/02 00:51 llm patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 69657
							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.



76/2 2026/08/02 00:52 tool read-file
0m Args:
{
  "File": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig",
  "FirstLine": 1,
  "LineCount": 50
}

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  46:\t\thelp\n  47:\t\t  This option enables the PCIE bus interface support for Broadcom\n  48:\t\t  IEEE802.11ac embedded FullMAC WLAN driver. Say Y if you want to\n  49:\t\t  use the driver for an PCIE wireless card.\n  50:\t\n"
}

77/2 2026/08/02 00:52 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 70698
							output: 57
							thoughts: 1455
						

Thoughts:
**Fuzzing Feasibility Analysis for BRCMFMAC Driver**

Okay, so I need to assess whether fuzzing `BRCMFMAC` and specifically the `BRCMFMAC_USB` configurations is worthwhile, given the changes. My initial thought is to consider `brcmf_pmksa_v2_op`. Is it actually reachable? Syzkaller's USB fuzzer offers arbitrary USB responses. However, the driver needs the firmware loaded first via `brcmf_usb_probe`, which in turn calls `brcmf_fw_get_firmwares`. The syzkaller image has to have the relevant firmware. A minimal Debian might or might not have `firmware-brcm80211` installed. If not, initialization fails. If present, the driver downloads firmware and sends `dcmds`. The fuzzer needs to provide responses to these `dcmds` without triggering errors in `brcmf_c_preinit_dcmds`. If the fuzzer returns 0 for a USB transfer, `brcmf_fil_iovar_data_get` will return 0, which leads to `brcmf_c_preinit_dcmds` succeeding. Then `brcmf_feat_attach` will be called, which reads `wlc_ver`. The fuzzer can generate random data, meaning the driver could see a `major >= 12`, enabling `BRCMF_FEAT_PMKID_V2`. This *might* work through a sequence of successful USB transfers followed by a netlink command to reach `brcmf_pmksa_v2_op`. Though unlikely, it's possible with syzkaller's coverage-guided approach.

The prompt stipulates to return "WorthFuzzing=false" if certain conditions are met, namely code that is impossible to reach in virtualized environments. While Broadcom PCIe Wi-Fi cards are not emulated in standard QEMU, the USB path appears viable. The PCIe-specific changes (`msgbuf.c`, `flowring.c`, `pcie.c`) are not reachable since QEMU doesn't emulate the necessary hardware. Similarly, SDIO changes (`sdio.c`) are out as syzkaller has no SDIO fuzzer. However, `cfg80211.c` is reachable via USB. Given that the only meaningful change within that file (aside from `brcmf_delay`) is `brcmf_pmksa_v2_op`, it's still worth fuzzing. It's a new function that does something functional, parsing and formatting data to be sent to the firmware. Checking the code again, `brcmf_pmksa_v2_op` seems correct, and it takes `pmksa` data from cfg80211 and updates the driver's internal V2 PMKSA list before sending it to the firmware via `brcmf_fil_iovar_data_set`. I'll focus on `brcmf_pmksa_v2_op`. Finally, syzkaller does offer `syz_usb_connect` calls which enable any USB device to be emulated.

Looking at the code again, `brcmf_pmksa_v2_op` is static, and is only called by other static functions. The prompt recommends preferring non-static API entry points, but the functions calling this one are also static, although assigned to `cfg80211_ops`, therefore, still worth fuzzing.



78/2 2026/08/02 00:52 tool grepper
0m Args:
{
  "Expression": "brcmf_cfg80211_set_pmksa",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=4486=static s32\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:4487:brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-4488-\t\t\t struct cfg80211_pmksa *pmksa)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=6083=static struct cfg80211_ops brcmf_cfg80211_ops = {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-6104-\t.resume = brcmf_cfg80211_resume,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:6105:\t.set_pmksa = brcmf_cfg80211_set_pmksa,\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-6106-\t.del_pmksa = brcmf_cfg80211_del_pmksa,\n"
}

79/2 2026/08/02 00:52 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 73377
							output: 52
							thoughts: 353
						

Thoughts:
**Analyzing Potential Functions for Further Examination**

Okay, so I'm looking for a non-static function to dig into deeper. The initial list is pretty sparse because, well, most of the functions are static. *brcmf_cfg80211_attach* is the first non-static function that comes to mind, but that's just the attach function. Not really a good starting point for investigation, I think.

The next thing I'm considering is *brcmf_pmksa_v2_op*. It's *potentially* static, but that's a good thing. If it *is* static, I can just focus on it. But I should check the compiler behavior, given the function's size. Let's see... the compiler might not inline it because it's pretty large, and it's called from three different locations. Let's verify: *brcmf_cfg80211_set_pmksa*, *brcmf_cfg80211_del_pmksa*, and *brcmf_cfg80211_flush_pmksa*. Okay, it's about 80 lines – definitely large enough to make the compiler hesitant to inline it everywhere. So *brcmf_pmksa_v2_op* looks like a solid focus.

Hang on, what about *brcmf_netif_mon_rx*? Let me get back to that one.

Okay, *brcmf_netif_mon_rx* is non-static: `void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)`. But it's only called from *msgbuf.c*, which is PCIe only. And since PCIe isn't easily fuzzable, it's probably unreachable. I need to make sure I'm not making assumptions, though. Let me check if *bcdc.c* (which handles USB and SDIO) calls it.



80/2 2026/08/02 00:52 tool grepper
0m Args:
{
  "Expression": "brcmf_netif_mon_rx",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

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"
}

81/2 2026/08/02 00:52 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 74755
							output: 44
							thoughts: 191
						

Thoughts:
**Analyzing Potential USB Reachability**

Okay, so I'm trying to figure out which functions are accessible through the USB interface in this Broadcom driver code. Let's see... I've checked `msgbuf.c` and found that `brcmf_netif_mon_rx` is only called within that file. Right, so that means it's not reachable via USB directly.

Next, let's look at `brcmf_flowring_block`. That's defined in `flowring.c`, but it's *only* used by `msgbuf.c`. So, that's another one that's off the table for USB access.

Alright, what about `brcmf_sdio_rxglom`? That function is in `sdio.c`, and that screams SDIO-specific. Definitely not reachable via USB.

Moving on, there's `brcmf_pcie_send_mb_data`. Clearly, that's in `pcie.c`. That's PCIe, so that function isn't reachable through a USB path either.

Now, the final one on my list is `brcmf_fws_macdesc_indicate` in `fwsignal.c`. The question here is... does `fwsignal.c` *ever* get used by the USB implementation? That's what I need to determine.



82/2 2026/08/02 00:52 tool grepper
0m Args:
{
  "Expression": "fwsignal",
  "PathPrefix": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/"
}

Results:
{
  "Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile=29=brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \\\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile-30-\t\tbcdc.o \\\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile:31:\t\tfwsignal.o\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile-32-brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \\\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c-18-#include \"bus.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c:19:#include \"fwsignal.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c-20-#include \"debug.h\"\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h=141=struct brcmf_bus_stats {\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-158- * @fwvid: firmware vendor-support identifier of the device.\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h:159: * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h-160- * @wowl_supported: is wowl supported by bus driver.\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-26-#include \"pno.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:27:#include \"fwsignal.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-28-#include \"cfg80211.h\"\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c-23-#include \"fweh.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c:24:#include \"fwsignal.h\"\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c-25-#include \"p2p.h\"\n"
}

83/2 2026/08/02 00:52 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 76017
							output: 283
							thoughts: 1416
						

Thoughts:
**Fuzzing Strategy for Broadcom WiFi Driver (USB)**

Okay, let's break this down. We're looking at changes in the Broadcom WiFi driver, specifically reachable functionality via USB. It seems `fwsignal.c` has a comment update, nothing actionable there. Similarly, the changes in `brcmf_netif_mon_rx`, `brcmf_flowring_block`, `brcmf_msgbuf_schedule_txdata`, `brcmf_pcie_send_mb_data`, and `brcmf_sdio_rxglom` are all PCIe or SDIO specific; not relevant for our USB focus. We have a similar situation with `brcms_c_ampdu_add_frame`. And we can also dismiss `brcmf_delay` for fuzzing efforts, as it’s a minor timing change.

The only *real* functional change is `brcmf_pmksa_v2_op`. This is a new V2 PMKSA cache update implementation; sounds like a good target. It takes `pmksa` fields and populates a struct sent to the firmware and can be reached via `NL80211_CMD_SET_PMKSA`.

To reach this, we need `BRCMFMAC` and `BRCMFMAC_USB` enabled. `BRCMFMAC_USB` depends on `USB`, so that's implicitly enabled. We also need `CFG80211` enabled. Syzkaller's `syz_usb_connect` can emulate the USB device. The driver will send `dcmds`. If the fuzzer replies with `wlc_ver` >= 12, then `BRCMF_FEAT_PMKID_V2` is enabled. Then `NL80211_CMD_SET_PMKSA` triggers `brcmf_pmksa_v2_op`. So, that's our reachable path.

Let's double-check. `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, and `brcmf_cfg80211_flush_pmksa` all call `brcmf_pmksa_v2_op`. Even though these functions are static, they have address taken in `cfg80211_ops`, so they are also actionable.

So, here's the plan:

*   **WorthFuzzing = true**
*   **FocusSymbols:** `brcmf_cfg80211_set_pmksa`, `brcmf_cfg80211_del_pmksa`, `brcmf_cfg80211_flush_pmksa`, `brcmf_pmksa_v2_op`
*   **EnableConfigs:** `BRCMFMAC`, `BRCMFMAC_USB` (which covers what we need)

We should be able to get this running in QEMU with syzkaller.



84/2 2026/08/02 00:53 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB"
  ],
  "FocusSymbols": [
    "brcmf_pmksa_v2_op",
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa"
  ],
  "Reasoning": "The patch modifies several components of the Broadcom Wi-Fi drivers. Changes to PCIe (msgbuf.c, flowring.c, pcie.c) and SDIO (sdio.c) are unreachable in standard virtualized environments as they require physical hardware. However, the brcmfmac driver supports USB, which can be emulated by syzkaller. The patch adds `brcmf_pmksa_v2_op` in the shared cfg80211.c to handle V2 PMKSA cache updates. This is reachable via cfg80211 netlink commands (e.g., NL80211_CMD_SET_PMKSA) if the emulated USB device reports a firmware version \u003e= 12. Therefore, this functional change is fuzzable.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BRCMFMAC",
    "BRCMFMAC_USB"
  ],
  "FocusSymbols": [
    "brcmf_pmksa_v2_op",
    "brcmf_cfg80211_set_pmksa",
    "brcmf_cfg80211_del_pmksa",
    "brcmf_cfg80211_flush_pmksa"
  ],
  "Reasoning": "The patch modifies several components of the Broadcom Wi-Fi drivers. Changes to PCIe (msgbuf.c, flowring.c, pcie.c) and SDIO (sdio.c) are unreachable in standard virtualized environments as they require physical hardware. However, the brcmfmac driver supports USB, which can be emulated by syzkaller. The patch adds `brcmf_pmksa_v2_op` in the shared cfg80211.c to handle V2 PMKSA cache updates. This is reachable via cfg80211 netlink commands (e.g., NL80211_CMD_SET_PMKSA) if the emulated USB device reports a firmware version \u003e= 12. Therefore, this functional change is fuzzable.",
  "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)