From: Kavita Kavita Date: Fri, 9 May 2025 15:50:29 +0000 (+0530) Subject: MLD: Handle link reconfiguration updates from the driver X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a1893fd3aa8805f4733493f20e2acac2d67ab50;p=thirdparty%2Fhostap.git MLD: Handle link reconfiguration updates from the driver Processess the NL80211_CMD_ASSOC_MLO_RECONF event from the driver. This event includes information about added links and the link reconfiguration response frame from the AP MLD. The event can be triggered by either wpa_supplicant or driver-initiated link reconfiguration updates. Also install group keys (e.g., GTK, IGTK, BIGTK, etc.) received with the link reconfiguration response frame for the newly added links. For removed links, the existing NL80211_CMD_LINKS_REMOVED event is used, requiring no additional changes in wpa_supplicant for both wpa_supplicant and driver-initiated link reconfiguration updates. Signed-off-by: Kavita Kavita --- diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 97b0e2e57..56d99f2a1 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -6128,6 +6128,11 @@ enum wpa_event_type { * EVENT_MLD_INTERFACE_FREED - Notification of AP MLD interface removal */ EVENT_MLD_INTERFACE_FREED, + + /** + * EVENT_SETUP_LINK_RECONFIG - Notification that new AP links added + */ + EVENT_SETUP_LINK_RECONFIG, }; @@ -7115,6 +7120,17 @@ union wpa_event_data { u8 valid_links; struct t2lm_mapping t2lmap[MAX_NUM_MLD_LINKS]; } t2l_map_info; + + /** + * struct reconfig_info - Data for EVENT_SETUP_LINK_RECONFIG + */ + struct reconfig_info { + u16 added_links; + u8 count; + const u8 *status_list; + const u8 *resp_ie; /* Starting from Group Key Data */ + size_t resp_ie_len; + } reconfig_info; }; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 7a9f18c21..045c82967 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -101,6 +101,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(TID_LINK_MAP); E2S(LINK_RECONFIG); E2S(MLD_INTERFACE_FREED); + E2S(SETUP_LINK_RECONFIG); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 46d049159..68ff64941 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1130,6 +1130,19 @@ static int nl80211_get_sta_mlo_info(void *priv, } +int get_sta_mlo_interface_info(struct wpa_driver_nl80211_data *drv) +{ + struct nl_msg *msg; + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE); + if (!msg || + send_and_recv_resp(drv, msg, get_mlo_info, &drv->sta_mlo_info)) + return -1; + + return 0; +} + + static void wpa_driver_nl80211_event_newlink( struct nl80211_global *global, struct wpa_driver_nl80211_data *drv, int ifindex, const char *ifname) @@ -1734,6 +1747,53 @@ try_again: } +const u8 * nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv) +{ + struct nl_msg *msg; + int ret; + struct nl80211_get_assoc_freq_arg arg; + int count = 0; + +try_again: + msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); + if (!msg) + return NULL; + os_memset(&arg, 0, sizeof(arg)); + arg.drv = drv; + ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler, + &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump for get_assoc_bssid"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump for get_assoc_bssid - try again"); + goto try_again; + } + } + if (ret == 0) { + os_memcpy(drv->bssid, arg.assoc_bssid, ETH_ALEN); + + if (drv->sta_mlo_info.valid_links) { + int i; + + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) + os_memcpy(drv->sta_mlo_info.links[i].bssid, + arg.bssid[i], ETH_ALEN); + } + + return drv->bssid; + } + + wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)", + ret, strerror(-ret)); + + return NULL; +} + + static int get_link_noise(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index bea87afeb..c570fba1c 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -330,6 +330,7 @@ int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, void *arg, int use_existing); void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx); unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv); +const u8 * nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv); int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid); enum chan_width convert2width(int width); void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv); @@ -431,4 +432,6 @@ struct hostapd_multi_hw_info * nl80211_get_multi_hw_info(struct i802_bss *bss, unsigned int *num_multi_hws); u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv); +int get_sta_mlo_interface_info(struct wpa_driver_nl80211_data *drv); + #endif /* DRIVER_NL80211_H */ diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index e7b67371a..9bf9888ae 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -1657,6 +1657,69 @@ static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv, } +static void mlme_event_link_addition(struct wpa_driver_nl80211_data *drv, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + u16 curr_valid_links, added_links; + u8 count; + const u8 *resp_ie; + const u8 *end; + + if (!frame) { + wpa_printf(MSG_DEBUG, + "Link Reconfiguration Response frame is NULL - unspecified reason"); + return; + } + wpa_hexdump(MSG_DEBUG, "JKM", frame, len); + end = frame + len; + + os_memset(&event, 0, sizeof(event)); + + mgmt = (const struct ieee80211_mgmt *) frame; + + if (len < 24 + 1 + sizeof(mgmt->u.action.u.link_reconf_resp)) { + wpa_printf(MSG_DEBUG, + "nl80211: Too short Link Reconfig Response frame"); + return; + } + + count = mgmt->u.action.u.link_reconf_resp.count; + event.reconfig_info.count = count; + resp_ie = mgmt->u.action.u.link_reconf_resp.variable; + if (end - resp_ie < 3 * count) { + wpa_printf(MSG_DEBUG, + "nl80211: Truncated Link Reconfig Response frame"); + return; + } + event.reconfig_info.status_list = resp_ie; + resp_ie += 3 * count; + curr_valid_links = drv->sta_mlo_info.valid_links; + + if (get_sta_mlo_interface_info(drv) < 0) { + wpa_printf(MSG_INFO, "nl80211: Failed to get STA MLO info"); + return; + } + + if (!nl80211_get_assoc_bssid(drv)) { + wpa_printf(MSG_INFO, + "nl80211: Failed to get BSSID info for newly added links"); + return; + } + + added_links = ~curr_valid_links & drv->sta_mlo_info.valid_links; + + event.reconfig_info.resp_ie = resp_ie; + event.reconfig_info.resp_ie_len = end - resp_ie; + event.reconfig_info.added_links = added_links; + + drv->sta_mlo_info.req_links = drv->sta_mlo_info.valid_links; + + wpa_supplicant_event(drv->ctx, EVENT_SETUP_LINK_RECONFIG, &event); +} + + static s8 nl80211_get_link_id_by_freq(struct i802_bss *bss, unsigned int freq) { @@ -4247,6 +4310,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_LINKS_REMOVED: wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL); break; + case NL80211_CMD_ASSOC_MLO_RECONF: + mlme_event_link_addition(drv, nla_data(frame), nla_len(frame)); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 49412854c..9a0463170 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -7282,3 +7282,70 @@ struct wpabuf * wpa_sm_known_sta_identification(struct wpa_sm *sm, const u8 *aa, return ie; } + + +static int mlo_ieee80211w_set_keys_for_new_links(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *ie, + u16 added_links_bitmap) +{ + int i; + + if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) || + sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED) + return 0; + + for_each_link(added_links_bitmap, i) { + if (_mlo_ieee80211w_set_keys(sm, i, ie)) + return -1; + } + + return 0; +} + + +static int wpa_supplicant_install_mlo_gtk_keys(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *ie, + u16 added_links_bitmap) +{ + int i; + + for_each_link(added_links_bitmap, i) { + 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_mlo_gtk(sm, i, ie->mlo_gtk[i], + ie->mlo_gtk_len[i], 0)) + return -1; + } + + return 0; +} + + +int wpa_sm_install_mlo_group_keys(struct wpa_sm *sm, const u8 *key_data, + size_t key_data_len, u16 added_links_bitmap) +{ + struct wpa_eapol_ie_parse ie; + + if (!sm) + return -1; + + wpa_hexdump_key(MSG_DEBUG, "RSN: IE KeyData for MLO link reconfig", + key_data, key_data_len); + + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) + return -1; + + if (wpa_supplicant_install_mlo_gtk_keys( + sm, &ie, added_links_bitmap) < 0) + return -1; + + if (mlo_ieee80211w_set_keys_for_new_links(sm, &ie, + added_links_bitmap) < 0) + return -1; + + return 0; +} diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index c011162f7..0c360bdea 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -676,5 +676,7 @@ void wpa_sm_set_cur_pmksa(struct wpa_sm *sm, const u8 * wpa_sm_get_auth_addr(struct wpa_sm *sm); struct wpabuf * wpa_sm_known_sta_identification(struct wpa_sm *sm, const u8 *aa, u64 timestamp); +int wpa_sm_install_mlo_group_keys(struct wpa_sm *sm, const u8 *key_data, + size_t key_data_len, u16 added_links_bitmap); #endif /* WPA_H */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index fe8e45e07..00b733a1c 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -6106,6 +6106,76 @@ static void wpas_tid_link_map(struct wpa_supplicant *wpa_s, } +static void wpas_setup_link_reconfig(struct wpa_supplicant *wpa_s, + struct reconfig_info *info) +{ + const u8 *key_data = info->resp_ie; + size_t key_data_len = 0; + const u8 *ies, *end; + bool success = false; + int i; + + if (!info->added_links) { + wpa_printf(MSG_INFO, "No links to be added"); + return; + } + + if (wpa_drv_get_mlo_info(wpa_s) < 0) { + wpa_printf(MSG_INFO, + "SETUP_LINK_RECONFIG: Failed to set reconfig info to wpa_s"); + return; + } + + if (wpa_sm_set_ml_info(wpa_s)) { + wpa_printf(MSG_ERROR, + "SETUP_LINK_RECONFIG: Failed to set reconfig info to wpa_sm"); + return; + } + + wpa_hexdump(MSG_DEBUG, "MLD: Reconfiguration Status List", + info->status_list, info->count * 3); + for (i = 0; i < info->count; i++) { + if (WPA_GET_LE16(info->status_list + i * 3 + 1) == + WLAN_STATUS_SUCCESS) + success = true; + } + + if (!key_data || info->resp_ie_len == 0) + return; + + if (success) { + /* Starting with Group Key Data subfield, Key Data Length + * field */ + if (info->resp_ie_len < 1U + key_data[0]) { + wpa_printf(MSG_INFO, + "MLD: Invalid keys in the link setup response"); + return; + } + + key_data_len = key_data[0]; + key_data++; + wpa_hexdump_key(MSG_DEBUG, + "MLD: Link reconfig resp - Group Key Data", + key_data, key_data_len); + + if (wpa_sm_install_mlo_group_keys(wpa_s->wpa, key_data, + key_data_len, + info->added_links)) { + wpa_printf(MSG_ERROR, + "SETUP_LINK_RECONFIG: Failed to install group keys for added links"); + return; + } + } + + ies = key_data + key_data_len; + end = info->resp_ie + info->resp_ie_len; + wpa_hexdump(MSG_DEBUG, "MLD: Link reconfig resp - IEs", ies, end - ies); + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_LINK_RECONFIG "valid_links=0x%x", + wpa_s->valid_links); +} + + static void wpas_link_reconfig(struct wpa_supplicant *wpa_s) { u8 bssid[ETH_ALEN]; @@ -7132,6 +7202,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (data) wpas_tid_link_map(wpa_s, &data->t2l_map_info); break; + case EVENT_SETUP_LINK_RECONFIG: + if (data) + wpas_setup_link_reconfig(wpa_s, &data->reconfig_info); + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break;