diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 4250caa04..f09f0f70f 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1441,6 +1441,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 0x00002000 #define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000 #define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000 +#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000 /** Bitfield of supported key management suites */ unsigned int key_mgmt; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index bc562ba7a..1e7fe7a98 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -166,6 +166,7 @@ struct wpa_driver_nl80211_data { unsigned int he_capab_vendor_cmd_avail:1; unsigned int fetch_bss_trans_status:1; unsigned int roam_vendor_cmd_avail:1; + unsigned int get_supported_akm_suites_avail:1; u64 vendor_scan_cookie; u64 remain_on_chan_cookie; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 8e2ebd210..bc2f9acf0 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -786,6 +786,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case QCA_NL80211_VENDOR_SUBCMD_ROAM: drv->roam_vendor_cmd_avail = 1; break; + case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS: + drv->get_supported_akm_suites_avail = 1; + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ } } @@ -958,6 +961,126 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv) } +static unsigned int get_akm_suites_info(struct nlattr *tb) +{ + int i, num; + unsigned int key_mgmt = 0; + u32 *akms; + + if (!tb) + return 0; + + num = nla_len(tb) / sizeof(u32); + akms = nla_data(tb); + for (i = 0; i < num; i++) { + u32 a = akms[i]; + + wpa_printf(MSG_DEBUG, + "nl80211: Supported AKM %02x-%02x-%02x:%u", + a >> 24, (a >> 16) & 0xff, + (a >> 8) & 0xff, a & 0xff); + switch (a) { + case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2; + break; + case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; + break; + case RSN_AUTH_KEY_MGMT_FT_802_1X: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT; + break; + case RSN_AUTH_KEY_MGMT_FT_PSK: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; + break; + case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B; + break; + case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192; + break; + case RSN_AUTH_KEY_MGMT_OWE: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OWE; + break; + case RSN_AUTH_KEY_MGMT_DPP: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_DPP; + break; + case RSN_AUTH_KEY_MGMT_FILS_SHA256: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256; + break; + case RSN_AUTH_KEY_MGMT_FILS_SHA384: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384; + break; + case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256; + break; + case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384; + break; + case RSN_AUTH_KEY_MGMT_SAE: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE; + break; + } + } + + return key_mgmt; +} + + +static int get_akm_suites_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + unsigned int *key_mgmt = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_VENDOR_DATA]) { + struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA]; + struct nlattr *tb_data[NL80211_ATTR_MAX + 1]; + + nla_parse(tb_data, NL80211_ATTR_MAX, + nla_data(nl_vend), nla_len(nl_vend), NULL); + + *key_mgmt = + get_akm_suites_info(tb_data[NL80211_ATTR_AKM_SUITES]); + } + + return NL_SKIP; +} + + +static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data *drv) +{ + struct nl_msg *msg; + unsigned int key_mgmt = 0; + int ret; + + if (!drv->get_supported_akm_suites_avail) + return -1; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS)) { + nlmsg_free(msg); + return -1; + } + + ret = send_and_recv_msgs(drv, msg, get_akm_suites_handler, &key_mgmt); + if (!ret) { + wpa_printf(MSG_DEBUG, + "nl80211: Replace capa.key_mgmt based on driver advertised capabilities: 0x%x", + key_mgmt); + drv->capa.key_mgmt = key_mgmt; + } + + return ret; +} + + static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -1183,11 +1306,18 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 | WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 | WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 | - WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384; + WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 | + WPA_DRIVER_CAPA_KEY_MGMT_SAE; else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 | WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384; +#ifdef CONFIG_DRIVER_NL80211_QCA + /* Override drv->capa.key_mgmt based on driver advertised capability + * constraints, if available. */ + qca_nl80211_get_akm_suites(drv); +#endif /* CONFIG_DRIVER_NL80211_QCA */ + drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP;