From 5d98f2713950e7b5455e227b1372d840316979a2 Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Tue, 27 Jun 2023 21:36:57 -0500 Subject: [PATCH 173/296] brcmfmac: extowe_ap mode supporting firmware reports assoc_req frame and passes it to the host driver. the host driver reports the content from the end of (re)assoc_req packet to hostapd. hostapd will process and calculate the ECDH_IE if necessary. it updates the content by NL80211_CMD_OWE_INFO nl80211 command. the driver will parse and prepare the command to the firmware. firmware needs to have owe_info iovar to support this feature. Signed-off-by: Carter Chen --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 185 +++++++++++++++++- .../broadcom/brcm80211/brcmfmac/fweh.h | 5 +- 2 files changed, 182 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 313c97c979d1..60b24fcb2241 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -62,6 +62,7 @@ #define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */ #define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */ #define RSN_AKM_SAE 8 /* SAE */ +#define RSN_AKM_OWE 18 /* OWE */ #define RSN_CAP_LEN 2 /* Length of RSN capabilities */ #define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3)) #define RSN_CAP_MFPR_MASK BIT(6) @@ -355,6 +356,15 @@ struct dot11_assoc_resp { u16 aid; /* association ID */ }; +struct brcmf_owe_info_buf { + u8 peer_mac[ETH_ALEN]; + __le16 status_le16;/* hostapd gives status of Assoc Resp */ + bool with_pmkid; + u8 pmkid[WLAN_PMKID_LEN]; + bool with_ecdh;/* if doing PMK Caching, might not have ECDH IE. */ + u8 ecdh_ie_info[0]; +}; + #define WLC_E_IF_ROLE_STA 0 /* Infra STA */ #define WLC_E_IF_ROLE_AP 1 /* Access Point */ @@ -415,6 +425,7 @@ struct wl_wsec_info { struct wl_wsec_info_tlv tlvs[1]; /* tlv data follows */ }; +static bool brcmf_has_pmkid(const u8 *parse, u32 len, u32 *offset_in_ie); static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg); static bool wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, @@ -5197,6 +5208,10 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, brcmf_dbg(TRACE, "RSN_AKM_SAE\n"); wpa_auth |= WPA3_AUTH_SAE_PSK; break; + case RSN_AKM_OWE: + brcmf_dbg(TRACE, "RSN_AKM_OWE\n"); + wpa_auth |= WPA3_AUTH_OWE; + break; default: bphy_err(drvr, "Invalid key mgmt info\n"); } @@ -5225,7 +5240,8 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 | WPA2_AUTH_1X_SHA256 | WFA_AUTH_DPP | - WPA3_AUTH_SAE_PSK))) { + WPA3_AUTH_SAE_PSK | + WPA3_AUTH_OWE))) { err = -EINVAL; goto exit; } @@ -5668,7 +5684,8 @@ s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif) static const s32 pktflags[] = { BRCMF_VNDR_IE_PRBREQ_FLAG, BRCMF_VNDR_IE_PRBRSP_FLAG, - BRCMF_VNDR_IE_BEACON_FLAG + BRCMF_VNDR_IE_BEACON_FLAG, + BRCMF_VNDR_IE_ASSOCRSP_FLAG }; int i; @@ -6099,6 +6116,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("set he bss_color error:%d\n", err); } + brcmf_vif_clear_mgmt_ies(ifp->vif); brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); brcmf_net_setcarrier(ifp, true); @@ -7028,6 +7046,108 @@ brcmf_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, return err; } +int brcmf_cfg80211_update_owe_info(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_update_owe_info *owe_info) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp; + int err = 0; + struct brcmf_owe_info_buf *owe_info_buf; + u8 *curr_ie_buf; + struct parsed_extension_ies owe_ecdh_ie; + struct parsed_ext_ie_info *extie_info; + u32 del_add_ie_buf_len = 0; + u32 total_owe_info_len = 0; + u32 pmkid_offset = 0; + + ifp = netdev_priv(dev); + if (owe_info) { + owe_info_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!owe_info_buf) + return -ENOMEM; + + curr_ie_buf = owe_info_buf->ecdh_ie_info; + + memcpy(owe_info_buf->peer_mac, owe_info->peer, ETH_ALEN); + owe_info_buf->status_le16 = cpu_to_le16(owe_info->status); + + owe_info_buf->with_ecdh = false; + if (owe_info->ie) { + if (brcmf_has_pmkid(owe_info->ie, + owe_info->ie_len, + &pmkid_offset)) { + u32 npmk, i; + struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; + + if (!check_vif_up(ifp->vif)) + return -EIO; + + npmk = le32_to_cpu(cfg->pmk_list.npmk); + for (i = 0; i < npmk; i++) { + if (!memcmp(owe_info_buf->peer_mac, + pmk[i].bssid, ETH_ALEN)) + break; + } + if (i < BRCMF_MAXPMKID) { + memcpy(pmk[i].bssid, + owe_info_buf->peer_mac, + ETH_ALEN); + memcpy(pmk[i].pmkid, + owe_info->ie + pmkid_offset, + WLAN_PMKID_LEN); + if (i == npmk) { + npmk++; + cfg->pmk_list.npmk = cpu_to_le32(npmk); + } + } else { + brcmf_err("Too many PMKSA entries cached %d\n", npmk); + return -EINVAL; + } + + err = brcmf_update_pmklist(cfg, ifp); + if (err < 0) { + brcmf_err("%s: set pmkid failed:%d\n", __func__, err); + return err; + } + + owe_info_buf->with_pmkid = true; + memcpy(owe_info_buf->pmkid, + owe_info->ie + pmkid_offset, + WLAN_PMKID_LEN); + } + + brcmf_parse_extension_ies(owe_info->ie, owe_info->ie_len, &owe_ecdh_ie); + if (owe_ecdh_ie.count > 1) { + brcmf_err("more ecdh_cnt found in info: %d\n", owe_ecdh_ie.count); + return -EINVAL; + } + + if (owe_ecdh_ie.count == 1) { + owe_info_buf->with_ecdh = true; + extie_info = &owe_ecdh_ie.ie_info[0]; + + del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, + BRCMF_VNDR_IE_ASSOCRSP_FLAG | + BRCMF_VNDR_IE_CUSTOM_FLAG, + extie_info->ie_ptr, + extie_info->ie_len, + "add"); + } + } + + total_owe_info_len = sizeof(struct brcmf_owe_info_buf) + del_add_ie_buf_len; + err = brcmf_fil_bsscfg_data_set(ifp, "owe_info", owe_info_buf, + total_owe_info_len); + + kfree(owe_info_buf); + } + + if (err) + brcmf_err("update owe_info error :%d\n", err); + + return err; +} + static struct cfg80211_ops brcmf_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, @@ -7079,6 +7199,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .change_bss = brcmf_cfg80211_change_bss, .external_auth = brcmf_cfg80211_external_auth, .set_cqm_rssi_config = brcmf_cfg80211_set_cqm_rssi_config, + .update_owe_info = brcmf_cfg80211_update_owe_info, }; struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings) @@ -7461,7 +7582,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, } static bool -brcmf_has_pmkid(const u8 *parse, u32 len) +brcmf_has_pmkid(const u8 *parse, u32 len, u32 *offset_in_ie) { const struct brcmf_tlv *rsn_ie; const u8 *ie; @@ -7494,10 +7615,15 @@ brcmf_has_pmkid(const u8 *parse, u32 len) goto done; /* Extract PMKID count */ count = ie[offset] + (ie[offset + 1] << 8); - if (count) + if (count) { + if (offset_in_ie) + *offset_in_ie = offset + RSN_PMKID_COUNT_LEN; return true; + } done: + if (offset_in_ie) + *offset_in_ie = 0; return false; } @@ -7563,7 +7689,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, 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) || + (brcmf_has_pmkid(roam_info.req_ie, roam_info.req_ie_len, NULL) || profile->is_ft || profile->is_okc)) roam_info.authorized = true; @@ -7611,7 +7737,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, conn_params.resp_ie_len = conn_info->resp_ie_len; if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X && - brcmf_has_pmkid(conn_params.req_ie, conn_params.req_ie_len)) + brcmf_has_pmkid(conn_params.req_ie, conn_params.req_ie_len, NULL)) conn_params.authorized = true; cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL); @@ -8090,6 +8216,51 @@ brcmf_notify_beacon_loss(struct brcmf_if *ifp, return 0; } +static s32 +brcmf_notify_ext_assoc_frame_rx(struct brcmf_if *ifp, + const struct brcmf_event_msg *e, void *data) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct net_device *ndev = ifp->ndev; + u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data); + struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; + u8 *frame = (u8 *)(rxframe + 1); + struct cfg80211_update_owe_info owe_info; + struct ieee80211_mgmt *mgmt_frame = (struct ieee80211_mgmt *)frame; + + brcmf_dbg(INFO, "Enter: event %s (%d) received\n", + brcmf_fweh_event_name(e->event_code), e->event_code); + + if (e->datalen < sizeof(*rxframe)) { + bphy_err(drvr, "Event %s (%d) data too small. Ignore\n", + brcmf_fweh_event_name(e->event_code), e->event_code); + return -EINVAL; + } + + memset(&owe_info, 0, sizeof(struct cfg80211_update_owe_info)); + owe_info.ie_len = mgmt_frame_len - offsetof(struct ieee80211_mgmt, u); + memcpy(owe_info.peer, e->addr, ETH_ALEN); + owe_info.ie = kzalloc(owe_info.ie_len, GFP_KERNEL); + + if (!owe_info.ie) + return -ENOMEM; + + if (ieee80211_is_assoc_req(mgmt_frame->frame_control)) { + frame += offsetof(struct ieee80211_mgmt, u.assoc_req.variable); + } else if (ieee80211_is_reassoc_req(mgmt_frame->frame_control)) { + frame += offsetof(struct ieee80211_mgmt, u.reassoc_req.variable); + } else { + bphy_err(drvr, "unexpected FC:0x%x\n", mgmt_frame->frame_control); + return -EINVAL; + } + + memcpy(owe_info.ie, frame, owe_info.ie_len); + cfg80211_update_owe_info_event(ndev, &owe_info, GFP_KERNEL); + + kfree(owe_info.ie); + return 0; +} + static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { conf->frag_threshold = (u32)-1; @@ -8169,6 +8340,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) brcmf_fweh_register(cfg->pub, BRCMF_E_TWT_TEARDOWN, brcmf_notify_twt_event); } + brcmf_fweh_register(cfg->pub, BRCMF_E_EXT_ASSOC_FRAME_RX, + brcmf_notify_ext_assoc_frame_rx); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 3b9f2dd78dc7..734070dc890a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -99,7 +99,8 @@ struct brcmf_cfg80211_info; BRCMF_ENUM_DEF(EXT_AUTH_FRAME_RX, 188) \ BRCMF_ENUM_DEF(MGMT_FRAME_TXSTATUS, 189) \ BRCMF_ENUM_DEF(MGMT_FRAME_OFF_CHAN_COMPLETE, 190) \ - BRCMF_ENUM_DEF(TWT_TEARDOWN, 195) + BRCMF_ENUM_DEF(TWT_TEARDOWN, 195) \ + BRCMF_ENUM_DEF(EXT_ASSOC_FRAME_RX, 196) #define BRCMF_ENUM_DEF(id, val) \ BRCMF_E_##id = (val), @@ -111,7 +112,7 @@ enum brcmf_fweh_event_code { * minimum length check in device firmware so it is * hard-coded here. */ - BRCMF_E_LAST = 196 + BRCMF_E_LAST = 197 }; #undef BRCMF_ENUM_DEF -- 2.25.1