diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 343508424..ba54da544 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -92,6 +92,15 @@ extern "C" { #define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH " /** Channel switch (followed by freq= and other channel parameters) */ #define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH " +/** MLO link channel switch started (followed by freq= and other channel + * parameters) + */ +#define WPA_EVENT_LINK_CHANNEL_SWITCH_STARTED \ + "CTRL-EVENT-STARTED-LINK-CHANNEL-SWITCH " +/** MLO link channel switch (followed by freq= 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 " diff --git a/src/drivers/driver.h b/src/drivers/driver.h index fca7d4b45..36ecf72f6 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -5426,6 +5426,24 @@ enum wpa_event_type { * 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, }; @@ -6141,6 +6159,7 @@ union wpa_event_data { * @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; @@ -6149,6 +6168,7 @@ union wpa_event_data { enum chan_width ch_width; int cf1; int cf2; + int link_id; } ch_switch; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 93b35a6d3..0ac0aa6de 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -96,6 +96,8 @@ const char * event_to_string(enum wpa_event_type event) E2S(CCA_ABORTED_NOTIFY); E2S(CCA_NOTIFY); E2S(PASN_AUTH); + E2S(LINK_CH_SWITCH); + E2S(LINK_CH_SWITCH_STARTED); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 60f1accaa..0de47ca41 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -782,10 +782,10 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) 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; @@ -849,6 +849,25 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, 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 ? @@ -3303,6 +3322,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, 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], @@ -3313,6 +3333,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, 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], diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index a9447c59b..e0a97bc2e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -5367,6 +5367,39 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 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)