[PATCH v3 4/5] wifi: brcmfmac: report port authorization after offloaded roaming

From: Jason Huang

Date: Mon Aug 10 2026 - 07:45:42 EST


From: Darren Li <hsin-hung.li@xxxxxxxxxxx>

Firmware can complete FT or OKC roaming before the driver reports the
connect or roam event to cfg80211. Detect those successful offloaded
cases when the profile uses firmware 1X or roaming offload and the
association request carries PMK cache state, FT is in use, or OKC is
enabled.

After reporting the connect or roam event, call cfg80211_port_authorized()
so nl80211 emits the dedicated NL80211_CMD_PORT_AUTHORIZED event instead
of reusing the reserved NL80211_ATTR_PORT_AUTHORIZED flag in CONNECT/ROAM
notifications.

Assisted-by: GitHub Copilot CLI:gpt-5.5
Signed-off-by: Darren Li <hsin-hung.li@xxxxxxxxxxx>
Signed-off-by: Chung-Hsien Hsu <Chung-Hsien.Hsu@xxxxxxxxxxxx>
Signed-off-by: Chi-hsien Lin <chi-hsien.lin@xxxxxxxxxxx>
Signed-off-by: Carella Chen <carella.chen@xxxxxxxxxxxx>
Signed-off-by: Jason Huang <jason.huang2@xxxxxxxxxxxx>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 65 ++++++++++++++++++++--
1 file changed, 60 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index f2916cc9e5fc..c11b3eac9d47 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -6466,6 +6466,47 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
return err;
}

+static bool brcmf_has_pmkid(const u8 *parse, u32 len)
+{
+ const struct brcmf_tlv *rsn_ie;
+ const u8 *ie;
+ u32 ie_len;
+ u32 offset;
+ u16 count;
+
+ if (!parse)
+ return false;
+
+ rsn_ie = brcmf_parse_tlvs(parse, len, WLAN_EID_RSN);
+ if (!rsn_ie)
+ return false;
+
+ ie = (const u8 *)rsn_ie;
+ ie_len = rsn_ie->len + TLV_HDR_LEN;
+
+ offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
+ if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
+ return false;
+
+ count = ie[offset] + (ie[offset + 1] << 8);
+ offset += WPA_IE_SUITE_COUNT_LEN + count * WPA_IE_MIN_OUI_LEN;
+ if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
+ return false;
+
+ count = ie[offset] + (ie[offset + 1] << 8);
+ offset += WPA_IE_SUITE_COUNT_LEN + count * WPA_IE_MIN_OUI_LEN;
+ if (offset + RSN_CAP_LEN >= ie_len)
+ return false;
+
+ offset += RSN_CAP_LEN;
+ if (offset + RSN_PMKID_COUNT_LEN > ie_len)
+ return false;
+
+ count = ie[offset] + (ie[offset + 1] << 8);
+
+ return count > 0;
+}
+
static s32
brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
@@ -6480,6 +6521,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
struct brcmf_bss_info_le *bi;
struct brcmu_chan ch;
struct cfg80211_roam_info roam_info = {};
+ bool authorized = false;
u32 freq;
s32 err = 0;
u8 *buf;
@@ -6526,14 +6568,18 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
roam_info.resp_ie = conn_info->resp_ie;
roam_info.resp_ie_len = conn_info->resp_ie_len;

+ if ((profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X ||
+ profile->use_fwsup == BRCMF_PROFILE_FWSUP_ROAM) &&
+ (brcmf_has_pmkid(roam_info.req_ie, roam_info.req_ie_len) ||
+ profile->is_ft || profile->is_okc))
+ authorized = true;
+
cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
+ if (authorized)
+ cfg80211_port_authorized(ndev, profile->bssid, NULL, 0,
+ GFP_KERNEL);
brcmf_dbg(CONN, "Report roaming result\n");

- if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X && profile->is_ft) {
- cfg80211_port_authorized(ndev, profile->bssid, NULL, 0, GFP_KERNEL);
- brcmf_dbg(CONN, "Report port authorized\n");
- }
-
set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
brcmf_dbg(TRACE, "Exit\n");
return err;
@@ -6548,6 +6594,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
struct cfg80211_connect_resp_params conn_params;
+ bool authorized;

brcmf_dbg(TRACE, "Enter\n");

@@ -6572,7 +6619,15 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
conn_params.req_ie_len = conn_info->req_ie_len;
conn_params.resp_ie = conn_info->resp_ie;
conn_params.resp_ie_len = conn_info->resp_ie_len;
+ authorized = completed &&
+ (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X ||
+ profile->use_fwsup == BRCMF_PROFILE_FWSUP_ROAM) &&
+ brcmf_has_pmkid(conn_params.req_ie,
+ conn_params.req_ie_len);
cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
+ if (authorized)
+ cfg80211_port_authorized(ndev, profile->bssid, NULL, 0,
+ GFP_KERNEL);
brcmf_dbg(CONN, "Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
}

--
2.25.1