Discussion:
[PATCH v2 00/17] mesh support for wpa_supplicant
Bob Copeland
2014-05-30 13:22:21 UTC
Permalink
Hi,

This is the second (publically posted) version of the
wpa_supplicant for mesh patches. There are still a few things
TODO but I'm overall happier with the patch order and the number
of patches (though a few could still probably be squashed).

I'll do another series soon incorporating the comments of
Yu Niiro and Chun-Yeow Yeoh.

Additional comments welcome.

Bob Copeland (5):
mesh_mpm: add mesh peering manager
driver: add new NL80211 cmds to support mesh ifaces
mesh: parse mesh-related information elements
aes_siv: implement RFC 5297 AES-SIV
mesh_rsn: add mesh robust security network

Jason Abele (1):
wpa_supplicant: implement mesh scanning

Jason Mobarak (1):
wpa_s: enable mesh HT mode

Javier Lopez (3):
wpa_s, ctrl_iface: Add mesh_group_{add,remove}
hwsim_tests: add test_wpas_mesh test cases
hostapd: check if mesh_conf struct is set

Thomas Pedersen (7):
data structures: add required mesh data fields
mesh: add mesh mode routines
events: handle mesh events coming from driver
config: add mesh mode, user_mpm, and no_auto_peer options
Makefile: add mesh support to wpa_s build
auth: handle auth frames for mesh ifaces
sample conf: add description for new mesh options

hostapd/Android.mk | 4 +
src/ap/ap_config.h | 29 +-
src/ap/hostapd.c | 27 +-
src/ap/hostapd.h | 11 +
src/ap/ieee802_11.c | 76 ++-
src/ap/sta_info.h | 18 +
src/ap/wpa_auth.c | 16 +
src/ap/wpa_auth.h | 3 +
src/common/defs.h | 36 ++
src/common/ieee802_11_common.c | 22 +
src/common/ieee802_11_common.h | 10 +
src/common/ieee802_11_defs.h | 36 ++
src/common/wpa_ctrl.h | 6 +
src/crypto/Makefile | 1 +
src/crypto/aes-siv.c | 181 +++++++
src/crypto/aes_siv.h | 17 +
src/drivers/driver.h | 88 +++-
src/drivers/driver_common.c | 1 +
src/drivers/driver_nl80211.c | 322 +++++++++++-
src/drivers/driver_wext.c | 5 +-
tests/hwsim/example-wpa_supplicant.config | 1 +
tests/hwsim/p2p0.conf | 1 +
tests/hwsim/p2p1.conf | 1 +
tests/hwsim/p2p2.conf | 1 +
tests/hwsim/test_wpas_mesh.py | 336 ++++++++++++
tests/hwsim/wpasupplicant.py | 12 +
wpa_supplicant/Android.mk | 13 +
wpa_supplicant/Makefile | 12 +
wpa_supplicant/ap.c | 42 +-
wpa_supplicant/ap.h | 5 +
wpa_supplicant/bss.c | 8 +-
wpa_supplicant/config.c | 70 ++-
wpa_supplicant/config.h | 11 +
wpa_supplicant/config_file.c | 3 +
wpa_supplicant/config_ssid.h | 21 +
wpa_supplicant/ctrl_iface.c | 107 +++-
wpa_supplicant/driver_i.h | 25 +
wpa_supplicant/events.c | 36 +-
wpa_supplicant/mesh.c | 326 ++++++++++++
wpa_supplicant/mesh.h | 38 ++
wpa_supplicant/mesh_mpm.c | 830 ++++++++++++++++++++++++++++++
wpa_supplicant/mesh_mpm.h | 26 +
wpa_supplicant/mesh_rsn.c | 552 ++++++++++++++++++++
wpa_supplicant/mesh_rsn.h | 39 ++
wpa_supplicant/scan.c | 5 +
wpa_supplicant/wpa_cli.c | 21 +
wpa_supplicant/wpa_supplicant.c | 54 +-
wpa_supplicant/wpa_supplicant.conf | 26 +
wpa_supplicant/wpa_supplicant_i.h | 7 +-
49 files changed, 3480 insertions(+), 58 deletions(-)
create mode 100644 src/crypto/aes-siv.c
create mode 100755 src/crypto/aes_siv.h
create mode 100644 tests/hwsim/test_wpas_mesh.py
create mode 100644 wpa_supplicant/mesh.c
create mode 100644 wpa_supplicant/mesh.h
create mode 100644 wpa_supplicant/mesh_mpm.c
create mode 100644 wpa_supplicant/mesh_mpm.h
create mode 100644 wpa_supplicant/mesh_rsn.c
create mode 100644 wpa_supplicant/mesh_rsn.h
--
1.9.2
Bob Copeland
2014-05-30 13:22:22 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Modify and add necessary fields to hostapd and wpa_supplicant data
structures required by mesh networks wpa_supplicant module.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Thomas Pedersen <***@noack.us>
---
src/ap/ap_config.h | 29 ++++++++++++++++++++++++++++-
src/ap/hostapd.h | 11 +++++++++++
src/ap/sta_info.h | 18 ++++++++++++++++++
src/common/ieee802_11_defs.h | 36 ++++++++++++++++++++++++++++++++++++
src/common/wpa_ctrl.h | 6 ++++++
wpa_supplicant/config_ssid.h | 3 +++
wpa_supplicant/wpa_supplicant_i.h | 5 +++++
7 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index dfbe626..4f6c163 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -15,6 +15,32 @@
#include "common/ieee802_11_common.h"
#include "wps/wps.h"

+#ifdef CONFIG_MESH
+/**
+ * mesh_conf - local MBSS state and settings
+ */
+struct mesh_conf {
+ u8 meshid[32];
+ u8 meshid_len;
+ /* Active Path Selection Protocol Identifier */
+ u8 mesh_pp_id;
+ /* Active Path Selection Metric Identifier */
+ u8 mesh_pm_id;
+ /* Congestion Control Mode Identifier */
+ u8 mesh_cc_id;
+ /* Synchronization Protocol Identifier */
+ u8 mesh_sp_id;
+ /* Authentication Protocol Identifier */
+ u8 mesh_auth_id;
+ u8 *ies;
+ int ie_len;
+#define MESH_CONF_SEC_NONE BIT(0)
+#define MESH_CONF_SEC_AUTH BIT(1)
+#define MESH_CONF_SEC_AMPE BIT(2)
+ int security;
+};
+#endif /* CONFIG_MESH */
+
#define MAX_STA_COUNT 2007
#define MAX_VLAN_ID 4094

@@ -396,7 +422,8 @@ struct hostapd_bss_config {
u8 ip_addr_start[4];
u8 ip_addr_end[4];
#endif /* CONFIG_P2P */
-
+#define MESH_ENABLED BIT(0)
+ int mesh;
int disassoc_low_ack;
int skip_inactivity_poll;

diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 090544d..fb67093 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -22,6 +22,9 @@ struct ieee80211_ht_capabilities;
struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
+#ifdef CONFIG_MESH
+struct mesh_conf;
+#endif /* CONFIG_MESH */

struct hostapd_iface;

@@ -227,6 +230,10 @@ struct hostapd_data {
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MESH
+ int num_plinks;
+ int max_plinks;
+#endif /* CONFIG_MESH */

#ifdef CONFIG_SQLITE
struct hostapd_eap_user tmp_eap_user;
@@ -264,6 +271,10 @@ struct hostapd_iface {
HAPD_IFACE_ENABLED
} state;

+#ifdef CONFIG_MESH
+ struct mesh_conf *mconf;
+#endif /* CONFIG_MESH */
+
size_t num_bss;
struct hostapd_data **bss;

diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 2dbdeb1..6e9d3f6 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -9,6 +9,11 @@
#ifndef STA_INFO_H
#define STA_INFO_H

+#ifdef CONFIG_MESH
+/* needed for mesh_plink_state enum */
+#include "common/defs.h"
+#endif /* CONFIG_MESH */
+
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
@@ -49,6 +54,19 @@ struct sta_info {
int supported_rates_len;
u8 qosinfo; /* Valid when WLAN_STA_WMM is set */

+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+ u16 peer_lid;
+ u16 my_lid;
+ u16 mpm_close_reason;
+ int mpm_retries;
+ u8 my_nonce[32];
+ u8 peer_nonce[32];
+ u8 aek[32]; /* SHA256 digest length */
+ u8 mtk[16];
+ u8 mgtk[16];
+#endif /* CONFIG_MESH */
+
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
unsigned int no_short_preamble_set:1;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index cb70130..b4feb64 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -194,6 +194,16 @@
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/* IEEE 802.11e */
#define WLAN_REASON_DISASSOC_LOW_ACK 34
+/* IEEE 802.11s */
+#define WLAN_REASON_MESH_PEERING_CANCELLED 52
+#define WLAN_REASON_MESH_MAX_PEERS 53
+#define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
+#define WLAN_REASON_MESH_CLOSE_RCVD 55
+#define WLAN_REASON_MESH_MAX_RETRIES 56
+#define WLAN_REASON_MESH_CONFIRM_TIMEOUT 57
+#define WLAN_REASON_MESH_INVALID_GTK 58
+#define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
+#define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60


/* Information Element IDs */
@@ -249,7 +259,12 @@
#define WLAN_EID_ADV_PROTO 108
#define WLAN_EID_QOS_MAP_SET 110
#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_MESH_CONFIG 113
+#define WLAN_EID_MESH_ID 114
+#define WLAN_EID_PEER_MGMT 117
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_AMPE 139
+#define WLAN_EID_MIC 140
#define WLAN_EID_CCKM 156
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
@@ -277,6 +292,7 @@
#define WLAN_ACTION_WNM 10
#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_SELF_PROTECTED 15
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_VENDOR_SPECIFIC 127

@@ -577,6 +593,10 @@ struct ieee80211_mgmt {
* Entries (optional) */
u8 variable[0];
} STRUCT_PACKED bss_tm_query;
+ struct {
+ u8 action; /* 15 */
+ u8 variable[0];
+ } STRUCT_PACKED slf_prot_action;
} u;
} STRUCT_PACKED action;
} u;
@@ -638,6 +658,15 @@ struct ieee80211_vht_operation {
le16 vht_basic_mcs_set;
} STRUCT_PACKED;

+struct ieee80211_ampe_ie {
+ u8 selected_pairwise_suite[4];
+ u8 local_nonce[32];
+ u8 peer_nonce[32];
+ u8 mgtk[16];
+ u8 key_rsc[8];
+ u8 key_expiration[4];
+} STRUCT_PACKED;
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -1085,6 +1114,13 @@ enum wifi_display_subelem {
WFD_SUBELEM_SESSION_INFO = 9
};

+/* 802.11s */
+#define MESH_SYNC_METHOD_NEIGHBOR_OFFSET 1
+#define MESH_SYNC_METHOD_VENDOR 255
+#define MESH_PATH_PROTOCOL_HWMP 1
+#define MESH_PATH_PROTOCOL_VENDOR 255
+#define MESH_PATH_METRIC_AIRTIME 1
+#define MESH_PATH_METRIC_VENDOR 255

#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */

diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 534bc99..c60b874 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -118,6 +118,12 @@ extern "C" {
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "

+/* MESH events */
+#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
+#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
+#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
+#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
+
/** P2P device found */
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "

diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index a458990..91a0065 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -316,6 +316,8 @@ struct wpa_ssid {
* 4 = P2P Group Formation (used internally; not in configuration
* files)
*
+ * 5 = Mesh
+ *
* Note: IBSS can only be used with key_mgmt NONE (plaintext and static
* WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
* (fixed group key TKIP/CCMP) is available for backwards compatibility,
@@ -330,6 +332,7 @@ struct wpa_ssid {
WPAS_MODE_AP = 2,
WPAS_MODE_P2P_GO = 3,
WPAS_MODE_P2P_GROUP_FORMATION = 4,
+ WPAS_MODE_MESH = 5,
} mode;

/**
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b5e137c..39f5c43 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -646,6 +646,11 @@ struct wpa_supplicant {
void *ap_configured_cb_data;
#endif /* CONFIG_AP */

+#ifdef CONFIG_MESH
+ struct hostapd_iface *ifmsh;
+ struct mesh_rsn *mesh_rsn;
+#endif /* CONFIG_MESH */
+
unsigned int off_channel_freq;
struct wpabuf *pending_action_tx;
u8 pending_action_src[ETH_ALEN];
--
1.9.2
Bob Copeland
2014-05-30 13:22:23 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Add routines to (de)initialize mesh interface data structures and
join and leave mesh networks.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Thomas Pedersen <***@noack.us>
---
wpa_supplicant/mesh.c | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh.h | 36 +++++++
2 files changed, 312 insertions(+)
create mode 100644 wpa_supplicant/mesh.c
create mode 100644 wpa_supplicant/mesh.h

diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
new file mode 100644
index 0000000..a71cd69
--- /dev/null
+++ b/wpa_supplicant/mesh.c
@@ -0,0 +1,276 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "mesh.h"
+
+static void
+wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+{
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ /* TODO: leave mesh (stop beacon). This will happen on link down
+ * anyway, so it's not urgent */
+}
+
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh)
+{
+ if (!ifmsh)
+ return;
+
+ if (ifmsh->mconf) {
+ if (ifmsh->mconf->ies)
+ ifmsh->mconf->ies = NULL;
+ /* We cannot free this struct
+ * because wpa_authenticator on
+ * hostapd side is also using it
+ * for now just set to NULL and
+ * let hostapd code free it.
+ */
+ os_free(ifmsh->mconf);
+ }
+
+ /* take care of shared data */
+ /* FIX: ugly failures when NA to mesh */
+ hostapd_interface_deinit(ifmsh);
+ hostapd_interface_free(ifmsh);
+}
+
+static struct mesh_conf *
+mesh_config_create(struct wpa_ssid *ssid)
+{
+ struct mesh_conf *conf;
+
+ conf = os_zalloc(sizeof(struct mesh_conf));
+ if (!conf)
+ return NULL;
+
+ os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
+ conf->meshid_len = ssid->ssid_len;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
+ conf->security |= MESH_CONF_SEC_AUTH |
+ MESH_CONF_SEC_AMPE;
+ else
+ conf->security |= MESH_CONF_SEC_NONE;
+
+ /* defaults */
+ conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
+ conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
+ conf->mesh_cc_id = 0;
+ conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
+ conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
+
+ return conf;
+}
+
+static int
+wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct hostapd_iface *ifmsh;
+ struct hostapd_data *bss;
+ struct hostapd_config *conf;
+ struct mesh_conf *mconf;
+ int basic_rates_erp[] = {10, 20, 55, 60, 110, 120, 240, -1 };
+ static int default_groups[] = { 19, 20, 21, 25, 26 };
+ size_t len;
+
+ wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+ if (!ifmsh)
+ return -ENOMEM;
+
+ ifmsh->num_bss = 1;
+ ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
+ sizeof(struct hostapd_data *));
+ if (!ifmsh->bss)
+ goto out_free;
+
+ ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
+ if (!bss)
+ goto out_free;
+
+ os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
+ bss->driver = wpa_s->driver;
+ bss->drv_priv = wpa_s->drv_priv;
+ bss->iface = ifmsh;
+ wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->current_ssid = ssid;
+
+ /* setup an AP config for auth processing */
+ conf = hostapd_config_defaults();
+ if (!conf)
+ goto out_free;
+
+ bss->conf = *conf->bss;
+ bss->conf->start_disabled = 1;
+ bss->conf->mesh = MESH_ENABLED;
+ bss->iconf = conf;
+ ifmsh->conf = conf;
+
+ ifmsh->bss[0]->max_plinks = 99;
+ os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
+
+ mconf = mesh_config_create(ssid);
+ if (!mconf)
+ goto out_free;
+ ifmsh->mconf = mconf;
+
+ /* need conf->hw_mode for supported rates. */
+ /* c.f. wpa_supplicant/ap.c:wpa_supplicant_conf_ap() */
+ if (ssid->frequency == 0) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ conf->channel = 1;
+ } else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ conf->channel = (ssid->frequency - 2407) / 5;
+ } else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
+ (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ conf->channel = (ssid->frequency - 5000) / 5;
+ } else if (ssid->frequency >= 56160 + 2160 * 1 &&
+ ssid->frequency <= 56160 + 2160 * 4) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+ conf->channel = (ssid->frequency - 56160) / 2160;
+ } else {
+ wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
+ ssid->frequency);
+ goto out_free;
+ }
+
+ /* XXX: hack! this is so an MPM which correctly sets the ERP
+ * mandatory rates as BSSBasicRateSet doesn't reject us. We
+ * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
+ * this is way easier. This also makes our BSSBasicRateSet
+ * advertised in beacons match the one in peering frames, sigh.
+ * */
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ conf->basic_rates = os_zalloc(sizeof(basic_rates_erp));
+ if (!conf->basic_rates)
+ goto out_free;
+ os_memcpy(conf->basic_rates,
+ basic_rates_erp, sizeof(basic_rates_erp));
+ }
+
+ hostapd_setup_interface(ifmsh);
+
+ if (wpa_drv_init_mesh(wpa_s)) {
+ wpa_msg(wpa_s, MSG_ERROR, "failed to init mesh in driver");
+ return -1;
+ }
+
+ if (mconf->security != MESH_CONF_SEC_NONE) {
+ bss->conf->wpa = ssid->proto;
+ bss->conf->wpa_key_mgmt = ssid->key_mgmt;
+ bss->conf->sae_groups = wpa_s->conf->sae_groups;
+
+ if (wpa_s->conf->sae_groups) {
+ bss->conf->sae_groups =
+ os_zalloc(sizeof(wpa_s->conf->sae_groups));
+ os_memcpy(bss->conf->sae_groups,
+ wpa_s->conf->sae_groups,
+ sizeof(wpa_s->conf->sae_groups));
+ } else {
+ bss->conf->sae_groups =
+ os_zalloc(sizeof(default_groups));
+ os_memcpy(bss->conf->sae_groups,
+ default_groups,
+ sizeof(default_groups));
+ }
+
+ len = os_strlen(ssid->passphrase);
+ bss->conf->ssid.wpa_passphrase = dup_binstr(ssid->passphrase, len);
+ }
+
+ return 0;
+out_free:
+ wpa_supplicant_mesh_deinit(wpa_s);
+ return -ENOMEM;
+}
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *ies, int ie_len)
+{
+ struct ieee802_11_elems elems;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ "new peer notification for " MACSTR, MAC2STR(addr));
+
+ if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+ wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
+ MAC2STR(addr));
+ }
+}
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_driver_mesh_join_params params;
+ int ret = 0;
+
+ if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ wpa_supplicant_mesh_deinit(wpa_s);
+
+ os_memset(&params, 0, sizeof(params));
+ params.meshid = ssid->ssid;
+ params.meshid_len = ssid->ssid_len;
+ params.freq = ssid->frequency;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
+ params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+ }
+
+ params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+
+ if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+ wpa_msg(wpa_s, MSG_ERROR, "failed to init mesh");
+ goto out;
+ }
+
+ if (wpa_s->ifmsh) {
+ params.ies = wpa_s->ifmsh->mconf->ies;
+ params.ie_len = wpa_s->ifmsh->mconf->ie_len;
+ params.basic_rates = wpa_s->ifmsh->basic_rates;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ret = wpa_drv_join_mesh(wpa_s, &params);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
+
+ /* hostapd sets the interface down until we associate */
+ wpa_drv_set_operstate(wpa_s, 1);
+
+out:
+ return ret;
+}
+
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+ int ret = 0;
+
+ wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
+
+ ret = wpa_drv_leave_mesh(wpa_s);
+
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d\n", ret);
+
+ wpa_drv_set_operstate(wpa_s, 1);
+
+ wpa_supplicant_mesh_deinit(wpa_s);
+
+ return ret;
+}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
new file mode 100644
index 0000000..f08e641
--- /dev/null
+++ b/wpa_supplicant/mesh.h
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_H
+#define MESH_H
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "notify.h"
+
+#include "ap/sta_info.h"
+#include "ap/hostapd.h"
+#include "ap/ieee802_11.h"
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s);
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *ies, int ie_len);
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh);
+#endif /* MESH_H */
--
1.9.2
Bob Copeland
2014-05-30 13:22:24 UTC
Permalink
The mesh peering manager establishes and maintains links among
mesh peers, tracking each peer link via a finite state machine.

This implementation supports open mesh peerings.

[assorted fixes from Yu Niiro <***@gmail.com>]
Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-off-by: Ashok Nagarajan <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Bob Copeland <***@bobcopeland.com>
---
wpa_supplicant/mesh.c | 21 +-
wpa_supplicant/mesh_mpm.c | 788 ++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh_mpm.h | 26 ++
3 files changed, 833 insertions(+), 2 deletions(-)
create mode 100644 wpa_supplicant/mesh_mpm.c
create mode 100644 wpa_supplicant/mesh_mpm.h

diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index a71cd69..4f82fca 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -7,6 +7,7 @@
*/

#include "mesh.h"
+#include "mesh_mpm.h"

static void
wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
@@ -35,6 +36,7 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
os_free(ifmsh->mconf);
}

+ mesh_mpm_deinit(wpa_s, ifmsh);
/* take care of shared data */
/* FIX: ugly failures when NA to mesh */
hostapd_interface_deinit(ifmsh);
@@ -81,6 +83,13 @@ wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
static int default_groups[] = { 19, 20, 21, 25, 26 };
size_t len;

+ if (!wpa_s->conf->user_mpm) {
+ /* not much for us to do here */
+ wpa_msg(wpa_s, MSG_WARNING, "WARNING: user_mpm is not enabled"
+ " on wpa_supplicant.conf");
+ return 0;
+ }
+
wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
if (!ifmsh)
return -ENOMEM;
@@ -204,7 +213,9 @@ void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
MAC2STR(addr));
+ return;
}
+ wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
}

int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
@@ -228,10 +239,16 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+ wpa_s->conf->user_mpm = 1;
}

- params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ if (wpa_s->conf->user_mpm) {
+ params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
+ params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ } else {
+ params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ }

if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
wpa_msg(wpa_s, MSG_ERROR, "failed to init mesh");
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
new file mode 100644
index 0000000..176e04c
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.c
@@ -0,0 +1,788 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "mesh_mpm.h"
+
+#include "eloop.h"
+#include "ap.h"
+
+/* TODO make configurable */
+#define dot11MeshMaxRetries 10
+#define dot11MeshRetryTimeout 1
+#define dot11MeshConfirmTimeout 1
+#define dot11MeshHoldingTimeout 1
+
+static void
+mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum mesh_plink_state next_state);
+static void
+mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum plink_action_field type,
+ u16 close_reason);
+
+struct mesh_peer_mgmt_ie {
+ const u8 *proto_id;
+ const u8 *llid;
+ const u8 *plid;
+ const u8 *reason;
+ const u8 *pmk;
+};
+
+static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
+ u8 action_field,
+ const u8 *ie, size_t len,
+ struct mesh_peer_mgmt_ie *mpm_ie)
+{
+ os_memset(mpm_ie, 0, sizeof(*mpm_ie));
+
+ /* remove optional pmk at end */
+ if (len >= 16) {
+ len -= 16;
+ mpm_ie->pmk = ie + len - 16;
+ }
+
+ if ((action_field == PLINK_OPEN && len != 4) ||
+ (action_field == PLINK_CONFIRM && len != 6) ||
+ (action_field == PLINK_CLOSE && len != 6 && len != 8)) {
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM: invalid peer mgmt ie");
+ return -1;
+ }
+
+ /* required fields */
+ mpm_ie->proto_id = ie;
+ mpm_ie->llid = ie + 2;
+ ie += 4;
+ len -= 4;
+
+ /* close reason is always present at end for close */
+ if (action_field == PLINK_CLOSE) {
+ mpm_ie->reason = ie + len - 2;
+ len -= 2;
+ }
+ /* plid, present for confirm, and possibly close */
+ if (len)
+ mpm_ie->plid = ie;
+
+ return 0;
+}
+
+enum plink_event {
+ PLINK_UNDEFINED,
+ OPN_ACPT,
+ OPN_RJCT,
+ OPN_IGNR,
+ CNF_ACPT,
+ CNF_RJCT,
+ CNF_IGNR,
+ CLS_ACPT,
+ CLS_IGNR
+};
+
+static const char *mplstate[] = {
+ [PLINK_LISTEN] = "LISTEN",
+ [PLINK_OPEN_SENT] = "OPEN_SENT",
+ [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [PLINK_CNF_RCVD] = "CNF_RCVD",
+ [PLINK_ESTAB] = "ESTAB",
+ [PLINK_HOLDING] = "HOLDING",
+ [PLINK_BLOCKED] = "BLOCKED"
+};
+
+static const char *mplevent[] = {
+ [PLINK_UNDEFINED] = "UNDEFINED",
+ [OPN_ACPT] = "OPN_ACPT",
+ [OPN_RJCT] = "OPN_RJCT",
+ [OPN_IGNR] = "OPN_IGNR",
+ [CNF_ACPT] = "CNF_ACPT",
+ [CNF_RJCT] = "CNF_RJCT",
+ [CNF_IGNR] = "CNF_IGNR",
+ [CLS_ACPT] = "CLS_ACPT",
+ [CLS_IGNR] = "CLS_IGNR"
+};
+
+#define mpl_dbg(wpa_s, sta, event) \
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",\
+ MAC2STR(sta->addr), mplstate[sta->plink_state],\
+ mplevent[event]);
+
+static int plink_free_count(struct hostapd_data *hapd)
+{
+ return hapd->max_plinks - hapd->num_plinks;
+}
+
+/* XXX: lifted from src/ap/ieee802_11.c */
+static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+ if (!elems->supp_rates) {
+ wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR,
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (elems->supp_rates_len + elems->ext_supp_rates_len >
+ sizeof(sta->supported_rates)) {
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid supported rates element length " MACSTR
+ " %d+%d ", MAC2STR(sta->addr), elems->supp_rates_len,
+ elems->ext_supp_rates_len);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->supported_rates_len = merge_byte_arrays(
+ sta->supported_rates, sizeof(sta->supported_rates),
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+/* generate an llid for a link and set to initial state */
+static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ u16 llid;
+
+ os_get_random((u8 *) &llid, sizeof(llid));
+
+ sta->my_lid = llid;
+ sta->peer_lid = 0;
+ sta->plink_state = PLINK_LISTEN;
+}
+
+/* configure peering state in ours and driver's station entry */
+static void
+wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum mesh_plink_state state)
+{
+ struct hostapd_sta_add_params params;
+ int ret;
+
+ sta->plink_state = state;
+
+ os_memset(&params, 0, sizeof(params));
+ params.addr = sta->addr;
+ params.plink_state = state;
+ params.set = 1;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
+ MAC2STR(sta->addr), mplstate[state]);
+ if ((ret = wpa_drv_sta_add(wpa_s, &params)))
+ wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR ": %d",
+ MAC2STR(sta->addr), ret);
+ return;
+}
+
+static void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
+ ap_free_sta(hapd, sta);
+ return;
+ }
+
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_LISTEN);
+ sta->my_lid = sta->peer_lid = sta->mpm_close_reason = 0;
+ sta->mpm_retries = 0;
+}
+
+static void plink_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct sta_info *sta = user_data;
+ u16 reason = 0;
+
+ switch (sta->plink_state) {
+ case PLINK_OPEN_RCVD:
+ case PLINK_OPEN_SENT:
+ /* retry timer */
+ if (sta->mpm_retries < dot11MeshMaxRetries) {
+ eloop_register_timeout(dot11MeshRetryTimeout, 0, plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+ sta->mpm_retries++;
+ break;
+ }
+ reason = WLAN_REASON_MESH_MAX_RETRIES;
+ /* fall through on else */
+
+ case PLINK_CNF_RCVD:
+ /* confirm timer */
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
+ sta->plink_state = PLINK_HOLDING;
+ eloop_register_timeout(dot11MeshHoldingTimeout, 0, plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case PLINK_HOLDING:
+ /* holding timer */
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+}
+
+int mesh_mpm_plink_close(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)ctx;
+ int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
+
+ if (sta) {
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ wpa_printf(MSG_DEBUG, "MPM: %s: closing plink sta=" MACSTR,
+ __func__, MAC2STR(sta->addr));
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ return 0;
+ }
+ return 1;
+}
+
+void
+mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
+{
+ struct hostapd_data *hapd = ifmsh->bss[0];
+
+ /* notify peers we're leaving */
+ ap_for_each_sta(hapd, mesh_mpm_plink_close, (void*)wpa_s);
+ /* TODO: deregister frames and events */
+
+ hapd->num_plinks = 0;
+ hostapd_free_stas(hapd);
+}
+
+/* for mesh_rsn to indicate this peer has completed authentication, and we're
+ * ready to start AMPE */
+void
+mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct hostapd_sta_add_params params;
+ struct sta_info *sta;
+ int ret;
+
+ sta = ap_get_sta(data, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_ERROR, "no such mesh peer!\n");
+ return;
+ }
+
+ /* TODO: should do nothing if this sta is already authenticated, but
+ * the AP code already sets this flag. */
+ sta->flags |= WLAN_STA_AUTH;
+
+ os_memset(&params, 0, sizeof(params));
+ params.addr = sta->addr;
+ params.flags = (WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED);
+ params.set = 1;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR,
+ MAC2STR(sta->addr));
+ if ((ret = wpa_drv_sta_add(wpa_s, &params)))
+ wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR ": %d",
+ MAC2STR(sta->addr), ret);
+
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+}
+
+void
+wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ struct ieee802_11_elems *elems)
+{
+ struct hostapd_sta_add_params params;
+ /* struct wmm_information_element *wmm; */
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct sta_info *sta;
+ int ret = 0;
+
+ sta = ap_get_sta(data, addr);
+ if (!sta) {
+ sta = ap_sta_add(data, addr);
+ if (!sta)
+ return;
+ }
+
+ /* initialize sta */
+ if (copy_supp_rates(wpa_s, sta, elems))
+ return;
+
+ mesh_mpm_init_link(wpa_s, sta);
+
+ /* insert into driver */
+ os_memset(&params, 0, sizeof(params));
+ params.supp_rates = sta->supported_rates;
+ params.supp_rates_len = sta->supported_rates_len;
+ params.addr = addr;
+ params.plink_state = sta->plink_state;
+ /* not used for mesh */
+ params.aid = 1;
+ params.listen_interval = 100;
+ /* TODO: HT capabilities */
+ params.flags |= WPA_STA_WMM;
+ params.flags_mask |= WPA_STA_AUTHENTICATED;
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ params.flags |= WPA_STA_AUTHORIZED;
+ params.flags |= WPA_STA_AUTHENTICATED;
+ } else {
+ sta->flags |= WLAN_STA_MFP;
+ params.flags |= WPA_STA_MFP;
+ }
+
+ if ((ret = wpa_drv_sta_add(wpa_s, &params))) {
+ wpa_msg(wpa_s, MSG_ERROR, "Driver failed to insert " MACSTR ": %d",
+ MAC2STR(addr), ret);
+ return;
+ }
+
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+}
+
+static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum plink_action_field type,
+ u16 close_reason)
+{
+ struct wpabuf *buf;
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct hostapd_data *bss = ifmsh->bss[0];
+ struct mesh_conf *conf = ifmsh->mconf;
+ u8 supp_rates[2 + 2 + 32];
+ u8 *pos;
+ u8 ie_len, add_plid = 0;
+ int ret;
+ int ampe = conf->security & MESH_CONF_SEC_AMPE;
+
+ buf = wpabuf_alloc(2 + /* capability info */
+ 2 + /* AID */
+ 2 + 8 + /* supported rates */
+ 2 + (32 - 8) +
+ 2 + 32 + /* mesh ID */
+ 2 + 7 + /* mesh config */
+ 2 + 26 + /* HT capabilities */
+ 2 + 22 + /* HT operation */
+ 2 + 23 + /* peering management */
+ 2 + 96 + /* AMPE */
+ 2 + 16); /* MIC */
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
+ wpabuf_put_u8(buf, type);
+
+ if (type != PLINK_CLOSE) {
+ /* capability info */
+ if (ampe)
+ wpabuf_put_le16(buf, IEEE80211_CAP_PRIVACY);
+ else
+ wpabuf_put_le16(buf, 0);
+
+ /* TODO: Generate proper AID? */
+ if (type == PLINK_CONFIRM)
+ wpabuf_put_le16(buf, 0);
+
+ /* IE: supp + ext. supp rates */
+ pos = hostapd_eid_supp_rates(bss, supp_rates);
+ pos = hostapd_eid_ext_supp_rates(bss, pos);
+ wpabuf_put_data(buf, supp_rates, pos - supp_rates);
+
+ /* IE: Mesh ID */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(buf, conf->meshid_len);
+ wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+
+ /* IE: mesh conf */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_CONFIG);
+ wpabuf_put_u8(buf, 7);
+ wpabuf_put_u8(buf, conf->mesh_pp_id);
+ wpabuf_put_u8(buf, conf->mesh_pm_id);
+ wpabuf_put_u8(buf, conf->mesh_cc_id);
+ wpabuf_put_u8(buf, conf->mesh_sp_id);
+ wpabuf_put_u8(buf, conf->mesh_auth_id);
+ /* TODO: formation info */
+ wpabuf_put_u8(buf, 0);
+ /* always forwarding & accepting plinks for now */
+ wpabuf_put_u8(buf, 0x1 | 0x8);
+ } else { /* Peer closing frame */
+ /* IE: Mesh ID */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(buf, conf->meshid_len);
+ wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+ }
+
+ /* IE: Mesh Peering Management element */
+ ie_len = 4;
+ if (ampe)
+ ie_len += PMKID_LEN;
+ switch (type) {
+ case PLINK_OPEN:
+ break;
+ case PLINK_CONFIRM:
+ ie_len += 2;
+ add_plid = 1;
+ break;
+ case PLINK_CLOSE:
+ if (sta) {
+ ie_len += 2;
+ add_plid = 1;
+ }
+ ie_len += 2; /* reason code */
+ break;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT);
+ wpabuf_put_u8(buf, ie_len);
+ /* peering protocol */
+ if (ampe)
+ wpabuf_put_le16(buf, 1);
+ else
+ wpabuf_put_le16(buf, 0);
+ if (sta)
+ wpabuf_put_le16(buf, sta->my_lid);
+ else
+ wpabuf_put_le16(buf, 0);
+ if (add_plid)
+ wpabuf_put_le16(buf, sta->peer_lid);
+ if (type == PLINK_CLOSE)
+ wpabuf_put_le16(buf, close_reason);
+
+ /* TODO HT IEs */
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+ sta->addr, wpa_s->own_addr, wpa_s->own_addr,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0)
+ wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: failed to send peering frame");
+
+ wpabuf_free(buf);
+}
+
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s,
+ struct rx_mgmt *rx_mgmt)
+{
+ struct hostapd_frame_info fi;
+ os_memset(&fi, 0, sizeof(fi));
+ fi.datarate = rx_mgmt->datarate;
+ fi.ssi_signal = rx_mgmt->ssi_signal;
+ ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame,
+ rx_mgmt->frame_len, &fi);
+}
+
+static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ u8 seq[6] = {};
+
+ wpa_msg(wpa_s, MSG_INFO, "mesh plink with "
+ MACSTR " established\n", MAC2STR(sta->addr));
+
+ if (conf->security & MESH_CONF_SEC_AMPE) {
+ /* key index != 0 is used to set key type */
+ wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
+ seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
+ wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
+ seq, sizeof(seq), sta->mgtk, sizeof(sta->mgtk));
+ wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
+ seq, sizeof(seq), sta->mgtk, sizeof(sta->mgtk));
+
+ wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
+ wpa_hexdump_key(MSG_DEBUG, "mgtk:", sta->mgtk, sizeof(sta->mgtk));
+ }
+
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
+ hapd->num_plinks++;
+
+ sta->flags |= WLAN_STA_ASSOC;
+
+ /* Send ctrl event */
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
+ MAC2STR(sta->addr));
+}
+
+/* initiate peering with station */
+static void
+mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum mesh_plink_state next_state)
+{
+ eloop_register_timeout(dot11MeshRetryTimeout, 0, plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+ wpa_mesh_set_plink_state(wpa_s, sta, next_state);
+}
+
+static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum plink_event event)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ u16 reason = 0;
+
+ mpl_dbg(wpa_s, sta, event);
+ switch (sta->plink_state) {
+ case PLINK_LISTEN:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case PLINK_OPEN_SENT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(dot11MeshHoldingTimeout, 0, plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0);
+ break;
+ case CNF_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+ eloop_register_timeout(dot11MeshConfirmTimeout, 0, plink_timer, wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case PLINK_OPEN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(dot11MeshHoldingTimeout, 0, plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0);
+ break;
+ case CNF_ACPT:
+ mesh_mpm_plink_estab(wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case PLINK_CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(dot11MeshHoldingTimeout, 0, plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_plink_estab(wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case PLINK_ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+
+ eloop_register_timeout(dot11MeshHoldingTimeout, 0, plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+
+ wpa_msg(wpa_s, MSG_INFO, "mesh plink with "
+ MACSTR " closed with reason %d\n",
+ MAC2STR(sta->addr), reason);
+
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR,
+ MAC2STR(sta->addr));
+
+ hapd->num_plinks--;
+
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = sta->mpm_close_reason;
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ wpa_msg(wpa_s, MSG_INFO, "Unsupported MPM event %s for state %s",
+ mplevent[event], mplstate[sta->plink_state]);
+ break;
+ }
+}
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u8 action_field;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct sta_info *sta;
+ u16 plid = 0, llid = 0;
+ enum plink_event event;
+ struct ieee802_11_elems elems;
+ struct mesh_peer_mgmt_ie peer_mgmt_ie;
+ const u8 *ies;
+ size_t ie_len;
+ int ret;
+
+ if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
+ return;
+
+ action_field = mgmt->u.action.u.slf_prot_action.action;
+
+ ies = mgmt->u.action.u.slf_prot_action.variable;
+ ie_len = (const u8 *) mgmt + len - mgmt->u.action.u.slf_prot_action.variable;
+
+ /* at least expect mesh id and peering mgmt */
+ if (ie_len < 2 + 2)
+ return;
+
+ if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
+ ies += 2; /* capability */
+ ie_len -= 2;
+ }
+ if (action_field == PLINK_CONFIRM) {
+ ies += 2; /* aid */
+ ie_len -= 2;
+ }
+
+ /* check for mesh peering, mesh id and mesh config IEs */
+ if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed)
+ return;
+ if (!elems.peer_mgmt)
+ return;
+ if ((action_field != PLINK_CLOSE) &&
+ (!elems.mesh_id || !elems.mesh_config))
+ return;
+
+ ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
+ elems.peer_mgmt,
+ elems.peer_mgmt_len,
+ &peer_mgmt_ie);
+ if (ret)
+ return;
+
+ /* the sender's llid is our plid and vice-versa */
+ plid = WPA_GET_LE16(peer_mgmt_ie.llid);
+ if (peer_mgmt_ie.plid)
+ llid = WPA_GET_LE16(peer_mgmt_ie.plid);
+
+ /* TODO check rateset */
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (!sta)
+ return;
+
+#ifdef CONFIG_SAE
+ /* peer is in sae_accepted? */
+ if (sta->sae && sta->sae->state != SAE_ACCEPTED)
+ return;
+#endif /* CONFIG_SAE */
+
+ if (!sta->my_lid)
+ mesh_mpm_init_link(wpa_s, sta);
+
+ if (sta->plink_state == PLINK_BLOCKED)
+ return;
+
+ /* Now we will figure out the appropriate event... */
+ switch (action_field) {
+ case PLINK_OPEN:
+ if (!plink_free_count(hapd) ||
+ (sta->peer_lid && sta->peer_lid != plid))
+ event = OPN_IGNR;
+ else {
+ sta->peer_lid = plid;
+ event = OPN_ACPT;
+ }
+ break;
+
+ case PLINK_CONFIRM:
+ if (!plink_free_count(hapd) ||
+ (sta->my_lid != llid || sta->peer_lid != plid))
+ event = CNF_IGNR;
+ else
+ event = CNF_ACPT;
+ break;
+
+ case PLINK_CLOSE:
+ if (sta->plink_state == PLINK_ESTAB)
+ /* Do not check for llid or plid. This does not
+ * follow the standard but since multiple plinks
+ * per cand are not supported, it is necessary in
+ * order to avoid a livelock when MP A sees an
+ * establish peer link to MP B but MP B does not
+ * see it. This can be caused by a timeout in
+ * B's peer link establishment or B being
+ * restarted.
+ */
+ event = CLS_ACPT;
+ else if (sta->peer_lid != plid)
+ event = CLS_IGNR;
+ else if (peer_mgmt_ie.plid && sta->my_lid != llid)
+ event = CLS_IGNR;
+ else
+ event = CLS_ACPT;
+ break;
+ default:
+ wpa_msg(wpa_s, MSG_ERROR, "Mesh plink: unknown frame subtype\n");
+ return;
+ }
+ mesh_mpm_fsm(wpa_s, sta, event);
+}
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
new file mode 100644
index 0000000..f890ad6
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.h
@@ -0,0 +1,26 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_MPM_H
+#define MESH_MPM_H
+#include "mesh.h"
+
+/* notify MPM of new mesh peer to be inserted in MPM and driver */
+void
+wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ struct ieee802_11_elems *elems);
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s,
+ struct rx_mgmt *rx_mgmt);
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len);
+void mesh_mpm_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh);
+void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+
+#endif /* MESH_MPM_H */
--
1.9.2
Yu Niiro
2014-06-25 04:05:28 UTC
Permalink
Hello Bob,

Thank you for your updates on the patches.
I made further testing with my devices and found some unlucky case for mesh
peerings.
Sometimes mesh STAs can not establish peering, i.e., after one of the mesh
STAs reboots.

In my view, the following change helps in mitigating this problem.


----
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 9ac7ea2..c7c08dd 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -841,15 +849,27 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
break;

case PLINK_CONFIRM:
- if (!plink_free_count() ||
- (sta->my_lid != llid || sta->peer_lid != plid))
- event = CNF_IGNR;
- else
+ if (sta->plink_state == PLINK_OPEN_RCVD){
+ if (!plink_free_count() ||
+ (sta->my_lid != llid || sta->peer_lid != plid))
{
+ event = CNF_RJCT;
+ }else{
+ event = CNF_ACPT;
+ }
+ }else if (sta->plink_state == PLINK_OPEN_SENT){
+ if (!plink_free_count() || sta->my_lid != llid ) {
+ event = CNF_RJCT;
+ }else{
+ sta->peer_lid = plid;
+ event = CNF_ACPT;
+ }
+ }else{
event = CNF_ACPT;
+ }
break;

case PLINK_CLOSE:

----

When a STA receives PLINK_CONFIRM frame, sta->peer_lid value might not be
set appropriately depending on the plink_state that the STA is in.
Particularly, when the sta->plink_state == PLINK_OPEN_SENT, it is possible
that the STA have not received plink frames from the peer yet. In such
case, sta->peer_lid contains incorrect value and the event end up with
CNF_RJCT.
To avoid this situation, I think that the event value should be set
determining the sta->plink_state.

I found the similar code in the Linux kernel implementation of mesh plink
frame processing, net/mac80211/mesh_plink.c, void mesh_rx_plink_frame().
Ideally, the plink frame should be handled in the same way in the kernel
version as well.


Hope this helps.

-- Yu
Bob Copeland
2014-06-28 16:37:35 UTC
Permalink
Post by Yu Niiro
Hello Bob,
Thank you for your updates on the patches.
I made further testing with my devices and found some unlucky case for mesh
peerings.
Sometimes mesh STAs can not establish peering, i.e., after one of the mesh
STAs reboots.
In my view, the following change helps in mitigating this problem.
Nice catch. I read through the standard, which had this to say:

13.3.7.2 Mesh Peering Confirm frame processing

"If the peerLinkID in the mesh peering instance has not been set, the
Local Link ID field of the Mesh Peering Confirm request shall be
copied..."

And I suppose it could happen if an open frame is lost, like this
(among other cases):

STA1 STA2
(idle)
|------------- OPEN -------------> |
(opn_snt) |
| (opn_rcvd)
| [lost] X------- OPEN ----- |
| <---------- CONFIRM ------------ |
Post by Yu Niiro
I found the similar code in the Linux kernel implementation of mesh plink
frame processing, net/mac80211/mesh_plink.c, void mesh_rx_plink_frame().
Ideally, the plink frame should be handled in the same way in the kernel
version as well.
Indeed, I'll make a patch for the kernel MPM.
--
Bob Copeland %% www.bobcopeland.com
Bob Copeland
2014-05-30 13:22:28 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Modify network mode to support mode number 5 when CONFIG_MESH is
enabled.

Add user_mpm config parameter, when this is set to 1 (the default) the
peer link management is done on userspace, otherwise the peer management
will be done by the kernel.

Also add no_auto_peer parameter, which controls wheter a station will
automatically initiate peering to another mesh peer that comes into
range.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Thomas Pedersen <***@noack.us>

---
Still TODO: incorporate various fixes from Yu Niiro for
saving options

wpa_supplicant/config.c | 9 +++++++++
wpa_supplicant/config.h | 11 +++++++++++
wpa_supplicant/config_file.c | 3 +++
wpa_supplicant/config_ssid.h | 8 ++++++++
wpa_supplicant/ctrl_iface.c | 2 ++
wpa_supplicant/mesh_mpm.c | 7 +++++++
6 files changed, 40 insertions(+)

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b4ee1f5..f517452 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1679,7 +1679,12 @@ static const struct parse_data ssid_fields[] = {
{ INTe(fragment_size) },
{ INTe(ocsp) },
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ { INT_RANGE(mode, 0, 5) },
+ { INT_RANGE(no_auto_peer, 0, 1) },
+#else
{ INT_RANGE(mode, 0, 4) },
+#endif /* CONFIG_MESH */
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
@@ -3240,6 +3245,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
return NULL;
config->eapol_version = DEFAULT_EAPOL_VERSION;
config->ap_scan = DEFAULT_AP_SCAN;
+ config->user_mpm = DEFAULT_USER_MPM;
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
@@ -3778,6 +3784,9 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(eapol_version, 1, 2), 0 },
{ INT(ap_scan), 0 },
{ FUNC(bgscan), 0 },
+#ifdef CONFIG_MESH
+ { INT(user_mpm), 0 },
+#endif /* CONFIG_MESH */
{ INT(disable_scan_offload), 0 },
{ INT(fast_reauth), 0 },
{ STR(opensc_engine_path), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index a398049..aa1a5c7 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -15,6 +15,7 @@
#else /* CONFIG_NO_SCAN_PROCESSING */
#define DEFAULT_AP_SCAN 1
#endif /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_USER_MPM 1
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
@@ -357,6 +358,16 @@ struct wpa_config {
int eapol_version;

/**
+ * user_mpm - MPM residency
+ *
+ * 0: MPM lives in driver.
+ * 1: wpa_supplicant handles peering and station allocation.
+ *
+ * If AMPE or SAE is enabled, the MPM is always in userspace.
+ */
+ int user_mpm;
+
+ /**
* ap_scan - AP scanning/selection
*
* By default, wpa_supplicant requests driver to perform AP
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 8f0561a..d004d83 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1148,6 +1148,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)

if (config->bgscan)
fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
+
+ if (config->user_mpm)
+ fprintf(f, "user_mpm=%d\n", config->user_mpm);
}

#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 91a0065..f0a8b32 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -638,6 +638,14 @@ struct wpa_ssid {
* dereferences since it may not be updated in all cases.
*/
void *parent_cred;
+
+ /**
+ * no_auto_peer - Do not automatically peer with compatible mesh peers
+ *
+ * When unset, the reception of a beacon from a another mesh peer in this
+ * MBSS will trigger a peering attempt.
+ */
+ int no_auto_peer;
};

#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index b8b6d95..5a53ed0 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2550,6 +2550,8 @@ static int wpa_supplicant_ctrl_iface_set_network(
wpa_config_update_psk(ssid);
else if (os_strcmp(name, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
+ else if (os_strcmp(name, "no_auto_peer") == 0)
+ ssid->no_auto_peer = atoi(value);

return 0;
}
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 176e04c..c7311ba 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -303,6 +303,7 @@ wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
int ret = 0;

sta = ap_get_sta(data, addr);
@@ -344,6 +345,12 @@ wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
return;
}

+ if (ssid && ssid->no_auto_peer) {
+ wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
+ MACSTR " because of no_auto_peer", MAC2STR(addr));
+ return;
+ }
+
mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
}
--
1.9.2
Bob Copeland
2014-05-30 13:22:35 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Modify sample wpa_supplicant.conf file to include user_mpm option
and new network mode (5), including open and secure mesh networking.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Thomas Pedersen <***@noack.us>

---
wpa_supplicant/wpa_supplicant.conf | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 86a4621..3d6e3ab 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -110,6 +110,15 @@ eapol_version=1
# networks are found, a new IBSS or AP mode network is created.
ap_scan=1

+# MPM residency
+# By default, wpa_supplicant implements the mesh peering manager (MPM)
+# for an open mesh. However, if the driver can implement the MPM, you
+# may set this to 0 to use the driver version.
+# When AMPE is enabled, the wpa_supplicant MPM is always used.
+# 0: MPM lives in the driver
+# 1: wpa_supplicant provides an MPM which handles peering (default)
+user_mpm=1
+
# EAP fast re-authentication
# By default, fast re-authentication is enabled for all EAP methods that
# support it. This variable can be used to disable fast re-authentication.
@@ -1258,6 +1267,23 @@ network={
psk="secret passphrase"
}

+# open mesh network
+network={
+ ssid="test mesh"
+ mode=5
+ frequency=2437
+ key_mgmt=NONE
+}
+
+# secure (SAE + AMPE) network
+network={
+ ssid="secure mesh"
+ mode=5
+ frequency=2437
+ key_mgmt=SAE
+ psk="very secret passphrase"
+}
+

# Catch all example that allows more or less all configuration modes
network={
--
1.9.2
Bob Copeland
2014-05-30 13:22:25 UTC
Permalink
- To support mesh mode, use u64 to fit all necessary driver flags.
- Create mesh_join and mesh_leave actions to kernel.
- Handle new_peer_candidate events from kernel.
- Register to receive necessary frames.
- Add plink_action_field and mesh_power_mode to hostapd_sta_add_params

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Bob Copeland <***@bobcopeland.com>

---
src/common/defs.h | 25 ++++
src/drivers/driver.h | 87 ++++++++++-
src/drivers/driver_common.c | 1 +
src/drivers/driver_nl80211.c | 297 ++++++++++++++++++++++++++++++++++++--
src/drivers/driver_wext.c | 5 +-
wpa_supplicant/driver_i.h | 25 ++++
wpa_supplicant/wpa_supplicant_i.h | 2 +-
7 files changed, 423 insertions(+), 19 deletions(-)

diff --git a/src/common/defs.h b/src/common/defs.h
index d4091e3..1ee7090 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -300,4 +300,29 @@ enum wpa_ctrl_req_type {
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8

+#ifdef CONFIG_MESH
+enum mesh_plink_state {
+ PLINK_LISTEN = 1,
+ PLINK_OPEN_SENT,
+ PLINK_OPEN_RCVD,
+ PLINK_CNF_RCVD,
+ PLINK_ESTAB,
+ PLINK_HOLDING,
+ PLINK_BLOCKED,
+};
+
+enum mesh_power_mode {
+ MESH_POWER_ACTIVE = 1,
+ MESH_POWER_LIGHT_SLEEP,
+ MESH_POWER_DEEP_SLEEP,
+};
+
+enum plink_action_field {
+ PLINK_OPEN = 1,
+ PLINK_CONFIRM,
+ PLINK_CLOSE
+};
+
+#endif /* CONFIG_MESH */
+
#endif /* DEFS_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 13bf718..a885dff 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -170,6 +170,7 @@ struct hostapd_hw_modes {
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
#define IEEE80211_MODE_AP 2
+#define IEEE80211_MODE_MESH 5

#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
@@ -870,6 +871,29 @@ struct wpa_driver_ap_params {
int osen;
};

+struct wpa_driver_mesh_bss_params {
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+ /* TODO: Other mesh configuration parameters would go here. See
+ * NL80211_MESHCONF_* in nl80211.h for all the mesh config parameters. */
+ unsigned int flags;
+};
+
+struct wpa_driver_mesh_join_params {
+ const u8 *meshid;
+ int meshid_len;
+ int *basic_rates;
+ int mcast_rate;
+ u8 *ies;
+ int ie_len;
+ int freq;
+ struct wpa_driver_mesh_bss_params conf;
+#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
+#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
+#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
+#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
+ unsigned int flags;
+};
+
/**
* struct wpa_driver_capa - Driver capability information
*/
@@ -979,7 +1003,9 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000
/* Driver supports CSA in AP mode */
#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000
- unsigned int flags;
+/* Driver supports mesh */
+#define WPA_DRIVER_FLAGS_MESH 0x0000000100000000ULL
+ u64 flags;

int max_scan_ssids;
int max_sched_scan_ssids;
@@ -1055,6 +1081,12 @@ struct hostapd_sta_add_params {
int vht_opmode_enabled;
u8 vht_opmode;
u32 flags; /* bitmask of WPA_STA_* flags */
+ u32 flags_mask; /* unset bits in flags */
+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+ enum plink_action_field plink_action;
+ enum mesh_power_mode power_mode;
+#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
const u8 *ext_capab;
@@ -1135,7 +1167,11 @@ enum wpa_driver_if_type {
* WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
* abstracted P2P Device function in the driver
*/
- WPA_IF_P2P_DEVICE
+ WPA_IF_P2P_DEVICE,
+ /*
+ * WPA_IF_MESH - Mesh interface
+ */
+ WPA_IF_MESH
};

struct wpa_init_params {
@@ -1173,6 +1209,7 @@ struct wpa_bss_params {
#define WPA_STA_SHORT_PREAMBLE BIT(2)
#define WPA_STA_MFP BIT(3)
#define WPA_STA_TDLS_PEER BIT(4)
+#define WPA_STA_AUTHENTICATED BIT(5)

enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -2761,6 +2798,28 @@ struct wpa_driver_ops {
* Returns: Length of written status information or -1 on failure
*/
int (*status)(void *priv, char *buf, size_t buflen);
+
+ /**
+ * init_mesh - Driver specific initialization for mesh
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*init_mesh)(void *priv);
+
+ /**
+ * join_mesh - Join a mesh network
+ * @priv: Private driver interface data
+ * @params: Mesh configuration parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*join_mesh)(void *priv, struct wpa_driver_mesh_join_params *params);
+
+ /**
+ * leave_mesh - Leave a mesh network
+ * @priv: Private driver interface data
+ * Returns 0 on success, -1 on failure
+ */
+ int (*leave_mesh)(void *priv);
};


@@ -3235,7 +3294,13 @@ enum wpa_event_type {
* to reduce issues due to interference or internal co-existence
* information in the driver.
*/
- EVENT_AVOID_FREQUENCIES
+ EVENT_AVOID_FREQUENCIES,
+
+ /**
+ * EVENT_NEW_PEER_CANDIDATE - new (unknown) mesh peer notification
+ */
+ EVENT_NEW_PEER_CANDIDATE
+
};


@@ -3874,6 +3939,22 @@ union wpa_event_data {
* This is used as the data with EVENT_AVOID_FREQUENCIES.
*/
struct wpa_freq_range_list freq_range;
+
+ /**
+ * struct mesh_peer
+ *
+ * @peer: peer address
+ * @ies: beacon IEs
+ * @ie_len: length of @ies
+ *
+ * Notification of new candidate mesh peer.
+ */
+ struct mesh_peer {
+ u8 peer[ETH_ALEN];
+ u8 *ies;
+ int ie_len;
+ } mesh_peer;
+
};

/**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 3058cd5..63138ab 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -70,6 +70,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
+ E2S(NEW_PEER_CANDIDATE);
E2S(WNM);
E2S(CONNECT_FAILED_REASON);
E2S(DFS_RADAR_DETECTED);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 1300703..e96b4e6 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -544,7 +544,8 @@ static int is_ap_interface(enum nl80211_iftype nlmode)
static int is_sta_interface(enum nl80211_iftype nlmode)
{
return (nlmode == NL80211_IFTYPE_STATION ||
- nlmode == NL80211_IFTYPE_P2P_CLIENT);
+ nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+ nlmode == NL80211_IFTYPE_MESH_POINT);
}


@@ -554,6 +555,11 @@ static int is_p2p_net_interface(enum nl80211_iftype nlmode)
nlmode == NL80211_IFTYPE_P2P_GO);
}

+static int is_mesh_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_MESH_POINT;
+}
+

static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
{
@@ -2459,6 +2465,36 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
}


+static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u8 *addr, *ie;
+ int ie_len;
+ union wpa_event_data data;
+
+ if (drv->nlmode != NL80211_IFTYPE_MESH_POINT)
+ return;
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+ return;
+
+ ie = nla_data(tb[NL80211_ATTR_IE]);
+ ie_len = nla_len(tb[NL80211_ATTR_IE]);
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.mesh_peer.peer, addr, ETH_ALEN);
+ if ((data.mesh_peer.ies = os_zalloc(ie_len)) == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: couldn't alloc peer IEs!");
+ return;
+ }
+ os_memcpy(data.mesh_peer.ies, ie, ie_len);
+ data.mesh_peer.ie_len = ie_len;
+ wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data);
+ os_free(data.mesh_peer.ies);
+}
+
static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
@@ -3113,6 +3149,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
case NL80211_CMD_VENDOR:
nl80211_vendor_event(drv, tb);
break;
+ case NL80211_CMD_NEW_PEER_CANDIDATE:
+ nl80211_new_peer_candidate(drv, tb);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -3415,6 +3454,9 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
case NL80211_IFTYPE_AP:
info->capa->flags |= WPA_DRIVER_FLAGS_AP;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
+ break;
case NL80211_IFTYPE_ADHOC:
info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
break;
@@ -4477,6 +4519,37 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
return ret;
}

+static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
+{
+ int ret = 0;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with mesh "
+ "handle %p", bss->nl_mgmt);
+
+ /* Auth frames for mesh SAE */
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4),
+ NULL, 0) < 0)
+ ret = -1;
+
+ /* Mesh peering open */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
+ ret = -1;
+ /* Mesh peering confirm */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
+ ret = -1;
+ /* Mesh peering close */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
+ ret = -1;
+
+ nl80211_mgmt_handle_register_eloop(bss);
+
+ return ret;
+}

static int nl80211_register_spurious_class3(struct i802_bss *bss)
{
@@ -4825,7 +4898,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)

if (!drv->start_iface_up)
(void) i802_set_iface_flags(bss, 0);
- if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+
+ if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE &&
+ drv->nlmode != NL80211_IFTYPE_MESH_POINT) {
if (!drv->hostapd || !drv->start_mode_ap)
wpa_driver_nl80211_set_mode(bss,
NL80211_IFTYPE_STATION);
@@ -5688,7 +5763,18 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
}

- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (!addr && key_len && set_tx) {
+ /* this is a group tx key */
+ if (alg == WPA_ALG_IGTK || alg == WPA_ALG_CCMP) {
+ wpa_printf(MSG_DEBUG, " TX GTK");
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
+ NL80211_KEYTYPE_GROUP);
+ if (alg == WPA_ALG_IGTK)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
+ else
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+ }
+ } else if (addr && !is_broadcast_ether_addr(addr)) {
wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);

@@ -7412,10 +7498,37 @@ static u32 sta_flags_nl80211(int flags)
f |= BIT(NL80211_STA_FLAG_MFP);
if (flags & WPA_STA_TDLS_PEER)
f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (flags & WPA_STA_AUTHENTICATED)
+ f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);

return f;
}

+#ifdef CONFIG_MESH
+static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
+{
+ switch (state) {
+ case PLINK_LISTEN:
+ return NL80211_PLINK_LISTEN;
+ case PLINK_OPEN_SENT:
+ return NL80211_PLINK_OPN_SNT;
+ case PLINK_OPEN_RCVD:
+ return NL80211_PLINK_OPN_RCVD;
+ case PLINK_CNF_RCVD:
+ return NL80211_PLINK_CNF_RCVD;
+ case PLINK_ESTAB:
+ return NL80211_PLINK_ESTAB;
+ case PLINK_HOLDING:
+ return NL80211_PLINK_HOLDING;
+ case PLINK_BLOCKED:
+ return NL80211_PLINK_BLOCKED;
+ default:
+ wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
+ state);
+ }
+ return -1;
+}
+#endif /* CONFIG_MESH */

static int wpa_driver_nl80211_sta_add(void *priv,
struct hostapd_sta_add_params *params)
@@ -7441,11 +7554,13 @@ static int wpa_driver_nl80211_sta_add(void *priv,

NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
- params->supp_rates);
- wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates,
- params->supp_rates_len);
+
if (!params->set) {
+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
+ params->supp_rates_len, params->supp_rates);
+ wpa_hexdump(MSG_DEBUG, " * supported rates",
+ params->supp_rates, params->supp_rates_len);
+
if (params->aid) {
wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
@@ -7490,8 +7605,10 @@ static int wpa_driver_nl80211_sta_add(void *priv,
params->vht_opmode);
}

- wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
+ if (params->capability) {
+ wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
+ }

if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
@@ -7517,12 +7634,18 @@ static int wpa_driver_nl80211_sta_add(void *priv,
}

os_memset(&upd, 0, sizeof(upd));
- upd.mask = sta_flags_nl80211(params->flags);
- upd.set = upd.mask;
+ upd.set = sta_flags_nl80211(params->flags);
+ upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
upd.set, upd.mask);
NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);

+#ifdef CONFIG_MESH
+ if (params->plink_state)
+ NLA_PUT_U8(msg, NL80211_ATTR_STA_PLINK_STATE,
+ sta_plink_state_nl80211(params->plink_state));
+#endif /* CONFIG_MESH */
+
if (params->flags & WPA_STA_WMM) {
struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);

@@ -8789,6 +8912,138 @@ static int wpa_driver_nl80211_connect(
}


+static int wpa_driver_nl80211_init_mesh(void *priv)
+{
+ if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
+ wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+ "mode mode");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_join_mesh(
+ void *priv,
+ struct wpa_driver_mesh_join_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+ 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->basic_rates) {
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES && params->basic_rates[i] >= 0;
+ i++)
+ rates[rates_len++] = params->basic_rates[i] / 5;
+
+ NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+ }
+
+ if (params->meshid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->meshid, params->meshid_len);
+ NLA_PUT(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
+ params->meshid);
+ }
+
+ wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
+ if (!container)
+ goto nla_put_failure;
+
+ if (params->ies) {
+ wpa_hexdump(MSG_DEBUG, " * IEs",
+ (unsigned char *) params->ies, params->ie_len);
+ NLA_PUT(msg, NL80211_MESH_SETUP_IE, params->ie_len,
+ params->ies);
+ }
+ /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
+ if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
+ NLA_PUT_U8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1);
+ NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_AUTH);
+ }
+ if (params->flags & WPA_DRIVER_MESH_FLAG_AMPE)
+ NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_AMPE);
+ if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
+ NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_MPM);
+ nla_nest_end(msg, container);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+ if (!container)
+ goto nla_put_failure;
+
+ if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS))
+ NLA_PUT_U32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0);
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+ bss->freq = params->freq;
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
+
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+static int wpa_driver_nl80211_leave_mesh(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_MESH);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave request send successfully");
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
static int wpa_driver_nl80211_associate(
void *priv, struct wpa_driver_associate_params *params)
{
@@ -8969,7 +9224,12 @@ done:
nl80211_mgmt_unsubscribe(bss, "mode change");
}

+ if (is_mesh_interface(nlmode))
+ if (nl80211_mgmt_subscribe_mesh(bss))
+ return -1;
+
if (!bss->in_deinit && !is_ap_interface(nlmode) &&
+ !is_mesh_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)
wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
"frame processing - ignore for now");
@@ -9484,6 +9744,9 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;

+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
if (drv->device_ap_sme)
return wpa_driver_nl80211_sta_remove(bss, addr);

@@ -9508,6 +9771,9 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;

+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
if (drv->device_ap_sme)
return wpa_driver_nl80211_sta_remove(bss, addr);

@@ -9834,6 +10100,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
return NL80211_IFTYPE_P2P_GO;
case WPA_IF_P2P_DEVICE:
return NL80211_IFTYPE_P2P_DEVICE;
+ case WPA_IF_MESH:
+ return NL80211_IFTYPE_MESH_POINT;
}
return -1;
}
@@ -11796,7 +12064,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
"capa.key_mgmt=0x%x\n"
"capa.enc=0x%x\n"
"capa.auth=0x%x\n"
- "capa.flags=0x%x\n"
+ "capa.flags=0x%llx\n"
"capa.max_scan_ssids=%d\n"
"capa.max_sched_scan_ssids=%d\n"
"capa.sched_scan_supported=%d\n"
@@ -11809,7 +12077,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
- drv->capa.flags,
+ (unsigned long long) drv->capa.flags,
drv->capa.max_scan_ssids,
drv->capa.max_sched_scan_ssids,
drv->capa.sched_scan_supported,
@@ -12096,6 +12364,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.deauthenticate = driver_nl80211_deauthenticate,
.authenticate = driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
+ .init_mesh = wpa_driver_nl80211_init_mesh,
+ .join_mesh = wpa_driver_nl80211_join_mesh,
+ .leave_mesh = wpa_driver_nl80211_leave_mesh,
.global_init = nl80211_global_init,
.global_deinit = nl80211_global_deinit,
.init2 = wpa_driver_nl80211_init,
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index e5734bd..0851c26 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1568,8 +1568,9 @@ static int wpa_driver_wext_get_range(void *priv)
drv->capa.max_scan_ssids = 1;

wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
- "flags 0x%x",
- drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ "flags 0x%llx",
+ drv->capa.key_mgmt, drv->capa.enc,
+ (unsigned long long) drv->capa.flags);
} else {
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
"assuming WPA is not supported");
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 938ece6..0a353f8 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -65,6 +65,31 @@ static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,
return -1;
}

+static inline int wpa_drv_init_mesh(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->init_mesh) {
+ return wpa_s->driver->init_mesh(wpa_s->drv_priv);
+ }
+ return -1;
+}
+
+static inline int wpa_drv_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_mesh_join_params *params)
+{
+ if (wpa_s->driver->join_mesh) {
+ return wpa_s->driver->join_mesh(wpa_s->drv_priv, params);
+ }
+ return -1;
+}
+
+static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->leave_mesh) {
+ return wpa_s->driver->leave_mesh(wpa_s->drv_priv);
+ }
+ return -1;
+}
+
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 39f5c43..0c53723 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -561,7 +561,7 @@ struct wpa_supplicant {
int scan_for_connection; /* whether the scan request was triggered for
* finding a connection */

- unsigned int drv_flags;
+ u64 drv_flags;
unsigned int drv_enc;

/*
--
1.9.2
Bob Copeland
2014-05-30 13:22:34 UTC
Permalink
From: Javier Lopez <***@gmail.com>

Parse MESH_GROUP_ADD/REMOVE commands on ctrl interface and call
wpa_supplicant routines. These commands are used to start or
join a mesh network.

The mesh id is given in the configuration file, therefore there is
no need to scan before joining a mesh network. We reuse the
connect_without_scan construct used by p2p for that same purpose.

Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-hostap: Javier Lopez <***@gmail.com>
---
wpa_supplicant/ctrl_iface.c | 73 +++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/wpa_cli.c | 21 ++++++++++++
wpa_supplicant/wpa_supplicant.c | 54 +++++++++++++++++++++++++++---
3 files changed, 144 insertions(+), 4 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 080f303..3b1b2ee 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2298,6 +2298,71 @@ static int wpa_supplicant_ctrl_iface_scan_results(
return pos - buf;
}

+#ifdef CONFIG_MESH
+static int wpa_supplicant_ctrl_iface_mesh_group_add(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+ "network id=%d", id);
+ return -1;
+ }
+ if (ssid->mode != 5) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+ "MESH_GROUP_ADD on a non mesh network");
+ return -1;
+ }
+
+ /*
+ * TODO: If necessary write our own group_add function,
+ * for now we can reuse select_network
+ */
+ wpa_supplicant_select_network(wpa_s, ssid);
+ return 0;
+}
+
+static int wpa_supplicant_ctrl_iface_mesh_group_remove(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ if (!cmd) {
+ wpa_printf(MSG_ERROR, "CTRL_IFACE: MESH_GROUP_REMOVE ifname "
+ "cannot be empty");
+ return -1;
+ }
+
+ /*
+ * TODO: Support a multiple mesh and other iface type combinations
+ */
+ if (os_strcmp(cmd, wpa_s->ifname) != 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE unknown "
+ "interface name: %s", cmd);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
+
+ wpa_s->reassociate = 0;
+ wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /*
+ * TODO: If necessary write our own group_remove function,
+ * for now we can reuse deauthenticate
+ */
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+
+ return 0;
+}
+#endif /* CONFIG_MESH */

static int wpa_supplicant_ctrl_iface_select_network(
struct wpa_supplicant *wpa_s, char *cmd)
@@ -6271,6 +6336,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_MESH
+ } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s, buf + 18))
+ reply_len = -1;
+#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
if (p2p_ctrl_find(wpa_s, buf + 9))
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 77c5295..525b52c 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1725,6 +1725,19 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
}

+#ifdef CONFIG_MESH
+static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv);
+}
+
+static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
+}
+#endif /* CONFIG_MESH */

#ifdef CONFIG_P2P

@@ -2748,6 +2761,14 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
+#ifdef CONFIG_MESH
+ { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
+ cli_cmd_flag_none,
+ "<network id> = join a mesh network (disable others)" },
+ { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
+ cli_cmd_flag_none,
+ "<ifname> = Remove Mesh group interface" },
+#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
cli_cmd_flag_none,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 5d9cbf7..d0b1b9b 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -51,6 +51,7 @@
#include "offchannel.h"
#include "hs20_supplicant.h"
#include "wnm_sta.h"
+#include "mesh.h"

const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -1398,6 +1399,31 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}

+ if (ssid->mode == WPAS_MODE_MESH) {
+#ifdef CONFIG_MESH
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
+ wpa_msg(wpa_s, MSG_INFO, "Driver does not support "
+ "mesh mode");
+ return;
+ }
+ if (bss)
+ ssid->frequency = bss->freq;
+ if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "couldn't join mesh");
+ return;
+ }
+ wpa_s->current_bss = bss;
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
+ "ssid=\"%s\" id=%d",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->id);
+#else /* CONFIG_MESH */
+ wpa_msg(wpa_s, MSG_ERROR, "mesh mode support not included in "
+ "the build");
+#endif /* CONFIG_MESH */
+ return;
+ }
+
#ifdef CONFIG_TDLS
if (bss)
wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1735,9 +1761,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.fixed_bssid = 1;
}

- if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
- params.freq == 0)
- params.freq = ssid->frequency; /* Initial channel for IBSS */
+ /* Initial frequency for IBSS/mesh */
+ if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
+ ssid->frequency > 0 && params.freq == 0)
+ params.freq = ssid->frequency; /* Initial channel for IBSS/mesh */

if (ssid->mode == WPAS_MODE_IBSS) {
if (ssid->beacon_int)
@@ -1963,6 +1990,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_tdls_teardown_peers(wpa_s->wpa);
#endif /* CONFIG_TDLS */

+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED
+ "%s", wpa_s->ifname);
+ wpa_supplicant_leave_mesh(wpa_s);
+ }
+#endif /* CONFIG_MESH */
+
if (addr) {
wpa_drv_deauthenticate(wpa_s, addr, reason_code);
os_memset(&event, 0, sizeof(event));
@@ -2128,8 +2164,11 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
if (ssid) {
wpa_s->current_ssid = ssid;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->connect_without_scan = (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+ } else {
+ wpa_s->connect_without_scan = NULL;
}
- wpa_s->connect_without_scan = NULL;
+
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;

@@ -3711,6 +3750,13 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
wpa_s->ctrl_iface = NULL;
}

+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ }
+#endif /* CONFIG_MESH */
+
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
--
1.9.2
Bob Copeland
2014-05-30 13:22:38 UTC
Permalink
From: Javier Lopez <***@gmail.com>

Modify hostapd.c logic to add checks for valid mconf data structure:

- For hostapd_setup_bss we don't need to flush old stations in case
we're rejoining a mesh network.

- In hostapd_setup_interface_complete, we don't need to setup the
interface until we join the mesh (same reasoning for
hostapd_tx_queue_params).

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Javier Lopez <***@gmail.com>

---
src/ap/hostapd.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 614a5bf..93f1b39 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -668,6 +668,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
+ int flush_old_stations = 1;

wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
__func__, hapd, hapd->conf->iface, first);
@@ -715,7 +716,13 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;

- hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_MESH
+ if (hapd->iface->mconf == NULL)
+ flush_old_stations = 0;
+#endif /* CONFIG_MESH */
+
+ if (flush_old_stations)
+ hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);

hostapd_broadcast_wep_clear(hapd);
@@ -870,6 +877,11 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
int i;
struct hostapd_tx_queue_params *p;

+#ifdef CONFIG_MESH
+ if (iface->mconf == NULL)
+ return;
+#endif /* CONFIG_MESH */
+
for (i = 0; i < NUM_TX_QUEUES; i++) {
p = &iface->conf->tx_queue[i];

@@ -1146,6 +1158,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
struct hostapd_data *hapd = iface->bss[0];
size_t j;
u8 *prev_addr;
+ int delay_apply_cfg = 0;

if (err)
goto fail;
@@ -1172,7 +1185,17 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
}
#endif /* NEED_AP_MLME */

- if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+#ifdef CONFIG_MESH
+ if (iface->mconf != NULL) {
+ wpa_printf(MSG_DEBUG, "%s: Mesh configuration will be "
+ "applied while joining the mesh network.",
+ iface->bss[0]->conf->iface);
+ delay_apply_cfg = 1;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!delay_apply_cfg &&
+ hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
--
1.9.2
Bob Copeland
2014-05-30 13:22:31 UTC
Permalink
This implementation provides:

- Mesh SAE authentication mechanism
- Key management (set/get PSK)
- Cryptographic key establishment
- Enhanced protection mechanisms for robust management frames

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Thomas Pedersen <***@noack.us>

---
wpa_supplicant/Android.mk | 4 +
wpa_supplicant/Makefile | 5 +-
wpa_supplicant/mesh.c | 8 +
wpa_supplicant/mesh_mpm.c | 30 ++-
wpa_supplicant/mesh_rsn.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh_rsn.h | 39 ++++
6 files changed, 635 insertions(+), 3 deletions(-)
create mode 100644 wpa_supplicant/mesh_rsn.c
create mode 100644 wpa_supplicant/mesh_rsn.h

diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 1532923..742121d 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -210,9 +210,13 @@ L_CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.c
ifdef CONFIG_MESH
NEED_80211_COMMON=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
L_CFLAGS += -DCONFIG_MESH
OBJS += mesh.c
OBJS += mesh_mpm.c
+OBJS += mesh_rsn.c
endif
endif

diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 7013a37..310d8af 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -254,8 +254,11 @@ endif

ifdef CONFIG_MESH
NEED_80211_COMMON=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
CFLAGS += -DCONFIG_MESH
-OBJS += mesh.o mesh_mpm.o
+OBJS += mesh.o mesh_mpm.o mesh_rsn.o
endif

ifdef CONFIG_P2P
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 4f82fca..d96d654 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -8,12 +8,16 @@

#include "mesh.h"
#include "mesh_mpm.h"
+#include "mesh_rsn.h"

static void
wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
{
wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
wpa_s->ifmsh = NULL;
+ if (wpa_s->mesh_rsn)
+ os_free(wpa_s->mesh_rsn);
+ wpa_s->mesh_rsn = NULL;
/* TODO: leave mesh (stop beacon). This will happen on link down
* anyway, so it's not urgent */
}
@@ -194,6 +198,10 @@ wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,

len = os_strlen(ssid->passphrase);
bss->conf->ssid.wpa_passphrase = dup_binstr(ssid->passphrase, len);
+
+ wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
+ if (!wpa_s->mesh_rsn)
+ goto out_free;
}

return 0;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index c7311ba..86d1679 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -7,6 +7,7 @@
*/

#include "mesh_mpm.h"
+#include "mesh_rsn.h"

#include "eloop.h"
#include "ap.h"
@@ -280,6 +281,8 @@ mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
* the AP code already sets this flag. */
sta->flags |= WLAN_STA_AUTH;

+ mesh_rsn_init_ampe_sta(wpa_s, sta);
+
os_memset(&params, 0, sizeof(params));
params.addr = sta->addr;
params.flags = (WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED);
@@ -351,7 +354,10 @@ wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
return;
}

- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ if (conf->security == MESH_CONF_SEC_NONE)
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ else
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
}

static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
@@ -364,7 +370,7 @@ 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];
- u8 *pos;
+ u8 *pos, *cat;
u8 ie_len, add_plid = 0;
int ret;
int ampe = conf->security & MESH_CONF_SEC_AMPE;
@@ -383,6 +389,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
if (!buf)
return;

+ cat = wpabuf_mhead_u8(buf);
wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
wpabuf_put_u8(buf, type);

@@ -461,15 +468,24 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
wpabuf_put_le16(buf, sta->peer_lid);
if (type == PLINK_CLOSE)
wpabuf_put_le16(buf, close_reason);
+ if (ampe)
+ mesh_rsn_get_pmkid(sta, (u8 *) wpabuf_put(buf, PMKID_LEN));

/* TODO HT IEs */

+ if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Mesh MPM: failed to add AMPE and MIC IE");
+ goto fail;
+ }
+
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
sta->addr, wpa_s->own_addr, wpa_s->own_addr,
wpabuf_head(buf), wpabuf_len(buf), 0);
if (ret < 0)
wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: failed to send peering frame");

+fail:
wpabuf_free(buf);
}

@@ -531,6 +547,7 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
enum plink_event event)
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
u16 reason = 0;

mpl_dbg(wpa_s, sta, event);
@@ -594,6 +611,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM, 0);
break;
case CNF_ACPT:
+ if (conf->security & MESH_CONF_SEC_AMPE)
+ mesh_rsn_derive_mtk(wpa_s, sta);
mesh_mpm_plink_estab(wpa_s, sta);
break;
default:
@@ -679,6 +698,7 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
{
u8 action_field;
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
struct sta_info *sta;
u16 plid = 0, llid = 0;
enum plink_event event;
@@ -745,6 +765,12 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);

+ if (mconf->security & MESH_CONF_SEC_AMPE)
+ if (mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ ies, ie_len))
+ return;
+
if (sta->plink_state == PLINK_BLOCKED)
return;

diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
new file mode 100644
index 0000000..a329ded
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.c
@@ -0,0 +1,552 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "mesh_rsn.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_ie.h"
+#include "ap/wpa_auth.h"
+#include "ap/wpa_auth_i.h"
+#include "ap/pmksa_cache_auth.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "wpas_glue.h"
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+ const char *txt)
+{
+ if (addr)
+ wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+ MAC2STR(addr), txt);
+ else
+ wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static const u8 * auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+ __func__, MAC2STR(addr), prev_psk);
+
+ if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+ if (!sta->sae || prev_psk)
+ return NULL;
+ return sta->sae->pmk;
+ }
+ return NULL;
+}
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+ const u8 *addr, int idx, u8 *key, size_t key_len)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ u8 seq[6];
+
+ os_memset(seq, 0, sizeof(seq));
+
+ if (addr) {
+ wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
+ " key_idx=%d)",
+ __func__, alg, MAC2STR(addr), idx);
+ } else {
+ wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
+ __func__, alg, idx);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
+
+ return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
+ 1, seq, 6, key, key_len);
+}
+
+static int auth_start_ampe(void *ctx, const u8 *addr)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+
+ if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH)
+ return -1;
+
+ mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr);
+ return 0;
+}
+
+static int
+__mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+{
+ struct wpa_auth_config conf;
+ struct wpa_auth_callbacks cb;
+ u8 seq[6] = {};
+
+ wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+ os_memset(&conf, 0, sizeof(conf));
+ conf.wpa = 2;
+ conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+ conf.wpa_pairwise = WPA_CIPHER_CCMP;
+ conf.rsn_pairwise = WPA_CIPHER_CCMP;
+ conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.eapol_version = 0;
+ conf.wpa_group_rekey = 600;
+
+ os_memset(&cb, 0, sizeof(cb));
+ cb.ctx = rsn;
+ cb.logger = auth_logger;
+ cb.get_psk = auth_get_psk;
+ cb.set_key = auth_set_key;
+ cb.start_ampe = auth_start_ampe;
+
+ rsn->auth = wpa_init(addr, &conf, &cb);
+ if (rsn->auth == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+ return -1;
+ }
+
+ /* TODO: support rekeying */
+ random_get_bytes(rsn->mgtk, 16);
+
+ /* TODO: don't hardcode key idx */
+ /* mcast mgmt */
+ wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
+ seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+ /* mcast data */
+ wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
+ seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+ return 0;
+}
+
+static void mesh_rsn_deinit(struct mesh_rsn *rsn)
+{
+ /* TODO: stuff */
+}
+
+struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+ struct mesh_conf *conf)
+{
+ struct mesh_rsn *mesh_rsn;
+ struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
+
+ mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
+ if (mesh_rsn == NULL)
+ return NULL;
+ mesh_rsn->wpa_s = wpa_s;
+
+ if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+ mesh_rsn_deinit(mesh_rsn);
+ return NULL;
+ }
+
+ bss->wpa_auth = mesh_rsn->auth;
+
+ conf->ies = mesh_rsn->auth->wpa_ie;
+ conf->ie_len = mesh_rsn->auth->wpa_ie_len;
+
+ wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+
+ return mesh_rsn;
+}
+
+static int index_within_array(const int *array, int idx)
+{
+ int i;
+ for (i = 0; i < idx; i++) {
+ if (array[i] == -1)
+ return 0;
+ }
+ return 1;
+}
+
+static int mesh_rsn_sae_group(struct wpa_supplicant *wpa_s,
+ struct sae_data *sae)
+{
+ int *groups = wpa_s->ifmsh->bss[0]->conf->sae_groups;
+
+ /* Configuration may have changed, so validate current index */
+ if (!index_within_array(groups, wpa_s->mesh_rsn->sae_group_index))
+ return -1;
+
+ for (;;) {
+ int group = groups[wpa_s->mesh_rsn->sae_group_index];
+ if (group < 0)
+ break;
+ if (sae_set_group(sae, group) == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+ sae->group);
+ return 0;
+ }
+ wpa_s->mesh_rsn->sae_group_index++;
+ }
+
+ return -1;
+}
+
+struct wpabuf *
+mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct sta_info *sta)
+{
+ struct wpabuf *buf;
+ int len;
+
+ if (ssid->passphrase == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
+ return NULL;
+ }
+
+ if (sae_prepare_commit(wpa_s->own_addr, sta->addr,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase), sta->sae) < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
+
+ len = wpa_s->mesh_rsn->sae_token ?
+ wpabuf_len(wpa_s->mesh_rsn->sae_token) : 0;
+ buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
+ if (buf == NULL)
+ return NULL;
+
+ sae_write_commit(sta->sae, buf, wpa_s->mesh_rsn->sae_token);
+
+ return buf;
+}
+
+static void mesh_rsn_send_auth(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const u8 *src,
+ u16 auth_transaction, u16 resp,
+ struct wpabuf *data)
+{
+ struct ieee80211_mgmt *auth;
+ u8 *buf;
+ size_t len;
+
+ len = IEEE80211_HDRLEN + sizeof(auth->u.auth) + wpabuf_len(data);
+ buf = os_zalloc(len);
+ if (buf == NULL)
+ return;
+
+ auth = (struct ieee80211_mgmt *) buf;
+ auth->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ os_memcpy(auth->da, dst, ETH_ALEN);
+ os_memcpy(auth->sa, src, ETH_ALEN);
+ os_memcpy(auth->bssid, src, ETH_ALEN);
+
+ auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
+ auth->u.auth.auth_transaction = host_to_le16(auth_transaction);
+ auth->u.auth.status_code = host_to_le16(resp);
+
+ if (data)
+ os_memcpy(auth->u.auth.variable,
+ wpabuf_head(data), wpabuf_len(data));
+
+ wpa_msg(wpa_s, MSG_DEBUG, "authentication frame: STA=" MACSTR
+ " auth_transaction=%d resp=%d (IE len=%lu)",
+ MAC2STR(dst), auth_transaction,
+ resp, (unsigned long) wpabuf_len(data));
+ if (wpa_drv_send_mlme(wpa_s, buf, len, 0) < 0)
+ perror("send_auth_reply: send");
+
+ os_free(buf);
+}
+
+/* initiate new SAE authentication with sta */
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpabuf *buf;
+
+ if (!sta->sae) {
+ sta->sae = os_zalloc(sizeof(*sta->sae));
+ if (sta->sae == NULL)
+ return -1;
+ }
+
+ buf = mesh_rsn_build_sae_commit(wpa_s, ssid, sta);
+ if (!buf)
+ return -1;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "AUTH: started authentication with SAE peer: "
+ MACSTR, MAC2STR(sta->addr));
+
+ sta->sae->state = SAE_NOTHING;
+ wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+
+ mesh_rsn_send_auth(wpa_s, sta->addr, wpa_s->own_addr,
+ SAE_COMMITTED, WLAN_STATUS_SUCCESS, buf);
+
+ /* maybe MPM does this
+ eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+ NULL);
+ */
+ wpabuf_free(buf);
+ return 0;
+}
+
+void mesh_rsn_get_pmkid(struct sta_info *sta, u8 *pmkid)
+{
+ struct wpa_state_machine *sm = sta->wpa_sm;
+ /* don't expect wpa auth to cache the pmkid for now */
+ rsn_pmkid(sta->sae->pmk, PMK_LEN, sm->wpa_auth->addr,
+ sm->addr, pmkid,
+ wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+}
+
+static void
+mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
+{
+ u8 *myaddr = rsn->auth->addr;
+ u8 *peer = sta->addr;
+ u8 *addr1 = peer, *addr2 = myaddr;
+ u8 context[AES_BLOCK_SIZE];
+ /* SAE */
+ RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+
+ if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+ addr1 = myaddr;
+ addr2 = peer;
+ }
+ os_memcpy(context + 4, addr1, ETH_ALEN);
+ os_memcpy(context + 10, addr2, ETH_ALEN);
+
+ sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
+ context, sizeof(context), sta->aek, sizeof(sta->aek));
+}
+
+/* derive mesh temporal key from pmk */
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
+{
+ u8 *ptr;
+ u8 *min, *max;
+ u8 smin[2], smax[2];
+ size_t nonce_len = sizeof(sta->my_nonce);
+ size_t lid_len = sizeof(sta->my_lid);
+
+ /* XXX use rsn pointer? */
+ u8 *myaddr = wpa_s->own_addr;
+ u8 *peer = sta->addr;
+
+ /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
+ u8 context[64 + 4 + 4 + 12];
+
+ ptr = context;
+ if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+ min = sta->my_nonce;
+ max = sta->peer_nonce;
+ } else {
+ min = sta->peer_nonce;
+ max = sta->my_nonce;
+ }
+ os_memcpy(ptr, min, nonce_len);
+ os_memcpy(ptr + nonce_len, max, nonce_len);
+ ptr += 2 * nonce_len;
+
+ /* FIXME memcmp here? */
+ if (sta->my_lid < sta->peer_lid) {
+ smin[0] = (sta->my_lid >> 8) & 0xff;
+ smin[1] = sta->my_lid & 0xff;
+ smax[0] = (sta->peer_lid >> 8) & 0xff;
+ smax[1] = sta->peer_lid & 0xff;
+ } else {
+ smin[0] = (sta->peer_lid >> 8) & 0xff;
+ smin[1] = sta->peer_lid & 0xff;
+ smax[0] = (sta->my_lid >> 8) & 0xff;
+ smax[1] = sta->my_lid & 0xff;
+ }
+ os_memcpy(ptr, smin, lid_len);
+ os_memcpy(ptr + lid_len, smax, lid_len);
+ ptr += 2 * lid_len;
+
+ /* SAE */
+ RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+ ptr += 4;
+
+ if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+ min = myaddr;
+ max = peer;
+ } else {
+ min = peer;
+ max = myaddr;
+ }
+ os_memcpy(ptr, min, ETH_ALEN);
+ os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+
+ sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+ "Temporal Key Derivation", context, sizeof(context),
+ sta->mtk, sizeof(sta->mtk));
+ return 0;
+}
+
+
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ random_get_bytes(sta->my_nonce, 32);
+ os_memset(sta->peer_nonce, 0, 32);
+ mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
+ /* TODO: init SIV-AES contexts for AMPE IE encryption */
+}
+
+/* insert AMPE and encrypted MIC at @ie.
+ * @mesh_rsn: mesh RSN context
+ * @sta: STA we're sending to
+ * @cat: pointer to category code in frame header.
+ * @buf: wpabuf to add encrypted AMPE and MIC to.
+ * */
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn,
+ struct sta_info *sta, const u8 *cat,
+ struct wpabuf *buf)
+{
+ struct ieee80211_ampe_ie *ampe;
+ u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
+ u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+ const u8 *aad[] = {rsn->auth->addr, sta->addr, cat};
+ const size_t aad_len[] = {ETH_ALEN, ETH_ALEN, ie - cat};
+ int ret = 0;
+
+ if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+ wpa_printf(MSG_ERROR, "protect frame: buffer too small\n");
+ return -EINVAL;
+ }
+
+ ampe_ie = os_zalloc(2 + sizeof(*ampe));
+ if (!ampe_ie) {
+ wpa_printf(MSG_ERROR, "protect frame: out of memory\n");
+ return -ENOMEM;
+ }
+
+ mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
+ if (!mic_ie) {
+ wpa_printf(MSG_ERROR, "protect frame: out of memory\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ /* IE: AMPE */
+ ampe_ie[0] = WLAN_EID_AMPE;
+ ampe_ie[1] = sizeof(*ampe);
+ ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
+
+ RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
+ wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
+ os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
+ os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
+ /* incomplete: see 13.5.4 */
+ /* TODO: static mgtk for now since we don't support rekeying! */
+ os_memcpy(ampe->mgtk, rsn->mgtk, 16);
+ /* TODO: Populate Key RSC */
+ os_memset(ampe->key_expiration, 0xff, 4); /* expire in 13 decades or so */
+
+ /* IE: MIC */
+ mic_ie[0] = WLAN_EID_MIC;
+ mic_ie[1] = AES_BLOCK_SIZE;
+ wpabuf_put_data(buf, mic_ie, 2);
+ /* MIC field is output ciphertext */
+
+ /* encrypt after MIC */
+ mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) + AES_BLOCK_SIZE);
+ if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+ aad, aad_len, mic_payload)) {
+ wpa_printf(MSG_ERROR, "protect frame: failed to encrypt\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+free:
+ if (ampe_ie)
+ os_free(ampe_ie);
+ if (mic_ie)
+ os_free(mic_ie);
+ return ret;
+}
+
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems,
+ const u8 *cat,
+ const u8 *start, size_t elems_len)
+{
+ int ret = 0;
+ struct ieee80211_ampe_ie *ampe;
+ u8 null_nonce[32] = {};
+ u8 ampe_eid;
+ u8 ampe_ie_len;
+ u8 *ampe_buf, *crypt = NULL;
+ size_t crypt_len;
+ const u8 *aad[] = {sta->addr, wpa_s->mesh_rsn->auth->addr, cat};
+ const size_t aad_len[] = {ETH_ALEN, ETH_ALEN, (elems->mic - 2) - cat};
+
+ if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
+ return -1;
+ }
+
+ ampe_buf = (u8 *) elems->mic + elems->mic_len;
+ if (elems_len < ampe_buf - start)
+ return -1;
+
+ crypt_len = elems_len - (elems->mic - start);
+ if (crypt_len < 2) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
+ return -1;
+ }
+
+ /* crypt is modified by siv_decrypt */
+ crypt = os_zalloc(crypt_len);
+ if (!crypt) {
+ wpa_printf(MSG_ERROR, "Mesh RSN: out of memory");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ os_memcpy(crypt, elems->mic, crypt_len);
+
+ if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
+ aad, aad_len, ampe_buf)) {
+ wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
+ ret = -1;
+ goto free;
+ }
+
+ ampe_eid = *ampe_buf++;
+ ampe_ie_len = *ampe_buf++;
+
+ if (ampe_eid != WLAN_EID_AMPE ||
+ ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
+ ret = -1;
+ goto free;
+ }
+
+ ampe = (struct ieee80211_ampe_ie *) ampe_buf;
+ if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
+ os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
+ ret = -1;
+ goto free;
+ }
+ memcpy(sta->peer_nonce, ampe->local_nonce, sizeof(ampe->local_nonce));
+ memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
+
+ /* todo parse mgtk expiration */
+free:
+ if (crypt)
+ os_free(crypt);
+ return ret;
+}
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
new file mode 100644
index 0000000..8582bfa
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.h
@@ -0,0 +1,39 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_RSN_H
+#define MESH_RSN_H
+#include "mesh_mpm.h"
+#include "common/sae.h"
+
+struct mesh_rsn {
+ struct wpa_supplicant *wpa_s;
+ struct wpa_authenticator *auth;
+ u8 psk[SAE_PMK_LEN];
+ u8 mgtk[16];
+#ifdef CONFIG_SAE
+ struct wpabuf *sae_token;
+ int sae_group_index;
+#endif /* CONFIG_SAE */
+};
+
+struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+ struct mesh_conf *conf);
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+void mesh_rsn_get_pmkid(struct sta_info *sta, u8 *pmkid);
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta);
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn,
+ struct sta_info *sta, const u8 *cat,
+ struct wpabuf *buf);
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *start, size_t elems_len);
+#endif /* MESH_RSN_H */
--
1.9.2
Bob Copeland
2014-05-30 13:22:30 UTC
Permalink
Add an implementation of Synthetic Initialization Vector (SIV)
Authenticated Encryption Using the Advanced Encryption Standard (AES).

This mode of AES is used to protect peering frames when using
the authenticated mesh peering exchange.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Bob Copeland <***@bobcopeland.com>
---
src/crypto/Makefile | 1 +
src/crypto/aes-siv.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++
src/crypto/aes_siv.h | 17 +++++
wpa_supplicant/Android.mk | 3 +
wpa_supplicant/Makefile | 3 +
5 files changed, 205 insertions(+)
create mode 100644 src/crypto/aes-siv.c
create mode 100755 src/crypto/aes_siv.h

diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 2a92109..3e90350 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -26,6 +26,7 @@ LIB_OBJS= \
aes-internal-dec.o \
aes-internal-enc.o \
aes-omac1.o \
+ aes-siv.o \
aes-unwrap.o \
aes-wrap.o \
des-internal.o \
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
new file mode 100644
index 0000000..731c680
--- /dev/null
+++ b/src/crypto/aes-siv.c
@@ -0,0 +1,181 @@
+/*
+ * AES SIV (RFC5297)
+ *
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+static const u8 zero[AES_BLOCK_SIZE];
+
+static void dbl(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i=0; i < AES_BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[AES_BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+static void xor(u8 *a, u8 *b)
+{
+ int i;
+ for (i=0; i < AES_BLOCK_SIZE; i++)
+ *a++ ^= *b++;
+}
+
+static void xorend(u8 *a, int alen, u8 *b, int blen)
+{
+ int i;
+
+ if (alen < blen)
+ return;
+
+ for (i=0; i < blen; i++) {
+ a[alen - blen + i] ^= b[i];
+ }
+}
+
+static void pad(u8 *pad, const u8 *addr, size_t len)
+{
+ os_memset(pad, 0, AES_BLOCK_SIZE);
+ memcpy(pad, addr, len);
+
+ if (len < AES_BLOCK_SIZE)
+ pad[len] = 0x80;
+}
+
+int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+ size_t *len, u8 *mac)
+{
+ u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
+ u8 *buf = NULL;
+ int ret;
+ int i;
+
+ if (!num_elem) {
+ memcpy(tmp, zero, sizeof(zero));
+ tmp[AES_BLOCK_SIZE - 1] = 1;
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ }
+
+ ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ if (ret)
+ return ret;
+
+ for (i=0; i < num_elem - 1; i++) {
+
+ ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ if (ret)
+ return ret;
+
+ dbl(tmp);
+ xor(tmp, tmp2);
+ }
+ if (len[i] >= AES_BLOCK_SIZE) {
+ buf = os_malloc(len[i]);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, addr[i], len[i]);
+ xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
+ ret = omac1_aes_128(key, buf, len[i], mac);
+ os_free(buf);
+ return ret;
+ }
+
+ dbl(tmp);
+ pad(tmp2, addr[i], len[i]);
+ xor(tmp, tmp2);
+
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+}
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+ size_t pwlen, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *out)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ u8 v[AES_BLOCK_SIZE];
+ int i;
+ u8 *iv, *crypt_pw;
+
+ if (num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+
+ for (i=0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = pw;
+ _len[num_elem] = pwlen;
+
+ aes_s2v(k1, num_elem + 1, _addr, _len, v);
+
+ iv = out;
+ crypt_pw = out + AES_BLOCK_SIZE;
+
+ memcpy(iv, v, AES_BLOCK_SIZE);
+ memcpy(crypt_pw, pw, pwlen);
+
+ /* zero out 63rd and 31st bits of ctr (from right) */
+ v[8] &= 0x7f;
+ v[12] &= 0x7f;
+ return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+}
+
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+ int num_elem, const u8 *addr[], const size_t *len,
+ u8 *out)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ size_t crypt_len = iv_c_len - 16;
+ int i, ret;
+
+ u8 iv[16];
+ u8 check[16];
+
+ if (num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+
+ for (i=0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = out;
+ _len[num_elem] = crypt_len;
+
+ memcpy(iv, iv_crypt, 16);
+ memcpy(out, iv_crypt + 16, crypt_len);
+
+ iv[8] &= 0x7f;
+ iv[12] &= 0x7f;
+
+ ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ if (ret)
+ return ret;
+
+ aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ if (os_memcmp(check, iv_crypt, 16) == 0)
+ return 0;
+
+ return -1;
+}
diff --git a/src/crypto/aes_siv.h b/src/crypto/aes_siv.h
new file mode 100755
index 0000000..546211b
--- /dev/null
+++ b/src/crypto/aes_siv.h
@@ -0,0 +1,17 @@
+/*
+ * AES SIV (RFC5297)
+ *
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef AES_SIV_H
+#define AES_SIV_H
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+ size_t pwlen, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *out);
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+ int num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+#endif /* AES_SIV_H */
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 388ac27..1532923 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1155,6 +1155,9 @@ ifdef CONFIG_INTERNAL_AES
AESOBJS += src/crypto/aes-internal-enc.c
endif
endif
+ifdef NEED_AES_SIV
+AESOBJS += src/crypto/aes-siv.c
+endif
ifdef NEED_AES
OBJS += $(AESOBJS)
endif
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 1e7d6b8..7013a37 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1147,6 +1147,9 @@ else
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
+ifdef NEED_AES_SIV
+AESOBJS += ../src/crypto/aes-siv.o
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-wrap.o
--
1.9.2
Yu Niiro
2014-06-25 04:27:51 UTC
Permalink
Hello again,
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.
---
Still TODO: fixup order of IEs
Yes. Order of IEs shall be fixed.
HT capabilities IE and HT operation IE shall be placed after the peering
management IE.
I would suggest to make the following changes.

----
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 377f663..5ba8998 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -401,9 +401,9 @@ static void mesh_mpm_send_plink_action(struct
wpa_supplicant *wpa_s,
2 + (32 - 8) +
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
+ 2 + 23 + /* peering management */
2 + 26 + /* HT capabilities */
2 + 22 + /* HT operation */
- 2 + 23 + /* peering management */
2 + 96 + /* AMPE */
2 + 16); /* MIC */
if (!buf)
@@ -446,11 +446,6 @@ static void mesh_mpm_send_plink_action(struct
wpa_supplicant *wpa_s,
/* always forwarding & accepting plinks for now */
/* TODO: PS bits */
wpabuf_put_u8(buf, 0x1 | 0x8);
-#ifdef CONFIG_IEEE80211N
- 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 */

} else { /* Peer closing frame */
/* IE: Mesh ID */
@@ -498,6 +493,15 @@ 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));

+#ifdef CONFIG_IEEE80211N
+ /* IE: HT Capability & Operation */
+ if (type != PLINK_CLOSE) {
+ 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,
"Mesh MPM: failed to add AMPE and MIC IE");


----

-- Yu
Yu Niiro
2014-06-25 04:32:44 UTC
Permalink
Hello Bob and all,

I sent my previous email a little too early. Forgotten to mention another
stuff.
It seems that STAs includes HT capability and operation IE regardless of
the capability.
Not sure the following change is sufficient, but it should fix one of the
issues.

----
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 2d056a1..36757c3 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -402,6 +402,7 @@ struct wpa_ssid {
*/
int frequency;

+#ifdef CONFIG_MESH
/**
* mesh_ht_mode - definition of HT mode in mesh mode
*
@@ -410,6 +411,7 @@ struct wpa_ssid {
* configured HT mode (HT20/HT40-/HT40+/NOHT).
*/
int mesh_ht_mode;
+#endif

int ht40;

diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 5ba8998..9ac7ea2 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -395,17 +395,23 @@ static void mesh_mpm_send_plink_action(struct
wpa_supplicant *wpa_s,
int ret;
int ampe = conf->security & MESH_CONF_SEC_AMPE;

- buf = wpabuf_alloc(2 + /* capability info */
- 2 + /* AID */
- 2 + 8 + /* supported rates */
- 2 + (32 - 8) +
- 2 + 32 + /* mesh ID */
- 2 + 7 + /* mesh config */
- 2 + 23 + /* peering management */
- 2 + 26 + /* HT capabilities */
- 2 + 22 + /* HT operation */
- 2 + 96 + /* AMPE */
- 2 + 16); /* MIC */
+ int buf_len = 2 + /* capability info */
+ 2 + /* AID */
+ 2 + 8 + /* supported rates */
+ 2 + (32 - 8) +
+ 2 + 32 + /* mesh ID */
+ 2 + 7 + /* mesh config */
+ 2 + 23; /* peering management */
+#ifdef CONFIG_IEEE80211N
+ if (wpa_s->current_ssid->mesh_ht_mode >= CHAN_HT20) {
+ buf_len += 2 + 26 + /* HT capabilities */
+ 2 + 22; /* HT operation */
+ }
+#endif /* CONFIG_IEEE80211N */
+ buf_len += 2 + 96 + /* AMPE */
+ 2 + 16; /* MIC */
+
+ buf = wpabuf_alloc(buf_len);
if (!buf)
return;

@@ -495,8 +501,9 @@ static void mesh_mpm_send_plink_action(struct
wpa_supplicant *wpa_s,

#ifdef CONFIG_IEEE80211N
/* IE: HT Capability & Operation */
- if (type != PLINK_CLOSE) {
- pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
+ if (wpa_s->current_ssid->mesh_ht_mode >= CHAN_HT20 &&
+ type != PLINK_CLOSE) {
+ 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);
}


----

-- Yu
Post by Yu Niiro
Hello again,
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.
---
Still TODO: fixup order of IEs
Yes. Order of IEs shall be fixed.
HT capabilities IE and HT operation IE shall be placed after the peering
management IE.
I would suggest to make the following changes.
----
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 377f663..5ba8998 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -401,9 +401,9 @@ static void mesh_mpm_send_plink_action(struct
wpa_supplicant *wpa_s,
2 + (32 - 8) +
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
+ 2 + 23 + /* peering management */
2 + 26 + /* HT capabilities */
2 + 22 + /* HT operation */
- 2 + 23 + /* peering management */
2 + 96 + /* AMPE */
2 + 16); /* MIC */
if (!buf)
@@ -446,11 +446,6 @@ static void mesh_mpm_send_plink_action(struct
wpa_supplicant *wpa_s,
/* always forwarding & accepting plinks for now */
/* TODO: PS bits */
wpabuf_put_u8(buf, 0x1 | 0x8);
-#ifdef CONFIG_IEEE80211N
- 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 */
} else { /* Peer closing frame */
/* IE: Mesh ID */
@@ -498,6 +493,15 @@ 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));
+#ifdef CONFIG_IEEE80211N
+ /* IE: HT Capability & Operation */
+ if (type != PLINK_CLOSE) {
+ 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,
"Mesh MPM: failed to add AMPE and MIC IE");
----
-- Yu
Bob Copeland
2014-06-28 16:43:13 UTC
Permalink
Post by Yu Niiro
Hello Bob and all,
I sent my previous email a little too early. Forgotten to mention another
stuff.
It seems that STAs includes HT capability and operation IE regardless of
the capability.
Not sure the following change is sufficient, but it should fix one of the
issues.
int ret;
int ampe = conf->security & MESH_CONF_SEC_AMPE;
- buf = wpabuf_alloc(2 + /* capability info */
- 2 + /* AID */
- 2 + 8 + /* supported rates */
- 2 + (32 - 8) +
- 2 + 32 + /* mesh ID */
- 2 + 7 + /* mesh config */
- 2 + 23 + /* peering management */
- 2 + 26 + /* HT capabilities */
- 2 + 22 + /* HT operation */
- 2 + 96 + /* AMPE */
- 2 + 16); /* MIC */
+ int buf_len = 2 + /* capability info */
+ 2 + /* AID */
+ 2 + 8 + /* supported rates */
+ 2 + (32 - 8) +
+ 2 + 32 + /* mesh ID */
+ 2 + 7 + /* mesh config */
+ 2 + 23; /* peering management */
+#ifdef CONFIG_IEEE80211N
+ if (wpa_s->current_ssid->mesh_ht_mode >= CHAN_HT20) {
+ buf_len += 2 + 26 + /* HT capabilities */
+ 2 + 22; /* HT operation */
+ }
+#endif /* CONFIG_IEEE80211N */
+ buf_len += 2 + 96 + /* AMPE */
+ 2 + 16; /* MIC */
+
+ buf = wpabuf_alloc(buf_len);
I don't think it's really necessary to reorder the additions here
to satisfy the IE order, or to even worry about allocating another
~120 bytes depending on whether or not we fill in the HT capabilities;
we can always over-allocate and not use the whole buffer if it makes
the code simpler.
--
Bob Copeland %% www.bobcopeland.com
Loading...