* 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,
};
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;
};
/**
E2S(TID_LINK_MAP);
E2S(LINK_RECONFIG);
E2S(MLD_INTERFACE_FREED);
+ E2S(SETUP_LINK_RECONFIG);
}
return "UNKNOWN";
}
+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)
}
+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];
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);
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 */
}
+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)
{
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);
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;
+}
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 */
}
+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];
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;