[PATCH 04/14] ap/nl80211: Suppport multiple CS counters
Ilan Peer
ilan.peer
Mon May 19 00:07:06 PDT 2014
From: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
Channel switch may be performed using both CSA and eCSA IEs together. This
may happen, for example with GO on band A with legacy clients.
Extend driver API to support up to 2 CSA counters.
This patch also includes the required implementation for cfg80211/nl80211.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/ap/hostapd.c | 4 +--
src/drivers/driver.h | 7 ++--
src/drivers/driver_nl80211.c | 74 +++++++++++++++++++++++++++++++++---------
3 files changed, 66 insertions(+), 19 deletions(-)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index e5a75ab..72f2b24 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2355,8 +2355,8 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
return ret;
}
- settings->counter_offset_beacon = iface->cs_c_off_beacon;
- settings->counter_offset_presp = iface->cs_c_off_proberesp;
+ settings->counter_offset_beacon[0] = iface->cs_c_off_beacon;
+ settings->counter_offset_presp[0] = iface->cs_c_off_proberesp;
return 0;
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index bb9dec5..6f42e26 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1046,6 +1046,9 @@ struct wpa_driver_capa {
unsigned int extended_capa_len;
struct wowlan_triggers wowlan_triggers;
+
+ /* maximum number of supported csa counters */
+ u16 max_csa_counters;
};
@@ -1296,8 +1299,8 @@ struct csa_settings {
struct beacon_data beacon_csa;
struct beacon_data beacon_after;
- u16 counter_offset_beacon;
- u16 counter_offset_presp;
+ u16 counter_offset_beacon[2];
+ u16 counter_offset_presp[2];
};
/* TDLS peer capabilities for send_tdls_mgmt() */
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 67332d9..d397ccd 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3855,6 +3855,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
capa->max_stations =
nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
+ /* TODO: get the number of counters from the kernel */
+ capa->max_csa_counters = 1;
+
return NL_SKIP;
}
@@ -11950,6 +11953,8 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nlattr *beacon_csa;
int ret = -ENOBUFS;
+ int csa_off_len = 0;
+ int i;
wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
settings->cs_count, settings->block_tx,
@@ -11966,20 +11971,58 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
(drv->nlmode != NL80211_IFTYPE_P2P_GO))
return -EOPNOTSUPP;
- /* check settings validity */
- if (!settings->beacon_csa.tail ||
- ((settings->beacon_csa.tail_len <=
- settings->counter_offset_beacon) ||
- (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
- settings->cs_count)))
+ /*
+ * Remove empty counters, assuming probe
+ * response and beacons counters match.
+ * This implementation assumes that there are only 2 counters.
+ */
+ if (settings->counter_offset_beacon[0] &&
+ !settings->counter_offset_beacon[1]) {
+ csa_off_len = 1;
+ } else if (settings->counter_offset_beacon[1] &&
+ !settings->counter_offset_beacon[0]) {
+ csa_off_len = 1;
+ settings->counter_offset_beacon[0] =
+ settings->counter_offset_beacon[1];
+ settings->counter_offset_presp[0] =
+ settings->counter_offset_presp[1];
+ } else if (settings->counter_offset_beacon[1] &&
+ settings->counter_offset_beacon[0]) {
+ csa_off_len = 2;
+ } else {
+ wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
return -EINVAL;
+ }
- if (settings->beacon_csa.probe_resp &&
- ((settings->beacon_csa.probe_resp_len <=
- settings->counter_offset_presp) ||
- (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
- settings->cs_count)))
+ /* check CSA counters validity */
+ if (drv->capa.max_csa_counters &&
+ csa_off_len > drv->capa.max_csa_counters) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Too many CSA counters provided");
return -EINVAL;
+ }
+
+ if (!settings->beacon_csa.tail)
+ return -EINVAL;
+
+ for (i = 0; i < csa_off_len; i++) {
+ u16 csa_c_off_bcn =
+ settings->counter_offset_beacon[i];
+ u16 csa_c_off_presp =
+ settings->counter_offset_presp[i];
+
+ if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
+ (settings->beacon_csa.tail[csa_c_off_bcn] !=
+ settings->cs_count))
+ return -EINVAL;
+
+ if (settings->beacon_csa.probe_resp &&
+ ((settings->beacon_csa.probe_resp_len <=
+ csa_c_off_presp) ||
+ (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
+ settings->cs_count)))
+ return -EINVAL;
+ }
msg = nlmsg_alloc();
if (!msg)
@@ -12009,12 +12052,13 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
if (ret)
goto error;
- NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
- settings->counter_offset_beacon);
+ NLA_PUT(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+ csa_off_len * sizeof(u16), settings->counter_offset_beacon);
if (settings->beacon_csa.probe_resp)
- NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
- settings->counter_offset_presp);
+ NLA_PUT(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+ csa_off_len * sizeof(u16),
+ settings->counter_offset_presp);
nla_nest_end(msg, beacon_csa);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
--
1.7.10.4
More information about the Hostap
mailing list