aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Goldenshtein <victorg@ti.com>2011-11-21 15:19:52 +0200
committerArik Nemtsov <arik@wizery.com>2012-09-13 14:53:28 +0300
commitff0a677405533513777ed413abff97483f5fda6d (patch)
tree345897e5425f8e1aa37f39ce603163a3deec7998
parent7b65de18e8276ed3b5d2cbb64dc06c347f3b0e78 (diff)
downloadexternal_wpa_supplicant_8_ti-ff0a677405533513777ed413abff97483f5fda6d.zip
external_wpa_supplicant_8_ti-ff0a677405533513777ed413abff97483f5fda6d.tar.gz
external_wpa_supplicant_8_ti-ff0a677405533513777ed413abff97483f5fda6d.tar.bz2
hostap: add channel switch ability to AP & GO (INTERNAL)
Add channel switch command and handle channel switch request/complete events. 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. New EVENT_REQ_CH_SW which indicates that the driver has requested to perform a channel switch. Signed-hostap: Victor Goldenshtein <victorg@ti.com>
-rw-r--r--hostapd/config_file.c2
-rw-r--r--src/ap/beacon.c25
-rw-r--r--src/ap/drv_callbacks.c33
-rw-r--r--src/ap/hostapd.c31
-rw-r--r--src/ap/hostapd.h5
-rw-r--r--src/ap/hw_features.c18
-rw-r--r--src/ap/hw_features.h1
-rw-r--r--src/ap/ieee802_11.c30
-rw-r--r--src/drivers/driver.h9
-rw-r--r--src/drivers/driver_common.c1
-rw-r--r--wpa_supplicant/events.c6
11 files changed, 158 insertions, 3 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 03f82b2..59745fa 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1441,6 +1441,8 @@ 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, "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/beacon.c b/src/ap/beacon.c
index a1bb067..72c3ead 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -33,6 +33,7 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "beacon.h"
+#include "hw_features.h"
#ifdef NEED_AP_MLME
@@ -171,6 +172,27 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
return pos;
}
+static u8 *hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
+{
+ int current_ch_flag = 0;
+
+ if (!hapd->next_channel)
+ return eid;
+
+ current_ch_flag = hostapd_hw_get_channel_flag(hapd,
+ hapd->iconf->channel);
+
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3; /* IE length */
+ /* STAs should cease transmit if the switch is due to radar */
+ *eid++ = (current_ch_flag & HOSTAPD_CHAN_RADAR) ? 1 : 0;
+ *eid++ = (u8)hapd->next_channel->chan;
+ *eid++ = (hapd->iconf->channel_switch_count > hapd->conf->dtim_period) ?
+ (u8)hapd->iconf->channel_switch_count :
+ hapd->conf->dtim_period * 2;
+ return eid;
+}
+
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
{
@@ -573,6 +595,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/drv_callbacks.c b/src/ap/drv_callbacks.c
index f80a08c..7e478a5 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -27,6 +27,7 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "hw_features.h"
+#include "beacon.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -286,8 +287,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
HOSTAPD_LEVEL_INFO, "driver had channel switch: "
"freq=%d, ht=%d, offset=%d", freq, ht, offset);
- hapd->iface->freq = freq;
-
channel = hostapd_hw_get_channel(hapd, freq);
if (!channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
@@ -299,6 +298,30 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
hapd->iconf->secondary_channel = offset;
+
+
+ if (hapd->iface->freq == freq)
+ return;
+
+ hapd->iface->freq = freq;
+
+ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq,
+ hapd->iconf->channel,
+ hapd->iconf->ieee80211n,
+ hapd->iconf->secondary_channel)) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "failed to update the freq !");
+ return;
+ }
+
+ hapd->next_channel = NULL;
+
+ /* update the DS IE */
+ ieee802_11_set_beacon(hapd);
+
+ wpa_printf(MSG_DEBUG, "AP/GO moved to channel %d", channel);
+
#endif /* NEED_AP_MLME */
}
@@ -627,6 +650,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset);
break;
+ case EVENT_REQ_CH_SW:
+ if (!data)
+ break;
+ ieee802_11_start_channel_switch(hapd, data->ch_switch.freq,
+ FALSE);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3406cd1..4e06808 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1106,3 +1106,34 @@ 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_get_valid_channel(struct hostapd_data *hapd,
+ int req_freq)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+ int i, channel_idx = 0;
+
+ wpa_printf(MSG_DEBUG, "Selecting next channel");
+
+ if (hapd->iface->current_mode == NULL)
+ return NULL;
+
+ mode = hapd->iface->current_mode;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_RADAR))
+ continue;
+ channel_idx++;
+
+ /* request specific channel */
+ if (req_freq && (req_freq == chan->freq))
+ return chan;
+ }
+
+ wpa_printf(MSG_WARNING, "Could't get requested channel");
+ return NULL;
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 0465844..feea42d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -162,6 +162,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,9 @@ 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_get_valid_channel(struct hostapd_data *hapd,
+ int req_freq);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 0900e78..930d35b 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -796,3 +796,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 ed1661a..0b23561 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1889,4 +1889,34 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}
+int ieee802_11_start_channel_switch(struct hostapd_data *hapd,
+ int freq, u8 radar_detected)
+{
+ struct hostapd_channel_data *next_channel;
+
+ next_channel = hostapd_get_valid_channel(hapd, freq);
+ if (!next_channel)
+ return -1;
+
+ hapd->next_channel = next_channel;
+ u8 radar_on_next_channel =
+ (next_channel->flag & HOSTAPD_CHAN_RADAR) ? 1 : 0;
+ wpa_printf(MSG_INFO, "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;
+ }
+ return 0;
+}
+
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b25b4b9..6446593 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3060,7 +3060,12 @@ enum wpa_event_type {
*
* Described in wpa_event_data.ch_switch
* */
- EVENT_CH_SWITCH
+ EVENT_CH_SWITCH,
+
+ /**
+ * EVENT_REQ_CH_SW - a request to perform a channel switch for GO/AP
+ */
+ EVENT_REQ_CH_SW
};
@@ -3723,6 +3728,8 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
/* driver_common.c */
void wpa_scan_results_free(struct wpa_scan_results *res);
+int ieee802_11_start_channel_switch(struct hostapd_data *hapd,
+ int freq, u8 radar_detected);
/* Convert wpa_event_type to a string for logging */
const char * event_to_string(enum wpa_event_type event);
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 5e4dc89..a0ada97 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -82,6 +82,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(ROAMING_ENABLED);
E2S(ROAMING_DISABLED);
E2S(START_ROAMING);
+ E2S(REQ_CH_SW);
}
return "UNKNOWN";
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 56ae94c..c3e9ed6 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2556,6 +2556,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->ch_switch.ch_offset);
#endif /* CONFIG_AP */
break;
+ case EVENT_REQ_CH_SW:
+ if (!data)
+ break;
+ ieee802_11_start_channel_switch(wpa_s->ap_iface->bss[0],
+ data->ch_switch.freq, FALSE);
+ break;
case EVENT_RX_MGMT: {
u16 fc, stype;
const struct ieee80211_mgmt *mgmt;