Discussion:
[PATCH v3 00/17] mesh support for wpa_supplicant
Bob Copeland
2014-06-30 03:44:23 UTC
Permalink
Hi,

This is the third version of the wpa_supplicant for mesh patches. Although
it's been about a month since last posting, there are not too many changes from
last time. I mostly wanted to address Yu Niiro and Chun-Yeow Yeoh's comments,
though I did a few minor fixes.

I'd like to fix up the remaining loose ends and then send it on to the hostapd
list for review there in the next week or two.

Still outstanding is at least the following:

- any changes to SAE including auth timer. I wanted to review this and the
standard in more detail than I had time for tonight.

- I left out the patch from Yu setting the default key management;
usage seemed to be a bit at odds with how it's used for infra
networks.

- in both mpm and rsn we have placeholder comments where there should
be some sort of cleanup code

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

Jason Abele (1):
wpa_supplicant: implement mesh scanning

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

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

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

hostapd/Android.mk | 4 +
src/ap/ap_config.h | 29 +-
src/ap/hostapd.c | 27 +-
src/ap/hostapd.h | 11 +
src/ap/ieee802_11.c | 76 ++-
src/ap/sta_info.h | 18 +
src/ap/wpa_auth.c | 16 +
src/ap/wpa_auth.h | 3 +
src/common/defs.h | 36 ++
src/common/ieee802_11_common.c | 22 +
src/common/ieee802_11_common.h | 10 +
src/common/ieee802_11_defs.h | 36 ++
src/common/wpa_ctrl.h | 6 +
src/crypto/Makefile | 1 +
src/crypto/aes-siv.c | 181 +++++++
src/crypto/aes_siv.h | 17 +
src/drivers/driver.h | 88 ++-
src/drivers/driver_common.c | 1 +
src/drivers/driver_nl80211.c | 322 ++++++++++-
src/drivers/driver_wext.c | 5 +-
tests/hwsim/example-wpa_supplicant.config | 1 +
tests/hwsim/p2p0.conf | 1 +
tests/hwsim/p2p1.conf | 1 +
tests/hwsim/p2p2.conf | 1 +
tests/hwsim/test_wpas_mesh.py | 336 ++++++++++++
tests/hwsim/wpasupplicant.py | 12 +
wpa_supplicant/Android.mk | 13 +
wpa_supplicant/Makefile | 12 +
wpa_supplicant/ap.c | 42 +-
wpa_supplicant/ap.h | 5 +
wpa_supplicant/bss.c | 8 +-
wpa_supplicant/config.c | 82 ++-
wpa_supplicant/config.h | 11 +
wpa_supplicant/config_file.c | 5 +
wpa_supplicant/config_ssid.h | 21 +
wpa_supplicant/ctrl_iface.c | 107 +++-
wpa_supplicant/driver_i.h | 25 +
wpa_supplicant/events.c | 36 +-
wpa_supplicant/mesh.c | 326 +++++++++++
wpa_supplicant/mesh.h | 38 ++
wpa_supplicant/mesh_mpm.c | 861 ++++++++++++++++++++++++++++++
wpa_supplicant/mesh_mpm.h | 26 +
wpa_supplicant/mesh_rsn.c | 546 +++++++++++++++++++
wpa_supplicant/mesh_rsn.h | 39 ++
wpa_supplicant/scan.c | 5 +
wpa_supplicant/wpa_cli.c | 21 +
wpa_supplicant/wpa_supplicant.c | 54 +-
wpa_supplicant/wpa_supplicant.conf | 26 +
wpa_supplicant/wpa_supplicant_i.h | 7 +-
49 files changed, 3519 insertions(+), 58 deletions(-)
create mode 100644 src/crypto/aes-siv.c
create mode 100755 src/crypto/aes_siv.h
create mode 100644 tests/hwsim/test_wpas_mesh.py
create mode 100644 wpa_supplicant/mesh.c
create mode 100644 wpa_supplicant/mesh.h
create mode 100644 wpa_supplicant/mesh_mpm.c
create mode 100644 wpa_supplicant/mesh_mpm.h
create mode 100644 wpa_supplicant/mesh_rsn.c
create mode 100644 wpa_supplicant/mesh_rsn.h
--
2.0.0.rc2
Bob Copeland
2014-06-30 03:44:28 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>

---

v6: Updated email addresses, added signed-hostap
---
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 cad0938..88d3f92 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
@@ -1134,7 +1136,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;
}
}
@@ -1414,6 +1420,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) {
@@ -2874,6 +2887,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);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh)
+ mesh_mpm_action_rx(wpa_s, mgmt, len);
+#endif /* CONFIG_MESH */
}


@@ -3221,7 +3238,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;
@@ -3235,6 +3254,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;
@@ -3461,6 +3486,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-06-30 03:44:38 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 7a77ac7..1efb5ad 100644
--- a/tests/hwsim/example-wpa_supplicant.config
+++ b/tests/hwsim/example-wpa_supplicant.config
@@ -74,6 +74,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 18c2c62..3ec6fab 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -245,6 +245,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-06-30 03:44:24 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

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

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

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

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

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

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

struct hostapd_iface;

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

+#ifdef CONFIG_MESH
+ struct hostapd_iface *ifmsh;
+ struct mesh_rsn *mesh_rsn;
+#endif /* CONFIG_MESH */
+
unsigned int off_channel_freq;
struct wpabuf *pending_action_tx;
u8 pending_action_src[ETH_ALEN];
--
2.0.0.rc2
Bob Copeland
2014-06-30 03:44:35 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 482fc64..d77db98 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 5a53ed0..080f303 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2106,6 +2106,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) {
@@ -2173,8 +2190,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);
@@ -2195,8 +2213,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]");
@@ -2204,6 +2224,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->caps & IEEE80211_CAP_IBSS) {
ret = os_snprintf(pos, end - pos, "[IBSS]");
if (ret < 0 || ret >= end - pos)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index d96d654..054df2b 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -226,6 +226,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 bc0daeb..91e25b3 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
2014-06-30 03:44:31 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

Signed-off-by: Javier Lopez <***@gmail.com>
Signed-hostap: Thomas Pedersen <***@noack.us>

--
v8: squashed all makefile changes together, reordered, added android.mk
bits
---
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 6db82f8..160fbde 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -229,6 +229,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 c8fe1c2..388ac27 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 f74d516..1e7d6b8 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -252,6 +252,12 @@ CFLAGS += -DCONFIG_IBSS_RSN
OBJS += ibss_rsn.o
endif

+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+CFLAGS += -DCONFIG_MESH
+OBJS += mesh.o mesh_mpm.o
+endif
+
ifdef CONFIG_P2P
OBJS += p2p_supplicant.o
OBJS += ../src/p2p/p2p.o
--
2.0.0.rc2
Bob Copeland
2014-06-30 03:44:34 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>
---
Still TODO: pick up Chun-Yeow Yeoh's changes
---
src/ap/ieee802_11.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-----
src/ap/wpa_auth.c | 16 +++++++++++
src/ap/wpa_auth.h | 3 +++
3 files changed, 88 insertions(+), 7 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 14fb567..b1b4ffb 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -447,6 +447,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
{
u16 resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
+ int start_ampe = 0;

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

+#ifdef CONFIG_MESH
+ if (sta->sae->state == SAE_ACCEPTED) {
+ if (auth_transaction == 1 || auth_transaction == 2) {
+ wpa_printf(MSG_DEBUG, "SAE: remove the STA "
+ "(" MACSTR ") doing reauthentication",
+ MAC2STR(sta->addr));
+ ap_free_sta(hapd, sta);
+ }
+ return;
+ }
+#endif /* CONFIG_MESH */
+
if (auth_transaction == 1) {
const u8 *token = NULL;
size_t token_len = 0;
@@ -482,16 +495,29 @@ 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 {
+ } else if (sta->sae->state != SAE_COMMITTED) {
data = auth_process_sae_commit(hapd, sta);
if (data == NULL)
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
else
sta->sae->state = SAE_COMMITTED;
+ } else if (sae_process_commit(sta->sae) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Failed to process peer commit");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ 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_COMMITTED &&
+ sta->sae->state != SAE_CONFIRMED) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -509,10 +535,18 @@ 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);

+ /* already confirmed */
+ 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;
+ }
+
+ start_ampe = 1;
data = auth_build_sae_confirm(hapd, sta);
if (data == NULL)
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -536,6 +570,8 @@ failed:
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0);
+ if (start_ampe)
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
wpabuf_free(data);
}
#endif /* CONFIG_SAE */
@@ -650,10 +686,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 authentication. */
+ 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) {
@@ -738,6 +784,19 @@ 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, "FT: 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 */
@@ -1749,6 +1808,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 77e7858..7bc9d94 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),
@@ -1517,6 +1526,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-06-30 03:44:36 UTC
Permalink
From: Javier Lopez <***@gmail.com>

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

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

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

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

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

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

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

#ifdef CONFIG_P2P

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

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

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

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

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

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

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

+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ }
+#endif /* CONFIG_MESH */
+
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
--
2.0.0.rc2
Bob Copeland
2014-06-30 03:44:30 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

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

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

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

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

---
Still TODO: incorporate various fixes from Yu Niiro for
saving options
---
wpa_supplicant/config.c | 9 +++++++++
wpa_supplicant/config.h | 11 +++++++++++
wpa_supplicant/config_file.c | 3 +++
wpa_supplicant/config_ssid.h | 8 ++++++++
wpa_supplicant/ctrl_iface.c | 2 ++
wpa_supplicant/mesh_mpm.c | 7 +++++++
6 files changed, 40 insertions(+)

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

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

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

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

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

return 0;
}
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 944fae0..a27c69f 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -325,6 +325,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);
@@ -365,6 +366,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-06-30 03:44:39 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.

Signed-off-by: Ashok Nagarajan <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
[Original implementation by Chun-Yeow Yeoh <***@gmail.com>]
Signed-hostap: Jason Mobarak <***@jason.mobarak.name>

---
Changes since v2:
- fixup IE order [Yu Niiro]
---
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 | 17 ++++++++++--
13 files changed, 173 insertions(+), 23 deletions(-)

diff --git a/src/common/defs.h b/src/common/defs.h
index 1ee7090..e4e6480 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 a885dff..94cb5d3 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -886,6 +886,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 e96b4e6..8a7af97 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -8941,12 +8941,37 @@ static int wpa_driver_nl80211_join_mesh(
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 b02c424..d3313d3 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 8a8e28a..d22c2be 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1528,7 +1528,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)
@@ -1539,6 +1538,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
@@ -1706,6 +1759,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) },
@@ -2172,6 +2228,9 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
#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 f0a8b32..44ce227 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
@@ -402,6 +403,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 054df2b..8f4a415 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"
@@ -204,6 +212,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);
@@ -255,6 +265,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 b5f3bfa..9f86f8f 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -344,6 +344,10 @@ wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,

mesh_mpm_init_link(wpa_s, sta);

+ copy_sta_ht_capab(data, sta, elems->ht_capabilities,
+ elems->ht_capabilities_len);
+ update_ht_state(data, sta);
+
/* insert into driver */
os_memset(&params, 0, sizeof(params));
params.supp_rates = sta->supported_rates;
@@ -352,7 +356,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) {
@@ -391,6 +395,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 ht_capa_oper[2 + 26 + 2 + 22];
u8 *pos, *cat;
u8 ie_len, add_plid = 0;
int ret;
@@ -421,6 +426,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);

@@ -491,7 +497,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-06-30 03:44:37 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>

---
Changes since v2:
- save sae key mgmt and mesh ht mode [Yu Niiro]
---
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 f517452..8a8e28a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -672,6 +672,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 */
+
return buf;
}
#endif /* NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index d004d83..32e3669 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -731,6 +731,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(dtim_period);
INT(beacon_int);

+ 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 86a4621..3d6e3ab 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -110,6 +110,15 @@ eapol_version=1
# networks are found, a new IBSS or AP mode network is created.
ap_scan=1

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

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

# Catch all example that allows more or less all configuration modes
network={
--
2.0.0.rc2
Bob Copeland
2014-06-30 03:44:40 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>

---
v4: Reword commit per Thomas' suggestion, specify why we're checking
mconf for null.
v6: Update email addresses, add signed-hostap.
v7: remove blank lines before Signed-hostap
---
src/ap/hostapd.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)

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

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

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

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

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

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

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

- if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+#ifdef CONFIG_MESH
+ if (iface->mconf != NULL) {
+ wpa_printf(MSG_DEBUG, "%s: Mesh configuration will be "
+ "applied while joining the mesh network.",
+ iface->bss[0]->conf->iface);
+ delay_apply_cfg = 1;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!delay_apply_cfg &&
+ hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
--
2.0.0.rc2
Bob Copeland
2014-06-30 03:44:25 UTC
Permalink
From: Thomas Pedersen <***@noack.us>

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

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

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

This implementation supports open mesh peerings.

[assorted fixes from Yu Niiro <***@gmail.com>]
Signed-off-by: Javier Lopez <***@gmail.com>
Signed-off-by: Javier Cardona <***@cozybit.com>
Signed-off-by: Ashok Nagarajan <***@gmail.com>
Signed-off-by: Jason Mobarak <***@jason.mobarak.name>
Signed-hostap: Bob Copeland <***@bobcopeland.com>

---
changes since v2:
- allow confirm frames with new plid [Yu Niiro]
- init llid if needed when opening link after sae auth [Yu Niiro]
- set aid
---
wpa_supplicant/mesh.c | 21 +-
wpa_supplicant/mesh_mpm.c | 815 ++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh_mpm.h | 26 ++
3 files changed, 860 insertions(+), 2 deletions(-)
create mode 100644 wpa_supplicant/mesh_mpm.c
create mode 100644 wpa_supplicant/mesh_mpm.h

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

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

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

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

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

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

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

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

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

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

---
changes since v2:
- cleanup some comments
---
wpa_supplicant/Android.mk | 4 +
wpa_supplicant/Makefile | 5 +-
wpa_supplicant/mesh.c | 8 +
wpa_supplicant/mesh_mpm.c | 30 ++-
wpa_supplicant/mesh_rsn.c | 546 ++++++++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/mesh_rsn.h | 39 ++++
6 files changed, 629 insertions(+), 3 deletions(-)
create mode 100644 wpa_supplicant/mesh_rsn.c
create mode 100644 wpa_supplicant/mesh_rsn.h

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

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

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

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

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

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

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

return 0;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index a27c69f..b5f3bfa 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"
@@ -299,6 +300,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);
@@ -372,7 +375,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,
@@ -385,7 +391,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;
@@ -404,6 +410,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);

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

/* TODO HT IEs */

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

+fail:
wpabuf_free(buf);
}

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

I went back through this file tonight and found a few things that I'll
fix in the next posting -- here's a diff of the changes:

diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 0da0f2f..819d75a 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -114,11 +114,11 @@ __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
/* TODO: support rekeying */
random_get_bytes(rsn->mgtk, 16);

- /* TODO: don't hardcode key idx */
- /* mcast mgmt */
+ /* group mgmt */
wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
- /* mcast data */
+
+ /* 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));

@@ -127,7 +127,8 @@ __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)

static void mesh_rsn_deinit(struct mesh_rsn *rsn)
{
- /* TODO: stuff */
+ os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ wpa_deinit(rsn->auth);
}

struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
@@ -330,7 +331,7 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
{
u8 *ptr;
u8 *min, *max;
- u8 smin[2], smax[2];
+ u16 min_lid, max_lid;
size_t nonce_len = sizeof(sta->my_nonce);
size_t lid_len = sizeof(sta->my_lid);

@@ -353,18 +354,14 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
ptr += 2 * nonce_len;

if (sta->my_lid < sta->peer_lid) {
- smin[0] = (sta->my_lid >> 8) & 0xff;
- smin[1] = sta->my_lid & 0xff;
- smax[0] = (sta->peer_lid >> 8) & 0xff;
- smax[1] = sta->peer_lid & 0xff;
+ min_lid = host_to_le16(sta->my_lid);
+ max_lid = host_to_le16(sta->peer_lid);
} else {
- smin[0] = (sta->peer_lid >> 8) & 0xff;
- smin[1] = sta->peer_lid & 0xff;
- smax[0] = (sta->my_lid >> 8) & 0xff;
- smax[1] = sta->my_lid & 0xff;
+ min_lid = host_to_le16(sta->peer_lid);
+ max_lid = host_to_le16(sta->my_lid);
}
- os_memcpy(ptr, smin, lid_len);
- os_memcpy(ptr + lid_len, smax, lid_len);
+ os_memcpy(ptr, &min_lid, lid_len);
+ os_memcpy(ptr + lid_len, &max_lid, lid_len);
ptr += 2 * lid_len;

/* SAE */
@@ -394,7 +391,6 @@ void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s,
random_get_bytes(sta->my_nonce, 32);
os_memset(sta->peer_nonce, 0, 32);
mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
- /* TODO: init SIV-AES contexts for AMPE IE encryption */
}

/* insert AMPE and encrypted MIC at @ie.
@@ -407,7 +403,7 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn,
struct sta_info *sta, const u8 *cat,
struct wpabuf *buf)
{
- struct ieee80211_ampe_ie *ampe;
+ 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};
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index 8582bfa..7b95637 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -14,7 +14,6 @@
struct mesh_rsn {
struct wpa_supplicant *wpa_s;
struct wpa_authenticator *auth;
- u8 psk[SAE_PMK_LEN];
u8 mgtk[16];
#ifdef CONFIG_SAE
struct wpabuf *sae_token;
--
Bob Copeland %% www.bobcopeland.com
Bob Copeland
2014-06-30 03:44:32 UTC
Permalink
Add an implementation of Synthetic Initialization Vector (SIV)
Authenticated Encryption Using the Advanced Encryption Standard (AES).

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

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

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

---

v2: - Split out the widing of the drv_flags / flags into separate patch.
- Squash with "Clarify comment on TODO" https://github.com/cozybit/wpa_s_mesh_android/commit/95430203e0462eb1c275380b6fed172f5ce9daf1
- Squash with "Add plink_action_field and mesh_power_mode to hostapd_sta_add_params" https://github.com/cozybit/wpa_s_mesh_android/commit/89d29f6a5c84a7b59ecfe1bb60c7271533bb6ea7
- Squash with "Clarify comment (issue #10)" https://github.com/cozybit/wpa_s_mesh_android/commit/21734bc9b50190f06040ca26f0819cbb75c9c522
- Squash with "closes #12" https://github.com/cozybit/wpa_s_mesh_android/commit/4d7209ed2d12a4eb1fbcafb26741f3b06f55149e
- Squash with "Closes #16" https://github.com/cozybit/wpa_s_mesh_android/commit/fa05631616199fa48f61c7e58e44729e216d5d64
- Squash with "No default mesh frequency. Closes #18" https://github.com/cozybit/wpa_s_mesh_android/commit/03f80b9c4ae3b9580d3759c3f564b257aa62022e
- Squash with "Closes #19" https://github.com/cozybit/wpa_s_mesh_android/commit/3cf9b4c238037e6bba73048d6f221f8ea9b1f445
- Squash with "Set mesh authentication protocol id in mesh config" https://github.com/cozybit/wpa_s_mesh_android/commit/caaf6ee68cc28cfde9400869440209b55c07a35f
- Squash with "PLINK_CLOSE can have only MESHID and MPM IEs" https://github.com/cozybit/wpa_s_mesh_android/commit/6c4fd81f8cfa5f576fbaffae3654eb38bdf91016

v3: Remove workaround for NL80211_FEATURE_SK_TX_STATUS
v4: No changes
v5: Removed extraneous else for NL80211_FEATURE_SK_TX_STATUS change
v6: Updated email addresses, added signed-hostap for Bob
v7: remove blank lines
v8: add u64 driver flags
---
src/common/defs.h | 25 ++++
src/drivers/driver.h | 87 ++++++++++-
src/drivers/driver_common.c | 1 +
src/drivers/driver_nl80211.c | 297 ++++++++++++++++++++++++++++++++++++--
src/drivers/driver_wext.c | 5 +-
wpa_supplicant/driver_i.h | 25 ++++
wpa_supplicant/wpa_supplicant_i.h | 2 +-
7 files changed, 423 insertions(+), 19 deletions(-)

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

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

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

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

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

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

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


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


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

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


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

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

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


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

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

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

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

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

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

return f;
}

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

/*
--
2.0.0.rc2
Loading...