Process EAPOL 3/4 frame and plumb PTK and per-link GTK/IGTK/BIGTK keys to driver. Signed-off-by: Veerendranath Jakkam <quic_vjakkam@xxxxxxxxxxx> --- src/rsn_supp/wpa.c | 494 ++++++++++++++++++++++++++++++++++++++++++- src/rsn_supp/wpa_i.h | 6 + 2 files changed, 498 insertions(+), 2 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 8ac22eac9..96adc4817 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1203,6 +1203,76 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, } +static int wpa_supplicant_install_mlo_gtk(struct wpa_sm *sm, u8 link_id, + const struct wpa_gtk_data *gd, + const u8 *key_rsc, int wnm_sleep) +{ + const u8 *_gtk = gd->gtk; + u8 gtk_buf[32]; + + /* Detect possible key reinstallation */ + if ((sm->links[link_id].gtk.gtk_len == (size_t) gd->gtk_len && + os_memcmp(sm->links[link_id].gtk.gtk, gd->gtk, + sm->links[link_id].gtk.gtk_len) == 0) || + (sm->links[link_id].gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len && + os_memcmp(sm->links[link_id].gtk_wnm_sleep.gtk, gd->gtk, + sm->links[link_id].gtk_wnm_sleep.gtk_len) == 0)) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA MLO: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)", + gd->keyidx, gd->tx, gd->gtk_len); + return 0; + } + + wpa_hexdump_key(MSG_DEBUG, "WPA MLO: Group Key", gd->gtk, gd->gtk_len); + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA MLO: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", + gd->keyidx, gd->tx, gd->gtk_len); + wpa_hexdump(MSG_DEBUG, "WPA MLO: RSC", key_rsc, gd->key_rsc_len); + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + os_memcpy(gtk_buf, gd->gtk, 16); + os_memcpy(gtk_buf + 16, gd->gtk + 24, 8); + os_memcpy(gtk_buf + 24, gd->gtk + 16, 8); + _gtk = gtk_buf; + } + if (sm->pairwise_cipher == WPA_CIPHER_NONE) { + if (wpa_sm_mlo_set_key(sm, link_id, gd->alg, NULL, gd->keyidx, + 1, key_rsc, gd->key_rsc_len, _gtk, + gd->gtk_len, + KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA MLO: Failed to set GTK to the driver " + "(Group only)"); + forced_memzero(gtk_buf, sizeof(gtk_buf)); + return -1; + } + } else if (wpa_sm_mlo_set_key(sm, link_id, gd->alg, + broadcast_ether_addr, gd->keyidx, + gd->tx, key_rsc, gd->key_rsc_len, _gtk, + gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA MLO: Failed to set GTK to " + "the driver (alg=%d keylen=%d keyidx=%d)", + gd->alg, gd->gtk_len, gd->keyidx); + forced_memzero(gtk_buf, sizeof(gtk_buf)); + return -1; + } + forced_memzero(gtk_buf, sizeof(gtk_buf)); + + if (wnm_sleep) { + sm->links[link_id].gtk_wnm_sleep.gtk_len = gd->gtk_len; + os_memcpy(sm->links[link_id].gtk_wnm_sleep.gtk, gd->gtk, + sm->links[link_id].gtk_wnm_sleep.gtk_len); + } else { + sm->links[link_id].gtk.gtk_len = gd->gtk_len; + os_memcpy(sm->links[link_id].gtk.gtk, gd->gtk, + sm->links[link_id].gtk.gtk_len); + } + + return 0; +} + + static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, int tx) { @@ -1251,6 +1321,82 @@ static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm, } +static int _wpa_supplicant_pairwise_mlo_gtk(struct wpa_sm *sm, u8 link_id, + const u8 *gtk, size_t gtk_len, + int key_info) +{ + struct wpa_gtk_data gd; + const u8 *key_rsc; + + /* + * MLO GTK KDE format: + * KeyID[bits 0-1], Tx [bit 2], Reserved [bit 3], link id [4-7] + * PN + * GTK + */ + + os_memset(&gd, 0, sizeof(gd)); + wpa_hexdump_key(MSG_DEBUG, "MLO RSN: received GTK in pairwise handshake", + gtk, gtk_len); + + if (gtk_len < 7 || gtk_len - 7 > sizeof(gd.gtk)) + return -1; + + gd.keyidx = gtk[0] & 0x3; + gtk += 1; + gtk_len -= 1; + + key_rsc = gtk; + + gtk += 6; + gtk_len -= 6; + + os_memcpy(gd.gtk, gtk, gtk_len); + gd.gtk_len = gtk_len; + + if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED && + (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, + gtk_len, gtk_len, + &gd.key_rsc_len, &gd.alg) || + wpa_supplicant_install_mlo_gtk(sm, link_id, &gd, key_rsc, 0))) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "MLO RSN: Failed to install GTK"); + forced_memzero(&gd, sizeof(gd)); + return -1; + } + forced_memzero(&gd, sizeof(gd)); + + return 0; +} + + +static int wpa_supplicant_pairwise_mlo_gtk(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + struct wpa_eapol_ie_parse *ie, + int key_info) +{ + u8 i; + + for (i = 0; i < MAX_NUM_MLO_LINKS; i++) { + if (!(sm->valid_links & BIT(i))) + continue; + + if (!ie->mlo_gtk[i]) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "MLO RSN: GTK not found for link ID %u", i); + return -1; + } + + if (_wpa_supplicant_pairwise_mlo_gtk(sm, i, ie->mlo_gtk[i], + ie->mlo_gtk_len[i], + key_info)) + return -1; + } + + return 0; +} + + static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, const struct wpa_eapol_key *key, const u8 *gtk, size_t gtk_len, @@ -1421,6 +1567,170 @@ static int wpa_supplicant_install_bigtk(struct wpa_sm *sm, return 0; } +static int wpa_supplicant_install_mlo_igtk(struct wpa_sm *sm, u8 link_id, + const struct wpa_mlo_igtk_kde *igtk, + int wnm_sleep) +{ + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher); + u16 keyidx = WPA_GET_LE16(igtk->hdr.keyid); + + /* Detect possible key reinstallation */ + if ((sm->links[link_id].igtk.igtk_len == len && + os_memcmp(sm->links[link_id].igtk.igtk, igtk->igtk, + sm->links[link_id].igtk.igtk_len) == 0) || + (sm->links[link_id].igtk_wnm_sleep.igtk_len == len && + os_memcmp(sm->links[link_id].igtk_wnm_sleep.igtk, igtk->igtk, + sm->links[link_id].igtk_wnm_sleep.igtk_len) == 0)) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)", + keyidx); + return 0; + } + + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: IGTK keyid %d pn " COMPACT_MACSTR, + keyidx, MAC2STR(igtk->hdr.pn)); + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len); + if (keyidx > 4095) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Invalid IGTK KeyID %d", keyidx); + return -1; + } + if (wpa_sm_mlo_set_key(sm, link_id, + wpa_cipher_to_alg(sm->mgmt_group_cipher), + broadcast_ether_addr, keyidx, 0, igtk->hdr.pn, + sizeof(igtk->hdr.pn), igtk->igtk, len, + KEY_FLAG_GROUP_RX) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Failed to configure IGTK to the driver"); + return -1; + } + + if (wnm_sleep) { + sm->links[link_id].igtk_wnm_sleep.igtk_len = len; + os_memcpy(sm->links[link_id].igtk_wnm_sleep.igtk, + igtk->igtk, + sm->links[link_id].igtk_wnm_sleep.igtk_len); + } else { + sm->links[link_id].igtk.igtk_len = len; + os_memcpy(sm->links[link_id].igtk.igtk, igtk->igtk, + sm->links[link_id].igtk.igtk_len); + } + + return 0; +} + + +static int +wpa_supplicant_install_mlo_bigtk(struct wpa_sm *sm, u8 link_id, + const struct wpa_mlo_bigtk_kde *bigtk, + int wnm_sleep) +{ + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher); + u16 keyidx = WPA_GET_LE16(bigtk->hdr.keyid); + + /* Detect possible key reinstallation */ + if ((sm->links[link_id].bigtk.bigtk_len == len && + os_memcmp(sm->links[link_id].bigtk.bigtk, bigtk->bigtk, + sm->links[link_id].bigtk.bigtk_len) == 0) || + (sm->links[link_id].bigtk_wnm_sleep.bigtk_len == len && + os_memcmp(sm->links[link_id].bigtk_wnm_sleep.bigtk, bigtk->bigtk, + sm->links[link_id].bigtk_wnm_sleep.bigtk_len) == 0)) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)", + keyidx); + return 0; + } + + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: BIGTK keyid %d pn " COMPACT_MACSTR, + keyidx, MAC2STR(bigtk->hdr.pn)); + wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len); + if (keyidx < 6 || keyidx > 7) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Invalid BIGTK KeyID %d", keyidx); + return -1; + } + if (wpa_sm_mlo_set_key(sm, link_id, + wpa_cipher_to_alg(sm->mgmt_group_cipher), + broadcast_ether_addr, keyidx, 0, bigtk->hdr.pn, + sizeof(bigtk->hdr.pn), bigtk->bigtk, len, + KEY_FLAG_GROUP_RX) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Failed to configure BIGTK to the driver"); + return -1; + } + + if (wnm_sleep) { + sm->links[link_id].bigtk_wnm_sleep.bigtk_len = len; + os_memcpy(sm->links[link_id].bigtk_wnm_sleep.bigtk, + bigtk->bigtk, + sm->links[link_id].bigtk_wnm_sleep.bigtk_len); + } else { + sm->links[link_id].bigtk.bigtk_len = len; + os_memcpy(sm->links[link_id].bigtk.bigtk, bigtk->bigtk, + sm->links[link_id].bigtk.bigtk_len); + } + + return 0; +} + + +static int _mlo_ieee80211w_set_keys(struct wpa_sm *sm, u8 link_id, + struct wpa_eapol_ie_parse *ie) +{ + size_t len; + + if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) || + sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED) + return 0; + + if (ie->mlo_igtk[link_id]) { + const struct wpa_mlo_igtk_kde *igtk; + + len = wpa_cipher_key_len(sm->mgmt_group_cipher); + if (ie->mlo_igtk_len[link_id] != + sizeof(struct wpa_mlo_igtk_hdr) + len) + return -1; + + igtk = (const struct wpa_mlo_igtk_kde *) ie->mlo_igtk[link_id]; + if (wpa_supplicant_install_mlo_igtk(sm, link_id, igtk, 0) < 0) + return -1; + } + + if (ie->mlo_bigtk[link_id] && sm->beacon_prot) { + const struct wpa_mlo_bigtk_kde *bigtk; + + len = wpa_cipher_key_len(sm->mgmt_group_cipher); + if (ie->mlo_bigtk_len[link_id] != + sizeof(struct wpa_mlo_bigtk_hdr) + len) + return -1; + + bigtk = (const struct wpa_mlo_bigtk_kde *) ie->mlo_bigtk[link_id]; + if (wpa_supplicant_install_mlo_bigtk(sm, link_id, bigtk, 0) < 0) + return -1; + } + + return 0; +} + + +static int mlo_ieee80211w_set_keys(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *ie) +{ + u8 i; + + for (i = 0; i < MAX_NUM_MLO_LINKS; i++) { + if (!(sm->valid_links & BIT(i))) + continue; + + if (_mlo_ieee80211w_set_keys(sm, i, ie)) + return -1; + } + + return 0; +} + static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) @@ -1782,6 +2092,162 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, } +static void wpa_supplicant_process_mlo_3_of_4(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + u16 ver, const u8 *key_data, + size_t key_data_len) +{ + u16 key_info, keylen; + struct wpa_eapol_ie_parse ie; + + wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); + wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA MLO: RX message 3 of 4-Way " + "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver); + + key_info = WPA_GET_BE16(key->key_info); + + wpa_hexdump(MSG_DEBUG, "WPA MLO: IE KeyData", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) + goto failed; + + if (ie.mlo_gtk_found && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA MLO: GTK IE in unencrypted key data"); + goto failed; + } + if (ie.mlo_igtk_found && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA MLO: IGTK KDE in unencrypted key data"); + goto failed; + } + + +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->key_mgmt) && + wpa_supplicant_validate_ie_ft(sm, sm->bssid, &ie) < 0) + goto failed; +#endif /* CONFIG_IEEE80211R */ + + if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA MLO: ANonce from message 1 of 4-Way Handshake " + "differs from 3 of 4-Way Handshake - drop packet (src=" + MACSTR ")", MAC2STR(sm->bssid)); + goto failed; + } + + keylen = WPA_GET_BE16(key->key_length); + if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA MLO: Invalid %s key length %d (src=" MACSTR + ")", wpa_cipher_txt(sm->pairwise_cipher), keylen, + MAC2STR(sm->bssid)); + goto failed; + } + +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(sm)) { + struct wpa_channel_info ci; + + if (wpa_sm_channel_info(sm, &ci) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "MLO: Failed to get channel info to validate received OCI in EAPOL-Key 3/4"); + return; + } + + if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci, + channel_width_to_int(ci.chanwidth), + ci.seg1_idx) != OCI_SUCCESS) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE + "addr=" MACSTR " frame=eapol-key-m3 error=%s", + MAC2STR(sm->bssid), ocv_errorstr); + return; + } + } +#endif /* CONFIG_OCV */ + + if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, + &sm->ptk) < 0) + goto failed; + + /* SNonce was successfully used in msg 3/4, so mark it to be renewed + * for the next 4-Way Handshake. If msg 3 is received again, the old + * SNonce will still be used to avoid changing PTK. */ + sm->renew_snonce = 1; + + if (key_info & WPA_KEY_INFO_INSTALL) { + int res; + + if (sm->use_ext_key_id) + res = wpa_supplicant_activate_ptk(sm); + else + res = wpa_supplicant_install_ptk(sm, key, + KEY_FLAG_RX_TX); + if (res) + goto failed; + } + + if (key_info & WPA_KEY_INFO_SECURE) { + wpa_sm_mlme_setprotection( + sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + eapol_sm_notify_portValid(sm->eapol, true); + } + wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); + + if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) { + /* No GTK to be set to the driver */ + } else if (!ie.mlo_gtk_found && sm->proto == WPA_PROTO_RSN) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "MLO RSN: No GTK KDE included in EAPOL-Key msg 3/4"); + goto failed; + } else if (ie.mlo_gtk_found && + wpa_supplicant_pairwise_mlo_gtk(sm, key, &ie, key_info) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "MLO RSN: Failed to configure MLO GTKs"); + goto failed; + } + + if (mlo_ieee80211w_set_keys(sm, &ie) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "MLO RSN: Failed to configure IGTK"); + goto failed; + } + + if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.mlo_gtk_found) + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info & WPA_KEY_INFO_SECURE); + + if (ie.mlo_gtk_found) + wpa_sm_set_rekey_offload(sm); + + /* Add PMKSA cache entry for Suite B AKMs here since PMKID can be + * calculated only after KCK has been derived. Though, do not replace an + * existing PMKSA entry after each 4-way handshake (i.e., new KCK/PMKID) + * to avoid unnecessary changes of PMKID while continuing to use the + * same PMK. */ + if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt) && + !sm->cur_pmksa) { + struct rsn_pmksa_cache_entry *sa; + + sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL, + sm->ptk.kck, sm->ptk.kck_len, + sm->bssid, sm->own_addr, + sm->network_ctx, sm->key_mgmt, NULL); + if (!sm->cur_pmksa) + sm->cur_pmksa = sa; + } + + if (ie.transition_disable) + wpa_sm_transition_disable(sm, ie.transition_disable[0]); + sm->msg_3_of_4_ok = 1; + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, const struct wpa_eapol_key *key, u16 ver, const u8 *key_data, @@ -2844,8 +3310,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, if (key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ENCR_KEY_DATA)) { /* 3/4 4-Way Handshake */ - wpa_supplicant_process_3_of_4(sm, key, ver, key_data, - key_data_len); + if (sm->valid_links) + wpa_supplicant_process_mlo_3_of_4( + sm, key, ver, key_data, key_data_len); + else + wpa_supplicant_process_3_of_4(sm, key, ver, + key_data, + key_data_len); } else { /* 1/4 4-Way Handshake */ wpa_supplicant_process_1_of_4(sm, src_addr, key, @@ -3136,6 +3607,7 @@ void wpa_sm_deinit(struct wpa_sm *sm) void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) { int clear_keys = 1; + int i; if (sm == NULL) return; @@ -3193,6 +3665,14 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) os_memset(&sm->igtk, 0, sizeof(sm->igtk)); os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); sm->tk_set = false; + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + os_memset(&sm->links[i].gtk, 0, sizeof(sm->gtk)); + os_memset(&sm->links[i].gtk_wnm_sleep, 0, + sizeof(sm->gtk_wnm_sleep)); + os_memset(&sm->links[i].igtk, 0, sizeof(sm->igtk)); + os_memset(&sm->links[i].igtk_wnm_sleep, 0, + sizeof(sm->igtk_wnm_sleep)); + } } #ifdef CONFIG_TDLS @@ -4053,6 +4533,8 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, void wpa_sm_drop_sa(struct wpa_sm *sm) { + int i; + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK"); sm->ptk_set = 0; sm->tptk_set = 0; @@ -4065,6 +4547,14 @@ void wpa_sm_drop_sa(struct wpa_sm *sm) os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep)); os_memset(&sm->igtk, 0, sizeof(sm->igtk)); os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + os_memset(&sm->links[i].gtk, 0, sizeof(sm->gtk)); + os_memset(&sm->links[i].gtk_wnm_sleep, 0, + sizeof(sm->gtk_wnm_sleep)); + os_memset(&sm->links[i].igtk, 0, sizeof(sm->igtk)); + os_memset(&sm->links[i].igtk_wnm_sleep, 0, + sizeof(sm->igtk_wnm_sleep)); + } #ifdef CONFIG_IEEE80211R os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); sm->xxkey_len = 0; diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index f60616352..abac0a2d3 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -226,6 +226,12 @@ struct wpa_sm { u8 bssid[ETH_ALEN]; u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe; size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len; + struct wpa_gtk gtk; + struct wpa_gtk gtk_wnm_sleep; + struct wpa_igtk igtk; + struct wpa_igtk igtk_wnm_sleep; + struct wpa_bigtk bigtk; + struct wpa_bigtk bigtk_wnm_sleep; } links[MAX_NUM_MLD_LINKS]; }; -- 2.25.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap