#endif /* CONFIG_DRIVER_NL80211_QCA */
+static void mlme_event_link_removal(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *mlo_links)
+{
+ struct nlattr *link;
+ u16 removed_links = 0;
+ int rem_links, i;
+
+ if (!mlo_links)
+ return;
+ nla_for_each_nested(link, mlo_links, rem_links) {
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ int link_id;
+
+ nla_parse(tb, NL80211_ATTR_MAX, nla_data(link), nla_len(link),
+ NULL);
+
+ if (!tb[NL80211_ATTR_MLO_LINK_ID])
+ continue;
+
+ link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ continue;
+
+ removed_links |= BIT(link_id);
+ }
+
+ drv->sta_mlo_info.valid_links &= ~removed_links;
+ drv->sta_mlo_info.req_links &= ~removed_links;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(removed_links & BIT(i)))
+ continue;
+
+ os_memset(&drv->sta_mlo_info.links[i], 0,
+ sizeof(drv->sta_mlo_info.links[i]));
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL);
+}
+
+
static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, bool qca_roam_auth,
struct nlattr *status,
break;
#endif /* CONFIG_IEEE80211AX */
case NL80211_CMD_LINKS_REMOVED:
- wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL);
+ mlme_event_link_removal(drv, tb[NL80211_ATTR_MLO_LINKS]);
break;
case NL80211_CMD_ASSOC_MLO_RECONF:
mlme_event_link_addition(drv, nla_data(frame), nla_len(frame));
}
+static void wpa_sm_clear_mlo_group_keys(struct wpa_sm *sm, int link_id)
+{
+ if (!sm)
+ return;
+
+ os_memset(&sm->mlo.links[link_id].gtk, 0,
+ sizeof(sm->mlo.links[link_id].gtk));
+ os_memset(&sm->mlo.links[link_id].gtk_wnm_sleep, 0,
+ sizeof(sm->mlo.links[link_id].gtk_wnm_sleep));
+ os_memset(&sm->mlo.links[link_id].igtk, 0,
+ sizeof(sm->mlo.links[link_id].igtk));
+ os_memset(&sm->mlo.links[link_id].igtk_wnm_sleep, 0,
+ sizeof(sm->mlo.links[link_id].igtk_wnm_sleep));
+ os_memset(&sm->mlo.links[link_id].bigtk, 0,
+ sizeof(sm->mlo.links[link_id].bigtk));
+ os_memset(&sm->mlo.links[link_id].bigtk_wnm_sleep, 0,
+ sizeof(sm->mlo.links[link_id].bigtk_wnm_sleep));
+}
+
+
int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
{
int i;
+ u16 removed_links;
if (!sm)
return -1;
os_memcpy(sm->mlo.ap_mld_addr, mlo->ap_mld_addr, ETH_ALEN);
+ removed_links = ~mlo->valid_links & sm->mlo.valid_links;
sm->mlo.assoc_link_id = mlo->assoc_link_id;
sm->mlo.valid_links = mlo->valid_links;
sm->mlo.req_links = mlo->req_links;
}
sm->mlo.links[i].ap_rsnxoe_len = len;
}
+
+ if (removed_links & BIT(i)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Clearing MLO group keys for link[%u]",
+ i);
+ wpa_sm_clear_mlo_group_keys(sm, i);
+ }
}
return 0;