From b67bedf2e3572411b1a65933a425dfef299ee185 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Fri, 24 Apr 2020 22:49:25 +0530 Subject: [PATCH] nl80211: Fetch information on supported AKMs from the driver The driver can advertise supported AKMs per wiphy and/or per interface. Populate per interface supported AKMs based on the driver advertisement in the following order of preference: 1. AKM suites advertised by NL80211_ATTR_IFTYPE_AKM_SUITES 2. AKM suites advertised by NL80211_ATTR_AKM_SUITES If neither of these is available: 3. AKMs support is assumed as per legacy behavior. In addition, extend other driver interface wrappers to set the per-interface values based on the global capability indication. Signed-off-by: Veerendranath Jakkam --- src/drivers/driver.h | 127 ++++++++-------- src/drivers/driver_bsd.c | 5 + src/drivers/driver_ndis.c | 6 + src/drivers/driver_nl80211.c | 15 +- src/drivers/driver_nl80211.h | 1 + src/drivers/driver_nl80211_capa.c | 231 +++++++++++++++++++++++++++--- src/drivers/driver_wext.c | 5 + 7 files changed, 311 insertions(+), 79 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index e3b13bc25..b0713249f 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1658,6 +1658,73 @@ struct wpa_driver_set_key_params { enum key_flag key_flag; }; +enum wpa_driver_if_type { + /** + * WPA_IF_STATION - Station mode interface + */ + WPA_IF_STATION, + + /** + * WPA_IF_AP_VLAN - AP mode VLAN interface + * + * This interface shares its address and Beacon frame with the main + * BSS. + */ + WPA_IF_AP_VLAN, + + /** + * WPA_IF_AP_BSS - AP mode BSS interface + * + * This interface has its own address and Beacon frame. + */ + WPA_IF_AP_BSS, + + /** + * WPA_IF_P2P_GO - P2P Group Owner + */ + WPA_IF_P2P_GO, + + /** + * WPA_IF_P2P_CLIENT - P2P Client + */ + WPA_IF_P2P_CLIENT, + + /** + * WPA_IF_P2P_GROUP - P2P Group interface (will become either + * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known) + */ + WPA_IF_P2P_GROUP, + + /** + * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the + * abstracted P2P Device function in the driver + */ + WPA_IF_P2P_DEVICE, + + /* + * WPA_IF_MESH - Mesh interface + */ + WPA_IF_MESH, + + /* + * WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only) + */ + WPA_IF_TDLS, + + /* + * WPA_IF_IBSS - IBSS interface (used for pref freq only) + */ + WPA_IF_IBSS, + + /* + * WPA_IF_NAN - NAN Device + */ + WPA_IF_NAN, + + /* keep last */ + WPA_IF_MAX +}; + /** * struct wpa_driver_capa - Driver capability information */ @@ -1681,6 +1748,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000 /** Bitfield of supported key management suites */ unsigned int key_mgmt; + unsigned int key_mgmt_iftype[WPA_IF_MAX]; #define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001 #define WPA_DRIVER_CAPA_ENC_WEP104 0x00000002 @@ -2045,65 +2113,6 @@ struct hostapd_acl_params { struct mac_address mac_acl[0]; }; -enum wpa_driver_if_type { - /** - * WPA_IF_STATION - Station mode interface - */ - WPA_IF_STATION, - - /** - * WPA_IF_AP_VLAN - AP mode VLAN interface - * - * This interface shares its address and Beacon frame with the main - * BSS. - */ - WPA_IF_AP_VLAN, - - /** - * WPA_IF_AP_BSS - AP mode BSS interface - * - * This interface has its own address and Beacon frame. - */ - WPA_IF_AP_BSS, - - /** - * WPA_IF_P2P_GO - P2P Group Owner - */ - WPA_IF_P2P_GO, - - /** - * WPA_IF_P2P_CLIENT - P2P Client - */ - WPA_IF_P2P_CLIENT, - - /** - * WPA_IF_P2P_GROUP - P2P Group interface (will become either - * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known) - */ - WPA_IF_P2P_GROUP, - - /** - * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the - * abstracted P2P Device function in the driver - */ - WPA_IF_P2P_DEVICE, - - /* - * WPA_IF_MESH - Mesh interface - */ - WPA_IF_MESH, - - /* - * WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only) - */ - WPA_IF_TDLS, - - /* - * WPA_IF_IBSS - IBSS interface (used for pref freq only) - */ - WPA_IF_IBSS, -}; - struct wpa_init_params { void *global_priv; const u8 *bssid; diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index b4400d7bf..5adee13a2 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -1451,6 +1451,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) #define GETPARAM(drv, param, v) \ (((v) = get80211param(drv, param)) != -1) struct bsd_driver_data *drv; + int i; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) @@ -1486,6 +1487,10 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) if (wpa_driver_bsd_capa(drv)) goto fail; + /* Update per interface supported AKMs */ + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt; + /* Down interface during setup. */ if (bsd_get_iface_flags(drv) < 0) goto fail; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 529fc3bc6..b5fff483e 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -2809,6 +2809,7 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname) { struct wpa_driver_ndis_data *drv; u32 mode; + int i; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) @@ -2855,6 +2856,11 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname) } wpa_driver_ndis_get_capability(drv); + /* Update per interface supported AKMs */ + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt; + + /* Make sure that the driver does not have any obsolete PMKID entries. */ wpa_driver_ndis_flush_pmkid(drv); diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index d48f8cb76..9c72341f9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2328,10 +2328,19 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) /* FT Action frames */ if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) ret = -1; - else + else if (!drv->has_driver_key_mgmt) { + int i; + + /* Update supported AKMs only if the driver doesn't advertize + * any AKM capabilities. */ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; + /* Update per interface supported AKMs */ + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt; + } + /* WNM - BSS Transition Management Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0) ret = -1; @@ -5056,6 +5065,10 @@ const char * nl80211_iftype_str(enum nl80211_iftype mode) return "P2P_GO"; case NL80211_IFTYPE_P2P_DEVICE: return "P2P_DEVICE"; + case NL80211_IFTYPE_OCB: + return "OCB"; + case NL80211_IFTYPE_NAN: + return "NAN"; default: return "unknown"; } diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index c3ad88a39..660f49879 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -111,6 +111,7 @@ struct wpa_driver_nl80211_data { unsigned int num_iface_ext_capa; int has_capability; + int has_driver_key_mgmt; int operstate; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 34ad0c694..a3341a088 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -79,6 +79,8 @@ struct wiphy_info_data { unsigned int mac_addr_rand_scan_supported:1; unsigned int mac_addr_rand_sched_scan_supported:1; unsigned int update_ft_ies_supported:1; + unsigned int has_key_mgmt:1; + unsigned int has_key_mgmt_iftype:1; }; @@ -252,6 +254,158 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info, } +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++) { + switch (akms[i]) { + 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 void get_iface_akm_suites_info(struct wiphy_info_data *info, + struct nlattr *nl_akms) +{ + struct nlattr *tb[NL80211_IFTYPE_AKM_ATTR_MAX + 1]; + struct nlattr *nl_iftype; + unsigned int key_mgmt; + int i; + + if (!nl_akms) + return; + + nla_parse(tb, NL80211_IFTYPE_AKM_ATTR_MAX, + nla_data(nl_akms), nla_len(nl_akms), NULL); + + if (!tb[NL80211_IFTYPE_AKM_ATTR_IFTYPES] || + !tb[NL80211_IFTYPE_AKM_ATTR_SUITES]) + return; + + info->has_key_mgmt_iftype = 1; + key_mgmt = get_akm_suites_info(tb[NL80211_IFTYPE_AKM_ATTR_SUITES]); + + nla_for_each_nested(nl_iftype, tb[NL80211_IFTYPE_AKM_ATTR_IFTYPES], i) { + switch (nla_type(nl_iftype)) { + case NL80211_IFTYPE_ADHOC: + info->drv->capa.key_mgmt_iftype[WPA_IF_IBSS] = key_mgmt; + break; + case NL80211_IFTYPE_STATION: + info->drv->capa.key_mgmt_iftype[WPA_IF_STATION] = + key_mgmt; + break; + case NL80211_IFTYPE_AP: + info->drv->capa.key_mgmt_iftype[WPA_IF_AP_BSS] = + key_mgmt; + break; + case NL80211_IFTYPE_AP_VLAN: + info->drv->capa.key_mgmt_iftype[WPA_IF_AP_VLAN] = + key_mgmt; + break; + case NL80211_IFTYPE_MESH_POINT: + info->drv->capa.key_mgmt_iftype[WPA_IF_MESH] = key_mgmt; + break; + case NL80211_IFTYPE_P2P_CLIENT: + info->drv->capa.key_mgmt_iftype[WPA_IF_P2P_CLIENT] = + key_mgmt; + break; + case NL80211_IFTYPE_P2P_GO: + info->drv->capa.key_mgmt_iftype[WPA_IF_P2P_GO] = + key_mgmt; + break; + case NL80211_IFTYPE_P2P_DEVICE: + info->drv->capa.key_mgmt_iftype[WPA_IF_P2P_DEVICE] = + key_mgmt; + break; + case NL80211_IFTYPE_NAN: + info->drv->capa.key_mgmt_iftype[WPA_IF_NAN] = key_mgmt; + break; + } + wpa_printf(MSG_DEBUG, "nl80211: %s supported key_mgmt 0x%x", + nl80211_iftype_str(nla_type(nl_iftype)), + key_mgmt); + } +} + + +static void wiphy_info_iftype_akm_suites(struct wiphy_info_data *info, + struct nlattr *tb) +{ + struct nlattr *nl_if; + int rem_if; + + if (!tb) + return; + + nla_for_each_nested(nl_if, tb, rem_if) + get_iface_akm_suites_info(info, nl_if); +} + + +static void wiphy_info_akm_suites(struct wiphy_info_data *info, + struct nlattr *tb) +{ + if (!tb) + return; + + info->has_key_mgmt = 1; + info->capa->key_mgmt = get_akm_suites_info(tb); + wpa_printf(MSG_DEBUG, "nl80211: wiphy supported key_mgmt 0x%x", + info->capa->key_mgmt); +} + + static void wiphy_info_cipher_suites(struct wiphy_info_data *info, struct nlattr *tb) { @@ -696,6 +850,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]); wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]); + wiphy_info_akm_suites(info, tb[NL80211_ATTR_AKM_SUITES]); + wiphy_info_iftype_akm_suites(info, tb[NL80211_ATTR_IFTYPE_AKM_SUITES]); if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " @@ -1098,6 +1254,8 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv) int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) { struct wiphy_info_data info; + int i; + if (wpa_driver_nl80211_get_info(drv, &info)) return -1; @@ -1105,27 +1263,62 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) return -1; drv->has_capability = 1; - drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK | - WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B | - WPA_DRIVER_CAPA_KEY_MGMT_OWE | - WPA_DRIVER_CAPA_KEY_MGMT_DPP; + drv->has_driver_key_mgmt = info.has_key_mgmt | info.has_key_mgmt_iftype; - if (drv->capa.enc & (WPA_DRIVER_CAPA_ENC_CCMP_256 | - WPA_DRIVER_CAPA_ENC_GCMP_256)) - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192; + /* Fallback to hardcoded defaults if the driver does nott advertize any + * AKM capabilities. */ + if (!drv->has_driver_key_mgmt) { + drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B | + WPA_DRIVER_CAPA_KEY_MGMT_OWE | + WPA_DRIVER_CAPA_KEY_MGMT_DPP; - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - 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_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; + if (drv->capa.enc & (WPA_DRIVER_CAPA_ENC_CCMP_256 | + WPA_DRIVER_CAPA_ENC_GCMP_256)) + drv->capa.key_mgmt |= + WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192; + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) + 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_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; + } + + if (!info.has_key_mgmt_iftype) { + /* If the driver does not advertize per interface AKM + * capabilities, consider all interfaces to support default AKMs + * in key_mgmt. */ + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt; + } else if (info.has_key_mgmt_iftype && !info.has_key_mgmt) { + /* If the driver advertizes only per interface supported AKMs + * but does not advertize per wiphy AKM capabilities, consider + * the default key_mgmt as a mask of per interface supported + * AKMs. */ + drv->capa.key_mgmt = 0; + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt |= drv->capa.key_mgmt_iftype[i]; + } else if (info.has_key_mgmt_iftype && info.has_key_mgmt) { + /* If the driver advertizes AKM capabilities both per wiphy and + * per interface, consider the interfaces for which per + * interface AKM capabilities were not received to support the + * default key_mgmt capabilities. + */ + for (i = 0; i < WPA_IF_MAX; i++) + if (!drv->capa.key_mgmt_iftype[i]) + drv->capa.key_mgmt_iftype[i] = + drv->capa.key_mgmt; + } drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 978e1cf43..8a3adee05 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -968,6 +968,7 @@ static void wext_check_hostap(struct wpa_driver_wext_data *drv) static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) { int send_rfkill_event = 0; + int i; if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { if (rfkill_is_blocked(drv->rfkill)) { @@ -996,6 +997,10 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) wpa_driver_wext_get_range(drv); + /* Update per interface supported AKMs */ + for (i = 0; i < WPA_IF_MAX; i++) + drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt; + /* * Unlock the driver's BSSID and force to a random SSID to clear any * previous association the driver might have when the supplicant