[PATCH 09/26] wpa_supplicant: Implement wpas_p2p_move_go_csa()

Ilan Peer ilan.peer
Tue Sep 8 02:46:16 PDT 2015


From: Andrei Otcheretianski <andrei.otcheretianski at intel.com>

Use channel switch mechanism to move a P2P GO to a new channel,
when required. In order to be able to reconfigure the GO channel,
split wpa_supplicant_conf_ap() function, so the frequency
configuration part can be reused to find additional CSA settings.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 wpa_supplicant/ap.c             |  27 ++++-----
 wpa_supplicant/ap.h             |   7 ++-
 wpa_supplicant/p2p_supplicant.c | 118 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 133 insertions(+), 19 deletions(-)

diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6d43619..f8e2c1d 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -75,11 +75,19 @@ no_vht:
 }
 #endif /* CONFIG_IEEE80211N */
 
-
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
-			       struct wpa_ssid *ssid,
-			       struct hostapd_config *conf)
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid,
+			      struct hostapd_config *conf)
 {
+	conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+					       &conf->channel);
+
+	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+			   ssid->frequency);
+		return -1;
+	}
+
 	/* TODO: enable HT40 if driver supports it;
 	 * drop to 11b if driver does not support 11g */
 
@@ -166,6 +174,7 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
 		}
 	}
 #endif /* CONFIG_IEEE80211N */
+	return 0;
 }
 
 
@@ -176,18 +185,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 	struct hostapd_bss_config *bss = conf->bss[0];
 
 	conf->driver = wpa_s->driver;
-
 	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
 
-	conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
-					       &conf->channel);
-	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
-		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
-			   ssid->frequency);
+	if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
 		return -1;
-	}
-
-	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
 
 	if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
 		conf->ieee80211h = 1;
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 594168c..b4bbaa4 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -10,6 +10,7 @@
 #ifndef AP_H
 #define AP_H
 
+struct hostapd_config;
 int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 			     struct wpa_ssid *ssid);
 void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
@@ -76,9 +77,9 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
 			   const struct wpabuf *pw, const u8 *pubkey_hash);
 
 struct hostapd_config;
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
-			       struct wpa_ssid *ssid,
-			       struct hostapd_config *conf);
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid,
+			      struct hostapd_config *conf);
 
 int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index b87624a..b1cc344 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -53,6 +53,13 @@
  */
 #define P2P_GO_FREQ_CHANGE_TIME 5
 
+/**
+ * Defines CSA parameters which are used when GO evacuates the no longer valid
+ * channel (and if the driver supports channel switch)
+ */
+#define P2P_GO_CSA_COUNT 7
+#define P2P_GO_CSA_BLOCK_TX 0
+
 #ifndef P2P_MAX_CLIENT_IDLE
 /*
  * How many seconds to try to reconnect to the GO when connection in P2P client
@@ -8469,14 +8476,119 @@ static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
 
 static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
 {
+	struct hostapd_config *conf;
+	struct p2p_go_neg_results params;
+	struct csa_settings csa_settings;
+	struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+	int old_freq = current_ssid->frequency;
+	int ret;
+	u8 chan;
+
 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "CSA is not enabled");
 		return -1;
 	}
 
-	/* TODO: Add CSA support */
-	wpa_dbg(wpa_s, MSG_DEBUG, "Moving GO with CSA is not implemented");
-	return -1;
+	/*
+	 * TODO: this function may not always work correctly. For example,
+	 * when we have a running GO and a BSS on a DFS channel.
+	 */
+	if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, NULL)) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P CSA: Failed to select new frequency for GO");
+		return -1;
+	}
+
+	if (current_ssid->frequency == params.freq) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P CSA: Selected same freq. Not moving GO");
+		return 0;
+	}
+
+	conf = hostapd_config_defaults();
+	if (!conf) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P CSA: Failed to allocate default config");
+		return -1;
+	}
+
+	current_ssid->frequency = params.freq;
+	if (wpa_supplicant_conf_ap_ht(wpa_s, current_ssid, conf)) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P CSA: Failed to create new GO config");
+		ret = -1;
+		goto out;
+	}
+
+	if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P CSA: CSA to a different band is not supported");
+		ret = -1;
+		goto out;
+	}
+
+	os_memset(&csa_settings, 0, sizeof(csa_settings));
+	csa_settings.cs_count = P2P_GO_CSA_COUNT;
+	csa_settings.block_tx = P2P_GO_CSA_BLOCK_TX;
+	csa_settings.freq_params.freq = params.freq;
+
+	if (ieee80211_freq_to_channel_ext(params.freq,
+					  conf->secondary_channel,
+					  conf->ieee80211ac,
+					  &wpa_s->ap_iface->cs_oper_class,
+					  &chan) ==
+	    NUM_HOSTAPD_MODES) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"P2P CSA: Selected invalid frequency");
+		ret = -1;
+		goto out;
+	}
+
+	csa_settings.freq_params.channel = chan;
+	csa_settings.freq_params.sec_channel_offset = conf->secondary_channel;
+	csa_settings.freq_params.ht_enabled = conf->ieee80211n;
+	csa_settings.freq_params.bandwidth = conf->secondary_channel ? 40 : 20;
+
+	if (conf->ieee80211ac) {
+		int freq1 = 0, freq2 = 0;
+
+		if (conf->vht_oper_centr_freq_seg0_idx)
+			freq1 = ieee80211_chan_to_freq(NULL,
+						       wpa_s->ap_iface->cs_oper_class,
+						       conf->vht_oper_centr_freq_seg0_idx);
+
+		if (conf->vht_oper_centr_freq_seg1_idx)
+			freq2 = ieee80211_chan_to_freq(NULL,
+						       wpa_s->ap_iface->cs_oper_class,
+						       conf->vht_oper_centr_freq_seg1_idx);
+
+		if (freq1 < 0 || freq2 < 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2P CSA: Selected invalid vht center freqs");
+			ret = -1;
+			goto out;
+		}
+
+		csa_settings.freq_params.vht_enabled = conf->ieee80211ac;
+		csa_settings.freq_params.center_freq1 = freq1;
+		csa_settings.freq_params.center_freq2 = freq2;
+
+		switch (conf->vht_oper_chwidth) {
+		case VHT_CHANWIDTH_80MHZ:
+		case VHT_CHANWIDTH_80P80MHZ:
+			csa_settings.freq_params.bandwidth = 80;
+			break;
+		case VHT_CHANWIDTH_160MHZ:
+			csa_settings.freq_params.bandwidth = 160;
+			break;
+		}
+	}
+
+	ret = ap_switch_channel(wpa_s, &csa_settings);
+out:
+	current_ssid->frequency = old_freq;
+	hostapd_config_free(conf);
+	return ret;
 }
 
 
-- 
1.9.1




More information about the Hostap mailing list