MLD STA: Add support for SAE external authentication offload to userspace
Enable MLO for SAE authentication when the driver indicates the AP MLD address in an external authentication request. The MAC address of the interface on which the external authentication request received will be used as the own MLD address. This commit does below for enabling MLO during external SAE authentication: - Use MLD addresses for SAE authentication. - Add Basic Multi-Link element with the own MLD address in SAE Authentication frames. - Send SAE Authentication frames with the source address as the own MLD address, destination address and BSSID as the AP MLD address to the driver. - Validate the MLD address indicated by the AP in SAE Authentication frames against the AP MLD address indicated in external authentication request. - Store the PMKSA with the AP MLD address after completing SAE authentication. Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
This commit is contained in:
parent
575712450a
commit
c91852044d
4 changed files with 134 additions and 18 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,7 +1694,6 @@ 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;
|
||||
|
||||
wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue