Discussion:
[PATCH/RFC 05/18] events: handle mesh events coming from driver
Bob Copeland
2014-07-14 05:19:10 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Handle EVENT_MGMT and EVENT_NEW_PEER_CANDIDATE for mesh interfaces.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-hostap: Thomas Pedersen <***@noack.us>
---
wpa_supplicant/events.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4e84f6e..663ffd5 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -42,6 +42,8 @@
#include "scan.h"
#include "offchannel.h"
#include "interworking.h"
+#include "mesh.h"
+#include "mesh_mpm.h"


#ifndef CONFIG_NO_SCAN_PROCESSING
@@ -1128,7 +1130,11 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
if (wpas_network_disabled(wpa_s, ssid))
continue;
if (ssid->mode == IEEE80211_MODE_IBSS ||
- ssid->mode == IEEE80211_MODE_AP)
+ ssid->mode == IEEE80211_MODE_AP ||
+#ifdef CONFIG_MESH
+ ssid->mode == IEEE80211_MODE_MESH ||
+#endif /* CONFIG_MESH */
+ 0)
return ssid;
}
}
@@ -1408,6 +1414,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
*/
return 1;
} else {
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Avoiding join because "
+ "we already joined a mesh group.");
+ return 0;
+ }
+#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -2865,6 +2878,10 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,

wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh)
+ mesh_mpm_action_rx(wpa_s, mgmt, len);
+#endif /* CONFIG_MESH */
}


@@ -3212,7 +3229,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_IBSS_RSN
- if (stype == WLAN_FC_STYPE_AUTH &&
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+ stype == WLAN_FC_STYPE_AUTH &&
data->rx_mgmt.frame_len >= 30) {
wpa_supplicant_event_ibss_auth(wpa_s, data);
break;
@@ -3227,6 +3246,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}

+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ mesh_mpm_mgmt_rx(wpa_s, &data->rx_mgmt);
+ break;
+ }
+#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
"management frame in non-AP mode");
break;
@@ -3459,6 +3484,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->connect_failed_reason.code);
#endif /* CONFIG_AP */
break;
+#ifdef CONFIG_MESH
+ case EVENT_NEW_PEER_CANDIDATE:
+ wpa_mesh_notify_peer(wpa_s, data->mesh_peer.peer,
+ data->mesh_peer.ies,
+ data->mesh_peer.ie_len);
+ break;
+#endif /* CONFIG_MESH */
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:12 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>
---
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 8cd4a2f..0b80ce2 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1695,7 +1695,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) },
@@ -3271,6 +3276,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;
@@ -3815,6 +3821,9 @@ static const struct global_parse_data global_fields[] = {
#endif /* CONFIG_MACSEC */
{ 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 52add9d..a6ca7de 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
@@ -368,6 +369,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 98855d8..f1880cd 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1179,6 +1179,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
fprintf(f, "p2p_search_delay=%u\n",
config->p2p_search_delay);
+
+ 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 394a956..daa7ce3 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -654,6 +654,14 @@ struct wpa_ssid {
#ifdef CONFIG_HS20
int update_identifier;
#endif /* CONFIG_HS20 */
+
+ /**
+ * 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 f612b49..9736192 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2556,6 +2556,8 @@ static int wpa_supplicant_ctrl_iface_update_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 4513709..d8fae01 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -348,6 +348,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);
@@ -389,6 +390,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);
}
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:11 UTC
Permalink
Add support for parsing mesh id, mesh config, mesh peering,
AMPE and MIC information elements.

Signed-hostap: Bob Copeland <***@bobcopeland.com>
---
src/common/ieee802_11_common.c | 22 ++++++++++++++++++++++
src/common/ieee802_11_common.h | 10 ++++++++++
2 files changed, 32 insertions(+)

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 173a400..7b06b77 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -249,6 +249,18 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
+ case WLAN_EID_MESH_CONFIG:
+ elems->mesh_config = pos;
+ elems->mesh_config_len = elen;
+ break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = pos;
+ elems->mesh_id_len = elen;
+ break;
+ case WLAN_EID_PEER_MGMT:
+ elems->peer_mgmt = pos;
+ elems->peer_mgmt_len = elen;
+ break;
case WLAN_EID_VHT_CAP:
elems->vht_capabilities = pos;
elems->vht_capabilities_len = elen;
@@ -290,6 +302,16 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->ssid_list = pos;
elems->ssid_list_len = elen;
break;
+ case WLAN_EID_AMPE:
+ elems->ampe = pos;
+ elems->ampe_len = elen;
+ break;
+ case WLAN_EID_MIC:
+ elems->mic = pos;
+ elems->mic_len = elen;
+ /* after mic everything is encrypted, so stop. */
+ left = elen;
+ break;
default:
unknown++;
if (!show_errors)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index cf83057..8d96dc2 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -28,6 +28,9 @@ struct ieee802_11_elems {
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
+ const u8 *mesh_config;
+ const u8 *mesh_id;
+ const u8 *peer_mgmt;
const u8 *vht_capabilities;
const u8 *vht_operation;
const u8 *vht_opmode_notif;
@@ -42,6 +45,8 @@ struct ieee802_11_elems {
const u8 *bss_max_idle_period;
const u8 *ssid_list;
const u8 *osen;
+ const u8 *ampe;
+ const u8 *mic;

u8 ssid_len;
u8 supp_rates_len;
@@ -60,6 +65,9 @@ struct ieee802_11_elems {
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
+ u8 mesh_config_len;
+ u8 mesh_id_len;
+ u8 peer_mgmt_len;
u8 vht_capabilities_len;
u8 vht_operation_len;
u8 vendor_ht_cap_len;
@@ -71,6 +79,8 @@ struct ieee802_11_elems {
u8 ext_capab_len;
u8 ssid_list_len;
u8 osen_len;
+ u8 ampe_len;
+ u8 mic_len;
};

typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:09 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 | 90 +++++++++++-
src/drivers/driver_common.c | 1 +
src/drivers/driver_nl80211.c | 302 ++++++++++++++++++++++++++++++++++++--
src/drivers/driver_wext.c | 5 +-
wpa_supplicant/driver_i.h | 22 +++
wpa_supplicant/wpa_supplicant_i.h | 2 +-
7 files changed, 428 insertions(+), 19 deletions(-)

diff --git a/src/common/defs.h b/src/common/defs.h
index d4091e3..fb289b0 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 352c163..f48ff84 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
@@ -893,6 +894,31 @@ struct wpa_driver_ap_params {
struct hostapd_freq_params *freq;
};

+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_* 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
*/
@@ -1003,7 +1029,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;
@@ -1081,6 +1109,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;
@@ -1161,7 +1195,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 {
@@ -1199,6 +1237,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,
@@ -3000,6 +3039,29 @@ struct wpa_driver_ops {
*/
int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
#endif /* CONFIG_MACSEC */
+
+ /**
+ * 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);
};


@@ -3475,7 +3537,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
+
};


@@ -4114,6 +4182,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 683123b..42097e2 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -567,7 +567,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;
}


@@ -577,6 +578,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)
{
@@ -2495,6 +2501,37 @@ 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)
{
@@ -3149,6 +3186,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);
@@ -3452,6 +3492,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;
@@ -4557,6 +4600,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)
{
@@ -4906,7 +4980,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);
@@ -5785,7 +5861,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);

@@ -7542,10 +7629,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)
@@ -7571,11 +7685,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);
@@ -7620,8 +7736,12 @@ 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",
@@ -7647,12 +7767,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);

@@ -8944,6 +9070,140 @@ 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; i++) {
+ if (params->basic_rates[i] < 0)
+ break;
+ 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)
{
@@ -9149,7 +9409,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");
@@ -9681,6 +9946,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);

@@ -9705,6 +9973,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);

@@ -10031,6 +10302,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;
}
@@ -12009,7 +12282,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"
@@ -12022,7 +12295,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,
@@ -12360,6 +12633,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 a4f9cec..6a56549 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 00703d9..1bc4340 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -65,6 +65,28 @@ 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 f35cd0d..20d5cbb 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -573,7 +573,7 @@ struct wpa_supplicant {
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;

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

/*
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:16 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Modify wpa_supplicant/hostapd logic to allow SAE auth on Mesh
interfaces.

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-hostap: Thomas Pedersen <***@noack.us>
---
src/ap/ieee802_11.c | 96 +++++++++++++++++++++++++++++++++++++++++++++--------
src/ap/wpa_auth.c | 16 +++++++++
src/ap/wpa_auth.h | 3 ++
3 files changed, 101 insertions(+), 14 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index de1ee5e..ac99eff 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -446,6 +446,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
{
u16 resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
+ Boolean send_auth = 0;

if (!sta->sae) {
if (auth_transaction != 1)
@@ -456,12 +457,21 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
sta->sae->state = SAE_NOTHING;
}

+ if (sta->sae->state == SAE_ACCEPTED && auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: remove the STA "
+ "(" MACSTR ") doing reauthentication",
+ MAC2STR(sta->addr));
+ ap_free_sta(hapd, sta);
+ return;
+ }
+
if (auth_transaction == 1) {
const u8 *token = NULL;
size_t token_len = 0;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"start SAE authentication (RX commit)");
+
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
@@ -481,22 +491,45 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
MAC2STR(sta->addr));
data = auth_build_token_req(hapd, sta->addr);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
- } else {
+ goto reply;
+ }
+ if (sta->sae->state == SAE_NOTHING ||
+ sta->sae->state == SAE_CONFIRMED) {
+ /* (re)send commit to peer */
data = auth_process_sae_commit(hapd, sta);
if (data == NULL)
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- else
- sta->sae->state = SAE_COMMITTED;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid,
+ WLAN_AUTH_SAE, 1, resp,
+ data ? wpabuf_head(data) : (u8 *) "",
+ data ? wpabuf_len(data) : 0);
+ wpabuf_free(data);
+ }
+ /* SAE_NOTHING / SAE_COMMITTED / SAE_CONFIRMED */
+ if (sae_process_commit(sta->sae) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: process peer commit failed");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ /* send confirm and transition to CONFIRMED */
+ data = auth_build_sae_confirm(hapd, sta);
+ if (data == NULL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else {
+ sta->sae->state = SAE_CONFIRMED;
+ auth_transaction = 2;
+ }
}
}
} else if (auth_transaction == 2) {
- if (sta->sae->state != SAE_COMMITTED) {
+ if (sta->sae->state == SAE_NOTHING ||
+ sta->sae->state == SAE_COMMITTED) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE confirm before commit");
- resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
- goto failed;
+ return;
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -508,10 +541,17 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
} else {
resp = WLAN_STATUS_SUCCESS;
sta->flags |= WLAN_STA_AUTH;
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sta->auth_alg = WLAN_AUTH_SAE;
mlme_authenticate_indication(hapd, sta);

+ if (sta->sae->state == SAE_CONFIRMED) {
+ sta->sae->state = SAE_ACCEPTED;
+ sae_clear_temp_data(sta->sae);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ return;
+ }
+
+ send_auth = 1;
data = auth_build_sae_confirm(hapd, sta);
if (data == NULL)
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -527,14 +567,14 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
auth_transaction);
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
-
-failed:
+reply:
sta->auth_alg = WLAN_AUTH_SAE;
-
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0);
+ if (send_auth)
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
wpabuf_free(data);
}
#endif /* CONFIG_SAE */
@@ -649,10 +689,20 @@ static void handle_auth(struct hostapd_data *hapd,
return;
}

- sta = ap_sta_add(hapd, mgmt->sa);
- if (!sta) {
- resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
- goto fail;
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED) {
+ /* if the mesh peer is not available, we don't do auth. */
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (!sta)
+ return;
+ } else
+#endif /* CONFIG_MESH */
+ {
+ sta = ap_sta_add(hapd, mgmt->sa);
+ if (!sta) {
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
}

if (vlan_id > 0) {
@@ -737,6 +787,21 @@ static void handle_auth(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
case WLAN_AUTH_SAE:
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED) {
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm =
+ wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Failed to initialize WPA "
+ "state machine");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_MESH */
handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
return;
#endif /* CONFIG_SAE */
@@ -1758,6 +1823,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
stype == WLAN_FC_STYPE_ACTION) &&
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MESH
+ !(hapd->conf->mesh & MESH_ENABLED) &&
+#endif /* CONFIG_MESH */
os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
MAC2STR(mgmt->bssid));
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 2bb8aab..75d4607 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -134,6 +134,15 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
encrypt);
}

+#ifdef CONFIG_MESH
+static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (wpa_auth->cb.start_ampe == NULL)
+ return -1;
+ return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+}
+#endif /* CONFIG_MESH */

int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
@@ -1519,6 +1528,13 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)

switch (event) {
case WPA_AUTH:
+#ifdef CONFIG_MESH
+ /* PTKs are derived through AMPE */
+ if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr))
+ /* not mesh */
+ break;
+ return 0;
+#endif /* CONFIG_MESH */
case WPA_ASSOC:
break;
case WPA_DEAUTH:
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 929a253..d3e9d4c 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -213,6 +213,9 @@ struct wpa_auth_callbacks {
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_MESH
+ int (*start_ampe)(void *ctx, const u8 *sta_addr);
+#endif /* CONFIG_MESH */
};

struct wpa_authenticator * wpa_init(const u8 *addr,
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:23 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 | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 26aca2b..a5052fa 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -691,6 +691,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);
@@ -745,7 +746,14 @@ 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);
@@ -900,6 +908,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];

@@ -1165,6 +1178,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;
@@ -1191,7 +1205,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,
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:21 UTC
Permalink
From: Javier Lopez <***@gmail.com>

This wpa_supplicant tests include basic tests for:

- Mesh scan
- Mesh group add/remove
- Mesh peer connected/disconnected
- Add/Set/Remove to test mesh mode network
- Open mesh connectivity test
- Secure mesh connectivity test
- no_auto_peer

Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
[no_auto_peer test by: Javier Cardona <***@cozybit.com>
Signed-hostap: Javier Lopez <***@gmail.com>
---
tests/hwsim/example-wpa_supplicant.config | 1 +
tests/hwsim/test_wpas_mesh.py | 332 ++++++++++++++++++++++++++++++
tests/hwsim/wpasupplicant.py | 12 ++
3 files changed, 345 insertions(+)
create mode 100644 tests/hwsim/test_wpas_mesh.py

diff --git a/tests/hwsim/example-wpa_supplicant.config b/tests/hwsim/example-wpa_supplicant.config
index a39b74d..63f5b2c 100644
--- a/tests/hwsim/example-wpa_supplicant.config
+++ b/tests/hwsim/example-wpa_supplicant.config
@@ -76,6 +76,7 @@ CONFIG_LIBNL32=y
CONFIG_IBSS_RSN=y

CONFIG_AP=y
+CONFIG_MESH=y
CONFIG_P2P=y
CONFIG_WIFI_DISPLAY=y

diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
new file mode 100644
index 0000000..f1eca36
--- /dev/null
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -0,0 +1,332 @@
+#!/usr/bin/python
+#
+# wpa_supplicant mesh mode tests
+# Copyright (c) 2014, cozybit Inc.
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+
+def check_mesh_scan(dev, params, other_started=False):
+ if not other_started:
+ dev.dump_monitor()
+ id = dev.request("SCAN " + params)
+ if "FAIL" in id:
+ raise Exception("Failed to start scan")
+ id = int(id)
+
+ if other_started:
+ ev = dev.wait_event(["CTRL-EVENT-SCAN-STARTED"])
+ if ev is None:
+ raise Exception("Other scan did not start")
+ if "id=" + str(id) in ev:
+ raise Exception("Own scan id unexpectedly included in start event")
+
+ ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+ if ev is None:
+ raise Exception("Other scan did not complete")
+ if "id=" + str(id) in ev:
+ raise Exception(
+ "Own scan id unexpectedly included in completed event")
+
+ ev = dev.wait_event(["CTRL-EVENT-SCAN-STARTED"])
+ if ev is None:
+ raise Exception("Scan did not start")
+ if "id=" + str(id) not in ev:
+ raise Exception("Scan id not included in start event")
+
+ ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+ if ev is None:
+ raise Exception("Scan did not complete")
+ if "id=" + str(id) not in ev:
+ raise Exception("Scan id not included in completed event")
+
+ res = dev.request("SCAN_RESULTS")
+
+ if not res.find("[MESH]"):
+ raise Exception("Scan did not contain a MESH network")
+
+
+def check_mesh_group_added(dev):
+ ev = dev.wait_event(["MESH-GROUP-STARTED"])
+ if ev is None:
+ raise Exception("Test exception: Couldn't join mesh")
+
+
+def check_mesh_group_removed(dev):
+ ev = dev.wait_event(["MESH-GROUP-REMOVED"])
+ if ev is None:
+ raise Exception("Test exception: Couldn't leave mesh")
+
+
+def check_mesh_peer_connected(dev):
+ ev = dev.wait_event(["MESH-PEER-CONNECTED"])
+ if ev is None:
+ raise Exception("Test exception: Remote peer did not connect.")
+
+
+def check_mesh_peer_disconnected(dev):
+ ev = dev.wait_event(["MESH-PEER-DISCONNECTED"])
+ if ev is None:
+ raise Exception("Test exception: Peer disconnect event not detected.")
+
+
+def test_wpas_add_set_remove_support(dev):
+ """wpa_supplicant MESH add/set/remove network support"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].remove_network(id)
+
+
+def test_wpas_mesh_group_added(dev):
+ """wpa_supplicant MESH group add"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+
+ # Check for MESH-GROUP-STARTED event
+ check_mesh_group_added(dev[0])
+
+
+def test_wpas_mesh_group_remove(dev):
+ """wpa_supplicant MESH group remove"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+ # Check for MESH-GROUP-STARTED event
+ check_mesh_group_added(dev[0])
+ dev[0].mesh_group_remove()
+ # Check for MESH-GROUP-REMOVED event
+ check_mesh_group_removed(dev[0])
+
+
+def test_wpas_mesh_peer_connected(dev):
+ """wpa_supplicant MESH peer connected"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[1].set_network(id, "key_mgmt", "NONE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for peer connected
+ check_mesh_peer_connected(dev[0])
+ check_mesh_peer_connected(dev[1])
+
+
+def test_wpas_mesh_peer_disconnected(dev):
+ """wpa_supplicant MESH peer disconnected"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[1].set_network(id, "key_mgmt", "NONE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for peer connected
+ check_mesh_peer_connected(dev[0])
+ check_mesh_peer_connected(dev[1])
+
+ # Remove group on dev 1
+ dev[1].mesh_group_remove()
+ # Device 0 should get a disconnection event
+ check_mesh_peer_disconnected(dev[0])
+
+
+def test_wpas_mesh_mode_scan(dev):
+ """wpa_supplicant MESH scan support"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[1].set_network(id, "key_mgmt", "NONE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for Mesh scan
+ check_mesh_scan(dev[0], "use_id=1")
+
+
+def wrap_wpas_mesh_test(test, dev, apdev):
+ import hwsim_utils
+
+ def _test_connectivity(dev1, dev2):
+ return hwsim_utils.test_connectivity(dev1.ifname, dev2.ifname)
+
+ return test(dev, apdev, _test_connectivity)
+
+
+def _test_wpas_mesh_open(dev, apdev, test_connectivity):
+ """wpa_supplicant open MESH network connectivity"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[1].set_network(id, "key_mgmt", "NONE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for peer connected
+ check_mesh_peer_connected(dev[0])
+ check_mesh_peer_connected(dev[1])
+
+ # Test connectivity 0->1 and 1->0
+ test_connectivity(dev[0], dev[1])
+ test_connectivity(dev[1], dev[0])
+
+
+def test_wpas_mesh_open(dev, apdev):
+ return wrap_wpas_mesh_test(_test_wpas_mesh_open, dev, apdev)
+
+
+def _test_wpas_mesh_open_no_auto(dev, apdev, test_connectivity):
+ """wpa_supplicant open MESH network connectivity"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
+ dev[1].set_network(id, "key_mgmt", "NONE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].set_network(id, "no_auto_peer", "1")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for peer connected
+ check_mesh_peer_connected(dev[0])
+ check_mesh_peer_connected(dev[1])
+
+ # Test connectivity 0->1 and 1->0
+ test_connectivity(dev[0], dev[1])
+ test_connectivity(dev[1], dev[0])
+
+
+def test_wpas_mesh_open_no_auto(dev, apdev):
+ return wrap_wpas_mesh_test(_test_wpas_mesh_open_no_auto, dev, apdev)
+
+
+def _test_wpas_mesh_secure(dev, apdev, test_connectivity):
+ """wpa_supplicant secure MESH network connectivity"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-sec")
+ dev[0].set_network(id, "key_mgmt", "SAE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].set_network_quoted(id, "psk", "thisismypassphrase!")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-sec")
+ dev[1].set_network(id, "key_mgmt", "SAE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].set_network_quoted(id, "psk", "thisismypassphrase!")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for peer connected
+ check_mesh_peer_connected(dev[0])
+ check_mesh_peer_connected(dev[1])
+
+ # Test connectivity 0->1 and 1->0
+ test_connectivity(dev[0], dev[1])
+ test_connectivity(dev[1], dev[0])
+
+
+def test_wpas_mesh_secure(dev, apdev):
+ return wrap_wpas_mesh_test(_test_wpas_mesh_secure, dev, apdev)
+
+
+def _test_wpas_mesh_secure_no_auto(dev, apdev, test_connectivity):
+ """wpa_supplicant secure MESH network connectivity"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "5")
+ dev[0].set_network_quoted(id, "ssid", "wpas-mesh-sec")
+ dev[0].set_network(id, "key_mgmt", "SAE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].set_network_quoted(id, "psk", "thisismypassphrase!")
+ dev[0].mesh_group_add(id)
+
+ id = dev[1].add_network()
+ dev[1].set_network(id, "mode", "5")
+ dev[1].set_network_quoted(id, "ssid", "wpas-mesh-sec")
+ dev[1].set_network(id, "key_mgmt", "SAE")
+ dev[1].set_network(id, "frequency", "2412")
+ dev[1].set_network_quoted(id, "psk", "thisismypassphrase!")
+ dev[1].set_network(id, "no_auto_peer", "1")
+ dev[1].mesh_group_add(id)
+
+ # Check for mesh joined
+ check_mesh_group_added(dev[0])
+ check_mesh_group_added(dev[1])
+
+ # Check for peer connected
+ check_mesh_peer_connected(dev[0])
+ check_mesh_peer_connected(dev[1])
+
+ # Test connectivity 0->1 and 1->0
+ test_connectivity(dev[0], dev[1])
+ test_connectivity(dev[1], dev[0])
+
+
+def test_wpas_mesh_secure_no_auto(dev, apdev):
+ return wrap_wpas_mesh_test(_test_wpas_mesh_secure_no_auto, dev, apdev)
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
index 5e24e20..9392111 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -249,6 +249,18 @@ class WpaSupplicant:
raise Exception("SELECT_NETWORK failed")
return None

+ def mesh_group_add(self, id):
+ id = self.request("MESH_GROUP_ADD " + str(id))
+ if "FAIL" in id:
+ raise Exception("MESH_GROUP_ADD failed")
+ return None
+
+ def mesh_group_remove(self):
+ id = self.request("MESH_GROUP_REMOVE " + str(self.ifname))
+ if "FAIL" in id:
+ raise Exception("MESH_GROUP_REMOVE failed")
+ return None
+
def connect_network(self, id, timeout=10):
self.dump_monitor()
self.select_network(id)
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:17 UTC
Permalink
From: Chun-Yeow Yeoh <***@gmail.com>

Add timer to do SAE re-authentication with number of tries defined
by MESH_AUTH_RETRY and timeout defined by MESH_AUTH_TIMEOUT.

Ignoring the sending of reply message on "SAE confirm before commit"
to avoid "ping-pong" issues with other mesh nodes. This is obvious when
number of mesh nodes in MBSS reaching 6.

Signed-off-by: Chun-Yeow Yeoh <***@gmail.com>
Signed-hostap: Bob Copeland <***@bobcopeland.com>
---
src/ap/sta_info.c | 8 ++++++++
src/ap/sta_info.h | 1 +
wpa_supplicant/Makefile | 4 ----
wpa_supplicant/mesh_mpm.c | 7 +++++++
wpa_supplicant/mesh_mpm.h | 2 ++
wpa_supplicant/mesh_rsn.c | 36 +++++++++++++++++++++++++++++++++++-
wpa_supplicant/mesh_rsn.h | 1 +
7 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 60f0768..2c01826 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -33,6 +33,10 @@
#include "wnm_ap.h"
#include "sta_info.h"

+#ifdef CONFIG_MESH
+#include "../../wpa_supplicant/mesh_mpm.h"
+#endif
+
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
@@ -224,6 +228,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
set_beacon++;
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */

+#ifdef CONFIG_MESH
+ mesh_mpm_free_sta(sta);
+#endif
+
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);

diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index a1a8ed1..3fe38b0 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -65,6 +65,7 @@ struct sta_info {
u8 aek[32]; /* SHA256 digest length */
u8 mtk[16];
u8 mgtk[16];
+ u8 sae_auth_retry;
#endif /* CONFIG_MESH */

unsigned int nonerp_set:1;
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b308de5..963b5cf 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -211,10 +211,6 @@ CFLAGS += -DCONFIG_MESH
OBJS += mesh.o mesh_mpm.o mesh_rsn.o
endif

-CFLAGS += -DCONFIG_MESH
-OBJS += mesh.o mesh_mpm.o
-endif
-
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index b32e12e..69ffba8 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -896,3 +896,10 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
}
mesh_mpm_fsm(wpa_s, sta, event);
}
+
+/* called by ap_free_sta */
+void mesh_mpm_free_sta(struct sta_info *sta)
+{
+ eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
+ eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
+}
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index f890ad6..0cba7ad 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -23,4 +23,6 @@ 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);

+void mesh_mpm_free_sta(struct sta_info *sta);
+
#endif /* MESH_MPM_H */
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index dacb1f3..7786a7d 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -18,6 +18,30 @@
#include "crypto/aes_siv.h"
#include "wpas_glue.h"

+#define MESH_AUTH_TIMEOUT 10
+#define MESH_AUTH_RETRY 3
+
+void mesh_auth_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct sta_info *sta = user_data;
+
+ if (sta->sae->state != SAE_ACCEPTED) {
+ wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with "
+ MACSTR " (attempt %d) ", MAC2STR(sta->addr),
+ sta->sae_auth_retry);
+ if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ } else {
+ /* block the STA if exceeded the number of attempts */
+ sta->plink_state = PLINK_BLOCKED;
+ sta->sae->state = SAE_NOTHING;
+ }
+ sta->sae_auth_retry++;
+ }
+
+}
+
static void auth_logger(void *ctx, const u8 *addr, logger_level level,
const char *txt)
{
@@ -28,7 +52,6 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
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)
{
@@ -72,10 +95,17 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
static int auth_start_ampe(void *ctx, const u8 *addr)
{
struct mesh_rsn *mesh_rsn = ctx;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;

if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH)
return -1;

+ hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ eloop_cancel_timeout(mesh_auth_timer, mesh_rsn->wpa_s, sta);
+
mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr);
return 0;
}
@@ -271,6 +301,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
struct wpabuf *buf;
+ unsigned int rnd;

if (!sta->sae) {
sta->sae = os_zalloc(sizeof(*sta->sae));
@@ -292,6 +323,9 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
mesh_rsn_send_auth(wpa_s, sta->addr, wpa_s->own_addr,
1, WLAN_STATUS_SUCCESS, buf);

+ rnd = rand() % MESH_AUTH_TIMEOUT;
+ eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
+ wpa_s, sta);
wpabuf_free(buf);
return 0;
}
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index 7b95637..2b60b99 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -35,4 +35,5 @@ 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);
+void mesh_auth_timer(void *eloop_ctx, void *user_data);
#endif /* MESH_RSN_H */
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:06 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 905aec3..5db0d85 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 3c8727b..0f9b1d2 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;

@@ -235,6 +238,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;
@@ -272,6 +279,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 03db98f..a1a8ed1 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 6de71e9..3238bd4 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 */
@@ -1087,6 +1116,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 d91594e..521b97b 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 ab474ff..394a956 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -317,6 +317,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,
@@ -331,6 +333,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 bf3d19d..f35cd0d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -659,6 +659,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];
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:15 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

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 | 10 +
wpa_supplicant/mesh.c | 8 +
wpa_supplicant/mesh_mpm.c | 30 ++-
wpa_supplicant/mesh_rsn.c | 545 ++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh_rsn.h | 38 ++++
6 files changed, 633 insertions(+), 2 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 48eb487..b406348 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 7ad7a5a..b308de5 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -201,6 +201,16 @@ endif

ifdef CONFIG_MESH
NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
+CONFIG_SAE=y
+CONFIG_AP=y
+CFLAGS += -DCONFIG_MESH
+OBJS += mesh.o mesh_mpm.o mesh_rsn.o
+endif
+
CFLAGS += -DCONFIG_MESH
OBJS += mesh.o mesh_mpm.o
endif
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 753ea1d..4635b0a 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 */
}
@@ -195,6 +199,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 d8fae01..b32e12e 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"
@@ -321,6 +322,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);
@@ -396,7 +399,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,
@@ -409,7 +415,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;
@@ -428,6 +434,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);

@@ -505,9 +512,17 @@ 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);
@@ -515,6 +530,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO,
"Mesh MPM: failed to send peering frame");

+fail:
wpabuf_free(buf);
}

@@ -584,6 +600,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);
@@ -655,6 +672,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *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:
@@ -749,6 +768,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;
@@ -817,6 +837,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..dacb1f3
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.c
@@ -0,0 +1,545 @@
+/*
+ * 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 = -1;
+
+ 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);
+
+ /* group mgmt */
+ wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
+ seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+ /* group privacy / data frames */
+ 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)
+{
+ os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ wpa_deinit(rsn->auth);
+}
+
+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_COMMITTED;
+ wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+
+ mesh_rsn_send_auth(wpa_s, sta->addr, wpa_s->own_addr,
+ 1, WLAN_STATUS_SUCCESS, buf);
+
+ 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;
+ u16 min_lid, max_lid;
+ size_t nonce_len = sizeof(sta->my_nonce);
+ size_t lid_len = sizeof(sta->my_lid);
+
+ 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;
+
+ if (sta->my_lid < sta->peer_lid) {
+ min_lid = host_to_le16(sta->my_lid);
+ max_lid = host_to_le16(sta->peer_lid);
+ } else {
+ min_lid = host_to_le16(sta->peer_lid);
+ max_lid = host_to_le16(sta->my_lid);
+ }
+ os_memcpy(ptr, &min_lid, lid_len);
+ os_memcpy(ptr + lid_len, &max_lid, 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);
+}
+
+/* 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 */
+ /* expire in 13 decades or so */
+ os_memset(ampe->key_expiration, 0xff, 4);
+
+ /* 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..7b95637
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.h
@@ -0,0 +1,38 @@
+/*
+ * 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 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 */
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:20 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/config.c | 12 ++++++++++++
wpa_supplicant/config_file.c | 2 ++
wpa_supplicant/wpa_supplicant.conf | 26 ++++++++++++++++++++++++++
3 files changed, 40 insertions(+)

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 0b80ce2..b1069ce 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -677,6 +677,18 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
}
#endif /* CONFIG_WPS */

+#ifdef CONFIG_SAE
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+
if (pos == buf) {
os_free(buf);
buf = NULL;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index f1880cd..4376412 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -743,6 +743,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(update_identifier);
#endif /* CONFIG_HS20 */

+ STR(mesh_ht_mode);
+
#undef STR
#undef INT
#undef INT_DEF
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 2a0dc20..f0c8636 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -114,6 +114,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.
@@ -1285,6 +1294,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={
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:19 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 | 74 +++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/wpa_cli.c | 21 ++++++++++++
wpa_supplicant/wpa_supplicant.c | 55 +++++++++++++++++++++++++++---
3 files changed, 146 insertions(+), 4 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 874e0c8..130449a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2331,6 +2331,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)
@@ -6692,6 +6757,15 @@ 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 8811d6f..1848266 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1743,6 +1743,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

@@ -2770,6 +2783,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 9414e8f..02b4bcf 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -52,6 +52,7 @@
#include "hs20_supplicant.h"
#include "wnm_sta.h"
#include "wpas_kay.h"
+#include "mesh.h"

const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -1421,6 +1422,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),
@@ -1764,9 +1790,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;

if (ssid->mode == WPAS_MODE_IBSS) {
if (ssid->beacon_int)
@@ -1994,6 +2021,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));
@@ -2159,8 +2195,12 @@ 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;

@@ -3812,6 +3852,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;
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:14 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 | 180 ++++++++++++++++++++++++++++++++++++++++++++++
src/crypto/aes_siv.h | 17 +++++
wpa_supplicant/Android.mk | 3 +
wpa_supplicant/Makefile | 3 +
5 files changed, 204 insertions(+)
create mode 100644 src/crypto/aes-siv.c
create mode 100644 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..5c67f76
--- /dev/null
+++ b/src/crypto/aes-siv.c
@@ -0,0 +1,180 @@
+/*
+ * 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 100644
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 c883f9f..48eb487 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 fada285..7ad7a5a 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1155,6 +1155,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
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:07 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 | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh.h | 36 +++++++
2 files changed, 313 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..5b4f5d9
--- /dev/null
+++ b/wpa_supplicant/mesh.c
@@ -0,0 +1,277 @@
+/*
+ * 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);
+ ifmsh->mconf = NULL;
+ }
+
+ /* take care of shared data */
+ 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 */
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:22 UTC
Permalink
From: Jason Mobarak <***@jason.mobarak.name>

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

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

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

diff --git a/src/common/defs.h b/src/common/defs.h
index fb289b0..92bc499 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -300,6 +300,17 @@ enum wpa_ctrl_req_type {
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8

+/**
+ * enum ht_mode - channel width and offset
+ */
+enum ht_mode {
+ CHAN_UNDEFINED = 0,
+ CHAN_NO_HT,
+ CHAN_HT20,
+ CHAN_HT40PLUS,
+ CHAN_HT40MINUS,
+};
+
#ifdef CONFIG_MESH
enum mesh_plink_state {
PLINK_LISTEN = 1,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index f48ff84..afcea45 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -911,6 +911,7 @@ struct wpa_driver_mesh_join_params {
u8 *ies;
int ie_len;
int freq;
+ enum ht_mode ht_mode;
struct wpa_driver_mesh_bss_params conf;
#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 42097e2..8b23342 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -9099,12 +9099,37 @@ wpa_driver_nl80211_join_mesh(void *priv,
nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_MESH);

NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- /* XXX: need chtype too in case we want HT */
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
}

+ if (params->ht_mode) {
+ unsigned int ht_value;
+ char *ht_mode = "";
+ switch (params->ht_mode) {
+ default:
+ case CHAN_NO_HT:
+ ht_value = NL80211_CHAN_NO_HT;
+ ht_mode = "NOHT";
+ break;
+ case CHAN_HT20:
+ ht_value = NL80211_CHAN_HT20;
+ ht_mode = "HT20";
+ break;
+ case CHAN_HT40PLUS:
+ ht_value = NL80211_CHAN_HT40PLUS;
+ ht_mode = "HT40+";
+ break;
+ case CHAN_HT40MINUS:
+ ht_value = NL80211_CHAN_HT40MINUS;
+ ht_mode = "HT40-";
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " * ht_mode=%s", ht_mode);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value);
+ }
+
if (params->basic_rates) {
u8 rates[NL80211_MAX_SUPP_RATES];
u8 rates_len = 0;
diff --git a/tests/hwsim/p2p0.conf b/tests/hwsim/p2p0.conf
index 9482bdc..79804a6 100644
--- a/tests/hwsim/p2p0.conf
+++ b/tests/hwsim/p2p0.conf
@@ -1,3 +1,4 @@
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
device_name=Device A
p2p_no_group_iface=1
+disable_scan_offload=1
diff --git a/tests/hwsim/p2p1.conf b/tests/hwsim/p2p1.conf
index 3622b15..7a713a8 100644
--- a/tests/hwsim/p2p1.conf
+++ b/tests/hwsim/p2p1.conf
@@ -1,3 +1,4 @@
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
device_name=Device B
p2p_no_group_iface=1
+disable_scan_offload=1
diff --git a/tests/hwsim/p2p2.conf b/tests/hwsim/p2p2.conf
index eda52e1..1df136f 100644
--- a/tests/hwsim/p2p2.conf
+++ b/tests/hwsim/p2p2.conf
@@ -1,3 +1,4 @@
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
device_name=Device C
p2p_no_group_iface=1
+disable_scan_offload=1
diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
index f1eca36..84ef00d 100644
--- a/tests/hwsim/test_wpas_mesh.py
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -43,7 +43,7 @@ def check_mesh_scan(dev, params, other_started=False):

res = dev.request("SCAN_RESULTS")

- if not res.find("[MESH]"):
+ if res.find("[MESH]") < 0:
raise Exception("Scan did not contain a MESH network")


@@ -168,6 +168,7 @@ def test_wpas_mesh_mode_scan(dev):
dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
dev[0].set_network(id, "key_mgmt", "NONE")
dev[0].set_network(id, "frequency", "2412")
+ dev[0].set_network(id, "mesh_ht_mode", "HT40+")
dev[0].mesh_group_add(id)

id = dev[1].add_network()
@@ -175,6 +176,7 @@ def test_wpas_mesh_mode_scan(dev):
dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
dev[1].set_network(id, "key_mgmt", "NONE")
dev[1].set_network(id, "frequency", "2412")
+ dev[1].set_network(id, "mesh_ht_mode", "HT40+")
dev[1].mesh_group_add(id)

# Check for mesh joined
@@ -201,6 +203,7 @@ def _test_wpas_mesh_open(dev, apdev, test_connectivity):
dev[0].set_network_quoted(id, "ssid", "wpas-mesh-open")
dev[0].set_network(id, "key_mgmt", "NONE")
dev[0].set_network(id, "frequency", "2412")
+ dev[0].set_network(id, "mesh_ht_mode", "HT40+")
dev[0].mesh_group_add(id)

id = dev[1].add_network()
@@ -208,6 +211,7 @@ def _test_wpas_mesh_open(dev, apdev, test_connectivity):
dev[1].set_network_quoted(id, "ssid", "wpas-mesh-open")
dev[1].set_network(id, "key_mgmt", "NONE")
dev[1].set_network(id, "frequency", "2412")
+ dev[1].set_network(id, "mesh_ht_mode", "HT40+")
dev[1].mesh_group_add(id)

# Check for mesh joined
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f9aa807..df95f51 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -74,25 +74,10 @@ no_vht:
}
#endif /* CONFIG_IEEE80211N */

-
-static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf)
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
{
- struct hostapd_bss_config *bss = conf->bss[0];
-
- conf->driver = wpa_s->driver;
-
- os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
-
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- if (conf->hw_mode == NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
- ssid->frequency);
- return -1;
- }
-
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */

@@ -155,6 +140,27 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
}
#endif /* CONFIG_IEEE80211N */
+}
+
+static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
+{
+ struct hostapd_bss_config *bss = conf->bss[0];
+
+ conf->driver = wpa_s->driver;
+
+ os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
+
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+ ssid->frequency);
+ return -1;
+ }
+
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);

#ifdef CONFIG_P2P
if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 8aa5ffa..4d80c7a 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -75,4 +75,9 @@ int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
const struct wpabuf *pw, const u8 *pubkey_hash);

+struct hostapd_config;
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf);
+
#endif /* AP_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b1069ce..efc0a96 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1543,7 +1543,6 @@ static int wpa_config_parse_psk_list(const struct parse_data *data,
return 0;
}

-
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_psk_list(const struct parse_data *data,
struct wpa_ssid *ssid)
@@ -1554,6 +1553,60 @@ static char * wpa_config_write_psk_list(const struct parse_data *data,

#endif /* CONFIG_P2P */

+#ifdef CONFIG_MESH
+static int wpa_config_parse_mesh_ht_mode(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int htval = 0;
+
+ if (os_strcmp(value, "NOHT") == 0)
+ htval = CHAN_NO_HT;
+ else if (os_strcmp(value, "HT20") == 0)
+ htval = CHAN_HT20;
+ else if (os_strcmp(value, "HT40-") == 0)
+ htval = CHAN_HT40MINUS;
+ else if (os_strcmp(value, "HT40+") == 0)
+ htval = CHAN_HT40PLUS;
+ else {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no ht_mode configured.", line);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "mesh_ht_mode: 0x%x", htval);
+ ssid->mesh_ht_mode = htval;
+ return 0;
+}
+
+#ifndef NO_CONFIG_WRITE
+static char *wpa_config_write_mesh_ht_mode(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *val;
+ switch (ssid->mesh_ht_mode) {
+ default:
+ val = NULL;
+ break;
+ case CHAN_NO_HT:
+ val = "NOHT";
+ break;
+ case CHAN_HT20:
+ val = "HT20";
+ break;
+ case CHAN_HT40MINUS:
+ val = "HT40-";
+ break;
+ case CHAN_HT40PLUS:
+ val = "HT40+";
+ break;
+ }
+ return val ? os_strdup(val) : NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MESH */
+
/* Helper macros for network block parser */

#ifdef OFFSET
@@ -1722,6 +1775,9 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
+#ifdef CONFIG_MESH
+ { FUNC(mesh_ht_mode) },
+#endif
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2197,6 +2253,9 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ ssid->mesh_ht_mode = DEFAULT_MESH_HT_MODE;
+#endif
#ifdef CONFIG_HT_OVERRIDES
ssid->disable_ht = DEFAULT_DISABLE_HT;
ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index daa7ce3..6234f71 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -27,6 +27,7 @@
#define DEFAULT_FRAGMENT_SIZE 1398

#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_MESH_HT_MODE CHAN_UNDEFINED /* undefined */
#define DEFAULT_DISABLE_HT 0
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_SGI 0
@@ -403,6 +404,15 @@ struct wpa_ssid {
*/
int frequency;

+ /**
+ * mesh_ht_mode - definition of HT mode in mesh mode
+ *
+ * Use the given HT mode for mesh networks. The driver will
+ * adapt to other stations if neccesary, but advertise the
+ * configured HT mode (HT20/HT40-/HT40+/NOHT).
+ */
+ int mesh_ht_mode;
+
int ht40;

int vht;
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index d8b648a..25b0eb6 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -6,6 +6,14 @@
* See README for more details.
*/

+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ap.h"
#include "mesh.h"
#include "mesh_mpm.h"
#include "mesh_rsn.h"
@@ -205,6 +213,8 @@ wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
goto out_free;
}

+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
return 0;
out_free:
wpa_supplicant_mesh_deinit(wpa_s);
@@ -256,6 +266,9 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
params.meshid = ssid->ssid;
params.meshid_len = ssid->ssid_len;
params.freq = ssid->frequency;
+#ifdef CONFIG_IEEE80211N
+ params.ht_mode = ssid->mesh_ht_mode;
+#endif /* CONFIG_IEEE80211N */

if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 69ffba8..af5b124 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -367,6 +367,12 @@ wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,

mesh_mpm_init_link(wpa_s, sta);

+#ifdef CONFIG_IEEE80211N
+ copy_sta_ht_capab(data, sta, elems->ht_capabilities,
+ elems->ht_capabilities_len);
+ update_ht_state(data, sta);
+#endif
+
/* insert into driver */
os_memset(&params, 0, sizeof(params));
params.supp_rates = sta->supported_rates;
@@ -375,7 +381,7 @@ wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
params.plink_state = sta->plink_state;
params.aid = sta->peer_lid;
params.listen_interval = 100;
- /* TODO: HT capabilities */
+ params.ht_capabilities = sta->ht_capabilities;
params.flags |= WPA_STA_WMM;
params.flags_mask |= WPA_STA_AUTHENTICATED;
if (conf->security == MESH_CONF_SEC_NONE) {
@@ -415,6 +421,9 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
struct hostapd_data *bss = ifmsh->bss[0];
struct mesh_conf *conf = ifmsh->mconf;
u8 supp_rates[2 + 2 + 32];
+#ifdef CONFIG_IEEE80211N
+ u8 ht_capa_oper[2 + 26 + 2 + 22];
+#endif
u8 *pos, *cat;
u8 ie_len, add_plid = 0;
int ret;
@@ -445,6 +454,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
else
wpabuf_put_le16(buf, 0);

+ /* aid */
if (type == PLINK_CONFIRM)
wpabuf_put_le16(buf, sta->peer_lid);

@@ -515,7 +525,14 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
if (ampe)
mesh_rsn_get_pmkid(sta, (u8 *) wpabuf_put(buf, PMKID_LEN));

- /* TODO HT IEs */
+#ifdef CONFIG_IEEE80211N
+ if (type != PLINK_CLOSE &&
+ wpa_s->current_ssid->mesh_ht_mode != CHAN_NO_HT) {
+ pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
+ pos = hostapd_eid_ht_operation(bss, pos);
+ wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
+ }
+#endif /* CONFIG_IEEE80211N */

if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
wpa_msg(wpa_s, MSG_INFO,
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:13 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-hostap: Thomas Pedersen <***@noack.us>
---
hostapd/Android.mk | 4 ++++
wpa_supplicant/Android.mk | 6 ++++++
wpa_supplicant/Makefile | 6 ++++++
3 files changed, 16 insertions(+)

diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index edaf6fc..c62d4a7 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -226,6 +226,10 @@ endif
ifdef CONFIG_WNM
L_CFLAGS += -DCONFIG_WNM
OBJS += src/ap/wnm_ap.c
+
+ifdef CONFIG_MESH
+L_CFLAGS += -DCONFIG_MESH
+endif
endif

ifdef CONFIG_IEEE80211N
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 43c3eed..c883f9f 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -208,6 +208,12 @@ endif
ifdef CONFIG_WNM
L_CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.c
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+L_CFLAGS += -DCONFIG_MESH
+OBJS += mesh.c
+OBJS += mesh_mpm.c
+endif
endif

ifdef CONFIG_TDLS
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8f7c23f..fada285 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -199,6 +199,12 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif

+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+CFLAGS += -DCONFIG_MESH
+OBJS += mesh.o mesh_mpm.o
+endif
+
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
--
2.0.0.rc2
Bob Copeland
2014-07-14 05:19:18 UTC
Permalink
From: Jason Abele <***@gmail.com>

When mesh is configured in, include the wildcard
mesh id so that mesh networks are returned. Tag any
returned mesh networks with [MESH].

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-hostap: Jason Abele <***@gmail.com>
---
wpa_supplicant/bss.c | 8 +++++++-
wpa_supplicant/ctrl_iface.c | 32 +++++++++++++++++++++++++++++---
wpa_supplicant/mesh.c | 12 ++++++++++++
wpa_supplicant/mesh.h | 2 ++
wpa_supplicant/scan.c | 5 +++++
5 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index f99a8a7..b032adb 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -591,7 +591,7 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
struct os_reltime *fetch_time)
{
- const u8 *ssid, *p2p;
+ const u8 *ssid, *p2p, *mesh;
struct wpa_bss *bss;

if (wpa_s->conf->ignore_old_scan_res) {
@@ -641,7 +641,13 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,

/* TODO: add option for ignoring BSSes we are not interested in
* (to save memory) */
+
+ mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
+ if (mesh)
+ ssid = mesh;
+
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
+
if (bss == NULL)
bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
else {
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 9736192..874e0c8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2113,6 +2113,23 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
}
#endif /* CONFIG_IEEE80211W */

+#ifdef CONFIG_MESH
+ if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == start ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sFT_SAE",
+ pos == start ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_MESH */
+
pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);

if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
@@ -2180,8 +2197,9 @@ static int wpa_supplicant_ctrl_iface_scan_result(
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *p2p;
+ const u8 *ie, *ie2, *p2p, *mesh;

+ mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
if (!p2p)
p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
@@ -2202,8 +2220,10 @@ static int wpa_supplicant_ctrl_iface_scan_result(
if (ie)
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (ie2)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+ if (ie2) {
+ const char *ie_name = mesh ? "RSN" : "WPA2";
+ pos = wpa_supplicant_ie_txt(pos, end, ie_name, ie2, 2 + ie2[1]);
+ }
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
ret = os_snprintf(pos, end - pos, "[WEP]");
@@ -2211,6 +2231,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(
return -1;
pos += ret;
}
+ if (mesh) {
+ ret = os_snprintf(pos, end - pos, "[MESH]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
if (bss_is_dmg(bss)) {
const char *s;
ret = os_snprintf(pos, end - pos, "[DMG]");
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 4635b0a..d8b648a 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -227,6 +227,18 @@ void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
}

+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie)
+{
+ /* EID + 0-length (wildcard) mesh-id */
+ size_t ielen = 2;
+
+ if (wpabuf_resize(extra_ie, ielen) == 0) {
+ wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(*extra_ie, 0);
+ }
+}
+
int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
index f08e641..9b14ecf 100644
--- a/wpa_supplicant/mesh.h
+++ b/wpa_supplicant/mesh.h
@@ -31,6 +31,8 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
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_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie);
void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
struct hostapd_iface *ifmsh);
#endif /* MESH_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 40eb8d8..74dd6c2 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -22,6 +22,7 @@
#include "notify.h"
#include "bss.h"
#include "scan.h"
+#include "mesh.h"


static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -453,6 +454,10 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
}
#endif /* CONFIG_P2P */

+#ifdef CONFIG_MESH
+ wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
+#endif /* CONFIG_MESH */
+
#endif /* CONFIG_WPS */

#ifdef CONFIG_HS20
--
2.0.0.rc2
Bob Copeland via Devel
2014-08-15 13:38:36 UTC
Permalink
This patchset developed at Cozybit adds mesh support to wpa_supplicant,
providing an alternative to the authsae daemon for running a secure
11s mesh network. Unlike authsae, it also supports running open mesh
with the peering manager in userspace.
I'll send along a v2 soon incorporating Masashi Honma's patches, along
with some other reworked bits here and there.

The following patch on top, thanks in part to Chun-Yeow Yeoh, fixes peering
when one side misses a commit message.

From 3948c663e3dfda2c4bf4f6fda8a16edf1a5780f9 Mon Sep 17 00:00:00 2001
From: Bob Copeland <***@bobcopeland.com>
Date: Thu, 14 Aug 2014 09:38:51 -0400
Subject: [PATCH] fixup auth sae - confirm without commit

---
src/ap/ieee802_11.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ac99eff..d146c1f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -325,7 +325,8 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
#ifdef CONFIG_SAE

static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta)
+ struct sta_info *sta,
+ Boolean has_peer_commit)
{
struct wpabuf *buf;

@@ -342,7 +343,7 @@ static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
return NULL;
}

- if (sae_process_commit(sta->sae) < 0) {
+ if (has_peer_commit && sae_process_commit(sta->sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
return NULL;
}
@@ -496,7 +497,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->sae->state == SAE_NOTHING ||
sta->sae->state == SAE_CONFIRMED) {
/* (re)send commit to peer */
- data = auth_process_sae_commit(hapd, sta);
+ data = auth_process_sae_commit(hapd, sta, TRUE);
if (data == NULL)
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
sta->auth_alg = WLAN_AUTH_SAE;
@@ -523,14 +524,28 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
}
}
} else if (auth_transaction == 2) {
- if (sta->sae->state == SAE_NOTHING ||
- sta->sae->state == SAE_COMMITTED) {
+ if (sta->sae->state == SAE_NOTHING) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE confirm before commit");
return;
}
+ if (sta->sae->state == SAE_COMMITTED) {
+ /*
+ * We got a confirm without a commit, but this is
+ * not fatal and can happen if commit was lost.
+ * Resend commit to trigger peer to resend commit
+ * and confirm.
+ */
+ data = auth_process_sae_commit(hapd, sta, FALSE);
+ if (data == NULL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else
+ auth_transaction = 1;
+ goto reply;
+ }
+
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE authentication (RX confirm)");
--
1.7.10.4
--
Bob Copeland %% www.bobcopeland.com
Loading...