@@ -812,7 +812,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int channel, int ht_enabled, int vht_enabled,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
- int center_segment0, int center_segment1)
+ int center_segment0, int center_segment1,
+ int radar_background)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
@@ -838,10 +839,14 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
+ data.radar_background = radar_background;
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res) {
- iface->cac_started = 1;
+ if (radar_background)
+ iface->radar_background.cac_started = 1;
+ else
+ iface->cac_started = 1;
os_get_reltime(&iface->dfs_cac_start);
}
@@ -130,7 +130,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int channel, int ht_enabled, int vht_enabled,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
- int center_segment0, int center_segment1);
+ int center_segment0, int center_segment1,
+ int radar_background);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
@@ -860,7 +860,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
/* Finally start CAC */
hostapd_set_state(iface, HAPD_IFACE_DFS);
- wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz background %d",
+ iface->freq,
+ !!(iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND));
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
@@ -877,13 +879,37 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
iface->conf->secondary_channel,
hostapd_get_oper_chwidth(iface->conf),
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
- hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
+ !!(iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
return -1;
}
+ if (iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) {
+ /* Cache background radar parameters */
+ iface->radar_background.channel = iface->conf->channel;
+ iface->radar_background.secondary_channel =
+ iface->conf->secondary_channel;
+ iface->radar_background.freq = iface->freq;
+ iface->radar_background.centr_freq_seg0_idx =
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+ iface->radar_background.centr_freq_seg1_idx =
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
+
+ /*
+ * Let's select a random channel according to the
+ * regulations and perform CAC on dedicated radar chain
+ */
+ res = dfs_set_valid_channel(iface, 1);
+ if (res < 0)
+ return res;
+
+ iface->radar_background.temp_ch = 1;
+ return 1;
+ }
+
return 0;
}
@@ -905,6 +931,88 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
}
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx, int *channel_type);
+
+static void
+hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
+{
+ int sec = 0, channel_type = DFS_NO_CAC_YET;
+ struct hostapd_channel_data *channel;
+ u8 oper_centr_freq_seg0_idx = 0;
+ u8 oper_centr_freq_seg1_idx = 0;
+
+ /*
+ * Allow selection of DFS channel in ETSI to comply with
+ * uniform spreading.
+ */
+ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
+ channel_type = DFS_ANY_CHANNEL;
+
+ channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx, channel_type);
+ if (!channel ||
+ channel->chan == iface->conf->channel ||
+ channel->chan == iface->radar_background.channel)
+ channel = dfs_downgrade_bandwidth(iface, &sec,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &channel_type);
+ if (!channel ||
+ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ channel->freq, channel->chan,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ sec, hostapd_get_oper_chwidth(iface->conf),
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx, 1)) {
+ wpa_printf(MSG_ERROR, "DFS failed start CAC offchannel");
+ iface->radar_background.channel = -1;
+ return;
+ }
+
+ iface->radar_background.channel = channel->chan;
+ iface->radar_background.freq = channel->freq;
+ iface->radar_background.secondary_channel = sec;
+ iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+ iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+
+ wpa_printf(MSG_DEBUG,
+ "%s: setting background chain to chan %d (%d MHz)",
+ __func__, channel->chan, channel->freq);
+}
+
+static int
+hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
+{
+ if (iface->radar_background.channel == -1 ||
+ iface->radar_background.freq != freq)
+ return 0;
+ return 1;
+}
+
+static int
+hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
+{
+ iface->conf->channel = iface->radar_background.channel;
+ iface->freq = iface->radar_background.freq;
+ iface->conf->secondary_channel =
+ iface->radar_background.secondary_channel;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ iface->radar_background.centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ iface->radar_background.centr_freq_seg1_idx);
+
+ hostpad_dfs_update_background_chain(iface);
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+
+ return 0;
+}
+
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
@@ -925,6 +1033,23 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
set_dfs_state(iface, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_AVAILABLE);
+
+ /*
+ * radar event from background chain for selected
+ * channel. Perfrom CSA, move main chain to selected
+ * channel and configure background chain to a new DFS
+ * channel
+ */
+ if ((iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) &&
+ hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 0;
+ if (!iface->radar_background.temp_ch)
+ return 0;
+
+ iface->radar_background.temp_ch = 0;
+ return hostapd_dfs_start_channel_switch_background(iface);
+ }
+
/*
* Just mark the channel available when CAC completion
* event is received in enabled state. CAC result could
@@ -941,6 +1066,10 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
iface->cac_started = 0;
}
}
+ } else if ((iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) &&
+ hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 0;
+ hostpad_dfs_update_background_chain(iface);
}
return 0;
@@ -1248,9 +1377,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
- /* Handle cases where all channels were initially unavailable */
- if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
+ /* Handle cases where all channels were initially unavailable */
hostapd_handle_dfs(iface);
+ } else if ((iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) &&
+ iface->radar_background.channel == -1) {
+ /* Reset radar background chanin if disabled */
+ hostpad_dfs_update_background_chain(iface);
+ }
return 0;
}
@@ -1288,17 +1422,24 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
- /* This is called when the driver indicates that an offloaded DFS has
- * started CAC. */
- hostapd_set_state(iface, HAPD_IFACE_DFS);
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 1;
+ } else {
+ /* This is called when the driver indicates that
+ * an offloaded DFS has started CAC.
+ */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ iface->cac_started = 1;
+ }
/* TODO: How to check CAC time for ETSI weather channels? */
iface->dfs_cac_ms = 60000;
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",
+ "seg1=%d cac_time=%ds background event %d",
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
- iface->dfs_cac_ms / 1000);
- iface->cac_started = 1;
+ iface->dfs_cac_ms / 1000,
+ !!hostapd_dfs_is_background_event(iface, freq));
+
os_get_reltime(&iface->dfs_cac_start);
return 0;
}
@@ -520,6 +520,21 @@ struct hostapd_iface {
int *basic_rates;
int freq;
+ /* Background radar configuration */
+ struct {
+ int channel;
+ int secondary_channel;
+ int freq;
+ int centr_freq_seg0_idx;
+ int centr_freq_seg1_idx;
+ /* Main chain is on temporary channel during
+ * CAC detection on radar offchain.
+ */
+ unsigned int temp_ch:1;
+ /* CAC started on radar offchain */
+ unsigned int cac_started:1;
+ } radar_background;
+
u16 hw_flags;
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
@@ -782,6 +782,11 @@ struct hostapd_freq_params {
* for IEEE 802.11ay EDMG configuration.
*/
struct ieee80211_edmg_config edmg;
+
+ /**
+ * radar_background - Whether radar/CAC background is requested
+ */
+ int radar_background;
};
/**
@@ -4912,6 +4912,8 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
+ wpa_printf(MSG_DEBUG, " * radar_background=%d",
+ freq->radar_background);
hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
@@ -4989,6 +4991,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
NL80211_CHAN_NO_HT))
return -ENOBUFS;
}
+ if (freq->radar_background)
+ nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND);
+
return 0;
}