nl80211: Fetch supported AKM list from the driver

Try to fetch the list of supported AKM suite selectors from the driver
through the vendor interface
QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS. If that command is
available and succeeds, use the returned list to populate the
wpa_driver_capa key_mgmt information instead of assuming all
cfg80211-based drivers support all AKMs. If the driver does not support
this command, the previous behavior is maintained.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Veerendranath Jakkam 2018-12-21 16:02:24 +05:30 committed by Jouni Malinen
parent dbe7f6da77
commit 8ec7c99ee4
3 changed files with 133 additions and 1 deletions

View file

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

View file

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

View file

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