}
+static unsigned int num_bits_set(u32 val)
+{
+ unsigned int c;
+
+ for (c = 0; val; c++)
+ val &= val - 1;
+
+ return c;
+}
+
+
static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
struct nl_msg *msg)
params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
- int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ u32 *mgmt;
+ unsigned int akm_count = 1, i;
+
+ /*
+ * Make sure the driver has capability to handle default AKM in
+ * key_mgmt_suite plus allowed AKMs in allowed_key_mgmts.
+ */
+ if (drv->capa.max_num_akms <=
+ num_bits_set(params->allowed_key_mgmts)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Not enough support for the allowed AKMs (max_num_akms=%u <= num_bits_set=%u)",
+ drv->capa.max_num_akms,
+ num_bits_set(params->allowed_key_mgmts));
+ return -1;
+ }
+
+ mgmt = os_malloc(sizeof(u32) * drv->capa.max_num_akms);
+ if (!mgmt)
+ return -1;
+
+ mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
switch (params->key_mgmt_suite) {
case WPA_KEY_MGMT_CCKM:
- mgmt = RSN_AUTH_KEY_MGMT_CCKM;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_CCKM;
break;
case WPA_KEY_MGMT_IEEE8021X:
- mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
break;
case WPA_KEY_MGMT_FT_IEEE8021X:
- mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X;
break;
case WPA_KEY_MGMT_FT_PSK:
- mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_PSK;
break;
case WPA_KEY_MGMT_IEEE8021X_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
break;
case WPA_KEY_MGMT_PSK_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256;
break;
case WPA_KEY_MGMT_OSEN:
- mgmt = RSN_AUTH_KEY_MGMT_OSEN;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN;
break;
case WPA_KEY_MGMT_SAE:
- mgmt = RSN_AUTH_KEY_MGMT_SAE;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_SAE;
break;
case WPA_KEY_MGMT_SAE_EXT_KEY:
- mgmt = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
break;
case WPA_KEY_MGMT_FT_SAE:
- mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE;
break;
case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
- mgmt = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
- mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
- mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
break;
case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
- mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
break;
case WPA_KEY_MGMT_FILS_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA256;
break;
case WPA_KEY_MGMT_FILS_SHA384:
- mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA384;
break;
case WPA_KEY_MGMT_FT_FILS_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
break;
case WPA_KEY_MGMT_FT_FILS_SHA384:
- mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
break;
case WPA_KEY_MGMT_OWE:
- mgmt = RSN_AUTH_KEY_MGMT_OWE;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_OWE;
break;
case WPA_KEY_MGMT_DPP:
- mgmt = RSN_AUTH_KEY_MGMT_DPP;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_DPP;
break;
case WPA_KEY_MGMT_PSK:
default:
- mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
break;
}
- wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
- if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
+
+ if (drv->capa.max_num_akms > 1) {
+ akm_count += wpa_key_mgmt_to_suites(
+ params->allowed_key_mgmts, &mgmt[1],
+ drv->capa.max_num_akms - 1);
+ }
+
+ for (i = 0; i < akm_count; i++)
+ wpa_printf(MSG_DEBUG, " * akm[%d]=0x%x", i, mgmt[i]);
+
+ if (nla_put(msg, NL80211_ATTR_AKM_SUITES,
+ akm_count * sizeof(u32), mgmt)) {
+ os_free(mgmt);
return -1;
+ }
+
+ os_free(mgmt);
}
if (params->req_handshake_offload &&
nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1;
- if (wpa_key_mgmt_sae(params->key_mgmt_suite) &&
+ if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
return -1;
#ifdef CONFIG_DRIVER_NL80211_QCA
if (params->req_key_mgmt_offload && params->psk &&
- (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
- params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_wpa_psk_no_sae(params->allowed_key_mgmts))) {
wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
ret = issue_key_mgmt_set_key(drv, params->psk, 32);
if (ret)
goto fail;
#ifdef CONFIG_SAE
- if (wpa_key_mgmt_sae(params->key_mgmt_suite) &&
+ if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
goto fail;
#endif /* CONFIG_SAE */
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- if (wpa_key_mgmt_sae(params->key_mgmt_suite))
+ if (wpa_key_mgmt_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_sae(params->allowed_key_mgmts))
bss->use_nl_connect = 1;
else
bss->use_nl_connect = 0;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
+ wpa_s->allowed_key_mgmts = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
wpa_supplicant_set_state(wpa_s, new_state);
}
+static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ int akm_count = wpa_s->max_num_akms;
+ u8 capab = 0;
+
+ if (akm_count < 2)
+ return;
+
+ akm_count--;
+ wpa_s->allowed_key_mgmts = 0;
+ switch (wpa_s->key_mgmt) {
+ case WPA_KEY_MGMT_PSK:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_PSK_SHA256:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ break;
+ case WPA_KEY_MGMT_SAE:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ default:
+ return;
+ }
+
+ if (wpa_s->conf->sae_pwe)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+
+ if (!((wpa_s->allowed_key_mgmts &
+ (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab))
+ return;
+
+ if (!wpa_s->rsnxe_len) {
+ wpa_s->rsnxe_len = 3;
+ wpa_s->rsnxe[0] = WLAN_EID_RSNX;
+ wpa_s->rsnxe[1] = 1;
+ wpa_s->rsnxe[2] = 0;
+ }
+
+ wpa_s->rsnxe[2] |= capab;
+}
+
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
* @wpa_s: Pointer to wpa_supplicant data
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
}
+ if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ wpas_update_allowed_key_mgmt(wpa_s, ssid);
+
return 0;
}
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
params.key_mgmt_suite = wpa_s->key_mgmt;
+ params.allowed_key_mgmts = wpa_s->allowed_key_mgmts;
params.wpa_proto = wpa_s->wpa_proto;
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
- params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
+ (params.allowed_key_mgmts &
+ (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
params.passphrase = ssid->passphrase;
if (ssid->psk_set)
params.psk = ssid->psk;
else
params.req_key_mgmt_offload = 1;
- if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
- params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
- params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
+ if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
+ wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
ssid->psk_set)
params.psk = ssid->psk;
}