DFS offload: Add main DFS handler for offloaded case

Add handling logic for DFS offloaded case, and add a helper function
that takes the frequency (MHz) as a param and returns 1 if given channel
requires DFS, or 0 otherwise.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Ahmad Kholaif 2015-03-04 17:24:36 -08:00 committed by Jouni Malinen
parent 5de81d7a7a
commit c13578c339
6 changed files with 109 additions and 1 deletions

View file

@ -1,7 +1,7 @@
/*
* DFS - Dynamic Frequency Selection
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
* Copyright (c) 2013, Qualcomm Atheros, Inc.
* Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -1012,3 +1012,53 @@ int hostapd_is_dfs_required(struct hostapd_iface *iface)
res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
return res;
}
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
"seg1=%d cac_time=%ds",
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
iface->cac_started = 1;
return 0;
}
/*
* Main DFS handler for offloaded case.
* 2 - continue channel/AP setup for non-DFS channel
* 1 - continue channel/AP setup for DFS channel
* 0 - channel/AP setup will be continued after CAC
* -1 - hit critical error
*/
int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
__func__, iface->cac_started);
/*
* If DFS has already been started, then we are being called from a
* callback to continue AP/channel setup. Reset the CAC start flag and
* return.
*/
if (iface->cac_started) {
wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
__func__, iface->cac_started);
iface->cac_started = 0;
return 1;
}
if (ieee80211_is_dfs(iface->freq)) {
wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
__func__, iface->freq);
return 0;
}
wpa_printf(MSG_DEBUG,
"%s: freq %d MHz does not require DFS. Continue channel/AP setup",
__func__, iface->freq);
return 2;
}

View file

@ -22,5 +22,9 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
#endif /* DFS_H */

View file

@ -1032,6 +1032,16 @@ static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
radar->cf1, radar->cf2);
}
static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
#endif /* NEED_AP_MLME */
@ -1207,6 +1217,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
hostapd_channel_list_updated(
hapd->iface, data->channel_list_changed.initiator);
break;
case EVENT_DFS_CAC_STARTED:
if (!data)
break;
hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
break;
#endif /* NEED_AP_MLME */
case EVENT_INTERFACE_ENABLED:
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);

View file

@ -1377,6 +1377,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
size_t j;
u8 *prev_addr;
int delay_apply_cfg = 0;
int res_dfs_offload = 0;
if (err)
goto fail;
@ -1403,6 +1404,23 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
goto fail;
return res;
}
} else {
/* If DFS is offloaded to the driver */
res_dfs_offload = hostapd_handle_dfs_offload(iface);
if (res_dfs_offload <= 0) {
if (res_dfs_offload < 0)
goto fail;
} else {
wpa_printf(MSG_DEBUG,
"Proceed with AP/channel setup");
/*
* If this is a DFS channel, move to completing
* AP setup.
*/
if (res_dfs_offload == 1)
goto dfs_offload;
/* Otherwise fall through. */
}
}
#endif /* NEED_AP_MLME */
@ -1497,6 +1515,19 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
goto fail;
}
if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
!res_dfs_offload) {
/*
* If freq is DFS, and DFS is offloaded to the driver, then wait
* for CAC to complete.
*/
wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
return res_dfs_offload;
}
#ifdef NEED_AP_MLME
dfs_offload:
#endif /* NEED_AP_MLME */
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)

View file

@ -826,6 +826,13 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
}
int ieee80211_is_dfs(int freq)
{
/* TODO: this could be more accurate to better cover all domains */
return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
}
static int is_11b(u8 rate)
{
return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;

View file

@ -108,6 +108,7 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
int ieee80211_is_dfs(int freq);
int supp_rates_11b_only(struct ieee802_11_elems *elems);