diff --git a/src/drivers/driver.h b/src/drivers/driver.h index cb27282aa..eb1366818 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2730,6 +2730,7 @@ enum wpa_drv_update_connect_params_mask { * the real status code for failures. Used only for the request interface * from user space to the driver. * @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE). + * @mld_addr: AP's MLD address or %NULL if MLO is not used */ struct external_auth { enum { @@ -2742,6 +2743,7 @@ struct external_auth { unsigned int key_mgmt_suite; u16 status; const u8 *pmkid; + const u8 *mld_addr; }; #define WPAS_MAX_PASN_PEERS 10 diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 29613161b..e3fcb4402 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -3116,6 +3116,7 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, { union wpa_event_data event; enum nl80211_external_auth_action act; + char mld_addr[50]; if (!tb[NL80211_ATTR_AKM_SUITES] || !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] || @@ -3146,10 +3147,21 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]); + mld_addr[0] = '\0'; + if (tb[NL80211_ATTR_MLD_ADDR]) { + event.external_auth.mld_addr = + nla_data(tb[NL80211_ATTR_MLD_ADDR]); + os_snprintf(mld_addr, sizeof(mld_addr), ", MLD ADDR: " MACSTR, + MAC2STR(event.external_auth.mld_addr)); + } + wpa_printf(MSG_DEBUG, - "nl80211: External auth action: %u, AKM: 0x%x", + "nl80211: External auth action: %u, AKM: 0x%x, SSID: %s, BSSID: " MACSTR "%s", event.external_auth.action, - event.external_auth.key_mgmt_suite); + event.external_auth.key_mgmt_suite, + wpa_ssid_txt(event.external_auth.ssid, + event.external_auth.ssid_len), + MAC2STR(event.external_auth.bssid), mld_addr); wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event); } diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index a728a0fff..f64072e00 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1302,11 +1302,30 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, #ifdef CONFIG_SAE +#define WPA_AUTH_FRAME_ML_IE_LEN (6 + ETH_ALEN) + +static void wpa_auth_ml_ie(struct wpabuf *buf, const u8 *mld_addr) +{ + + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 4 + ETH_ALEN); + wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK); + + /* Basic Multi-Link element Control field */ + wpabuf_put_u8(buf, 0x0); + wpabuf_put_u8(buf, 0x0); + + /* Common Info */ + wpabuf_put_u8(buf, 0x7); /* length = Length field + MLD MAC address */ + wpabuf_put_data(buf, mld_addr, ETH_ALEN); +} + + static int sme_external_auth_build_buf(struct wpabuf *buf, struct wpabuf *params, const u8 *sa, const u8 *da, u16 auth_transaction, u16 seq_num, - u16 status_code) + u16 status_code, const u8 *mld_addr) { struct ieee80211_mgmt *resp; @@ -1325,6 +1344,9 @@ static int sme_external_auth_build_buf(struct wpabuf *buf, if (params) wpabuf_put_buf(buf, params); + if (mld_addr) + wpa_auth_ml_ie(buf, mld_addr); + return 0; } @@ -1338,7 +1360,9 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, bool use_pk; u16 status; - resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, NULL, + resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, + wpa_s->sme.ext_ml_auth ? + wpa_s->sme.ext_auth_ap_mld_addr : NULL, 1, 0, &use_pt, &use_pk); if (!resp) { wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit"); @@ -1346,7 +1370,9 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, } wpa_s->sme.sae.state = SAE_COMMITTED; - buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp)); + buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp) + + (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : + 0)); if (!buf) { wpabuf_free(resp); return -1; @@ -1360,7 +1386,11 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, else status = WLAN_STATUS_SUCCESS; sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - bssid, 1, wpa_s->sme.seq_num, status); + wpa_s->sme.ext_ml_auth ? + wpa_s->sme.ext_auth_ap_mld_addr : bssid, 1, + wpa_s->sme.seq_num, status, + wpa_s->sme.ext_ml_auth ? + wpa_s->own_addr : NULL); wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); @@ -1427,7 +1457,9 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s, } wpa_s->sme.sae.state = SAE_CONFIRMED; - buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp)); + buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp) + + (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : + 0)); if (!buf) { wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure"); wpabuf_free(resp); @@ -1436,7 +1468,10 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s, wpa_s->sme.seq_num++; sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, da, 2, wpa_s->sme.seq_num, - WLAN_STATUS_SUCCESS); + WLAN_STATUS_SUCCESS, + wpa_s->sme.ext_ml_auth ? + wpa_s->own_addr : NULL); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); @@ -1488,6 +1523,13 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, os_memcpy(wpa_s->sme.ext_auth_ssid, data->external_auth.ssid, data->external_auth.ssid_len); wpa_s->sme.ext_auth_ssid_len = data->external_auth.ssid_len; + if (data->external_auth.mld_addr) { + wpa_s->sme.ext_ml_auth = true; + os_memcpy(wpa_s->sme.ext_auth_ap_mld_addr, + data->external_auth.mld_addr, ETH_ALEN); + } else { + wpa_s->sme.ext_ml_auth = false; + } wpa_s->sme.seq_num = 0; wpa_s->sme.sae.state = SAE_NOTHING; wpa_s->sme.sae.send_confirm = 0; @@ -1549,6 +1591,42 @@ static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s, } +static int sme_external_ml_auth(struct wpa_supplicant *wpa_s, + const u8 *data, size_t len, int ie_offset) +{ + struct ieee802_11_elems elems; + const u8 *mld_addr; + + if (ieee802_11_parse_elems(data + ie_offset, len - ie_offset, + &elems, 0) != ParseOK) { + wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements"); + return -1; + } + + if (!elems.basic_mle || !elems.basic_mle_len) { + wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication"); + return -1; + } + + mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len); + if (!mld_addr) { + wpa_printf(MSG_DEBUG, "MLD: No MLD address in ML element"); + return -1; + } + + wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr)); + + if (os_memcmp(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected " + MACSTR ")", MAC2STR(wpa_s->ap_mld_addr)); + return -1; + } + + return 0; +} + + static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, u16 status_code, const u8 *data, size_t len, int external, const u8 *sa, int *ie_offset) @@ -1616,8 +1694,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, token_len = elen - 1; } - if (ie_offset) - *ie_offset = token_pos + token_len - data; + *ie_offset = token_pos + token_len - data; wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len); if (!wpa_s->sme.sae_token) { @@ -1628,13 +1705,18 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token", wpa_s->sme.sae_token); - if (!external) + if (!external) { sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 2); - else + } else { + if (wpa_s->sme.ext_ml_auth && + sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + return -1; + sme_external_auth_send_sae_commit( wpa_s, wpa_s->sme.ext_auth_bssid, wpa_s->sme.ext_auth_wpa_ssid); + } return 0; } @@ -1650,13 +1732,18 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (sme_set_sae_group(wpa_s, external) < 0) return -1; /* no other groups enabled */ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group"); - if (!external) + if (!external) { sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 1); - else + } else { + if (wpa_s->sme.ext_ml_auth && + sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + return -1; + sme_external_auth_send_sae_commit( wpa_s, wpa_s->sme.ext_auth_bssid, wpa_s->sme.ext_auth_wpa_ssid); + } return 0; } @@ -1744,11 +1831,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpabuf_free(wpa_s->sme.sae_token); wpa_s->sme.sae_token = NULL; - if (!external) + if (!external) { sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 0); - else + } else { + if (wpa_s->sme.ext_ml_auth && + sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + return -1; + sme_external_auth_send_sae_confirm(wpa_s, sa); + } return 0; } else if (auth_transaction == 2) { if (status_code != WLAN_STATUS_SUCCESS) @@ -1759,6 +1851,10 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (sae_check_confirm(&wpa_s->sme.sae, data, len, ie_offset) < 0) return -1; + if (external && wpa_s->sme.ext_ml_auth && + sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + return -1; + wpa_s->sme.sae.state = SAE_ACCEPTED; sae_clear_temp_data(&wpa_s->sme.sae); @@ -1824,12 +1920,13 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) { int res; + int ie_offset = 0; res = sme_sae_auth( wpa_s, le_to_host16(header->u.auth.auth_transaction), le_to_host16(header->u.auth.status_code), header->u.auth.variable, - len - auth_length, 1, header->sa, NULL); + len - auth_length, 1, header->sa, &ie_offset); if (res < 0) { /* Notify failure to the driver */ sme_send_external_auth_status( @@ -1842,7 +1939,10 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, if (res != 1) return; - if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0) + if (sme_sae_set_pmk(wpa_s, + wpa_s->sme.ext_ml_auth ? + wpa_s->sme.ext_auth_ap_mld_addr : + wpa_s->sme.ext_auth_bssid) < 0) return; } } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 06dcde199..cb7d5f5a1 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -981,6 +981,8 @@ struct wpa_supplicant { u8 ext_auth_ssid[SSID_MAX_LEN]; size_t ext_auth_ssid_len; int ext_auth_key_mgmt; + u8 ext_auth_ap_mld_addr[ETH_ALEN]; + bool ext_ml_auth; int *sae_rejected_groups; #endif /* CONFIG_SAE */ } sme;