From 2d3f27aeb53b35fc55453afe1d9c07c95e7ceded Mon Sep 17 00:00:00 2001 From: Suresh Sanaboina Date: Thu, 22 Jun 2023 04:52:12 -0500 Subject: [PATCH 176/296] brcmfmac: External roam time enhancements Signed-off-by: Suresh Sanaboina --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 185 +++++++++++++++--- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 1 + .../broadcom/brcm80211/brcmfmac/fweh.h | 2 + 3 files changed, 161 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index afb75c6f030d..79487d8d0f40 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -350,10 +350,24 @@ struct parsed_extension_ies { struct parsed_ext_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; }; +/* flags */ +#define BRCMF_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ + +struct dot11_assoc_req { + u16 capability; /* capability information */ + u16 listen; /* listen interval */ +}; + +struct dot11_reassoc_req { + u16 capability; /* capability information */ + u16 listen; /* listen interval */ + u8 ap[ETH_ALEN]; /* Current AP address */ +}; + struct dot11_assoc_resp { - u16 capability; /* capability information */ - u16 status; /* status code */ - u16 aid; /* association ID */ + u16 capability; /* capability information */ + u16 status; /* status code */ + u16 aid; /* association ID */ }; struct brcmf_owe_info_buf { @@ -3988,8 +4002,8 @@ static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg, return err; } -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, - struct brcmf_if *ifp) +static const struct brcmf_bss_info_le * +brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) { struct brcmf_pub *drvr = cfg->pub; struct brcmf_bss_info_le *bi = NULL; @@ -3997,7 +4011,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, brcmf_dbg(TRACE, "Enter\n"); if (brcmf_is_ibssmode(ifp->vif)) - return err; + return NULL; *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, @@ -4009,9 +4023,12 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4); err = brcmf_inform_single_bss(cfg, bi); + brcmf_dbg(TRACE, "Exit"); + return bi; + update_bss_info_out: brcmf_dbg(TRACE, "Exit"); - return err; + return NULL; } void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) @@ -7282,7 +7299,9 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, event == BRCMF_E_PSK_SUP && status == BRCMF_E_STATUS_FWSUP_COMPLETED) set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); - if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { + if ((event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) || + (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_SUCCESS && + (e->flags & BRCMF_EVENT_MSG_LINK))) { brcmf_dbg(CONN, "Processing set ssid\n"); memcpy(vif->profile.bssid, e->addr, ETH_ALEN); if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK && @@ -7357,6 +7376,24 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) conn_info->resp_ie_len = 0; } +static void brcmf_clear_assoc_req_ie(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + + kfree(conn_info->req_ie); + conn_info->req_ie = NULL; + conn_info->req_ie_len = 0; +} + +static void brcmf_clear_assoc_resp_ie(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + + kfree(conn_info->resp_ie); + conn_info->resp_ie = NULL; + conn_info->resp_ie_len = 0; +} + u8 brcmf_map_prio_to_prec(void *config, u8 prio) { struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config; @@ -7504,8 +7541,16 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT]; u32 req_len; u32 resp_len; + u32 flags; s32 err = 0; + brcmf_dbg(CONN, "req: %p, req len (%d) resp: %p resp len (%d)\n", conn_info->req_ie, + conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len); + + if (conn_info->req_ie_len && conn_info->resp_ie_len && + conn_info->req_ie && conn_info->resp_ie) + return 0; + brcmf_clear_assoc_ies(cfg); err = brcmf_fil_iovar_data_get(ifp, "assoc_info", @@ -7518,6 +7563,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf; req_len = le32_to_cpu(assoc_info->req_len); resp_len = le32_to_cpu(assoc_info->resp_len); + flags = le32_to_cpu(assoc_info->flags); if (req_len > WL_EXTRA_BUF_MAX || resp_len > WL_EXTRA_BUF_MAX) { bphy_err(drvr, "invalid lengths in assoc info: req %u resp %u\n", req_len, resp_len); @@ -7531,7 +7577,12 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, bphy_err(drvr, "could not get assoc req (%d)\n", err); return err; } - conn_info->req_ie_len = req_len; + + if (assoc_info->flags & BRCMF_ASSOC_REQ_IS_REASSOC) + conn_info->req_ie_len = req_len - sizeof(struct dot11_reassoc_req); + else + conn_info->req_ie_len = req_len - sizeof(struct dot11_assoc_req); + conn_info->req_ie = kmemdup(cfg->extra_buf, conn_info->req_ie_len, GFP_KERNEL); @@ -7649,23 +7700,10 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, brcmf_get_assoc_ies(cfg, ifp); memcpy(profile->bssid, e->addr, ETH_ALEN); - brcmf_update_bss_info(cfg, ifp); - - buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (buf == NULL) { - err = -ENOMEM; - goto done; - } - - /* data sent to dongle has to be little endian */ - *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, - buf, WL_BSS_INFO_MAX); - - if (err) + bi = (struct brcmf_bss_info_le *)brcmf_update_bss_info(cfg, ifp); + if (!bi) goto done; - bi = (struct brcmf_bss_info_le *)(buf + 4); ch.chspec = le16_to_cpu(bi->chanspec); cfg->d11inf.decchspec(&ch); @@ -7832,8 +7870,14 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, &ifp->vif->sme_state); set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); - } else - brcmf_bss_connect_done(cfg, ndev, e, true); + } else { + if (e->event_code == BRCMF_E_LINK && !profile->is_ft && + test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) { + brcmf_bss_roaming_done(cfg, ndev, e); + } else { + brcmf_bss_connect_done(cfg, ndev, e, true); + } + } brcmf_net_setcarrier(ifp, true); } else if (brcmf_is_linkdown(ifp->vif, e)) { brcmf_dbg(CONN, "Linkdown\n"); @@ -7881,7 +7925,8 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp, if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) { - brcmf_bss_roaming_done(cfg, ifp->ndev, e); + if (ifp->vif->profile.is_ft) + brcmf_bss_roaming_done(cfg, ifp->ndev, e); } else { brcmf_bss_connect_done(cfg, ifp->ndev, e, true); brcmf_net_setcarrier(ifp, true); @@ -8269,6 +8314,88 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) conf->retry_long = (u32)-1; } +static s32 +brcmf_notify_assoc_req_ie(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) +{ + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + u32 event = e->event_code; + u32 status = e->status; + u32 req_len = e->datalen; + + brcmf_dbg(INFO, "Enter: event %s (%d), status=%d\n", + brcmf_fweh_event_name(e->event_code), e->event_code, + e->status); + + if (event == BRCMF_E_ASSOC_REQ_IE && status == BRCMF_E_STATUS_SUCCESS) { + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) || + test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { + brcmf_clear_assoc_req_ie(cfg); + + conn_info->req_ie_len = req_len; + conn_info->req_ie = kmemdup(data, conn_info->req_ie_len, GFP_KERNEL); + if (!conn_info->req_ie) + conn_info->req_ie_len = 0; + brcmf_dbg(CONN, "req ie (%p) req len (%d)\n", conn_info->req_ie, + conn_info->req_ie_len); + } else { + brcmf_err("No (Re)connection is in progress, Ignore event\n"); + } + } else { + brcmf_err("Failed to handle the event\n"); + } + + return 0; +} + +static s32 +brcmf_notify_assoc_resp_ie(struct brcmf_if *ifp, + const struct brcmf_event_msg *e, void *data) +{ + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT]; + u32 event = e->event_code; + u32 status = e->status; + u32 resp_len = e->datalen; + s32 err = 0; + + brcmf_dbg(INFO, "Enter: event %s (%d), status=%d\n", + brcmf_fweh_event_name(e->event_code), e->event_code, + e->status); + + if (event == BRCMF_E_ASSOC_RESP_IE && status == BRCMF_E_STATUS_SUCCESS) { + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) || + test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { + brcmf_clear_assoc_resp_ie(cfg); + + conn_info->resp_ie_len = resp_len; + conn_info->resp_ie = kmemdup(data, conn_info->resp_ie_len, GFP_KERNEL); + if (!conn_info->resp_ie) + conn_info->resp_ie_len = 0; + + brcmf_dbg(CONN, "resp ie (%p) resp len (%d)\n", conn_info->resp_ie, + conn_info->resp_ie_len); + err = brcmf_fil_iovar_data_get(ifp, "wme_ac_sta", + edcf_acparam_info, + sizeof(edcf_acparam_info)); + if (err) { + brcmf_err("could not get wme_ac_sta (%d)\n", err); + brcmf_clear_assoc_resp_ie(cfg); + } else { + brcmf_wifi_prioritize_acparams(edcf_acparam_info, + cfg->ac_priority); + } + } else { + brcmf_err("No (Re)connection is in progress, Ignore event\n"); + } + } else { + brcmf_err("Failed to handle the event\n"); + } + + return 0; +} + static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) { struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); @@ -8342,6 +8469,10 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) } brcmf_fweh_register(cfg->pub, BRCMF_E_EXT_ASSOC_FRAME_RX, brcmf_notify_ext_assoc_frame_rx); + brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_REQ_IE, + brcmf_notify_assoc_req_ie); + brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_RESP_IE, + brcmf_notify_assoc_resp_ie); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 1bf9479e3cb3..3c79f26c9c2c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -288,6 +288,7 @@ struct brcmf_cfg80211_connect_info { struct brcmf_cfg80211_assoc_ielen_le { __le32 req_len; __le32 resp_len; + __le32 flags; }; struct brcmf_cfg80211_edcf_acparam { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 734070dc890a..bd6ac6219493 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -90,6 +90,8 @@ struct brcmf_cfg80211_info; BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ BRCMF_ENUM_DEF(SA_COMPLETE_IND, 80) \ + BRCMF_ENUM_DEF(ASSOC_REQ_IE, 87) \ + BRCMF_ENUM_DEF(ASSOC_RESP_IE, 88) \ BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ BRCMF_ENUM_DEF(PHY_TEMP, 111) \ BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ -- 2.25.1