int ap_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings) { #ifdef NEED_AP_MLME if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) return -1; return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings); #else /* NEED_AP_MLME */ return -1; #endif /* NEED_AP_MLME */ }
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; int secondary_channel; u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; int skip_radar = 1; struct csa_settings csa_settings; unsigned int i; int err = 1; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", hostapd_csa_in_progress(iface) ? "yes" : "no"); /* Check if CSA in progress */ if (hostapd_csa_in_progress(iface)) return 0; /* Check if active CAC */ if (iface->cac_started) return hostapd_dfs_start_channel_switch_cac(iface); /* Perform channel switch/CSA */ channel = dfs_get_valid_channel(iface, &secondary_channel, &vht_oper_centr_freq_seg0_idx, &vht_oper_centr_freq_seg1_idx, skip_radar); if (!channel) { /* * If there is no channel to switch immediately to, check if * there is another channel where we can switch even if it * requires to perform a CAC first. */ skip_radar = 0; channel = dfs_get_valid_channel(iface, &secondary_channel, &vht_oper_centr_freq_seg0_idx, &vht_oper_centr_freq_seg1_idx, skip_radar); if (!channel) { wpa_printf(MSG_INFO, "%s: no DFS channels left, waiting for NOP to finish", __func__); return err; } iface->freq = channel->freq; iface->conf->channel = channel->chan; iface->conf->secondary_channel = secondary_channel; iface->conf->vht_oper_centr_freq_seg0_idx = vht_oper_centr_freq_seg0_idx; iface->conf->vht_oper_centr_freq_seg1_idx = vht_oper_centr_freq_seg1_idx; hostapd_disable_iface(iface); hostapd_enable_iface(iface); return 0; } wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel->chan); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL "freq=%d chan=%d sec_chan=%d", channel->freq, channel->chan, secondary_channel); /* Setup CSA request */ os_memset(&csa_settings, 0, sizeof(csa_settings)); csa_settings.cs_count = 5; csa_settings.block_tx = 1; err = hostapd_set_freq_params(&csa_settings.freq_params, iface->conf->hw_mode, channel->freq, channel->chan, iface->conf->ieee80211n, iface->conf->ieee80211ac, secondary_channel, iface->conf->vht_oper_chwidth, vht_oper_centr_freq_seg0_idx, vht_oper_centr_freq_seg1_idx, iface->current_mode->vht_capab, iface->conf->bwmode); if (err) { wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); hostapd_disable_iface(iface); return err; } for (i = 0; i < iface->num_bss; i++) { err = hostapd_switch_channel(iface->bss[i], &csa_settings); if (err) break; } if (err) { wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", err); iface->freq = channel->freq; iface->conf->channel = channel->chan; iface->conf->secondary_channel = secondary_channel; iface->conf->vht_oper_centr_freq_seg0_idx = vht_oper_centr_freq_seg0_idx; iface->conf->vht_oper_centr_freq_seg1_idx = vht_oper_centr_freq_seg1_idx; hostapd_disable_iface(iface); hostapd_enable_iface(iface); return 0; } /* Channel configuration will be updated once CSA completes and * ch_switch_notify event is received */ wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); return 0; }