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 <vjakkam@codeaurora.org>
This commit is contained in:
Veerendranath Jakkam 2020-04-24 22:49:25 +05:30 committed by Jouni Malinen
parent 6fffb320fc
commit b67bedf2e3
7 changed files with 311 additions and 79 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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";
}

View File

@ -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;

View File

@ -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 |

View File

@ -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