[PATCH 3/4] wpa_supplicant: Add AP channel switch mechanism
Ilan Peer
ilan.peer
Thu Nov 14 02:28:31 PST 2013
From: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
Build CSA settings and call the driver to perform the switch.
Construct beacon, probe resp. and assoc resp. frames both for
CSA period and for the new channel. These frames are
built based on the current configuration.
Add CSA IE in beacons and probe resp
Signed-hostap: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/ap/ap_drv_ops.h | 9 ++
src/ap/beacon.c | 157 ++++++++++++++++++++----------
src/ap/beacon.h | 4 +
src/ap/drv_callbacks.c | 8 ++
src/ap/hostapd.c | 217 ++++++++++++++++++++++++++++++++++++++++++
src/ap/hostapd.h | 17 ++++
src/common/ieee802_11_defs.h | 4 +
src/common/wpa_ctrl.h | 2 +
src/drivers/driver.h | 6 +-
wpa_supplicant/ap.c | 8 ++
wpa_supplicant/ap.h | 3 +
11 files changed, 382 insertions(+), 53 deletions(-)
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index ce2bb91..5a696ad 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -257,4 +257,13 @@ static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
return hapd->driver->get_radio_name(hapd->drv_priv);
}
+static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
+ struct csa_settings *settings)
+{
+ if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
+ return -ENOTSUP;
+
+ return hapd->driver->switch_channel(hapd->drv_priv, settings);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 6c8b78f..4722198 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -202,6 +202,25 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
return eid + ielen;
}
+static u8 *hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 chan;
+ if (!hapd->iface->cs_freq)
+ return eid;
+
+ if (ieee80211_freq_to_chan(hapd->iface->cs_freq, &chan) ==
+ NUM_HOSTAPD_MODES)
+ return eid;
+
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3;
+ *eid++ = hapd->iface->cs_block_tx;
+ *eid++ = chan;
+ *eid++ = hapd->iface->cs_count;
+
+ return eid;
+}
+
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
struct sta_info *sta,
@@ -209,7 +228,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
int is_p2p, size_t *resp_len)
{
struct ieee80211_mgmt *resp;
- u8 *pos, *epos;
+ u8 *pos, *epos, *old_pos;
size_t buflen;
#define MAX_PROBERESP_LEN 768
@@ -283,6 +302,14 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
+ old_pos = pos;
+ pos = hostapd_eid_csa(hapd, pos);
+
+ /* save an offset to the counter - should be last byte */
+ hapd->iface->cs_c_off_proberesp = (pos != old_pos) ?
+ (unsigned int)pos - 1 -
+ (unsigned int)resp : 0;
+
#ifdef CONFIG_IEEE80211AC
pos = hostapd_eid_vht_capabilities(hapd, pos);
pos = hostapd_eid_vht_operation(hapd, pos);
@@ -587,23 +614,20 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
-
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
{
struct ieee80211_mgmt *head = NULL;
u8 *tail = NULL;
size_t head_len = 0, tail_len = 0;
u8 *resp = NULL;
size_t resp_len = 0;
- struct wpa_driver_ap_params params;
- struct wpabuf *beacon, *proberesp, *assocresp;
+
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos;
+ u8 *pos, *tailpos, *old_pos;
#endif /* NEED_AP_MLME */
- hapd->beacon_set_done = 1;
-
#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
@@ -625,7 +649,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
wpa_printf(MSG_ERROR, "Failed to set beacon data");
os_free(head);
os_free(tail);
- return;
+ return -1;
}
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -699,6 +723,11 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_interworking(hapd, tailpos);
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+ old_pos = tailpos;
+ tailpos = hostapd_eid_csa(hapd, tailpos);
+ hapd->iface->cs_c_off_beacon = (old_pos != tailpos) ?
+ (unsigned int)tailpos - 1 -
+ (unsigned int)tail : 0;
#ifdef CONFIG_IEEE80211AC
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
@@ -744,76 +773,104 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
#endif /* NEED_AP_MLME */
- os_memset(¶ms, 0, sizeof(params));
- params.head = (u8 *) head;
- params.head_len = head_len;
- params.tail = tail;
- params.tail_len = tail_len;
- params.proberesp = resp;
- params.proberesp_len = resp_len;
- params.dtim_period = hapd->conf->dtim_period;
- params.beacon_int = hapd->iconf->beacon_int;
- params.basic_rates = hapd->iface->basic_rates;
- params.ssid = hapd->conf->ssid.ssid;
- params.ssid_len = hapd->conf->ssid.ssid_len;
- params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+ os_memset(params, 0, sizeof(*params));
+ params->head = (u8 *)head;
+ params->head_len = head_len;
+ params->tail = tail;
+ params->tail_len = tail_len;
+ params->proberesp = resp;
+ params->proberesp_len = resp_len;
+ params->dtim_period = hapd->conf->dtim_period;
+ params->beacon_int = hapd->iconf->beacon_int;
+ params->basic_rates = hapd->iface->basic_rates;
+ params->ssid = hapd->conf->ssid.ssid;
+ params->ssid_len = hapd->conf->ssid.ssid_len;
+ params->pairwise_ciphers = hapd->conf->rsn_pairwise ?
hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
- params.group_cipher = hapd->conf->wpa_group;
- params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
- params.auth_algs = hapd->conf->auth_algs;
- params.wpa_version = hapd->conf->wpa;
- params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ params->group_cipher = hapd->conf->wpa_group;
+ params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+ params->auth_algs = hapd->conf->auth_algs;
+ params->wpa_version = hapd->conf->wpa;
+ params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
- params.hide_ssid = NO_SSID_HIDING;
+ params->hide_ssid = NO_SSID_HIDING;
break;
case 1:
- params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+ params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
break;
case 2:
- params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+ params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
break;
}
- hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
- params.beacon_ies = beacon;
- params.proberesp_ies = proberesp;
- params.assocresp_ies = assocresp;
- params.isolate = hapd->conf->isolate;
+ params->isolate = hapd->conf->isolate;
#ifdef NEED_AP_MLME
- params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+ params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
- params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+ params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
hapd->iconf->preamble == SHORT_PREAMBLE;
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
- params.short_slot_time =
+ params->short_slot_time =
hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
else
- params.short_slot_time = -1;
+ params->short_slot_time = -1;
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
- params.ht_opmode = -1;
+ params->ht_opmode = -1;
else
- params.ht_opmode = hapd->iface->ht_op_mode;
+ params->ht_opmode = hapd->iface->ht_op_mode;
#endif /* NEED_AP_MLME */
- params.interworking = hapd->conf->interworking;
+ params->interworking = hapd->conf->interworking;
if (hapd->conf->interworking &&
!is_zero_ether_addr(hapd->conf->hessid))
- params.hessid = hapd->conf->hessid;
- params.access_network_type = hapd->conf->access_network_type;
- params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+ params->hessid = hapd->conf->hessid;
+ params->access_network_type = hapd->conf->access_network_type;
+ params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
#ifdef CONFIG_HS20
- params.disable_dgaf = hapd->conf->disable_dgaf;
+ params->disable_dgaf = hapd->conf->disable_dgaf;
#endif /* CONFIG_HS20 */
+ return 0;
+}
+
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
+{
+ os_free(params->tail);
+ os_free(params->head);
+ os_free(params->proberesp);
+}
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+ struct wpa_driver_ap_params params;
+ struct wpabuf *beacon, *proberesp, *assocresp;
+
+ if (hapd->iface->csa_in_progress) {
+ wpa_printf(MSG_ERROR, "Can't set beacons during CSA period");
+ return;
+ }
+
+ hapd->beacon_set_done = 1;
+
+ if (ieee802_11_build_ap_params(hapd, ¶ms) < 0)
+ return;
+
+ if (hostapd_build_ap_extra_ies(hapd, &beacon,
+ &proberesp, &assocresp) < 0)
+ goto fail;
+
+ params.beacon_ies = beacon;
+ params.proberesp_ies = proberesp;
+ params.assocresp_ies = assocresp;
+
if (hostapd_drv_set_ap(hapd, ¶ms))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
- hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
- os_free(tail);
- os_free(head);
- os_free(resp);
+ hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+fail:
+ ieee802_11_free_ap_params(¶ms);
}
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index 37f10d2..cb72635 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -24,5 +24,9 @@ void handle_probe_req(struct hostapd_data *hapd,
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
void ieee802_11_update_beacons(struct hostapd_iface *iface);
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params);
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
+
#endif /* BEACON_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 0f4b12e..5d57499 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -403,6 +403,14 @@ 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->csa_in_progress &&
+ (freq == hapd->iface->cs_freq)) {
+ hostapd_cleanup_cs_params(hapd);
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED " freq: %d",
+ freq);
+ }
#endif /* NEED_AP_MLME */
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 60224cc..fe67726 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2014,3 +2014,220 @@ void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
hostapd_state_text(s));
iface->state = s;
}
+
+static inline void free_beacon_data(struct beacon_data *beacon)
+{
+ os_free(beacon->head);
+ os_free(beacon->tail);
+ os_free(beacon->probe_resp);
+ os_free(beacon->beacon_ies);
+ os_free(beacon->proberesp_ies);
+ os_free(beacon->assocresp_ies);
+}
+
+static int hostapd_build_beacon_data(struct hostapd_iface *iface,
+ struct beacon_data *beacon)
+{
+ struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
+ struct wpa_driver_ap_params params;
+ int ret;
+ struct hostapd_data *hapd = iface->bss[0];
+
+ ret = ieee802_11_build_ap_params(hapd, ¶ms);
+ if (ret < 0)
+ return ret;
+
+ ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
+ &proberesp_extra,
+ &assocresp_extra);
+ if (ret)
+ goto free_ap_params;
+
+ ret = -1;
+ beacon->head = os_malloc(params.head_len);
+ if (!beacon->head)
+ goto free_ap_extra_ies;
+
+ os_memcpy(beacon->head, params.head, params.head_len);
+ beacon->head_len = params.head_len;
+
+ beacon->tail = os_malloc(params.tail_len);
+ if (!beacon->tail)
+ goto free_beacon;
+
+ os_memcpy(beacon->tail, params.tail, params.tail_len);
+ beacon->tail_len = params.tail_len;
+
+ if (params.proberesp != NULL) {
+ beacon->probe_resp = os_malloc(params.proberesp_len);
+ if (!beacon->probe_resp)
+ goto free_beacon;
+
+ os_memcpy(beacon->probe_resp, params.proberesp,
+ params.proberesp_len);
+ beacon->probe_resp_len = params.proberesp_len;
+ }
+
+ /* copy the extra ies */
+ if (beacon_extra) {
+ beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
+ if (!beacon->beacon_ies)
+ goto free_beacon;
+
+ os_memcpy(beacon->beacon_ies,
+ beacon_extra->buf, wpabuf_len(beacon_extra));
+ beacon->beacon_ies_len = wpabuf_len(beacon_extra);
+ }
+
+ if (proberesp_extra) {
+ beacon->proberesp_ies =
+ os_malloc(wpabuf_len(proberesp_extra));
+ if (!beacon->proberesp_ies)
+ goto free_beacon;
+
+ os_memcpy(beacon->proberesp_ies,
+ proberesp_extra->buf, wpabuf_len(proberesp_extra));
+ beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
+ }
+
+ if (assocresp_extra) {
+ beacon->assocresp_ies =
+ os_malloc(wpabuf_len(assocresp_extra));
+ if (!beacon->assocresp_ies)
+ goto free_beacon;
+
+ os_memcpy(beacon->assocresp_ies,
+ assocresp_extra->buf, wpabuf_len(assocresp_extra));
+ beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
+ }
+
+ ret = 0;
+free_beacon:
+ /* if the function fails, the caller should not free beacon data */
+ if (ret)
+ free_beacon_data(beacon);
+
+free_ap_extra_ies:
+ hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
+ assocresp_extra);
+free_ap_params:
+ ieee802_11_free_ap_params(¶ms);
+ return ret;
+}
+
+/*
+ * TODO: this flow currently supports only changing frequency within the
+ * same hw_mode. Any other changes to mac parameters or provided
+ * settings (even width) are not supported.
+ */
+static int hostapd_change_config_freq(struct hostapd_data *hapd,
+ struct hostapd_config *conf,
+ struct hostapd_freq_params *params,
+ struct hostapd_freq_params *old_params)
+{
+ int channel;
+
+ if (!params->channel) {
+ /* check if the new channel is supported by hw */
+ channel = hostapd_hw_get_channel(hapd, params->freq);
+ if (!channel)
+ return -1;
+ } else {
+ channel = params->channel;
+ }
+
+ /* if a pointer to old_params is provided we save previous state */
+ if (old_params) {
+ old_params->channel = conf->channel;
+ old_params->ht_enabled = conf->ieee80211n;
+ old_params->sec_channel_offset = conf->secondary_channel;
+ }
+
+ conf->channel = channel;
+ conf->ieee80211n = params->ht_enabled;
+ conf->secondary_channel = params->sec_channel_offset;
+
+ /* TODO: maybe call here hostapd_config_check here? */
+
+ return 0;
+}
+
+int hostapd_fill_csa_settings(struct hostapd_iface *iface,
+ struct csa_settings *settings)
+{
+ struct hostapd_freq_params old_freq;
+ int ret;
+
+ os_memset(&old_freq, 0, sizeof(old_freq));
+ if (!iface || !iface->freq || iface->csa_in_progress)
+ return -1;
+
+ ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
+ &settings->freq_params,
+ &old_freq);
+ if (ret)
+ return ret;
+
+ ret = hostapd_build_beacon_data(iface, &settings->beacon_after);
+
+ /* change back the configuration */
+ hostapd_change_config_freq(iface->bss[0], iface->conf,
+ &old_freq, NULL);
+
+ if (ret)
+ return ret;
+
+ /* set channel switch parameters for csa ie */
+ iface->cs_freq = settings->freq_params.freq;
+ iface->cs_count = settings->cs_count;
+ iface->cs_block_tx = settings->block_tx;
+
+ ret = hostapd_build_beacon_data(iface, &settings->beacon_csa);
+ if (ret) {
+ free_beacon_data(&settings->beacon_after);
+ return ret;
+ }
+
+ settings->counter_offset_beacon = iface->cs_c_off_beacon;
+ settings->counter_offset_presp = iface->cs_c_off_proberesp;
+
+ return 0;
+}
+
+void hostapd_free_csa_settings(struct csa_settings *settings)
+{
+ free_beacon_data(&settings->beacon_csa);
+ free_beacon_data(&settings->beacon_after);
+}
+
+
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
+{
+ hapd->iface->cs_freq = 0;
+ hapd->iface->cs_count = 0;
+ hapd->iface->cs_block_tx = 0;
+ hapd->iface->cs_c_off_beacon = 0;
+ hapd->iface->cs_c_off_proberesp = 0;
+ hapd->iface->csa_in_progress = 0;
+}
+
+int hostapd_switch_channel(struct hostapd_data *hapd,
+ struct csa_settings *settings)
+{
+ int ret;
+ ret = hostapd_fill_csa_settings(hapd->iface, settings);
+ if (ret)
+ return ret;
+
+ ret = hostapd_drv_switch_channel(hapd, settings);
+ hostapd_free_csa_settings(settings);
+
+ if (!ret)
+ hapd->iface->csa_in_progress = 1;
+ else
+ /* if we failed, clean cs parameters */
+ hostapd_cleanup_cs_params(hapd);
+
+ return ret;
+}
+
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 1887531..2b87f39 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -27,6 +27,8 @@ union wps_event_data;
struct hostapd_iface;
struct hostapd_dynamic_iface;
+struct csa_settings;
+
struct hapd_interfaces {
int (*reload_config)(struct hostapd_iface *iface);
struct hostapd_config * (*config_read_cb)(const char *config_fname);
@@ -332,6 +334,14 @@ struct hostapd_iface {
/* lowest observed noise floor in dBm */
s8 lowest_nf;
+ /* channel switch parameters */
+ int cs_freq;
+ u8 cs_count;
+ int cs_block_tx;
+ unsigned int cs_c_off_beacon;
+ unsigned int cs_c_off_proberesp;
+ int csa_in_progress;
+
#ifdef CONFIG_ACS
unsigned int acs_num_completed_scans;
#endif /* CONFIG_ACS */
@@ -378,6 +388,13 @@ int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
+int hostapd_fill_csa_settings(struct hostapd_iface *iface,
+ struct csa_settings *settings);
+void hostapd_free_csa_settings(struct csa_settings *settings);
+int hostapd_switch_channel(struct hostapd_data *hapd,
+ struct csa_settings *settings);
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
+
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index ca122d9..9b2d54f 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1157,4 +1157,8 @@ enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_IGTK = 1
};
+/* Channel Switch modes (802.11h) */
+#define CHAN_SWITCH_MODE_ALLOW_TX 0
+#define CHAN_SWITCH_MODE_BLOCK_TX 1
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 0b6e395..7705479 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -176,6 +176,8 @@ extern "C" {
#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
+#define AP_CSA_FINISHED "AP-CSA-FINISHED"
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index c9a0a3a..b5e53c4 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -627,7 +627,7 @@ struct wpa_driver_ap_params {
/**
* head - Beacon head from IEEE 802.11 header to IEs before TIM IE
*/
- const u8 *head;
+ u8 *head;
/**
* head_len - Length of the head buffer in octets
@@ -637,7 +637,7 @@ struct wpa_driver_ap_params {
/**
* tail - Beacon tail following TIM IE
*/
- const u8 *tail;
+ u8 *tail;
/**
* tail_len - Length of the tail buffer in octets
@@ -668,7 +668,7 @@ struct wpa_driver_ap_params {
* This is used by drivers that reply to Probe Requests internally in
* AP mode and require the full Probe Response template.
*/
- const u8 *proberesp;
+ u8 *proberesp;
/**
* proberesp_len - Length of the proberesp buffer in octets
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6887469..38cfe2f 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1057,6 +1057,14 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
return 0;
}
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return -1;
+
+ return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+}
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
int offset)
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 74a0b18..00acbed 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -66,4 +66,7 @@ wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_AP */
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings);
+
#endif /* AP_H */
--
1.7.10.4
More information about the Hostap
mailing list