[PATCH 1/4] nl80211/hostap: extend channel switch notify handling
Janusz Dziedzic
janusz.dziedzic
Mon Nov 25 11:16:12 PST 2013
Adds support for VHT by parsing bandwidth and
center_freq{1,2}.
Signed-hostap: Michal Kazior <michal.kazior at tieto.com>
Signed-hostap: Janusz Dziedzic <janusz.dziedzic at tieto.com>
---
src/ap/drv_callbacks.c | 47 ++++++++++++++++--
src/ap/hostapd.h | 2 +-
src/drivers/driver.h | 6 +++
src/drivers/driver_nl80211.c | 113 ++++++++++++++++++++++++++----------------
wpa_supplicant/ap.c | 4 +-
wpa_supplicant/ap.h | 2 +-
wpa_supplicant/events.c | 5 +-
7 files changed, 126 insertions(+), 53 deletions(-)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 1b69ba8..e092132 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -381,14 +381,14 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset)
+ int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
- int channel;
-
+ int channel, chwidth, seg0_idx=0, seg1_idx=0;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "driver had channel switch: "
- "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+ "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
+ freq, ht, offset, width, cf1, cf2);
hapd->iface->freq = freq;
@@ -400,9 +400,43 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
return;
}
+ switch (width) {
+ case CHAN_WIDTH_80:
+ chwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case CHAN_WIDTH_80P80:
+ chwidth = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case CHAN_WIDTH_160:
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ case CHAN_WIDTH_40:
+ default:
+ chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ switch (hapd->iface->current_mode->mode) {
+ case HOSTAPD_MODE_IEEE80211A:
+ if (cf1 > 5000)
+ seg0_idx = (cf1 - 5000) / 5;
+ if (cf2 > 5000)
+ seg1_idx = (cf2 - 5000) / 5;
+ break;
+ default:
+ seg0_idx = hostapd_hw_get_channel(hapd, cf1);
+ seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+ break;
+ }
+
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
hapd->iconf->secondary_channel = offset;
+ hapd->iconf->vht_oper_chwidth = chwidth;
+ hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
+ hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
if (hapd->iface->csa_in_progress && freq == hapd->iface->cs_freq) {
hostapd_cleanup_cs_params(hapd);
@@ -976,7 +1010,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_ch_switch(hapd, data->ch_switch.freq,
data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset);
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
break;
case EVENT_CONNECT_FAILED_REASON:
if (!data)
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index c25917d..932fe63 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -414,7 +414,7 @@ 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,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset);
+ int offset, int width, int cf1, int cf2);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 3502eb8..a3602ed 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -4028,11 +4028,17 @@ union wpa_event_data {
* @freq: Frequency of new channel in MHz
* @ht_enabled: Whether this is an HT channel
* @ch_offset: Secondary channel offset
+ * @ch_width: Channel width
+ * @cf1: Center frequency 1
+ * @cf2: Center frequency 2
*/
struct ch_switch {
int freq;
int ht_enabled;
int ch_offset;
+ enum chan_width ch_width;
+ int cf1;
+ int cf2;
} ch_switch;
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index eaca172..f8bcbd1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -504,6 +504,27 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
}
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+ switch (width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ return CHAN_WIDTH_20_NOHT;
+ case NL80211_CHAN_WIDTH_20:
+ return CHAN_WIDTH_20;
+ case NL80211_CHAN_WIDTH_40:
+ return CHAN_WIDTH_40;
+ case NL80211_CHAN_WIDTH_80:
+ return CHAN_WIDTH_80;
+ case NL80211_CHAN_WIDTH_80P80:
+ return CHAN_WIDTH_80P80;
+ case NL80211_CHAN_WIDTH_160:
+ return CHAN_WIDTH_160;
+ }
+ return CHAN_WIDTH_UNKNOWN;
+}
+
+
static int is_ap_interface(enum nl80211_iftype nlmode)
{
return (nlmode == NL80211_IFTYPE_AP ||
@@ -1484,36 +1505,59 @@ 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 *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
{
+ struct i802_bss *bss;
union wpa_event_data data;
int ht_enabled = 1;
int chan_offset = 0;
+ int ifidx;
wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
- if (!freq || !type)
+ if (!freq)
return;
- switch (nla_get_u32(type)) {
- case NL80211_CHAN_NO_HT:
- ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- chan_offset = -1;
- break;
+ ifidx = nla_get_u32(ifindex);
+ for (bss = drv->first_bss; bss; bss = bss->next)
+ if (bss->ifindex == ifidx)
+ break;
+
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
+ }
+
+ if (type) {
+ switch (nla_get_u32(type)) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
}
data.ch_switch.freq = nla_get_u32(freq);
data.ch_switch.ht_enabled = ht_enabled;
data.ch_switch.ch_offset = chan_offset;
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ data.ch_switch.cf2 = 0;
+
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
- drv->first_bss->freq = data.ch_switch.freq;
+ bss->freq = data.ch_switch.freq;
wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
}
@@ -2534,8 +2578,6 @@ static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
}
-static enum chan_width convert2width(int width);
-
static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
@@ -2702,8 +2744,13 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
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]);
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2]);
break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -10020,27 +10067,6 @@ nla_put_failure:
}
-/* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
-{
- switch (width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- return CHAN_WIDTH_20_NOHT;
- case NL80211_CHAN_WIDTH_20:
- return CHAN_WIDTH_20;
- case NL80211_CHAN_WIDTH_40:
- return CHAN_WIDTH_40;
- case NL80211_CHAN_WIDTH_80:
- return CHAN_WIDTH_80;
- case NL80211_CHAN_WIDTH_80P80:
- return CHAN_WIDTH_80P80;
- case NL80211_CHAN_WIDTH_160:
- return CHAN_WIDTH_160;
- }
- return CHAN_WIDTH_UNKNOWN;
-}
-
-
static int get_channel_width(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -11288,9 +11314,10 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
struct nlattr *beacon_csa;
int ret = -ENOBUFS;
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d)",
- settings->cs_count, settings->block_tx,
- settings->freq_params.freq);
+ 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,
+ settings->freq_params.freq, settings->freq_params.bandwidth,
+ settings->freq_params.center_freq1, settings->freq_params.center_freq2);
if (!drv->channel_switch_supported) {
wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index cbe67a4..394ab30 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1085,13 +1085,13 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset)
+ int offset, int width, int cf1, int cf2)
{
if (!wpa_s->ap_iface)
return;
wpa_s->assoc_freq = freq;
- hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+ hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
}
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 33a3d0f..c382898 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -54,7 +54,7 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s,
struct csa_settings *settings);
int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset);
+ int offset, int width, int cf1, int cf2);
struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef);
#ifdef CONFIG_AP
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 35712e5..bcb1cbc 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2918,7 +2918,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset);
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
break;
#endif /* CONFIG_AP */
#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
--
1.7.9.5
More information about the Hostap
mailing list