#define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH "
/** Channel switch (followed by freq=<MHz> and other channel parameters) */
#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
+/** MLO link channel switch started (followed by freq=<MHz> and other channel
+ * parameters)
+ */
+#define WPA_EVENT_LINK_CHANNEL_SWITCH_STARTED \
+ "CTRL-EVENT-STARTED-LINK-CHANNEL-SWITCH "
+/** MLO link channel switch (followed by freq=<MHz> and other channel
+ * parameters)
+ */
+#define WPA_EVENT_LINK_CHANNEL_SWITCH "CTRL-EVENT-LINK-CHANNEL-SWITCH "
/** SAE authentication failed due to unknown password identifier */
#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
* PASN authentication and secure ranging context for multiple peers.
*/
EVENT_PASN_AUTH,
+
+ /**
+ * EVENT_LINK_CH_SWITCH - MLD AP link decided to switch channels
+ *
+ * Described in wpa_event_data.ch_switch.
+ *
+ */
+ EVENT_LINK_CH_SWITCH,
+
+ /**
+ * EVENT_LINK_CH_SWITCH_STARTED - MLD AP link started to switch channels
+ *
+ * This is a pre-switch event indicating the shortly following switch
+ * of operating channels.
+ *
+ * Described in wpa_event_data.ch_switch.
+ */
+ EVENT_LINK_CH_SWITCH_STARTED,
};
* @ch_width: Channel width
* @cf1: Center frequency 1
* @cf2: Center frequency 2
+ * @link_id: Link ID of the MLO link
*/
struct ch_switch {
int freq;
enum chan_width ch_width;
int cf1;
int cf2;
+ int link_id;
} ch_switch;
/**
E2S(CCA_ABORTED_NOTIFY);
E2S(CCA_NOTIFY);
E2S(PASN_AUTH);
+ E2S(LINK_CH_SWITCH);
+ E2S(LINK_CH_SWITCH_STARTED);
}
return "UNKNOWN";
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *ifindex, struct nlattr *freq,
- struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2,
- int finished)
+ struct nlattr *ifindex, struct nlattr *link,
+ struct nlattr *freq, struct nlattr *type,
+ struct nlattr *bw, struct nlattr *cf1,
+ struct nlattr *cf2, int finished)
{
struct i802_bss *bss;
union wpa_event_data data;
if (finished)
bss->freq = data.ch_switch.freq;
+
+ if (link) {
+ u8 link_id = nla_get_u8(link);
+
+ if (link_id < MAX_NUM_MLD_LINKS &&
+ drv->sta_mlo_info.valid_links & BIT(link_id)) {
+ data.ch_switch.link_id = link_id;
+ drv->sta_mlo_info.links[link_id].freq =
+ data.ch_switch.freq;
+ wpa_supplicant_event(
+ bss->ctx,
+ finished ? EVENT_LINK_CH_SWITCH :
+ EVENT_LINK_CH_SWITCH_STARTED, &data);
+ }
+
+ if (link_id != drv->mlo_assoc_link_id)
+ return;
+ }
+
drv->assoc_freq = data.ch_switch.freq;
wpa_supplicant_event(bss->ctx, finished ?
case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
mlme_event_ch_switch(drv,
tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_MLO_LINK_ID],
tb[NL80211_ATTR_WIPHY_FREQ],
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
tb[NL80211_ATTR_CHANNEL_WIDTH],
case NL80211_CMD_CH_SWITCH_NOTIFY:
mlme_event_ch_switch(drv,
tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_MLO_LINK_ID],
tb[NL80211_ATTR_WIPHY_FREQ],
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
tb[NL80211_ATTR_CHANNEL_WIDTH],
break;
#endif /* CONFIG_AP */
+ case EVENT_LINK_CH_SWITCH_STARTED:
+ case EVENT_LINK_CH_SWITCH:
+ if (!data || !wpa_s->current_ssid ||
+ !(wpa_s->valid_links & BIT(data->ch_switch.link_id)))
+ break;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ "%sfreq=%d link_id=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ event == EVENT_LINK_CH_SWITCH ?
+ WPA_EVENT_LINK_CHANNEL_SWITCH :
+ WPA_EVENT_LINK_CHANNEL_SWITCH_STARTED,
+ data->ch_switch.freq,
+ data->ch_switch.link_id,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ channel_width_to_string(data->ch_switch.ch_width),
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+ if (event == EVENT_LINK_CH_SWITCH_STARTED)
+ break;
+
+ wpa_s->links[data->ch_switch.link_id].freq =
+ data->ch_switch.freq;
+ if (wpa_s->links[data->ch_switch.link_id].bss &&
+ wpa_s->links[data->ch_switch.link_id].bss->freq !=
+ data->ch_switch.freq) {
+ wpa_s->links[data->ch_switch.link_id].bss->freq =
+ data->ch_switch.freq;
+ notify_bss_changes(
+ wpa_s, WPA_BSS_FREQ_CHANGED_FLAG,
+ wpa_s->links[data->ch_switch.link_id].bss);
+ }
+ break;
case EVENT_CH_SWITCH_STARTED:
case EVENT_CH_SWITCH:
if (!data || !wpa_s->current_ssid)