mesh: Enable mesh HT mode
authorJason Mobarak <x@jason.mobarak.name>
Mon, 1 Sep 2014 04:23:36 +0000 (00:23 -0400)
committerJouni Malinen <j@w1.fi>
Sun, 16 Nov 2014 17:43:11 +0000 (19:43 +0200)
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.

[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-off-by: Jason Mobarak <x@jason.mobarak.name>
src/common/defs.h
src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/config.c
wpa_supplicant/config_file.c
wpa_supplicant/config_ssid.h
wpa_supplicant/mesh.c
wpa_supplicant/mesh_mpm.c

index 2efb985..e1bbd50 100644 (file)
@@ -308,6 +308,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,
+};
+
 enum mesh_plink_state {
        PLINK_LISTEN = 1,
        PLINK_OPEN_SENT,
index 3476e8e..5be123b 100644 (file)
@@ -945,6 +945,7 @@ struct wpa_driver_mesh_join_params {
        const 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
index cf4e540..05d8ff5 100644 (file)
@@ -8732,12 +8732,38 @@ 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;
index 02ea609..f3acbc1 100644 (file)
@@ -75,24 +75,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 +141,28 @@ 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 &&
index 8aa5ffa..4d80c7a 100644 (file)
@@ -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 */
index 637cdf1..9e261ba 100644 (file)
@@ -1588,6 +1588,66 @@ 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
@@ -1757,6 +1817,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 /* CONFIG_MESH */
        { INT(wpa_ptk_rekey) },
        { STR(bgscan) },
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2235,6 +2298,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 /* CONFIG_MESH */
 #ifdef CONFIG_HT_OVERRIDES
        ssid->disable_ht = DEFAULT_DISABLE_HT;
        ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
index d58707e..852140f 100644 (file)
@@ -743,6 +743,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        INT(update_identifier);
 #endif /* CONFIG_HS20 */
        write_int(f, "mac_addr", ssid->mac_addr, -1);
+       STR(mesh_ht_mode);
 
 #undef STR
 #undef INT
index a4910d0..85d976c 100644 (file)
@@ -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;
index 6439d64..4a6924b 100644 (file)
@@ -21,6 +21,7 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "notify.h"
+#include "ap.h"
 #include "mesh_mpm.h"
 #include "mesh_rsn.h"
 #include "mesh.h"
@@ -241,6 +242,8 @@ static int 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);
@@ -295,6 +298,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;
index e440d4f..322c96c 100644 (file)
@@ -213,6 +213,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 /* CONFIG_IEEE80211N */
        u8 *pos, *cat;
        u8 ie_len, add_plid = 0;
        int ret;
@@ -243,6 +246,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                /* capability info */
                wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0);
 
+               /* aid */
                if (type == PLINK_CONFIRM)
                        wpabuf_put_le16(buf, sta->peer_lid);
 
@@ -309,7 +313,14 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta,
                                   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,
@@ -520,6 +531,12 @@ void 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 /* CONFIG_IEEE80211N */
+
        /* insert into driver */
        os_memset(&params, 0, sizeof(params));
        params.supp_rates = sta->supported_rates;
@@ -528,7 +545,7 @@ void 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) {