From 6315bfdba2ecf6bd6b1d0a7814efff63869dbf93 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 8 Sep 2015 12:46:15 +0300 Subject: [PATCH] Add support for eCSA Extended channel switch provides an ability to switch between operating classes and is required for P2P Devices by the P2P specification when switching in 5 GHz. When the operating class is provided for channel switch, the AP/P2P GO will use eCSA IE in addition to the regular CSA IE both on 2.4 GHz and 5 GHz bands. Transitions between different hw_modes are not supported. Signed-off-by: Andrei Otcheretianski --- src/ap/beacon.c | 57 ++++++++++++++++++++++++++++++++++---------- src/ap/hostapd.c | 4 ++++ src/ap/hostapd.h | 5 ++++ src/ap/ieee802_11_shared.c | 2 ++ src/common/ieee802_11_defs.h | 1 + 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/ap/beacon.c b/src/ap/beacon.c index ea6b009..f9bbf1a 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -310,6 +310,22 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) } +static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid) +{ + if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class) + return eid; + + *eid++ = WLAN_EID_EXT_CHANSWITCH_ANN; + *eid++ = 4; + *eid++ = hapd->cs_block_tx; + *eid++ = hapd->iface->cs_oper_class; + *eid++ = hapd->cs_freq_params.channel; + *eid++ = hapd->cs_count; + + return eid; +} + + static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) { u8 sec_ch; @@ -333,26 +349,39 @@ static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, - u8 *start, unsigned int *csa_counter_off) + u8 *start, unsigned int *csa_counter_off, + unsigned int *ecsa_counter_off) { - u8 *old_pos = pos; + u8 *curr_pos = pos; + u8 *csa_pos = pos; - if (!csa_counter_off) + if (!csa_counter_off || !ecsa_counter_off) return pos; *csa_counter_off = 0; - pos = hostapd_eid_csa(hapd, pos); + *ecsa_counter_off = 0; + + curr_pos = hostapd_eid_csa(hapd, curr_pos); + + /* save an offset to the csa counter - should be last byte */ + if (curr_pos != pos) + *csa_counter_off = curr_pos - start - 1; - if (pos != old_pos) { - /* save an offset to the counter - should be last byte */ - *csa_counter_off = pos - start - 1; - pos = hostapd_eid_secondary_channel(hapd, pos); + csa_pos = curr_pos; + curr_pos = hostapd_eid_ecsa(hapd, curr_pos); + + /* save an offset to the eCSA counter - should be last byte */ + if (curr_pos != csa_pos) + *ecsa_counter_off = curr_pos - start - 1; + + /* at least one of ies is added */ + if (pos != curr_pos) { + curr_pos = hostapd_eid_secondary_channel(hapd, curr_pos); #ifdef CONFIG_IEEE80211AC - pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); + curr_pos = hostapd_eid_wb_chsw_wrapper(hapd, curr_pos); #endif /* CONFIG_IEEE80211AC */ } - - return pos; + return curr_pos; } @@ -449,7 +478,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_roaming_consortium(hapd, pos); pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, - &hapd->cs_c_off_proberesp); + &hapd->cs_c_off_proberesp, + &hapd->cs_c_off_ecsa_proberesp); #ifdef CONFIG_FST if (hapd->iface->fst_ies) { @@ -1018,7 +1048,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_adv_proto(hapd, tailpos); tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, - &hapd->cs_c_off_beacon); + &hapd->cs_c_off_beacon, + &hapd->cs_c_off_ecsa_beacon); #ifdef CONFIG_FST if (hapd->iface->fst_ies) { diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 89bfe5b..bf16e74 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2850,6 +2850,8 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon; settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; + settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; + settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp; return 0; } @@ -2863,6 +2865,8 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd) hapd->cs_c_off_beacon = 0; hapd->cs_c_off_proberesp = 0; hapd->csa_in_progress = 0; + hapd->cs_c_off_ecsa_beacon = 0; + hapd->cs_c_off_ecsa_proberesp = 0; } diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index dcf51f0..ffc4533 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -228,6 +228,8 @@ struct hostapd_data { unsigned int cs_c_off_beacon; unsigned int cs_c_off_proberesp; int csa_in_progress; + unsigned int cs_c_off_ecsa_beacon; + unsigned int cs_c_off_ecsa_proberesp; /* BSS Load */ unsigned int bss_load_update_timeout; @@ -402,6 +404,9 @@ struct hostapd_iface { u64 last_channel_time_busy; u8 channel_utilization; + /* eCSA IE will be added only if operating class is specified */ + u8 cs_oper_class; + unsigned int dfs_cac_ms; struct os_reltime dfs_cac_start; diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index d462ac8..9e3363e 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -172,6 +172,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) case 0: /* Bits 0-7 */ if (hapd->iconf->obss_interval) *pos |= 0x01; /* Bit 0 - Coexistence management */ + if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) + *pos |= 0x04; /* Bit 2 - Extended Channel Switching */ break; case 1: /* Bits 8-15 */ if (hapd->conf->proxy_arp) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 44530ce..cc67658 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -247,6 +247,7 @@ #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 #define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59 +#define WLAN_EID_EXT_CHANSWITCH_ANN 60 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_WAPI 68 -- 2.1.4