[PATCH 1/7] wifi: brcmfmac: match firmware capabilities as whole words
From: Andre Eikmeyer
Date: Wed Nov 04 2026 - 10:22:45 EST
brcmf_feat_firmware_capabilities() looks for each capability with
strnstr() in the space separated reply of the "cap" iovar, so a
capability matches inside a longer one. The Apple firmware for the
BCM4364 lists "hp2p" but not "p2p":
... evt_ext lpr_scan bkoff_evt hp2p rng_reseed arpoe
The driver still sets BRCMF_FEAT_P2P and advertises the P2P interface
types. wpa_supplicant then creates a P2P device, which fails because
the firmware rejects p2p_disc and p2p_da_override with
BCME_UNSUPPORTED:
brcmf_p2p_set_firmware: failed to update device address ret -52
brcmf_p2p_create_p2pdev: set p2p_disc error
brcmf_cfg80211_add_iface: add iface p2p-dev-wlp3s0 type 10 failed: err=-52
Split the reply at spaces and compare whole words. The trailing spaces
in "sae", which kept it from matching "sae-ap" and "sae_ext", and in
"fbt" can go.
Fixes: ec64241c9fd2 ("brcmfmac: obtain feature info using 'cap' firmware command")
Reported-by: Aditya Garg <aditya.garg@xxxxxxxxx>
Closes: https://lore.kernel.org/all/MA0P287MB021718EE92FC809CB2BB0F82B8BD2@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/
Tested-by: Yossef Osman <Yossef.Osman@xxxxxxxxx>
Tested-by: Aditya Garg <aditya.garg@xxxxxxxxx>
Signed-off-by: Andre Eikmeyer <dev@deq.rocks>
---
.../wireless/broadcom/brcm80211/brcmfmac/feature.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index cc19e5e7ebf..b324eb53a69 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -42,10 +42,10 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
{ BRCMF_FEAT_MONITOR_FLAG, "rtap" },
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
{ BRCMF_FEAT_DOT11H, "802.11h" },
- { BRCMF_FEAT_SAE, "sae " },
+ { BRCMF_FEAT_SAE, "sae" },
{ BRCMF_FEAT_FWAUTH, "idauth" },
{ BRCMF_FEAT_SAE_EXT, "sae_ext" },
- { BRCMF_FEAT_FBT, "fbt " },
+ { BRCMF_FEAT_FBT, "fbt" },
{ BRCMF_FEAT_OKC, "okc" },
};
@@ -231,6 +231,7 @@ static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
char caps[MAX_CAPS_BUFFER_SIZE];
+ char *cap, *next;
enum brcmf_feat_id id;
int i, err;
@@ -240,10 +241,15 @@ static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
return;
}
+ caps[sizeof(caps) - 1] = '\0';
brcmf_dbg(INFO, "[ %s]\n", caps);
- for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) {
- if (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) {
+ /* Match whole words, "hp2p" must not enable P2P */
+ next = caps;
+ while ((cap = strsep(&next, "\n "))) {
+ for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) {
+ if (strcmp(cap, brcmf_fwcap_map[i].fwcap_id))
+ continue;
id = brcmf_fwcap_map[i].feature;
brcmf_dbg(INFO, "enabling feature: %s\n",
brcmf_feat_names[id]);