2012-01-26 12:42:17

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 0/7] hostap: add DFS master ability

This patch set (with nl/cfg/mac80211 patch series) adds support for DFS (Dynamic Frequency Selection) according 802.11h.


Main idea
===================

DFS master algorithm is implemented in the hostapd, while nl/cfg/mac80211 will pipe relevant commands/events to the driver/hostapd.

Based on the assumption that the device/driver supports radar interference detection i.e., it is capable to generate radar_detected event by using different pattern detection techniques:


1. Pattern detection in the HW: the device generates 'radar_detected' event.
2. Pattern detection in the driver: the driver receives radar pulses from the device and generates 'radar detected' event.


Main DFS procedures
===================

1. Hostapd gets driver's dfs capabilities.

2. If 80211h is enabled in the hostapd.conf and the driver supports one of the above radar detection techniques, hostapd may use DFS channels.

3. Hostapd selects an operational channel (default from hostapd.conf), if selected channel is a DFS channel, hostapd sends start_radar_detection command to the device/driver which starts monitoring for radar interference while hostapd sets a timer for a CAC (Channel Availability Check) time, which is 60 seconds.

4. As CAC timer expires and no radar has been detected, hostapd may continue with the init flow, otherwise if interference is detected hostapd selects another channel (random selection) and repeats the CAC on the new channel (in case the new channel is also a DFS channel), while the original channel is added to a "black list" for a period of ''No-Occupancy'' time (time that the channel can't be used/selected).

5. While using the channel the device/driver continuously monitors for potential radar interference. If interference is detected hostapd notified with 'radar detected' event, which selects a new channel and triggers a channel switch procedure, if the new channel is also a DFS channel, hostapd performs the CAC test, once it's successfully passed hostapd instructs the driver to initiate the transmission on the channel.


Victor Goldenshtein (7):
hostapd: implement dfs drv ops functions
hostapd: add channel switch ability
hostapd: add dfs events
hostapd: add dfs support into interface init flow
nl80211: add support to enable TX on oper-channel
nl80211: add channel switch command/event
nl80211: add start radar detection command/event

hostapd/config_file.c | 10 +++
src/ap/ap_config.h | 4 +
src/ap/ap_drv_ops.c | 34 +++++++++
src/ap/ap_drv_ops.h | 4 +
src/ap/beacon.c | 16 ++++
src/ap/drv_callbacks.c | 40 +++++++++++
src/ap/hostapd.c | 158 ++++++++++++++++++++++++++++++++++++++++--
src/ap/hostapd.h | 10 +++
src/ap/hw_features.c | 48 ++++++++++---
src/ap/hw_features.h | 10 +++
src/ap/ieee802_11.c | 116 +++++++++++++++++++++++++++++++
src/ap/ieee802_11.h | 4 +
src/drivers/driver.h | 87 +++++++++++++++++++++++-
src/drivers/driver_common.c | 2 +
src/drivers/driver_nl80211.c | 125 +++++++++++++++++++++++++++++++++
src/utils/eloop.c | 4 +
src/utils/eloop.h | 7 ++
17 files changed, 662 insertions(+), 17 deletions(-)

--
1.7.5.4



2012-01-26 12:42:50

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 6/7] nl80211: add channel switch command/event

Implement channel switch command and handle
channel switch complete event.

Signed-off-by: Boris Presman <[email protected]>
Signed-off-by: Victor Goldenshtein <[email protected]>
---
src/drivers/driver_nl80211.c | 54 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e3d6a3c..744e736 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2026,6 +2026,8 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
int cmd, struct nlattr **tb)
{
+ union wpa_event_data data;
+
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2132,6 +2134,17 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
case NL80211_CMD_PROBE_CLIENT:
nl80211_client_probe_event(drv, tb);
break;
+ case NL80211_CMD_AP_CHANNEL_SWITCH:
+ os_memset(&data, 0, sizeof(data));
+ if (tb[NL80211_ATTR_WIPHY_FREQ]) {
+ data.channel_switch_complete.freq =
+ nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+ }
+ data.channel_switch_complete.status = TRUE;
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch complete event");
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_SWITCH_COMPLETE,
+ &data);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -8653,6 +8666,46 @@ nla_put_failure:
}


+static int wpa_driver_nl80211_channel_switch(void *priv,
+ struct hostapd_channel_switch *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch, "
+ "ch_switch_count = %d, tx_block = %d, "
+ "freq = %d, post_switch_block_tx = %d.",
+ params->ch_switch_count, params->tx_block,
+ params->freq, params->post_switch_block_tx);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_AP_CHANNEL_SWITCH);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, params->ch_switch_count);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+
+ if (params->tx_block)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+
+ if (params->post_switch_block_tx)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_POST_BLOCK_TX);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to channel switch: "
+ "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+ return -1;
+}
+
+
#ifdef CONFIG_TDLS

static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -8947,6 +9000,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.poll_client = nl80211_poll_client,
.set_p2p_powersave = nl80211_set_p2p_powersave,
.enable_tx = wpa_driver_nl80211_enable_dfs_tx,
+ .channel_switch = wpa_driver_nl80211_channel_switch,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
--
1.7.5.4


2012-01-26 13:36:30

by Victor Goldenshtein

[permalink] [raw]
Subject: Re: [RFC 4/7] hostapd: add dfs support into interface init flow

On Thu, Jan 26, 2012 at 3:10 PM, Felix Fietkau <[email protected]> wrote:
>> +
>> + ? ? ? ? ? ? eloop_enable();
>> + ? ? ? ? ? ? wpa_printf(MSG_DEBUG, "Continuing with init flow");
>> ? ? ? }
>>
>> ? ? ? if (iface->current_mode) {
> This seems like a bit of a hack to me. Wouldn't it be better to prevent
> eloop_terminate() from being called instead of adding another function
> to override the eloop termination?

Couldn't find a cleaner way to do it, I mean without the usage of the
eloop_run() + eloop_terminate().
We need to check a DFS channel prior starting the tx, i.e. - listen
for radar event during the initialization flow, prior the
hostapd_global_run(), I would gladly hear other ideas for this
implementation.


--
Thanks,
Victor.

2012-01-26 12:42:29

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 2/7] hostapd: add channel switch ability

Add channel switch command and handle channel switch
complete event.

New hostapd_eid_csa() which builds the channel switch
announcement, add CSA logic into ieee802_11_set_beacon().

Set WLAN_CAPABILITY_SPECTRUM_MGMT bit in the capability
information field in beacon frames and probe response
frames.

Signed-off-by: Boris Presman <[email protected]>
Signed-off-by: Victor Goldenshtein <[email protected]>
---
hostapd/config_file.c | 10 ++++
src/ap/ap_config.h | 1 +
src/ap/beacon.c | 16 ++++++
src/ap/hostapd.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++
src/ap/hostapd.h | 10 ++++
src/ap/hw_features.c | 18 ++++++
src/ap/hw_features.h | 1 +
src/ap/ieee802_11.c | 116 ++++++++++++++++++++++++++++++++++++++++
src/ap/ieee802_11.h | 4 ++
src/drivers/driver.h | 26 +++++++++
10 files changed, 343 insertions(+), 0 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 467d39f..5d412e0 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1141,6 +1141,12 @@ static int hostapd_config_check(struct hostapd_config *conf)
return -1;
}

+ if (conf->ieee80211h && (!conf->ieee80211d)) {
+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+ "IEEE 802.11d enabled");
+ return -1;
+ }
+
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(&conf->bss[i], conf))
return -1;
@@ -1342,6 +1348,10 @@ struct hostapd_config * hostapd_config_read(const char *fname)
conf->country[2] = ' ';
} else if (os_strcmp(buf, "ieee80211d") == 0) {
conf->ieee80211d = atoi(pos);
+ } else if (os_strcmp(buf, "ieee80211h") == 0) {
+ conf->ieee80211h = atoi(pos);
+ } else if (os_strcmp(buf, "channel_switch_count") == 0) {
+ conf->channel_switch_count = atoi(pos);
} else if (os_strcmp(buf, "ieee8021x") == 0) {
bss->ieee802_1x = atoi(pos);
} else if (os_strcmp(buf, "eapol_version") == 0) {
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index eddc9b7..f635347 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -412,6 +412,7 @@ struct hostapd_config {

/* DFS */
int channel_switch_count;
+ int ieee80211h;

struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];

diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4ea8684..714f89d 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -171,6 +171,19 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
return pos;
}

+static u8 *hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
+{
+ if (!(hapd->iconf->ieee80211h) || !(hapd->next_channel))
+ return eid;
+
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3; /* IE length */
+ *eid++ = 1; /* STAs should cease transmit */
+ *eid++ = (u8)hapd->next_channel->chan;
+ *eid++ = (u8)hapd->iconf->channel_switch_count;
+ return eid;
+}
+

static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
{
@@ -567,6 +580,9 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_country(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);

+ /* Channel Switch Announcement */
+ tailpos = hostapd_eid_csa(hapd, tailpos);
+
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 0c5ee2e..ce37922 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -944,3 +944,144 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
}
+
+struct hostapd_channel_data *hostapd_dfs_get_valid_channel(struct hostapd_data
+ *hapd)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+ int i, channel_idx = 0, new_channel_idx;
+ struct os_time now;
+ u32 rand;
+
+ wpa_printf(MSG_DEBUG, "Selecting next channel");
+
+ if (hapd->iface->current_mode == NULL)
+ return NULL;
+
+ mode = hapd->iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return NULL;
+
+ os_get_time(&now);
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ /*
+ * Reactivate the disabled channels after
+ * Non-Occupancy Period.
+ */
+ if (chan->flag & HOSTAPD_CHAN_RADAR_DETECTED) {
+ if ((chan->last_radar_detection.sec +
+ DFS_MIN_NON_OCC_TIME_SEC) < now.sec) {
+ wpa_printf(MSG_DEBUG, "Activating channel %d.",
+ chan->chan);
+ chan->flag &= ~HOSTAPD_CHAN_RADAR_DETECTED;
+ chan->last_radar_detection.sec = 0;
+ chan->last_radar_detection.usec = 0;
+ } else
+ continue;
+ }
+ channel_idx++;
+ }
+
+ os_get_random((u8 *)&rand, sizeof(rand));
+ new_channel_idx = rand % channel_idx;
+
+ for (i = 0, channel_idx = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR_DETECTED))
+ continue;
+ if (channel_idx == new_channel_idx) {
+ wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+ return chan;
+ }
+ channel_idx++;
+ }
+
+ return NULL;
+}
+
+void hostapd_resume_dfs_cac(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "Resuming DFS channel availability check");
+
+ /*
+ * We get here after successful CAC (channel availability check) during:
+ * 1. Initialization: in this case we continue with the init flow.
+ * 2. Operational mode: system switched to a DFS channel (probably due
+ * to radar event), which requires to perform a CAC prior enabling the
+ * tx on the new channel.
+ */
+
+ if (hapd->iface->dfs_state & DFS_INIT_PHASE_CAC) {
+ eloop_terminate();
+ hapd->iface->dfs_state &= ~DFS_INIT_PHASE_CAC;
+ }
+
+ /* Enable TX on operational channel */
+ hostapd_enable_tx(hapd);
+}
+
+int hostapd_check_set_freq(struct hostapd_data *hapd)
+{
+ int flag;
+
+ wpa_printf(MSG_DEBUG, "Check and set freq %d, channel %d",
+ hapd->iface->freq, hapd->iconf->channel);
+
+ flag = hostapd_get_channel_flag(hapd, hapd->iconf->channel);
+
+ if ((flag & HOSTAPD_CHAN_RADAR) &&
+ !(hapd->iface->dfs_state & DFS_ENABLED)) {
+ wpa_printf(MSG_ERROR, "Can't set DFS frequency, "
+ "DFS functionality is not enabled/supported");
+ return -1;
+ }
+
+ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode,
+ hapd->iface->freq,
+ hapd->iconf->channel,
+ hapd->iconf->ieee80211n,
+ hapd->iconf->secondary_channel)) {
+ wpa_printf(MSG_ERROR, "Could not set channel for "
+ "kernel driver");
+ return -1;
+ }
+
+ if (flag & HOSTAPD_CHAN_RADAR) {
+ if (hostapd_start_radar_detection(hapd)) {
+ wpa_printf(MSG_ERROR, "Could not start "
+ "radar detection for kernel driver");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "CAC, listen %d seconds for radar "
+ "interference", DFS_MIN_CAC_TIME_SEC);
+
+ eloop_register_timeout(DFS_MIN_CAC_TIME_SEC, 0,
+ hostapd_resume_dfs_cac, hapd, NULL);
+
+ /*
+ * Listen for radar interference for CAC period, eloop_run()
+ * will be terminated after CAC timeout.
+ */
+ if (!(hapd->iface->dfs_state & DFS_INIT_PHASE_CAC)) {
+ hapd->iface->dfs_state |= DFS_INIT_PHASE_CAC;
+ eloop_run();
+ }
+
+ } else if (hapd->iface->dfs_state & DFS_INIT_PHASE_CAC) {
+ wpa_printf(MSG_DEBUG, "moved to non-DFS channel");
+ hapd->iface->dfs_state &= ~DFS_INIT_PHASE_CAC;
+ hostapd_enable_tx(hapd);
+ eloop_terminate();
+ }
+ return 0;
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index c6f6205..c506a69 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -155,6 +155,8 @@ struct hostapd_data {
void (*setup_complete_cb)(void *ctx);
void *setup_complete_cb_ctx;

+ struct hostapd_channel_data *next_channel;
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -236,6 +238,10 @@ struct hostapd_iface {
int olbc_ht;

u16 ht_op_mode;
+
+ /* dfs states */
+ u8 dfs_state;
+
void (*scan_cb)(struct hostapd_iface *iface);

int (*ctrl_iface_init)(struct hostapd_data *hapd);
@@ -258,6 +264,8 @@ void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
+struct hostapd_channel_data *hostapd_dfs_get_valid_channel(struct hostapd_data
+ *hapd);

/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@@ -274,5 +282,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
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);
+void hostapd_resume_dfs_cac(void *eloop_ctx, void *timeout_ctx);
+int hostapd_check_set_freq(struct hostapd_data *hapd);

#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8c6fef2..d64fbeb 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -751,3 +751,21 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)

return 0;
}
+
+
+int hostapd_get_channel_flag(struct hostapd_data *hapd, int chan)
+{
+ int i;
+
+ if (!hapd->iface->current_mode)
+ return 0;
+
+ for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+ struct hostapd_channel_data *ch =
+ &hapd->iface->current_mode->channels[i];
+ if (ch->chan == chan)
+ return ch->flag;
+ }
+
+ return 0;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index abadcd1..c8a7f60 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -28,6 +28,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
+int hostapd_get_channel_flag(struct hostapd_data *hapd, int chan);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index a1a7270..55245d0 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -159,6 +159,9 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
hapd->iface->num_sta_no_short_slot_time == 0)
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;

+ if (hapd->iconf->ieee80211h)
+ capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
return capab;
}

@@ -1850,4 +1853,117 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}


+int ieee802_11_radar_detected(struct hostapd_data *hapd)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan = NULL;
+ struct os_time now;
+ int i;
+
+ eloop_cancel_timeout(hostapd_resume_dfs_cac, hapd, NULL);
+
+ if (hapd->iface->current_mode == NULL)
+ return 0;
+
+ mode = hapd->iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
+ wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
+ return 0;
+ }
+
+ for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+ chan = &hapd->iface->current_mode->channels[i];
+ if (chan->freq == hapd->iface->freq) {
+ if (chan->flag & HOSTAPD_CHAN_RADAR) {
+ chan->flag |= HOSTAPD_CHAN_RADAR_DETECTED;
+ os_get_time(&now);
+ chan->last_radar_detection.sec = now.sec;
+ wpa_printf(MSG_DEBUG, "Disabling channel %d, "
+ "for %d seconds", chan->chan,
+ DFS_MIN_NON_OCC_TIME_SEC);
+ return 1; /* Channel found */
+ }
+ }
+ }
+ wpa_printf(MSG_WARNING, "Should'n get a radar event on "
+ "the current freq (%d)", hapd->iface->freq);
+ return 0;
+}
+
+int ieee802_11_start_channel_switch(struct hostapd_data *hapd,
+ u8 radar_detected)
+{
+ struct hostapd_channel_data *next_channel;
+
+ next_channel = hostapd_dfs_get_valid_channel(hapd);
+
+ if (!next_channel)
+ return -1;
+
+ if (!(hapd->iface->dfs_state & DFS_INIT_PHASE_CAC)) {
+ hapd->next_channel = next_channel;
+ u8 radar_on_next_channel =
+ (next_channel->flag & HOSTAPD_CHAN_RADAR) ? 1 : 0;
+ wpa_printf(MSG_DEBUG, "switching to %sch. #%d, freq %d",
+ radar_on_next_channel ? "(DFS) " : "",
+ next_channel->chan, next_channel->freq);
+
+ /* Add CSA */
+ ieee802_11_set_beacon(hapd);
+
+ if (hostapd_channel_switch(hapd, next_channel->chan,
+ next_channel->freq, radar_detected,
+ radar_on_next_channel)) {
+ wpa_printf(MSG_ERROR, "Channel switch failed");
+ return -1;
+ }
+ } else {
+ hapd->iconf->channel = next_channel->chan;
+ hapd->iface->freq = next_channel->freq;
+
+ if (hostapd_check_set_freq(hapd)) {
+ wpa_printf(MSG_ERROR, "Couldn't check/set freq, "
+ "terminating");
+ eloop_terminate();
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int ieee802_11_complete_channel_switch(struct hostapd_data *hapd)
+{
+
+ wpa_printf(MSG_DEBUG, "Completing channel switch");
+
+ if (hapd->next_channel == NULL) {
+ wpa_printf(MSG_WARNING, "next_channel is not defined");
+ return 0;
+ }
+
+ hapd->iconf->channel = (u8)hapd->next_channel->chan;
+ hapd->iface->freq = hapd->next_channel->freq;
+
+ if (hapd->next_channel->flag & HOSTAPD_CHAN_RADAR) {
+ eloop_register_timeout(DFS_MIN_CAC_TIME_SEC, 0,
+ hostapd_resume_dfs_cac, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "listen %d seconds for radar "
+ "interference prior enabling the tx",
+ DFS_MIN_CAC_TIME_SEC);
+
+ if (hostapd_start_radar_detection(hapd)) {
+ wpa_printf(MSG_ERROR, "Could not start radar "
+ "detection for kernel driver");
+ return -1;
+ }
+ }
+
+ hapd->next_channel = NULL;
+ /* Remove CSA */
+ ieee802_11_set_beacon(hapd);
+
+ return 0;
+}
+
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 43042a5..16a68e1 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -78,5 +78,9 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+int ieee802_11_radar_detected(struct hostapd_data *hapd);
+int ieee802_11_start_channel_switch(struct hostapd_data *hapd,
+ u8 radar_detected);
+int ieee802_11_complete_channel_switch(struct hostapd_data *hapd);

#endif /* IEEE802_11_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 512b4c3..1f2e521 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -34,6 +34,7 @@
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
#define HOSTAPD_CHAN_HT40 0x00000040
+#define HOSTAPD_CHAN_RADAR_DETECTED 0x00000080

/**
* struct hostapd_channel_data - Channel information
@@ -58,6 +59,8 @@ struct hostapd_channel_data {
* max_tx_power - maximum transmit power in dBm
*/
u8 max_tx_power;
+
+ struct os_time last_radar_detection;
};

#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
@@ -964,6 +967,29 @@ struct wpa_signal_info {
int current_txrate;
};

+/*
+ * DFS Channel Availability Check Time - the time a system shall monitor a
+ * 'radar channel' for presence of radar prior to initiating a TX.
+ */
+#define DFS_MIN_CAC_TIME_SEC 60
+
+/*
+ * DFS Non-Occupancy Time - a period of time after radar is detected on a
+ * channel that the channel may not be used.
+ *
+ */
+#define DFS_MIN_NON_OCC_TIME_SEC 1800
+
+/*
+ * DFS functionality is enabled.
+ */
+#define DFS_ENABLED BIT(0)
+
+/*
+ * DFS channel availability check during initialization.
+ */
+#define DFS_INIT_PHASE_CAC BIT(1)
+
/**
* struct wpa_driver_ops - Driver interface API definition
*
--
1.7.5.4


2012-01-26 12:42:39

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 4/7] hostapd: add dfs support into interface init flow

Implement Channel Availability Check (CAC) during initialization
phase. According to DFS requirements the AP should monitor 'radar
channels' for potential radar interference for a minimum CAC time
prior enabling the transmissions.

Add dfs support into hw features, allow the usage of the radar
channels if ieee80211h is enabled in the hostapd.conf and the
driver supports radar detection.

Parse and handle driver's DFS capabilities, userspace applications
must be fully synchronized with device capabilities to detect radar
patterns in the air which may influence userspace behavior.

Signed-off-by: Boris Presman <[email protected]>
Signed-off-by: Victor Goldenshtein <[email protected]>
---
src/ap/hostapd.c | 17 +++++++++++------
src/ap/hw_features.c | 30 ++++++++++++++++++++----------
src/ap/hw_features.h | 9 +++++++++
src/drivers/driver.h | 5 +++++
src/drivers/driver_nl80211.c | 7 +++++++
src/utils/eloop.c | 4 ++++
src/utils/eloop.h | 7 +++++++
7 files changed, 63 insertions(+), 16 deletions(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ce37922..411b681 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -708,6 +708,12 @@ static int setup_interface(struct hostapd_iface *iface)
"be completed in a callback");
return 0;
}
+
+ if (iface->current_mode->dfs_supported &&
+ iface->conf->ieee80211h) {
+ wpa_printf(MSG_DEBUG, "DFS support is enabled");
+ iface->dfs_state |= DFS_ENABLED;
+ }
}
return hostapd_setup_interface_complete(iface, 0);
}
@@ -733,14 +739,13 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_hw_mode_txt(hapd->iconf->hw_mode),
hapd->iconf->channel, iface->freq);

- if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
- hapd->iconf->channel,
- hapd->iconf->ieee80211n,
- hapd->iconf->secondary_channel)) {
- wpa_printf(MSG_ERROR, "Could not set channel for "
- "kernel driver");
+ if (hostapd_check_set_freq(hapd)) {
+ wpa_printf(MSG_ERROR, "Couldn't check/set freq");
return -1;
}
+
+ eloop_enable();
+ wpa_printf(MSG_DEBUG, "Continuing with init flow");
}

if (iface->current_mode) {
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d64fbeb..1804978 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -70,26 +70,36 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)

for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *feature = &modes[i];
+ u8 dfs_enabled = (hapd->iconf->ieee80211h &&
+ feature->dfs_supported);
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
+ u8 dfs = FALSE;
/*
* Disable all channels that are marked not to allow
- * IBSS operation or active scanning. In addition,
- * disable all channels that require radar detection,
- * since that (in addition to full DFS) is not yet
- * supported.
+ * IBSS operation or active scanning.
+ * Use radar channels only if the driver supports
+ * DFS.
*/
- if (feature->channels[j].flag &
- (HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_RADAR))
+ if ((feature->channels[j].flag &
+ HOSTAPD_CHAN_RADAR) && dfs_enabled) {
+ dfs = TRUE;
+ } else if (feature->channels[j].flag &
+ (HOSTAPD_CHAN_NO_IBSS |
+ HOSTAPD_CHAN_PASSIVE_SCAN |
+ HOSTAPD_CHAN_DISABLED)) {
feature->channels[j].flag |=
HOSTAPD_CHAN_DISABLED;
- if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+ }
+
+ if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) {
continue;
- wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
+ }
+
+ wpa_printf(MSG_WARNING, "Allowed %schannel: mode=%d "
"chan=%d freq=%d MHz max_tx_power=%d dBm",
+ dfs ? "(DFS) " : "",
feature->mode,
feature->channels[j].chan,
feature->channels[j].freq,
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index c8a7f60..a8442b5 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -46,6 +46,11 @@ static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
return -100;
}

+static inline int hostapd_select_radar_detector(struct hostapd_iface *iface)
+{
+ return -1;
+}
+
static inline const char * hostapd_hw_mode_txt(int mode)
{
return NULL;
@@ -67,6 +72,10 @@ static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
return 0;
}

+static inline int hostapd_get_channel_flag(struct hostapd_data *hapd, int chan)
+{
+ return 0;
+}
#endif /* NEED_AP_MLME */

#endif /* HW_FEATURES_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 68bf2e7..ed256d2 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -110,6 +110,11 @@ struct hostapd_hw_modes {
u8 a_mpdu_params;

unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+
+ /**
+ * dfs_supported - DFS radar detection is supported in driver/HW.
+ */
+ u8 dfs_supported;
};


diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 82f5664..f1e6ca2 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4692,6 +4692,13 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
*(phy_info->num_modes) += 1;

+ if (tb_msg[NL80211_ATTR_FEATURE_FLAGS]) {
+ u32 drv_feature_flags =
+ nla_get_u32(tb_msg[NL80211_ATTR_FEATURE_FLAGS]);
+ mode->dfs_supported = !!(drv_feature_flags &
+ NL80211_FEATURE_DFS);
+ }
+
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
nla_len(nl_band), NULL);

diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index b550c63..9f1fb34 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -576,6 +576,10 @@ void eloop_terminate(void)
eloop.terminate = 1;
}

+void eloop_enable(void)
+{
+ eloop.terminate = 0;
+}

void eloop_destroy(void)
{
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index a656bf8..0aeb0f0 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -287,6 +287,13 @@ void eloop_run(void);
void eloop_terminate(void);

/**
+ * eloop_enable - Enable event loop
+ *
+ * Enables the event loop.
+ */
+void eloop_enable(void);
+
+/**
* eloop_destroy - Free any resources allocated for the event loop
*
* After calling eloop_destroy(), other eloop_* functions must not be called
--
1.7.5.4


2012-01-30 10:35:24

by David Goodenough

[permalink] [raw]
Subject: Re: [RFC 0/7] hostap: add DFS master ability

On Monday 30 Jan 2012, Goldenshtein, Victor wrote:
> On Thu, Jan 26, 2012 at 9:27 PM, David Goodenough
>
> <[email protected]> wrote:
> > As I understand it hostapd is not involved in mesh (802.11s) networks,
> > so how does this integrate there? As I understand it 802.11s is entirely
> > done in the kernel.
>
> At this point we don't have any plans to extend DFS support to mesh
> networks.
That is fine, and obviously your choice. My point is simply that provision
so that someone else can add it would be sensible, and in particular to
assume that anything that could have mesh support would have a userland
component kind of locks it out as I understand 802.11s support at the
moment.

David

2012-01-26 12:42:34

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 3/7] hostapd: add dfs events

Add EVENT_RADAR_DETECTED and EVENT_CHANNEL_SWITCH_COMPLETE
events.

EVENT_RADAR_DETECTED indicates that radar was detected on
operational channel. EVENT_CHANNEL_SWITCH_COMPLETE indicates
that device has finished the channel switch process.

Signed-off-by: Boris Presman <[email protected]>
Signed-off-by: Victor Goldenshtein <[email protected]>
---
src/ap/drv_callbacks.c | 40 ++++++++++++++++++++++++++++++++++++++++
src/drivers/driver.h | 22 +++++++++++++++++++++-
src/drivers/driver_common.c | 2 ++
3 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index b7febdc..d5079c4 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -464,6 +464,37 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
ieee802_1x_receive(hapd, src, data, data_len);
}

+static void hostapd_event_radar_detected(struct hostapd_data *hapd,
+ struct radar_detected *radar)
+{
+ if (!hapd->iconf->ieee80211h)
+ return;
+
+ if ((!(hapd->iface->dfs_state & DFS_INIT_PHASE_CAC)) &&
+ (hapd->iface->freq != radar->freq)) {
+ wpa_printf(MSG_WARNING, "False radar detection, op_freq(%d) != "
+ "radar_freq(%d)", hapd->iface->freq, radar->freq);
+ return;
+ }
+
+ if (ieee802_11_radar_detected(hapd))
+ ieee802_11_start_channel_switch(hapd, TRUE);
+ else
+ wpa_printf(MSG_DEBUG, "False radar detection");
+}
+
+static void hostapd_event_complete_channel_switch(struct hostapd_data *hapd,
+ struct channel_switch_complete *channel_switch)
+{
+ if (hapd->next_channel->freq != channel_switch->freq) {
+ wpa_printf(MSG_WARNING, "Switched to wrong freq, next_freq(%d) "
+ "!= ch_switch_freq(%d)", hapd->next_channel->freq,
+ channel_switch->freq);
+ }
+
+ if (channel_switch->status)
+ ieee802_11_complete_channel_switch(hapd);
+}

void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
@@ -576,6 +607,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
+ case EVENT_RADAR_DETECTED:
+ if (data)
+ hostapd_event_radar_detected(hapd, &data->radar_detected);
+ break;
+ case EVENT_CHANNEL_SWITCH_COMPLETE:
+ if (data)
+ hostapd_event_complete_channel_switch(hapd,
+ &data->channel_switch_complete);
+ break;
#ifdef NEED_AP_MLME
case EVENT_RX_ACTION:
if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 1f2e521..68bf2e7 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2973,7 +2973,17 @@ enum wpa_event_type {
/**
* EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
*/
- EVENT_EAPOL_TX_STATUS
+ EVENT_EAPOL_TX_STATUS,
+
+ /**
+ * EVENT_RADAR_DETECTED - notify of radar detection
+ */
+ EVENT_RADAR_DETECTED,
+
+ /**
+ * EVENT_CHANNEL_SWITCH_COMPLETE - notify of channel switch complete
+ */
+ EVENT_CHANNEL_SWITCH_COMPLETE
};


@@ -3563,6 +3573,16 @@ union wpa_event_data {
int data_len;
int ack;
} eapol_tx_status;
+
+ struct radar_detected {
+ int status;
+ int freq;
+ } radar_detected;
+
+ struct channel_switch_complete {
+ int status;
+ int freq;
+ } channel_switch_complete;
};

/**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 26ca8d6..8e0492a 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -83,6 +83,8 @@ const char * event_to_string(enum wpa_event_type event)
E2S(SCHED_SCAN_STOPPED);
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
+ E2S(RADAR_DETECTED);
+ E2S(CHANNEL_SWITCH_COMPLETE);
}

return "UNKNOWN";
--
1.7.5.4


2012-01-30 11:08:47

by David Goodenough

[permalink] [raw]
Subject: Re: [RFC 0/7] hostap: add DFS master ability

On Monday 30 Jan 2012, Julian Calaby wrote:
> On Mon, Jan 30, 2012 at 21:35, David Goodenough
>
> <[email protected]> wrote:
> > On Monday 30 Jan 2012, Goldenshtein, Victor wrote:
> >> On Thu, Jan 26, 2012 at 9:27 PM, David Goodenough
> >>
> >> <[email protected]> wrote:
> >> > As I understand it hostapd is not involved in mesh (802.11s) networks,
> >> > so how does this integrate there? As I understand it 802.11s is
> >> > entirely done in the kernel.
> >>
> >> At this point we don't have any plans to extend DFS support to mesh
> >> networks.
> >
> > That is fine, and obviously your choice. My point is simply that
> > provision so that someone else can add it would be sensible, and in
> > particular to assume that anything that could have mesh support would
> > have a userland component kind of locks it out as I understand 802.11s
> > support at the moment.
>
> I understand that using *secure* mesh requires a userspace component:
>
> http://o11s.org/trac/wiki/HOWTO
>
> Arguably there's no reason why a separate userspace component couldn't
> handle DFS for mesh interfaces. A project for the future could be to
> split it out of hostapd so it can be re-used for interfaces that
> aren't managed by hostapd.
>
> Thanks,
True, I had not thought of that one. So maybe it would be worth making
the DFS code in hostapd sufficiently modular that it can easily be moved/
copies/re-implemented into other environments.

David

2012-01-26 19:27:22

by David Goodenough

[permalink] [raw]
Subject: Re: [RFC 0/7] hostap: add DFS master ability

On Thursday 26 Jan 2012, Victor Goldenshtein wrote:
> This patch set (with nl/cfg/mac80211 patch series) adds support for DFS
> (Dynamic Frequency Selection) according 802.11h.
>
>
> Main idea
> ===================
>
> DFS master algorithm is implemented in the hostapd, while nl/cfg/mac80211
> will pipe relevant commands/events to the driver/hostapd.
As I understand it hostapd is not involved in mesh (802.11s) networks,
so how does this integrate there? As I understand it 802.11s is entirely
done in the kernel.

David
>
> Based on the assumption that the device/driver supports radar interference
> detection i.e., it is capable to generate radar_detected event by using
> different pattern detection techniques:
>
>
> 1. Pattern detection in the HW: the device generates 'radar_detected'
> event. 2. Pattern detection in the driver: the driver receives radar
> pulses from the device and generates 'radar detected' event.
>
>
> Main DFS procedures
> ===================
>
> 1. Hostapd gets driver's dfs capabilities.
>
> 2. If 80211h is enabled in the hostapd.conf and the driver supports one of
> the above radar detection techniques, hostapd may use DFS channels.
>
> 3. Hostapd selects an operational channel (default from hostapd.conf), if
> selected channel is a DFS channel, hostapd sends start_radar_detection
> command to the device/driver which starts monitoring for radar
> interference while hostapd sets a timer for a CAC (Channel Availability
> Check) time, which is 60 seconds.
>
> 4. As CAC timer expires and no radar has been detected, hostapd may
> continue with the init flow, otherwise if interference is detected hostapd
> selects another channel (random selection) and repeats the CAC on the new
> channel (in case the new channel is also a DFS channel), while the
> original channel is added to a "black list" for a period of
> ''No-Occupancy'' time (time that the channel can't be used/selected).
>
> 5. While using the channel the device/driver continuously monitors for
> potential radar interference. If interference is detected hostapd notified
> with 'radar detected' event, which selects a new channel and triggers a
> channel switch procedure, if the new channel is also a DFS channel,
> hostapd performs the CAC test, once it's successfully passed hostapd
> instructs the driver to initiate the transmission on the channel.
>
>
> Victor Goldenshtein (7):
> hostapd: implement dfs drv ops functions
> hostapd: add channel switch ability
> hostapd: add dfs events
> hostapd: add dfs support into interface init flow
> nl80211: add support to enable TX on oper-channel
> nl80211: add channel switch command/event
> nl80211: add start radar detection command/event
>
> hostapd/config_file.c | 10 +++
> src/ap/ap_config.h | 4 +
> src/ap/ap_drv_ops.c | 34 +++++++++
> src/ap/ap_drv_ops.h | 4 +
> src/ap/beacon.c | 16 ++++
> src/ap/drv_callbacks.c | 40 +++++++++++
> src/ap/hostapd.c | 158
> ++++++++++++++++++++++++++++++++++++++++-- src/ap/hostapd.h |
> 10 +++
> src/ap/hw_features.c | 48 ++++++++++---
> src/ap/hw_features.h | 10 +++
> src/ap/ieee802_11.c | 116 +++++++++++++++++++++++++++++++
> src/ap/ieee802_11.h | 4 +
> src/drivers/driver.h | 87 +++++++++++++++++++++++-
> src/drivers/driver_common.c | 2 +
> src/drivers/driver_nl80211.c | 125 +++++++++++++++++++++++++++++++++
> src/utils/eloop.c | 4 +
> src/utils/eloop.h | 7 ++
> 17 files changed, 662 insertions(+), 17 deletions(-)


2012-01-26 12:42:23

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 1/7] hostapd: implement dfs drv ops functions

Add nl80211 driver operation functions:
hostapd_enable_tx – to enable tx on DFS channel after
channel availability check.
hostapd_channel_switch – to handle channel switch request.
hostapd_start_radar_detection – to enable radar detection
on DFS channel.

Signed-off-by: Victor Goldenshtein <[email protected]>
---
src/ap/ap_config.h | 3 +++
src/ap/ap_drv_ops.c | 34 ++++++++++++++++++++++++++++++++++
src/ap/ap_drv_ops.h | 4 ++++
src/drivers/driver.h | 34 ++++++++++++++++++++++++++++++++++
4 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 485092d..eddc9b7 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -410,6 +410,9 @@ struct hostapd_config {

int ieee80211d;

+ /* DFS */
+ int channel_switch_count;
+
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];

/*
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 429c187..628f90e 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -590,3 +590,37 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
+
+
+int hostapd_enable_tx(struct hostapd_data *hapd)
+{
+ if (!hapd->driver || !hapd->driver->enable_tx)
+ return 0;
+ return hapd->driver->enable_tx(hapd->drv_priv);
+}
+
+
+int hostapd_channel_switch(struct hostapd_data *hapd, int channel, int freq,
+ u8 tx_block, u8 post_switch_block_tx)
+{
+ struct hostapd_channel_switch params;
+
+ if (!hapd->driver || !hapd->driver->channel_switch)
+ return 0;
+
+ params.channel = channel;
+ params.freq = freq;
+ params.tx_block = tx_block;
+ params.post_switch_block_tx = post_switch_block_tx;
+ params.ch_switch_count = hapd->iface->conf->channel_switch_count;
+
+ return hapd->driver->channel_switch(hapd->drv_priv, &params);
+}
+
+int hostapd_start_radar_detection(struct hostapd_data *hapd)
+{
+ if (!hapd->driver || !hapd->driver->start_radar_detection)
+ return 0;
+
+ return hapd->driver->start_radar_detection(hapd->drv_priv);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 835cdde..051f6fa 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -100,6 +100,10 @@ int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
int reassoc, u16 status, const u8 *ie, size_t len);
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen);
+int hostapd_enable_tx(struct hostapd_data *hapd);
+int hostapd_channel_switch(struct hostapd_data *hapd, int channel, int freq,
+ u8 tx_block, u8 post_switch_block_tx);
+int hostapd_start_radar_detection(struct hostapd_data *hapd);


#include "drivers/driver.h"
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d72c83b..512b4c3 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -847,6 +847,17 @@ struct hostapd_freq_params {
* enabled, secondary channel above primary */
};

+struct hostapd_channel_switch {
+ int freq;
+ int channel;
+ int tx_block; /* immediately block the tx on the
+ * operational channel
+ * (prior channel switch) */
+ int post_switch_block_tx; /* block tx on the target ch (after
+ * channel switch) */
+ int ch_switch_count;
+};
+
enum wpa_driver_if_type {
/**
* WPA_IF_STATION - Station mode interface
@@ -2483,6 +2494,29 @@ struct wpa_driver_ops {
*/
void (*poll_client)(void *priv, const u8 *own_addr,
const u8 *addr, int qos);
+
+ /**
+ * enable_tx - Enable TX
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*enable_tx)(void *priv);
+
+ /**
+ * channel_switch - Perform a channel switch
+ * @priv: Private driver interface data
+ * @params: Channels switch parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*channel_switch)(void *priv,
+ struct hostapd_channel_switch *params);
+
+ /**
+ * start_radar_detection - Listen for radar interference on the channel.
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*start_radar_detection)(void *priv);
};


--
1.7.5.4


2012-01-26 13:10:16

by Felix Fietkau

[permalink] [raw]
Subject: Re: [RFC 4/7] hostapd: add dfs support into interface init flow

On 2012-01-26 1:41 PM, Victor Goldenshtein wrote:
> Implement Channel Availability Check (CAC) during initialization
> phase. According to DFS requirements the AP should monitor 'radar
> channels' for potential radar interference for a minimum CAC time
> prior enabling the transmissions.
>
> Add dfs support into hw features, allow the usage of the radar
> channels if ieee80211h is enabled in the hostapd.conf and the
> driver supports radar detection.
>
> Parse and handle driver's DFS capabilities, userspace applications
> must be fully synchronized with device capabilities to detect radar
> patterns in the air which may influence userspace behavior.
>
> Signed-off-by: Boris Presman <[email protected]>
> Signed-off-by: Victor Goldenshtein <[email protected]>
> ---
> src/ap/hostapd.c | 17 +++++++++++------
> src/ap/hw_features.c | 30 ++++++++++++++++++++----------
> src/ap/hw_features.h | 9 +++++++++
> src/drivers/driver.h | 5 +++++
> src/drivers/driver_nl80211.c | 7 +++++++
> src/utils/eloop.c | 4 ++++
> src/utils/eloop.h | 7 +++++++
> 7 files changed, 63 insertions(+), 16 deletions(-)
>
> diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
> index ce37922..411b681 100644
> --- a/src/ap/hostapd.c
> +++ b/src/ap/hostapd.c
> @@ -733,14 +739,13 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
> hostapd_hw_mode_txt(hapd->iconf->hw_mode),
> hapd->iconf->channel, iface->freq);
>
> - if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
> - hapd->iconf->channel,
> - hapd->iconf->ieee80211n,
> - hapd->iconf->secondary_channel)) {
> - wpa_printf(MSG_ERROR, "Could not set channel for "
> - "kernel driver");
> + if (hostapd_check_set_freq(hapd)) {
> + wpa_printf(MSG_ERROR, "Couldn't check/set freq");
> return -1;
> }
> +
> + eloop_enable();
> + wpa_printf(MSG_DEBUG, "Continuing with init flow");
> }
>
> if (iface->current_mode) {
This seems like a bit of a hack to me. Wouldn't it be better to prevent
eloop_terminate() from being called instead of adding another function
to override the eloop termination?

- Felix

2012-01-30 07:32:33

by Victor Goldenshtein

[permalink] [raw]
Subject: Re: [RFC 0/7] hostap: add DFS master ability

On Thu, Jan 26, 2012 at 9:27 PM, David Goodenough
<[email protected]> wrote:
> As I understand it hostapd is not involved in mesh (802.11s) networks,
> so how does this integrate there? ?As I understand it 802.11s is entirely
> done in the kernel.
>

At this point we don't have any plans to extend DFS support to mesh networks.

--
Thanks,
Victor.

2012-01-30 11:02:22

by Julian Calaby

[permalink] [raw]
Subject: Re: [RFC 0/7] hostap: add DFS master ability

On Mon, Jan 30, 2012 at 21:35, David Goodenough
<[email protected]> wrote:
> On Monday 30 Jan 2012, Goldenshtein, Victor wrote:
>> On Thu, Jan 26, 2012 at 9:27 PM, David Goodenough
>>
>> <[email protected]> wrote:
>> > As I understand it hostapd is not involved in mesh (802.11s) networks,
>> > so how does this integrate there? ?As I understand it 802.11s is entirely
>> > done in the kernel.
>>
>> At this point we don't have any plans to extend DFS support to mesh
>> networks.
> That is fine, and obviously your choice. ?My point is simply that provision
> so that someone else can add it would be sensible, and in particular to
> assume that anything that could have mesh support would have a userland
> component kind of locks it out as I understand 802.11s support at the
> moment.

I understand that using *secure* mesh requires a userspace component:

http://o11s.org/trac/wiki/HOWTO

Arguably there's no reason why a separate userspace component couldn't
handle DFS for mesh interfaces. A project for the future could be to
split it out of hostapd so it can be re-used for interfaces that
aren't managed by hostapd.

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/

2012-01-26 12:42:55

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 7/7] nl80211: add start radar detection command/event

Add command to trigger radar detection in the driver/HW.
Once radar detection has started, the driver/device shall
continuously monitor the Operating Channel (In-Service
Monitoring) to ensure that there is no radar interferences
on that channel. Process radar detection event in
do_process_drv_event().

Signed-off-by: Victor Goldenshtein <[email protected]>
---
src/drivers/driver_nl80211.c | 37 +++++++++++++++++++++++++++++++++++++
1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 744e736..2d52c72 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2145,6 +2145,16 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_SWITCH_COMPLETE,
&data);
break;
+ case NL80211_CMD_DFS_RADAR_DETECTION:
+ os_memset(&data, 0, sizeof(data));
+ if (tb[NL80211_ATTR_WIPHY_FREQ]) {
+ data.radar_detected.freq =
+ nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+ }
+ data.radar_detected.status = TRUE;
+ wpa_printf(MSG_DEBUG, "nl80211: Radar detected event");
+ wpa_supplicant_event(drv->ctx, EVENT_RADAR_DETECTED, &data);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -8706,6 +8716,32 @@ nla_put_failure:
}


+static int wpa_driver_nl80211_start_radar_detection(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Start radar detection");
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_DFS_RADAR_DETECTION);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+ "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+ return -1;
+}
+
+
#ifdef CONFIG_TDLS

static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -9001,6 +9037,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_p2p_powersave = nl80211_set_p2p_powersave,
.enable_tx = wpa_driver_nl80211_enable_dfs_tx,
.channel_switch = wpa_driver_nl80211_channel_switch,
+ .start_radar_detection = wpa_driver_nl80211_start_radar_detection,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
--
1.7.5.4


2012-01-26 12:42:44

by Victor Goldenshtein

[permalink] [raw]
Subject: [RFC 5/7] nl80211: add support to enable TX on oper-channel

Once a channel has been passes the channel availability
check (CAC) the ap may start the tx with
wpa_driver_nl80211_enable_dfs_tx().

Add wpa_driver_nl80211_enable_dfs_tx() + init drv_ops.

Signed-off-by: Boris Presman <[email protected]>
Signed-off-by: Victor Goldenshtein <[email protected]>
---
src/drivers/driver_nl80211.c | 27 +++++++++++++++++++++++++++
1 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index f1e6ca2..e3d6a3c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -8627,6 +8627,32 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
}


+static int wpa_driver_nl80211_enable_dfs_tx(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Enable DFS tx");
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_DFS_ENABLE_TX);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to enable DFS tx: "
+ "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+ return -1;
+}
+
+
#ifdef CONFIG_TDLS

static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -8920,6 +8946,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_rekey_info = nl80211_set_rekey_info,
.poll_client = nl80211_poll_client,
.set_p2p_powersave = nl80211_set_p2p_powersave,
+ .enable_tx = wpa_driver_nl80211_enable_dfs_tx,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
--
1.7.5.4


2012-02-09 23:19:53

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [RFC 1/7] hostapd: implement dfs drv ops functions

On Thu, Jan 26, 2012 at 4:41 AM, Victor Goldenshtein <[email protected]> wrote:
> Add nl80211 driver operation functions:
> hostapd_enable_tx – to enable tx on DFS channel after
> channel availability check.
> hostapd_channel_switch – to handle channel switch request.
> hostapd_start_radar_detection – to enable radar detection
> on DFS channel.
>
> Signed-off-by: Victor Goldenshtein <[email protected]>
> ---
>  src/ap/ap_config.h   |    3 +++
>  src/ap/ap_drv_ops.c  |   34 ++++++++++++++++++++++++++++++++++
>  src/ap/ap_drv_ops.h  |    4 ++++
>  src/drivers/driver.h |   34 ++++++++++++++++++++++++++++++++++
>  4 files changed, 75 insertions(+), 0 deletions(-)
>
> diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
> index 485092d..eddc9b7 100644
> --- a/src/ap/ap_config.h
> +++ b/src/ap/ap_config.h
> @@ -410,6 +410,9 @@ struct hostapd_config {
>
>        int ieee80211d;
>
> +       /* DFS */
> +       int channel_switch_count;
> +
>        struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
>
>        /*
> diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
> index 429c187..628f90e 100644
> --- a/src/ap/ap_drv_ops.c
> +++ b/src/ap/ap_drv_ops.c
> @@ -590,3 +590,37 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
>        return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
>                                          reason);
>  }
> +
> +
> +int hostapd_enable_tx(struct hostapd_data *hapd)
> +{
> +       if (!hapd->driver || !hapd->driver->enable_tx)
> +               return 0;
> +       return hapd->driver->enable_tx(hapd->drv_priv);

No checks on if the channel is DFS, if we started DFS, etc?

Luis

2012-02-09 20:18:43

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [RFC 0/7] hostap: add DFS master ability

On Mon, Jan 30, 2012 at 3:08 AM, David Goodenough
<[email protected]> wrote:
> On Monday 30 Jan 2012, Julian Calaby wrote:
>> On Mon, Jan 30, 2012 at 21:35, David Goodenough
>>
>> <[email protected]> wrote:
>> > On Monday 30 Jan 2012, Goldenshtein, Victor wrote:
>> >> On Thu, Jan 26, 2012 at 9:27 PM, David Goodenough
>> >>
>> >> <[email protected]> wrote:
>> >> > As I understand it hostapd is not involved in mesh (802.11s) networks,
>> >> > so how does this integrate there?  As I understand it 802.11s is
>> >> > entirely done in the kernel.
>> >>
>> >> At this point we don't have any plans to extend DFS support to mesh
>> >> networks.
>> >
>> > That is fine, and obviously your choice.  My point is simply that
>> > provision so that someone else can add it would be sensible, and in
>> > particular to assume that anything that could have mesh support would
>> > have a userland component kind of locks it out as I understand 802.11s
>> > support at the moment.
>>
>> I understand that using *secure* mesh requires a userspace component:
>>
>> http://o11s.org/trac/wiki/HOWTO
>>
>> Arguably there's no reason why a separate userspace component couldn't
>> handle DFS for mesh interfaces. A project for the future could be to
>> split it out of hostapd so it can be re-used for interfaces that
>> aren't managed by hostapd.
>>
>> Thanks,
> True, I had not thought of that one.  So maybe it would be worth making
> the DFS code in hostapd sufficiently modular that it can easily be moved/
> copies/re-implemented into other environments.

The secure mesh userspace stuff IMHO should be stuffed into hostapd.

Luis

2012-02-15 16:47:33

by Victor Goldenshtein

[permalink] [raw]
Subject: Re: [RFC 1/7] hostapd: implement dfs drv ops functions

On Fri, Feb 10, 2012 at 1:19 AM, Luis R. Rodriguez <[email protected]> wrote:
> No checks on if the channel is DFS, if we started DFS, etc?
>

Will add few sanity checks.

Thanks for the reviews ;)
Victor.