diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 8ddf754f6..58753e55a 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -772,7 +772,8 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset, int width, int cf1, int cf2) + int offset, int width, int cf1, int cf2, + int finished) { /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */ @@ -783,7 +784,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", + "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", + finished ? "had" : "starting", freq, ht, hapd->iconf->ch_switch_vht_config, offset, width, channel_width_to_string(width), cf1, cf2); @@ -851,6 +853,15 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features, hapd->iface->num_hw_features); + wpa_msg(hapd->msg_ctx, MSG_INFO, + "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d", + finished ? WPA_EVENT_CHANNEL_SWITCH : + WPA_EVENT_CHANNEL_SWITCH_STARTED, + freq, ht, offset, channel_width_to_string(width), + cf1, cf2, is_dfs); + if (!finished) + return; + if (hapd->csa_in_progress && freq == hapd->cs_freq_params.freq) { hostapd_cleanup_cs_params(hapd); @@ -1689,6 +1700,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_AUTH: hostapd_notif_auth(hapd, &data->auth); break; + case EVENT_CH_SWITCH_STARTED: case EVENT_CH_SWITCH: if (!data) break; @@ -1697,7 +1709,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.ch_offset, data->ch_switch.ch_width, data->ch_switch.cf1, - data->ch_switch.cf2); + data->ch_switch.cf2, + event == EVENT_CH_SWITCH); break; case EVENT_CONNECT_FAILED_REASON: if (!data) diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 790d37754..0f76cd6c8 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -607,7 +607,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len, int ssi_signal); void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset, int width, int cf1, int cf2); + int offset, int width, int cf1, int cf2, + int finished); struct survey_results; void hostapd_event_get_survey(struct hostapd_iface *iface, struct survey_results *survey_results); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f65077e04..b24ae63e5 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -87,6 +87,9 @@ extern "C" { #define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS " /** Regulatory domain channel */ #define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE " +/** Channel switch started (followed by freq= and other channel parameters) + */ +#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 " /** SAE authentication failed due to unknown password identifier */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index cb561acba..095bfd96a 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1122,6 +1122,11 @@ enum hide_ssid { HIDDEN_SSID_ZERO_CONTENTS }; +enum ch_switch_state { + CH_SW_STARTED, + CH_SW_FINISHED +}; + struct wowlan_triggers { u8 any; u8 disconnect; @@ -4540,6 +4545,15 @@ enum wpa_event_type { * */ EVENT_CH_SWITCH, + /** + * EVENT_CH_SWITCH_STARTED - AP or GO 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_CH_SWITCH_STARTED, /** * EVENT_WNM - Request WNM operation * diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index e55e6cd2b..b52e8baba 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -67,6 +67,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(DRIVER_CLIENT_POLL_OK); E2S(EAPOL_TX_STATUS); E2S(CH_SWITCH); + E2S(CH_SWITCH_STARTED); E2S(WNM); E2S(CONNECT_FAILED_REASON); E2S(DFS_RADAR_DETECTED); diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index ee7b4da38..7abbafcd8 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -534,7 +534,8 @@ 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) + struct nlattr *cf1, struct nlattr *cf2, + int finished) { struct i802_bss *bss; union wpa_event_data data; @@ -542,7 +543,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, int chan_offset = 0; int ifidx; - wpa_printf(MSG_DEBUG, "nl80211: Channel switch event"); + wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event", + finished ? "" : " started"); if (!freq) return; @@ -596,7 +598,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, bss->freq = data.ch_switch.freq; drv->assoc_freq = data.ch_switch.freq; - wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data); + wpa_supplicant_event(bss->ctx, finished ? + EVENT_CH_SWITCH : EVENT_CH_SWITCH_STARTED, &data); } @@ -2508,6 +2511,16 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_PMK], tb[NL80211_ATTR_PMKID]); break; + case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: + mlme_event_ch_switch(drv, + tb[NL80211_ATTR_IFINDEX], + tb[NL80211_ATTR_WIPHY_FREQ], + tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], + tb[NL80211_ATTR_CHANNEL_WIDTH], + tb[NL80211_ATTR_CENTER_FREQ1], + tb[NL80211_ATTR_CENTER_FREQ2], + 0); + break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, tb[NL80211_ATTR_IFINDEX], @@ -2515,7 +2528,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], - tb[NL80211_ATTR_CENTER_FREQ2]); + tb[NL80211_ATTR_CENTER_FREQ2], + 1); break; case NL80211_CMD_DISCONNECT: mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 4e1916942..7a3ec3067 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1387,7 +1387,7 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos) void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, - int offset, int width, int cf1, int cf2) + int offset, int width, int cf1, int cf2, int finished) { struct hostapd_iface *iface = wpa_s->ap_iface; @@ -1399,7 +1399,7 @@ void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, if (wpa_s->current_ssid) wpa_s->current_ssid->frequency = freq; hostapd_event_ch_switch(iface->bss[0], freq, ht, - offset, width, cf1, cf2); + offset, width, cf1, cf2, finished); } diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 447b55186..6c6e94cdf 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -54,7 +54,7 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings); int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr); void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, - int offset, int width, int cf1, int cf2); + int offset, int width, int cf1, int cf2, int finished); struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef); #ifdef CONFIG_AP diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 3ff8ba92d..cab0a6d9a 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -4462,18 +4462,24 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.wds); break; #endif /* CONFIG_AP */ + + case EVENT_CH_SWITCH_STARTED: case EVENT_CH_SWITCH: if (!data || !wpa_s->current_ssid) break; - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH - "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d", + wpa_msg(wpa_s, MSG_INFO, + "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d", + event == EVENT_CH_SWITCH ? WPA_EVENT_CHANNEL_SWITCH : + WPA_EVENT_CHANNEL_SWITCH_STARTED, data->ch_switch.freq, 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_CH_SWITCH_STARTED) + break; wpa_s->assoc_freq = data->ch_switch.freq; wpa_s->current_ssid->frequency = data->ch_switch.freq; @@ -4489,7 +4495,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.ch_offset, data->ch_switch.ch_width, data->ch_switch.cf1, - data->ch_switch.cf2); + data->ch_switch.cf2, + 1); } #endif /* CONFIG_AP */