the callbacks are a copy of the 'channel_switch' callback as they essentially need the same data Signed-off-by: Omer Dagan <omer.dagan@xxxxxxxxxxx> --- src/ap/drv_callbacks.c | 84 ++++++++++++++++++++++++++++++ src/drivers/driver_nl80211_event.c | 67 ++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index cf01854e1..97620e2ba 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -738,6 +738,90 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, } +void hostapd_event_ch_switch_started(struct hostapd_data *hapd, int freq, int ht, + int offset, int width, int cf1, int cf2) +{ + /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */ + +#ifdef NEED_AP_MLME + int channel, chwidth, is_dfs; + u8 seg0_idx = 0, seg1_idx = 0; + size_t i; + + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "driver starting channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", + freq, ht, hapd->iconf->ch_switch_vht_config, offset, + width, channel_width_to_string(width), cf1, cf2); + + hapd->iface->freq = freq; + + channel = hostapd_hw_get_channel(hapd, freq); + if (!channel) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "driver switched to bad channel!"); + } + + switch (width) { + case CHAN_WIDTH_80: + chwidth = VHT_CHANWIDTH_80MHZ; + break; + case CHAN_WIDTH_80P80: + chwidth = VHT_CHANWIDTH_80P80MHZ; + break; + case CHAN_WIDTH_160: + chwidth = VHT_CHANWIDTH_160MHZ; + break; + case CHAN_WIDTH_20_NOHT: + case CHAN_WIDTH_20: + case CHAN_WIDTH_40: + default: + chwidth = VHT_CHANWIDTH_USE_HT; + break; + } + + switch (hapd->iface->current_mode->mode) { + case HOSTAPD_MODE_IEEE80211A: + if (cf1 > 5000) + seg0_idx = (cf1 - 5000) / 5; + if (cf2 > 5000) + seg1_idx = (cf2 - 5000) / 5; + break; + default: + ieee80211_freq_to_chan(cf1, &seg0_idx); + ieee80211_freq_to_chan(cf2, &seg1_idx); + break; + } + + hapd->iconf->channel = channel; + hapd->iconf->ieee80211n = ht; + if (!ht) { + hapd->iconf->ieee80211ac = 0; + } else if (hapd->iconf->ch_switch_vht_config) { + /* CHAN_SWITCH VHT config */ + if (hapd->iconf->ch_switch_vht_config & + CH_SWITCH_VHT_ENABLED) + hapd->iconf->ieee80211ac = 1; + else if (hapd->iconf->ch_switch_vht_config & + CH_SWITCH_VHT_DISABLED) + hapd->iconf->ieee80211ac = 0; + } + hapd->iconf->ch_switch_vht_config = 0; + + hapd->iconf->secondary_channel = offset; + hapd->iconf->vht_oper_chwidth = chwidth; + hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; + hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; + + is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features, + hapd->iface->num_hw_features); + + wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH_STARTED + "freq=%d dfs=%d", freq, is_dfs); + +#endif /* NEED_AP_MLME */ +} void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, int offset, int width, int cf1, int cf2) { diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index ffddd94d2..caae814f1 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -528,6 +528,73 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1; } +static void mlme_event_ch_switch_started(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 i802_bss *bss; + union wpa_event_data data; + int ht_enabled = 1; + int chan_offset = 0; + int ifidx; + + wpa_printf(MSG_DEBUG, "nl80211: Channel switch started event"); + + if (!freq) + return; + + ifidx = nla_get_u32(ifindex); + bss = get_bss_ifindex(drv, ifidx); + if (bss == NULL) { + wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch started, ignoring", + ifidx); + return; + } + + if (type) { + enum nl80211_channel_type ch_type = nla_get_u32(type); + + wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type); + switch (ch_type) { + case NL80211_CHAN_NO_HT: + ht_enabled = 0; + break; + case NL80211_CHAN_HT20: + break; + case NL80211_CHAN_HT40PLUS: + chan_offset = 1; + break; + case NL80211_CHAN_HT40MINUS: + chan_offset = -1; + break; + } + } else if (bw && cf1) { + /* This can happen for example with VHT80 ch switch */ + chan_offset = calculate_chan_offset(nla_get_u32(bw), + nla_get_u32(freq), + nla_get_u32(cf1), + cf2 ? nla_get_u32(cf2) : 0); + } else { + wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail"); + } + + os_memset(&data, 0, sizeof(data)); + data.ch_switch.freq = nla_get_u32(freq); + data.ch_switch.ht_enabled = ht_enabled; + data.ch_switch.ch_offset = chan_offset; + if (bw) + data.ch_switch.ch_width = convert2width(nla_get_u32(bw)); + if (cf1) + data.ch_switch.cf1 = nla_get_u32(cf1); + if (cf2) + data.ch_switch.cf2 = nla_get_u32(cf2); + + bss->freq = data.ch_switch.freq; + drv->assoc_freq = data.ch_switch.freq; + + wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH_STARTED, &data); +} static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, struct nlattr *ifindex, struct nlattr *freq, -- 2.17.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap