2012-08-08 12:02:08

by Victor Goldenshtein

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

v3:

Rebased to latest.

0001-hostapd-implement-dfs-drv-ops-functions.patch
1. added HT40 check in hostapd_channel_switch() & hostapd_start_radar_detection().

0003-hostapd-add-dfs-events.patch
1. removed "channel_switch_complete" in wpa_event_data union.
2. renamed "EVENT_CHANNEL_SWITCH_COMPLETE" to "EVENT_AP_CH_SWITCH_COMPLETE".
3. renamed "hostapd_event_complete_channel_switch()" to hostapd_event_ap_ch_switch().

0006-nl80211-add-channel-switch-command-event.patch
1. reuse "NL80211_CMD_CH_SWITCH_NOTIFY" event also for AP.
2. set also the NL80211_ATTR_WIPHY_CHANNEL_TYPE in nl80211_ap_channel_switch().
3. update the "bss->freq" only if the channel switch command succeeded.

0007-nl80211-add-start-radar-detection-command-event.patch
1. set also the NL80211_ATTR_WIPHY_CHANNEL_TYPE in nl80211_start_radar_detection().

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 | 95 +++++++++++++++++++++++++
src/ap/ap_drv_ops.h | 5 ++
src/ap/beacon.c | 16 ++++
src/ap/drv_callbacks.c | 45 ++++++++++++
src/ap/hostapd.c | 161 ++++++++++++++++++++++++++++++++++++++++--
src/ap/hostapd.h | 13 ++++
src/ap/hw_features.c | 48 ++++++++++---
src/ap/hw_features.h | 10 +++
src/ap/ieee802_11.c | 117 ++++++++++++++++++++++++++++++
src/ap/ieee802_11.h | 4 +
src/drivers/driver.h | 89 +++++++++++++++++++++++-
src/drivers/driver_common.c | 2 +
src/drivers/driver_nl80211.c | 152 ++++++++++++++++++++++++++++++++++++++-
src/utils/eloop.c | 1 +
16 files changed, 751 insertions(+), 21 deletions(-)

--
1.7.5.4



2012-08-08 12:02:16

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v3 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 IE. Add this CSA to the beacon frame prior
performing a channel switch and remove it once it's
completed.

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

Signed-hostap: Boris Presman <[email protected]>
Signed-hostap: Victor Goldenshtein <[email protected]>
---
hostapd/config_file.c | 10 ++++
src/ap/ap_config.h | 1 +
src/ap/beacon.c | 16 ++++++
src/ap/hostapd.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++
src/ap/hostapd.h | 7 +++
src/ap/hw_features.c | 18 ++++++
src/ap/hw_features.h | 1 +
src/ap/ieee802_11.c | 117 +++++++++++++++++++++++++++++++++++++++
src/ap/ieee802_11.h | 4 ++
src/drivers/driver.h | 16 ++++++
10 files changed, 335 insertions(+), 0 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 03f29ad..2f28375 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1304,6 +1304,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;
@@ -1526,6 +1532,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
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 c21a7a8..2b88546 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -456,6 +456,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 ca3f054..9455d2b 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -172,6 +172,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)
{
@@ -578,6 +591,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 ba8d832..2fbc6ef 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1103,3 +1103,148 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
+
+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;
+ int flag;
+
+ wpa_printf(MSG_DEBUG, "Resuming DFS channel availability check");
+
+ flag = hostapd_hw_get_channel_flag(hapd, hapd->iconf->channel);
+
+ /*
+ * 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, hapd->iface->freq, flag);
+}
+
+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_hw_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, hapd->iface->freq,
+ flag)) {
+ 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, hapd->iface->freq, flag);
+ eloop_terminate();
+ }
+ return 0;
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index cdd7556..4465e82 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -156,6 +156,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;
@@ -271,6 +273,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,
@@ -291,5 +295,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset);
+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 76c4211..bbd2b03 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -794,3 +794,21 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)

return 0;
}
+
+
+int hostapd_hw_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..b8e287b 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_hw_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 3996c90..2269cd5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -153,6 +153,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;
}

@@ -1849,4 +1852,118 @@ 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->freq,
+ next_channel->flag,
+ 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) {
+ if (hostapd_start_radar_detection(hapd, hapd->iface->freq,
+ hapd->next_channel->flag)) {
+ wpa_printf(MSG_ERROR, "Could not start radar "
+ "detection for kernel driver");
+ return -1;
+ }
+ 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);
+ }
+
+ 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 9993bee..1539045 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -75,5 +75,9 @@ 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);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+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 bc714e8..047a5aa 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -28,6 +28,7 @@
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
#define HOSTAPD_CHAN_HT40 0x00000040
+#define HOSTAPD_CHAN_RADAR_DETECTED 0x00000080

/*
* DFS functionality is enabled.
@@ -35,6 +36,11 @@
#define DFS_ENABLED BIT(0)

/*
+ * DFS channel availability check during initialization.
+ */
+#define DFS_INIT_PHASE_CAC BIT(1)
+
+/*
* DFS Channel Availability Check Time - the time a system shall monitor a
* 'radar channel' for presence of radar prior to initiating a TX, spec defines
* it as 60 seconds.
@@ -42,6 +48,14 @@
*/
#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
+
+
/**
* struct hostapd_channel_data - Channel information
*/
@@ -65,6 +79,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)
--
1.7.5.4


2012-08-08 12:02:34

by Victor Goldenshtein

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

Implement AP channel switch command and handle
channel switch complete event.

Signed-hostap: Boris Presman <[email protected]>
Signed-hostap: Victor Goldenshtein <[email protected]>
---
src/drivers/driver_nl80211.c | 65 +++++++++++++++++++++++++++++++++++++++--
1 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index fadd4cb..c2780a4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1197,7 +1197,8 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,


static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *freq, struct nlattr *type)
+ struct nlattr *freq, struct nlattr *type,
+ enum wpa_event_type event)
{
union wpa_event_data data;
int ht_enabled = 1;
@@ -1226,7 +1227,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
data.ch_switch.ht_enabled = ht_enabled;
data.ch_switch.ch_offset = chan_offset;

- wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
+ wpa_supplicant_event(drv->ctx, event, &data);
}


@@ -2151,8 +2152,18 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
tb[NL80211_ATTR_RESP_IE]);
break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
- mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
- tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ /*
+ * TODO: as soon as GO will support DFS, AP
+ * and GO channel switches should be united.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_AP)
+ mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ EVENT_AP_CH_SWITCH_COMPLETE);
+ else
+ mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ EVENT_CH_SWITCH);
break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -8876,6 +8887,51 @@ nla_put_failure:
}


+static int nl80211_ap_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_CH_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);
+
+ /* only HT20 is supported at this point */
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+ 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) {
+ bss->freq = params->freq;
+ 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,
@@ -9171,6 +9227,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.poll_client = nl80211_poll_client,
.set_p2p_powersave = nl80211_set_p2p_powersave,
.enable_tx = nl80211_enable_dfs_tx,
+ .hapd_channel_switch = nl80211_ap_channel_switch,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
--
1.7.5.4


2012-08-08 12:02:23

by Victor Goldenshtein

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

Add EVENT_RADAR_DETECTED and EVENT_AP_CH_SWITCH_COMPLETE
events.

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

Signed-hostap: Boris Presman <[email protected]>
Signed-hostap: Victor Goldenshtein <[email protected]>
---
src/ap/drv_callbacks.c | 45 +++++++++++++++++++++++++++++++++++++++++++
src/drivers/driver.h | 20 ++++++++++++++++++-
src/drivers/driver_common.c | 2 +
3 files changed, 66 insertions(+), 1 deletions(-)

diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index c793c6a..d7148b0 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -684,6 +684,34 @@ 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_ap_ch_switch(struct hostapd_data *hapd, int freq)
+{
+ if (hapd->next_channel->freq != freq)
+ wpa_printf(MSG_WARNING, "Switched to wrong freq, next_freq(%d) "
+ "!= ch_switch_freq(%d)", hapd->next_channel->freq,
+ freq);
+
+ ieee802_11_complete_channel_switch(hapd);
+}

void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
@@ -707,6 +735,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
event_to_string(event), event);
#endif /* CONFIG_NO_STDOUT_DEBUG */

+ if ((hapd->iface->dfs_state & DFS_INIT_PHASE_CAC) &&
+ (event != EVENT_RADAR_DETECTED)) {
+ wpa_dbg(hapd->msg_ctx, level, "Irrelevant event "
+ "during DFS init phase");
+ return;
+ }
+
switch (event) {
case EVENT_MICHAEL_MIC_FAILURE:
michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
@@ -816,6 +851,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset);
break;
+ case EVENT_AP_CH_SWITCH_COMPLETE:
+ if (!data)
+ break;
+ hostapd_event_ap_ch_switch(hapd, data->ch_switch.freq);
+ break;
+ case EVENT_RADAR_DETECTED:
+ if (!data)
+ break;
+ hostapd_event_radar_detected(hapd, &data->radar_detected);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 047a5aa..5b031a8 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3111,7 +3111,17 @@ enum wpa_event_type {
*
* This event can be used to request a WNM operation to be performed.
*/
- EVENT_WNM
+ EVENT_WNM,
+
+ /**
+ * EVENT_AP_CH_SWITCH_COMPLETE - notify of channel switch complete
+ */
+ EVENT_AP_CH_SWITCH_COMPLETE,
+
+ /**
+ * EVENT_RADAR_DETECTED - notify of radar detection
+ */
+ EVENT_RADAR_DETECTED
};


@@ -3736,6 +3746,14 @@ union wpa_event_data {
int ht_enabled;
int ch_offset;
} ch_switch;
+
+ /**
+ * struct radar_detected
+ * @freq: Frequency of new channel in MHz
+ */
+ struct radar_detected {
+ int freq;
+ } radar_detected;
};

/**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 418cf1a..2232ade 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -79,6 +79,8 @@ const char * event_to_string(enum wpa_event_type event)
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
E2S(WNM);
+ E2S(AP_CH_SWITCH_COMPLETE);
+ E2S(RADAR_DETECTED);
}

return "UNKNOWN";
--
1.7.5.4


2012-08-08 12:02:12

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v3 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-hostap: Victor Goldenshtein <[email protected]>
---
src/ap/ap_config.h | 3 ++
src/ap/ap_drv_ops.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/ap/ap_drv_ops.h | 5 +++
src/ap/hostapd.h | 6 +++
src/drivers/driver.h | 48 +++++++++++++++++++++++++
5 files changed, 157 insertions(+), 0 deletions(-)

diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index bfb2d8a..c21a7a8 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -454,6 +454,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 64c9c20..d1d9e8b 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -621,3 +621,98 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
hapd->own_addr, hapd->own_addr, data,
len, 0);
}
+
+int hostapd_enable_tx(struct hostapd_data *hapd, int freq, int flags)
+{
+ struct os_time now;
+
+ if (!hapd->driver || !hapd->driver->enable_tx)
+ return 0;
+
+ if ((flags & HOSTAPD_CHAN_RADAR) &&
+ !(hapd->iface->dfs_state & DFS_ENABLED)) {
+ wpa_printf(MSG_ERROR, "Can't enable tx, "
+ "DFS functionality is not enabled");
+ return -1;
+ }
+
+ os_get_time(&now);
+
+ if ((flags & HOSTAPD_CHAN_RADAR) &&
+ now.sec - hapd->iface->dfs_start_cac_ts < DFS_MIN_CAC_TIME_SEC) {
+ wpa_printf(MSG_ERROR, "Can't enable tx, "
+ "DFS min CAC time hasn't passed");
+ return -1;
+ }
+
+ hapd->iface->dfs_start_cac_ts = 0;
+
+ return hapd->driver->enable_tx(hapd->drv_priv, freq);
+}
+
+
+int hostapd_channel_switch(struct hostapd_data *hapd, int freq, int flags,
+ u8 tx_block, u8 post_switch_block_tx)
+{
+ struct hostapd_channel_switch params;
+
+ if (!hapd->driver || !hapd->driver->hapd_channel_switch)
+ return 0;
+
+ if ((flags & HOSTAPD_CHAN_RADAR) &&
+ !(hapd->iface->dfs_state & DFS_ENABLED)) {
+ wpa_printf(MSG_ERROR, "Can't switch to radar channel, "
+ "DFS functionality is not enabled");
+ return -1;
+ }
+
+ if (hapd->iface->conf->secondary_channel) {
+ wpa_printf(MSG_ERROR, "Channel switch is not supported "
+ "with HT40");
+ return -1;
+ }
+
+ 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->hapd_channel_switch(hapd->drv_priv, &params);
+}
+
+int hostapd_start_radar_detection(struct hostapd_data *hapd, int freq,
+ int flags)
+{
+ int ret;
+ struct os_time now;
+
+ if (!hapd->driver || !hapd->driver->start_radar_detection)
+ return 0;
+
+ if (!(flags & HOSTAPD_CHAN_RADAR)) {
+ wpa_printf(MSG_ERROR, "Can't start radar detection, the channel"
+ " %d is not DFS channel", (int)hapd->iconf->channel);
+ return -1;
+ }
+
+ if (!(hapd->iface->dfs_state & DFS_ENABLED)) {
+ wpa_printf(MSG_ERROR, "Can't start radar detection, "
+ "DFS functionality is not enabled");
+ return -1;
+ }
+
+ if (hapd->iface->conf->secondary_channel) {
+ wpa_printf(MSG_ERROR, "Can't start radar detection, "
+ "DFS functionality on HT40 is not supported");
+ return -1;
+ }
+
+ ret = hapd->driver->start_radar_detection(hapd->drv_priv, freq);
+ if (!ret) {
+ os_get_time(&now);
+ hapd->iface->dfs_start_cac_ts = now.sec;
+ } else
+ hapd->iface->dfs_start_cac_ts = 0;
+
+ return ret;
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 9c53b99..f36bec1 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -97,6 +97,11 @@ 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 freq, int flags);
+int hostapd_channel_switch(struct hostapd_data *hapd, int freq, int flags,
+ u8 tx_block, u8 post_switch_block_tx);
+int hostapd_start_radar_detection(struct hostapd_data *hapd, int freq,
+ int flags);


#include "drivers/driver.h"
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f7ed311..cdd7556 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -240,6 +240,12 @@ struct hostapd_iface {
int olbc_ht;

u16 ht_op_mode;
+
+ /* dfs states */
+ u8 dfs_state;
+ /* dfs start channel availability check time stamp */
+ os_time_t dfs_start_cac_ts;
+
void (*scan_cb)(struct hostapd_iface *iface);

int (*ctrl_iface_init)(struct hostapd_data *hapd);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 82b72cd..bc714e8 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -29,6 +29,19 @@
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
#define HOSTAPD_CHAN_HT40 0x00000040

+/*
+ * DFS functionality is enabled.
+ */
+#define DFS_ENABLED BIT(0)
+
+/*
+ * DFS Channel Availability Check Time - the time a system shall monitor a
+ * 'radar channel' for presence of radar prior to initiating a TX, spec defines
+ * it as 60 seconds.
+ * Driver will block any attempt to enable the TX prior this minimal CAC time.
+ */
+#define DFS_MIN_CAC_TIME_SEC 60
+
/**
* struct hostapd_channel_data - Channel information
*/
@@ -904,6 +917,16 @@ struct hostapd_freq_params {
* enabled, secondary channel above primary */
};

+struct hostapd_channel_switch {
+ int freq;
+ 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
@@ -2603,6 +2626,31 @@ struct wpa_driver_ops {
* avoid frequency conflict in single channel concurrency.
*/
int (*switch_channel)(void *priv, unsigned int freq);
+
+ /**
+ * hapd_channel_switch - Perform an AP channel switch
+ * @priv: Private driver interface data
+ * @params: Channels switch parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*hapd_channel_switch)(void *priv,
+ struct hostapd_channel_switch *params);
+
+ /**
+ * enable_tx - Enable TX
+ * @priv: Private driver interface data
+ * @freq: Frequency (in MHz) of the channel
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*enable_tx)(void *priv, int freq);
+
+ /**
+ * start_radar_detection - Listen for radar interference on the channel.
+ * @priv: Private driver interface data
+ * @freq: Frequency (in MHz) of the channel
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*start_radar_detection)(void *priv, int freq);
};


--
1.7.5.4


2012-08-08 12:02:25

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v3 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 with AP channel switch ability.

Signed-hostap: Boris Presman <[email protected]>
Signed-hostap: Victor Goldenshtein <[email protected]>
---
src/ap/hostapd.c | 16 ++++++++++------
src/ap/hw_features.c | 30 ++++++++++++++++++++----------
src/ap/hw_features.h | 9 +++++++++
src/drivers/driver.h | 5 +++++
src/drivers/driver_nl80211.c | 9 +++++++++
src/utils/eloop.c | 1 +
6 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 2fbc6ef..24a5384 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -857,6 +857,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);
}
@@ -882,14 +888,12 @@ 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;
}
+
+ 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 bbd2b03..3fc43eb 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 b8e287b..67bab44 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 5b031a8..ed032b9 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -140,6 +140,11 @@ struct hostapd_hw_modes {
u8 vht_mcs_set[8];

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 36cdbc8..3ac485c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4786,6 +4786,15 @@ 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) &&
+ (drv_feature_flags &
+ NL80211_FEATURE_AP_CH_SWITCH));
+ }
+
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 bb32401..8cb34dc 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -775,6 +775,7 @@ void eloop_run(void)
}

out:
+ eloop.terminate = 0;
#ifndef CONFIG_ELOOP_POLL
os_free(rfds);
os_free(wfds);
--
1.7.5.4


2012-08-08 12:02:39

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v3 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-hostap: Victor Goldenshtein <[email protected]>
---
src/drivers/driver_nl80211.c | 50 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c2780a4..31edc98 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2067,6 +2067,22 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
}

+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.radar_detected.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Radar detected event on freq = %d",
+ data.radar_detected.freq);
+
+ wpa_supplicant_event(drv->ctx, EVENT_RADAR_DETECTED, &data);
+}

static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
int wds)
@@ -2210,6 +2226,9 @@ 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_RADAR_DETECT:
+ nl80211_radar_event(drv, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -8932,6 +8951,36 @@ nla_put_failure:
}


+static int nl80211_start_radar_detection(void *priv, int freq)
+{
+ 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_RADAR_DETECT);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+ /* only HT20 is supported at this point */
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+ 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,
@@ -9228,6 +9277,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_p2p_powersave = nl80211_set_p2p_powersave,
.enable_tx = nl80211_enable_dfs_tx,
.hapd_channel_switch = nl80211_ap_channel_switch,
+ .start_radar_detection = nl80211_start_radar_detection,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
--
1.7.5.4


2012-08-08 12:02:29

by Victor Goldenshtein

[permalink] [raw]
Subject: [PATCH v3 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-hostap: Boris Presman <[email protected]>
Signed-hostap: Victor Goldenshtein <[email protected]>
---
src/drivers/driver_nl80211.c | 28 ++++++++++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 3ac485c..fadd4cb 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -8849,6 +8849,33 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
}


+static int nl80211_enable_dfs_tx(void *priv, int freq)
+{
+ 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);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+ 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,
@@ -9143,6 +9170,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 = nl80211_enable_dfs_tx,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
--
1.7.5.4