Parcourir la source

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 <andrei.otcheretianski@intel.com>
Andrei Otcheretianski il y a 9 ans
Parent
commit
6315bfdba2
5 fichiers modifiés avec 56 ajouts et 13 suppressions
  1. 44 13
      src/ap/beacon.c
  2. 4 0
      src/ap/hostapd.c
  3. 5 0
      src/ap/hostapd.h
  4. 2 0
      src/ap/ieee802_11_shared.c
  5. 1 0
      src/common/ieee802_11_defs.h

+ 44 - 13
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) {

+ 4 - 0
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;
 }
 
 

+ 5 - 0
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;
 

+ 2 - 0
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)

+ 1 - 0
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