Patchwork [PATCH/RFC,17/18] wpa_s: enable mesh HT mode

login
register
mail settings
Submitter Bob Copeland
Date July 14, 2014, 5:19 a.m.
Message ID <1405315163-9492-18-git-send-email-me@bobcopeland.com>
Download mbox | patch
Permalink /patch/369496/
State Superseded
Headers show

Comments

Bob Copeland - July 14, 2014, 5:19 a.m.
From: Jason Mobarak <x@jason.mobarak.name>

Add a new option "mesh_ht_mode" that specifies the HT mode for the
mesh, with this option on, mesh beacons, actions frames, and probe
responses with include the appropriate HT information elements.

Change the mesh tests to check for the presence of HT in the scan
results, for this to work "disable_scan_offload" must be added to
p2p*.conf.

[original implementation by Chun-Yeow Yeoh <yeohchunyeow@gmail.com>]
[some fixes by Masashi Honma <masashi.honma@gmail.com>]
Signed-off-by: Ashok Nagarajan <ashok.dragon@gmail.com>
Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-hostap: Jason Mobarak <x@jason.mobarak.name>
---
 src/common/defs.h             | 11 ++++++++
 src/drivers/driver.h          |  1 +
 src/drivers/driver_nl80211.c  | 27 ++++++++++++++++++-
 tests/hwsim/p2p0.conf         |  1 +
 tests/hwsim/p2p1.conf         |  1 +
 tests/hwsim/p2p2.conf         |  1 +
 tests/hwsim/test_wpas_mesh.py |  6 ++++-
 wpa_supplicant/ap.c           | 42 ++++++++++++++++-------------
 wpa_supplicant/ap.h           |  5 ++++
 wpa_supplicant/config.c       | 61 ++++++++++++++++++++++++++++++++++++++++++-
 wpa_supplicant/config_ssid.h  | 10 +++++++
 wpa_supplicant/mesh.c         | 13 +++++++++
 wpa_supplicant/mesh_mpm.c     | 21 +++++++++++++--
 13 files changed, 177 insertions(+), 23 deletions(-)

Patch

diff --git a/src/common/defs.h b/src/common/defs.h
index fb289b0..92bc499 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -300,6 +300,17 @@  enum wpa_ctrl_req_type {
 /* Maximum number of EAP methods to store for EAP server user information */
 #define EAP_MAX_METHODS 8
 
+/**
+ *  enum ht_mode - channel width and offset
+ */
+enum ht_mode {
+	CHAN_UNDEFINED = 0,
+	CHAN_NO_HT,
+	CHAN_HT20,
+	CHAN_HT40PLUS,
+	CHAN_HT40MINUS,
+};
+
 #ifdef CONFIG_MESH
 enum mesh_plink_state {
 	PLINK_LISTEN = 1,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index f48ff84..afcea45 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -911,6 +911,7 @@  struct wpa_driver_mesh_join_params {
 	u8 *ies;
 	int ie_len;
 	int freq;
+	enum ht_mode ht_mode;
 	struct wpa_driver_mesh_bss_params conf;
 #define WPA_DRIVER_MESH_FLAG_USER_MPM	0x00000001
 #define WPA_DRIVER_MESH_FLAG_DRIVER_MPM	0x00000002
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 42097e2..8b23342 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -9099,12 +9099,37 @@  wpa_driver_nl80211_join_mesh(void *priv,
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_MESH);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	/* XXX: need chtype too in case we want HT */
 	if (params->freq) {
 		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
 		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
 	}
 
+	if (params->ht_mode) {
+		unsigned int ht_value;
+		char *ht_mode = "";
+		switch (params->ht_mode) {
+		default:
+		case CHAN_NO_HT:
+			ht_value = NL80211_CHAN_NO_HT;
+			ht_mode = "NOHT";
+			break;
+		case CHAN_HT20:
+			ht_value = NL80211_CHAN_HT20;
+			ht_mode = "HT20";
+			break;
+		case CHAN_HT40PLUS:
+			ht_value = NL80211_CHAN_HT40PLUS;
+			ht_mode = "HT40+";
+			break;
+		case CHAN_HT40MINUS:
+			ht_value = NL80211_CHAN_HT40MINUS;
+			ht_mode = "HT40-";
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "  * ht_mode=%s", ht_mode);
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value);
+	}
+
 	if (params->basic_rates) {
 		u8 rates[NL80211_MAX_SUPP_RATES];
 		u8 rates_len = 0;
diff --git a/tests/hwsim/p2p0.conf b/tests/hwsim/p2p0.conf
index 9482bdc..79804a6 100644
--- a/tests/hwsim/p2p0.conf
+++ b/tests/hwsim/p2p0.conf
@@ -1,3 +1,4 @@ 
 ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
 device_name=Device A
 p2p_no_group_iface=1
+disable_scan_offload=1
diff --git a/tests/hwsim/p2p1.conf b/tests/hwsim/p2p1.conf
index 3622b15..7a713a8 100644
--- a/tests/hwsim/p2p1.conf
+++ b/tests/hwsim/p2p1.conf
@@ -1,3 +1,4 @@ 
 ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
 device_name=Device B
 p2p_no_group_iface=1
+disable_scan_offload=1
diff --git a/tests/hwsim/p2p2.conf b/tests/hwsim/p2p2.conf
index eda52e1..1df136f 100644
--- a/tests/hwsim/p2p2.conf
+++ b/tests/hwsim/p2p2.conf
@@ -1,3 +1,4 @@ 
 ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
 device_name=Device C
 p2p_no_group_iface=1
+disable_scan_offload=1
diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
index f1eca36..84ef00d 100644
--- a/tests/hwsim/test_wpas_mesh.py
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -43,7 +43,7 @@  def check_mesh_scan(dev, params, other_started=False):
 
     res = dev.request("SCAN_RESULTS")
 
-    if not res.find("[MESH]"):
+    if res.find("[MESH]") < 0:
         raise Exception("Scan did not contain a MESH network")
 
 
@@ -168,6 +168,7 @@  def test_wpas_mesh_mode_scan(dev):
     dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
     dev[0].set_network(id, "key_mgmt", "NONE")
     dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "mesh_ht_mode", "HT40+")
     dev[0].mesh_group_add(id)
 
     id = dev[1].add_network()
@@ -175,6 +176,7 @@  def test_wpas_mesh_mode_scan(dev):
     dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
     dev[1].set_network(id, "key_mgmt", "NONE")
     dev[1].set_network(id, "frequency", "2412")
+    dev[1].set_network(id, "mesh_ht_mode", "HT40+")
     dev[1].mesh_group_add(id)
 
     # Check for mesh joined
@@ -201,6 +203,7 @@  def _test_wpas_mesh_open(dev, apdev, test_connectivity):
     dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
     dev[0].set_network(id, "key_mgmt", "NONE")
     dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "mesh_ht_mode", "HT40+")
     dev[0].mesh_group_add(id)
 
     id = dev[1].add_network()
@@ -208,6 +211,7 @@  def _test_wpas_mesh_open(dev, apdev, test_connectivity):
     dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
     dev[1].set_network(id, "key_mgmt", "NONE")
     dev[1].set_network(id, "frequency", "2412")
+    dev[1].set_network(id, "mesh_ht_mode", "HT40+")
     dev[1].mesh_group_add(id)
 
     # Check for mesh joined
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f9aa807..df95f51 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -74,25 +74,10 @@  no_vht:
 }
 #endif /* CONFIG_IEEE80211N */
 
-
-static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
-				  struct wpa_ssid *ssid,
-				  struct hostapd_config *conf)
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid,
+			       struct hostapd_config *conf)
 {
-	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);
-		return -1;
-	}
-
 	/* TODO: enable HT40 if driver supports it;
 	 * drop to 11b if driver does not support 11g */
 
@@ -155,6 +140,27 @@  static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 		}
 	}
 #endif /* CONFIG_IEEE80211N */
+}
+
+static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid,
+				  struct hostapd_config *conf)
+{
+	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);
+		return -1;
+	}
+
+	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
 
 #ifdef CONFIG_P2P
 	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 8aa5ffa..4d80c7a 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -75,4 +75,9 @@  int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
 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);
+
 #endif /* AP_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b1069ce..efc0a96 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1543,7 +1543,6 @@  static int wpa_config_parse_psk_list(const struct parse_data *data,
 	return 0;
 }
 
-
 #ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_psk_list(const struct parse_data *data,
 					struct wpa_ssid *ssid)
@@ -1554,6 +1553,60 @@  static char * wpa_config_write_psk_list(const struct parse_data *data,
 
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_MESH
+static int wpa_config_parse_mesh_ht_mode(const struct parse_data *data,
+					 struct wpa_ssid *ssid, int line,
+					 const char *value)
+{
+	int htval = 0;
+
+	if (os_strcmp(value, "NOHT") == 0)
+		htval = CHAN_NO_HT;
+	else if (os_strcmp(value, "HT20") == 0)
+		htval = CHAN_HT20;
+	else if (os_strcmp(value, "HT40-") == 0)
+		htval = CHAN_HT40MINUS;
+	else if (os_strcmp(value, "HT40+") == 0)
+		htval = CHAN_HT40PLUS;
+	else {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no ht_mode configured.", line);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "mesh_ht_mode: 0x%x", htval);
+	ssid->mesh_ht_mode = htval;
+	return 0;
+}
+
+#ifndef NO_CONFIG_WRITE
+static char *wpa_config_write_mesh_ht_mode(const struct parse_data *data,
+					   struct wpa_ssid *ssid)
+{
+	char *val;
+	switch (ssid->mesh_ht_mode) {
+	default:
+		val = NULL;
+		break;
+	case CHAN_NO_HT:
+		val = "NOHT";
+		break;
+	case CHAN_HT20:
+		val = "HT20";
+		break;
+	case CHAN_HT40MINUS:
+		val = "HT40-";
+		break;
+	case CHAN_HT40PLUS:
+		val = "HT40+";
+		break;
+	}
+	return val ? os_strdup(val) : NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MESH */
+
 /* Helper macros for network block parser */
 
 #ifdef OFFSET
@@ -1722,6 +1775,9 @@  static const struct parse_data ssid_fields[] = {
 	{ INT_RANGE(peerkey, 0, 1) },
 	{ INT_RANGE(mixed_cell, 0, 1) },
 	{ INT_RANGE(frequency, 0, 65000) },
+#ifdef CONFIG_MESH
+	{ FUNC(mesh_ht_mode) },
+#endif
 	{ INT(wpa_ptk_rekey) },
 	{ STR(bgscan) },
 	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2197,6 +2253,9 @@  void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
 	ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
 	ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+	ssid->mesh_ht_mode = DEFAULT_MESH_HT_MODE;
+#endif
 #ifdef CONFIG_HT_OVERRIDES
 	ssid->disable_ht = DEFAULT_DISABLE_HT;
 	ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index daa7ce3..6234f71 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -27,6 +27,7 @@ 
 #define DEFAULT_FRAGMENT_SIZE 1398
 
 #define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_MESH_HT_MODE CHAN_UNDEFINED /* undefined */
 #define DEFAULT_DISABLE_HT 0
 #define DEFAULT_DISABLE_HT40 0
 #define DEFAULT_DISABLE_SGI 0
@@ -403,6 +404,15 @@  struct wpa_ssid {
 	 */
 	int frequency;
 
+	/**
+	 * mesh_ht_mode - definition of HT mode in mesh mode
+	 *
+	 * Use the given HT mode for mesh networks. The driver will
+	 * adapt to other stations if neccesary, but advertise the
+	 * configured HT mode (HT20/HT40-/HT40+/NOHT).
+	 */
+	int mesh_ht_mode;
+
 	int ht40;
 
 	int vht;
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index d8b648a..25b0eb6 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -6,6 +6,14 @@ 
  * See README for more details.
  */
 
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ap.h"
 #include "mesh.h"
 #include "mesh_mpm.h"
 #include "mesh_rsn.h"
@@ -205,6 +213,8 @@  wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
 			goto out_free;
 	}
 
+	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
 	return 0;
 out_free:
 	wpa_supplicant_mesh_deinit(wpa_s);
@@ -256,6 +266,9 @@  int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
 	params.meshid = ssid->ssid;
 	params.meshid_len = ssid->ssid_len;
 	params.freq = ssid->frequency;
+#ifdef CONFIG_IEEE80211N
+	params.ht_mode = ssid->mesh_ht_mode;
+#endif /* CONFIG_IEEE80211N */
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
 		params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 69ffba8..af5b124 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -367,6 +367,12 @@  wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
 
 	mesh_mpm_init_link(wpa_s, sta);
 
+#ifdef CONFIG_IEEE80211N
+	copy_sta_ht_capab(data, sta, elems->ht_capabilities,
+			elems->ht_capabilities_len);
+	update_ht_state(data, sta);
+#endif
+
 	/* insert into driver */
 	os_memset(&params, 0, sizeof(params));
 	params.supp_rates = sta->supported_rates;
@@ -375,7 +381,7 @@  wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
 	params.plink_state = sta->plink_state;
 	params.aid = sta->peer_lid;
 	params.listen_interval = 100;
-	/* TODO: HT capabilities */
+	params.ht_capabilities = sta->ht_capabilities;
 	params.flags |= WPA_STA_WMM;
 	params.flags_mask |= WPA_STA_AUTHENTICATED;
 	if (conf->security == MESH_CONF_SEC_NONE) {
@@ -415,6 +421,9 @@  static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
 	struct hostapd_data *bss = ifmsh->bss[0];
 	struct mesh_conf *conf = ifmsh->mconf;
 	u8 supp_rates[2 + 2 + 32];
+#ifdef CONFIG_IEEE80211N
+	u8 ht_capa_oper[2 + 26 + 2 + 22];
+#endif
 	u8 *pos, *cat;
 	u8 ie_len, add_plid = 0;
 	int ret;
@@ -445,6 +454,7 @@  static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
 		else
 			wpabuf_put_le16(buf, 0);
 
+		/* aid */
 		if (type == PLINK_CONFIRM)
 			wpabuf_put_le16(buf, sta->peer_lid);
 
@@ -515,7 +525,14 @@  static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
 	if (ampe)
 		mesh_rsn_get_pmkid(sta, (u8 *) wpabuf_put(buf, PMKID_LEN));
 
-	/* TODO HT IEs */
+#ifdef CONFIG_IEEE80211N
+	if (type != PLINK_CLOSE &&
+	    wpa_s->current_ssid->mesh_ht_mode != CHAN_NO_HT) {
+		pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
+		pos = hostapd_eid_ht_operation(bss, pos);
+		wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
+	}
+#endif /* CONFIG_IEEE80211N */
 
 	if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
 		wpa_msg(wpa_s, MSG_INFO,