[PATCH BlueZ v2] mesh: Add start up management command chain

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This allows co-existense of meshd and bluetoothd. meshd will
automatically take control of the first available LE-capable
controller that is powered down.
---
 Makefile.mesh |   4 +-
 mesh/btmesh.c |   5 +-
 mesh/main.c   |  22 ++---
 mesh/mesh.c   | 253 +++++++++++++++++++++++++++++++++++++++++++++-----
 mesh/mesh.h   |   4 +-
 mesh/net.c    |  49 +++++-----
 6 files changed, 269 insertions(+), 68 deletions(-)

diff --git a/Makefile.mesh b/Makefile.mesh
index 643b1a59a..e93e68e38 100644
--- a/Makefile.mesh
+++ b/Makefile.mesh
@@ -23,7 +23,7 @@ libexec_PROGRAMS += mesh/meshd
 mesh_meshd_SOURCES = $(mesh_sources) mesh/main.c
 
 mesh_meshd_LDADD = src/shared/ecc.lo src/shared/queue.lo src/shared/io-ell.lo \
-				src/shared/util.lo src/shared/hci.lo \
+				src/shared/util.lo src/shared/hci.lo src/shared/mgmt.lo \
 				@DBUS_LIBS@ @ELL_LIBS@ -ljson-c
 
 noinst_PROGRAMS += mesh/btmesh
@@ -34,7 +34,7 @@ mesh_btmesh_SOURCES = $(mesh_sources) \
 						mesh/btmesh.c
 
 mesh_btmesh_LDADD = src/shared/ecc.lo src/shared/queue.lo src/shared/io-ell.lo \
-				src/shared/util.lo src/shared/hci.lo \
+				src/shared/util.lo src/shared/hci.lo src/shared/mgmt.lo \
 				src/libshared-mainloop.la \
 				-lreadline @ELL_LIBS@ -ljson-c
 
diff --git a/mesh/btmesh.c b/mesh/btmesh.c
index c312d85db..108ec39f3 100644
--- a/mesh/btmesh.c
+++ b/mesh/btmesh.c
@@ -153,8 +153,8 @@ int main(int argc, char *argv[])
 
 	l_info("Starting mesh on hci%d\n", index);
 
-	mesh = mesh_create(index);
-	if (!mesh || !mesh_load_config(mesh, config_option)) {
+	mesh = mesh_new(index, config_option);
+	if (!mesh) {
 		l_info("Failed to create mesh\n");
 		bt_shell_cleanup();
 		return EXIT_FAILURE;
@@ -170,6 +170,7 @@ int main(int argc, char *argv[])
 	bt_shell_run();
 
 	mesh_unref(mesh);
+	mesh_cleanup();
 	l_main_exit();
 
 	return status;
diff --git a/mesh/main.c b/mesh/main.c
index 8c03f51eb..289b0582b 100644
--- a/mesh/main.c
+++ b/mesh/main.c
@@ -30,6 +30,9 @@
 #include <sys/stat.h>
 #include <ell/ell.h>
 
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
 #include "mesh/mesh.h"
 #include "mesh/net.h"
 #include "mesh/storage.h"
@@ -81,6 +84,7 @@ int main(int argc, char *argv[])
 	sigset_t mask;
 	struct bt_mesh *mesh = NULL;
 	const char *config_file = NULL;
+	int index = MGMT_INDEX_NONE;
 
 	if (!l_main_init())
 		return -1;
@@ -107,12 +111,7 @@ int main(int argc, char *argv[])
 				goto done;
 			}
 
-			mesh = mesh_create(atoi(str));
-			if (!mesh) {
-				l_error("Failed to initialize mesh");
-				status = EXIT_FAILURE;
-				goto done;
-			}
+			index = atoi(str);
 
 			break;
 		case 'n':
@@ -135,14 +134,8 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	if (!mesh) {
-		usage();
-		status = EXIT_FAILURE;
-		goto done;
-	}
-
-	if (!mesh_load_config(mesh, config_file)) {
-		l_error("Failed to load mesh configuration: %s", config_file);
+	if (!mesh_new(index, config_file)) {
+		l_error("Failed to initialize mesh");
 		status = EXIT_FAILURE;
 		goto done;
 	}
@@ -168,6 +161,7 @@ int main(int argc, char *argv[])
 
 done:
 	mesh_unref(mesh);
+	mesh_cleanup();
 	l_main_exit();
 
 	return status;
diff --git a/mesh/mesh.c b/mesh/mesh.c
index a6f733f5c..3fba0140c 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -26,9 +26,11 @@
 #include <ell/ell.h>
 
 #include "lib/bluetooth.h"
+#include "lib/mgmt.h"
 
-#include "mesh/mesh-defs.h"
+#include "src/shared/mgmt.h"
 
+#include "mesh/mesh-defs.h"
 #include "mesh/mesh-io.h"
 #include "mesh/node.h"
 #include "mesh/net.h"
@@ -44,11 +46,25 @@ struct scan_filter {
 
 struct bt_mesh {
 	struct mesh_net *net;
-	int ref_count;
+	struct mesh_io *io;
 	struct l_queue *filters;
+	int ref_count;
+	uint16_t index;
+	uint16_t req_index;
 	uint8_t max_filters;
 };
 
+static struct l_queue *controllers;
+static struct l_queue *mesh_list;
+static struct mgmt *mgmt_mesh;
+static bool initialized;
+static struct bt_mesh *current;
+
+static bool simple_match(const void *a, const void *b)
+{
+	return a == b;
+}
+
 static void save_exit_config(struct bt_mesh *mesh)
 {
 	const char *cfg_filename;
@@ -64,36 +80,233 @@ static void save_exit_config(struct bt_mesh *mesh)
 		l_info("Saved final configuration to %s", cfg_filename);
 }
 
-struct bt_mesh *mesh_create(uint16_t index)
+static void start_io(struct bt_mesh *mesh, uint16_t index)
 {
-	struct bt_mesh *mesh;
 	struct mesh_io *io;
 	struct mesh_io_caps caps;
 
+	l_debug("Starting mesh on hci %u", index);
+
+	io = mesh_io_new(index, MESH_IO_TYPE_GENERIC);
+	if (!io) {
+		l_error("Failed to start mesh io (hci %u)", index);
+		current = NULL;
+		return;
+	}
+
+	mesh_io_get_caps(io, &caps);
+	mesh->max_filters = caps.max_num_filters;
+
+	mesh_net_attach(mesh->net, io);
+	mesh_net_set_window_accuracy(mesh->net, caps.window_accuracy);
+	mesh->io = io;
+	mesh->index = index;
+
+	current = NULL;
+
+	l_debug("Started mesh (io %p) on hci %u", mesh->io, index);
+}
+
+static void read_info_cb(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	uint16_t index = L_PTR_TO_UINT(user_data);
+	const struct mgmt_rp_read_info *rp = param;
+	uint32_t current_settings, supported_settings;
+
+	if (!current)
+		/* Already initialized */
+		return;
+
+	l_debug("hci %u status 0x%02x", index, status);
+
+	if (status != MGMT_STATUS_SUCCESS) {
+		l_error("Failed to read info for hci index %u: %s (0x%02x)",
+					index, mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		l_error("Read info response too short");
+		return;
+	}
+
+	current_settings = btohl(rp->current_settings);
+	supported_settings = btohl(rp->supported_settings);
+
+	l_debug("settings: supp %8.8x curr %8.8x",
+					supported_settings, current_settings);
+
+	if (current_settings & MGMT_SETTING_POWERED) {
+		l_info("Controller hci %u is in use", index);
+		return;
+	}
+
+	if (!(supported_settings & MGMT_SETTING_LE)) {
+		l_info("Controller hci %u does not support LE", index);
+		return;
+	}
+
+	start_io(current, index);
+}
+
+static void index_added(uint16_t index, uint16_t length, const void *param,
+							void *user_data)
+{
+	l_debug("hci device %u", index);
+
+	if (!current)
+		return;
+
+	if (current->req_index != MGMT_INDEX_NONE &&
+					index != current->req_index) {
+		l_debug("Ignore index %d", index);
+		return;
+	}
+
+	if (l_queue_find(controllers, simple_match, L_UINT_TO_PTR(index)))
+		return;
+
+	l_queue_push_tail(controllers, L_UINT_TO_PTR(index));
+
+	if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INFO, index, 0, NULL,
+			read_info_cb, L_UINT_TO_PTR(index), NULL) > 0)
+		return;
+
+	l_queue_remove(controllers, L_UINT_TO_PTR(index));
+}
+
+static void index_removed(uint16_t index, uint16_t length, const void *param,
+							void *user_data)
+{
+	l_warn("Hci dev %4.4x removed", index);
+	l_queue_remove(controllers, L_UINT_TO_PTR(index));
+}
+
+static void read_index_list_cb(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_rp_read_index_list *rp = param;
+	uint16_t num;
+	int i;
+
+	if (status != MGMT_STATUS_SUCCESS) {
+		l_error("Failed to read index list: %s (0x%02x)",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		l_error("Read index list response sixe too short");
+		return;
+	}
+
+	num = btohs(rp->num_controllers);
+
+	l_debug("Number of controllers: %u", num);
+
+	if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+		l_error("Incorrect packet size for index list response");
+		return;
+	}
+
+	for (i = 0; i < num; i++) {
+		uint16_t index;
+
+		index = btohs(rp->index[i]);
+		index_added(index, 0, NULL, user_data);
+	}
+}
+
+static bool load_config(struct bt_mesh *mesh, const char *in_config_name)
+{
+	if (!mesh->net)
+		return false;
+
+	if (!storage_parse_config(mesh->net, in_config_name))
+		return false;
+
+	/* Register foundational models */
+	mesh_config_srv_init(mesh->net, PRIMARY_ELE_IDX);
+
+	return true;
+}
+
+static bool init_mesh(void)
+{
+	if (initialized)
+		return true;
+
+	controllers = l_queue_new();
+	if (!controllers)
+		return false;
+
+	mesh_list = l_queue_new();
+	if (!mesh_list)
+		return false;
+
+	mgmt_mesh = mgmt_new_default();
+	if (!mgmt_mesh)
+		goto fail;
+
+	mgmt_register(mgmt_mesh, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+						index_added, NULL, NULL);
+	mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+						index_removed, NULL, NULL);
+
+	initialized = true;
+	return true;
+
+fail:
+	l_error("Failed to initialize mesh management");
+
+	l_queue_destroy(controllers, NULL);
+
+	return false;
+}
+
+struct bt_mesh *mesh_new(uint16_t index, const char *config_file)
+{
+	struct bt_mesh *mesh;
+
+	if (!init_mesh())
+		return NULL;
+
 	mesh = l_new(struct bt_mesh, 1);
 	if (!mesh)
 		return NULL;
 
+	mesh->req_index = index;
+	mesh->index = MGMT_INDEX_NONE;
+
 	mesh->net = mesh_net_new(index);
 	if (!mesh->net) {
 		l_free(mesh);
 		return NULL;
 	}
 
-	io = mesh_io_new(index, MESH_IO_TYPE_GENERIC);
-	if (!io) {
-		mesh_net_unref(mesh->net);
+	if (!load_config(mesh, config_file)) {
+		l_error("Failed to load mesh configuration: %s", config_file);
 		l_free(mesh);
 		return NULL;
 	}
 
-	mesh_io_get_caps(io, &caps);
-	mesh->max_filters = caps.max_num_filters;
+	/*
+	 * TODO: Check if another mesh is searching for io.
+	 * If so, add to pending list and return.
+	 */
+	l_debug("send read index_list");
+	if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INDEX_LIST,
+				MGMT_INDEX_NONE, 0, NULL,
+				read_index_list_cb, mesh, NULL) > 0) {
+		current = mesh;
+		l_queue_push_tail(mesh_list, mesh);
+		return mesh_ref(mesh);
+	}
 
-	mesh_net_attach(mesh->net, io);
-	mesh_net_set_window_accuracy(mesh->net, caps.window_accuracy);
+	l_free(mesh);
 
-	return mesh_ref(mesh);
+	return NULL;
 }
 
 struct bt_mesh *mesh_ref(struct bt_mesh *mesh)
@@ -127,18 +340,15 @@ void mesh_unref(struct bt_mesh *mesh)
 		mesh_io_destroy(io);
 
 	mesh_net_unref(mesh->net);
+	l_queue_remove(mesh_list, mesh);
 	l_free(mesh);
 }
 
-bool mesh_load_config(struct bt_mesh *mesh, const char *in_config_name)
+void mesh_cleanup(void)
 {
-	if (!storage_parse_config(mesh->net, in_config_name))
-		return false;
-
-	/* Register foundational models */
-	mesh_config_srv_init(mesh->net, PRIMARY_ELE_IDX);
-
-	return true;
+	l_queue_destroy(controllers, NULL);
+	l_queue_destroy(mesh_list, NULL);
+	mgmt_unref(mgmt_mesh);
 }
 
 bool mesh_set_output(struct bt_mesh *mesh, const char *config_name)
@@ -177,8 +387,5 @@ const char *mesh_status_str(uint8_t err)
 
 struct mesh_net *mesh_get_net(struct bt_mesh *mesh)
 {
-	if (!mesh)
-		return NULL;
-
 	return mesh->net;
 }
diff --git a/mesh/mesh.h b/mesh/mesh.h
index 7cd1e6158..8d389883b 100644
--- a/mesh/mesh.h
+++ b/mesh/mesh.h
@@ -21,11 +21,11 @@
 struct bt_mesh;
 struct mesh_net;
 
-struct bt_mesh *mesh_create(uint16_t index);
+struct bt_mesh *mesh_new(uint16_t index, const char *in_config_name);
 struct bt_mesh *mesh_ref(struct bt_mesh *mesh);
 void mesh_unref(struct bt_mesh *mesh);
-bool mesh_load_config(struct bt_mesh *mesh, const char *in_config_name);
 bool mesh_set_output(struct bt_mesh *mesh, const char *out_config_name);
+void mesh_cleanup(void);
 const char *mesh_status_str(uint8_t err);
 
 /* Command line testing */
diff --git a/mesh/net.c b/mesh/net.c
index 544f9efa5..fb17e639d 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -1133,7 +1133,8 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,
 		return MESH_STATUS_STORAGE_FAIL;
 	}
 
-	start_network_beacon(subnet, net);
+	if (net->io)
+		start_network_beacon(subnet, net);
 
 	return MESH_STATUS_SUCCESS;
 }
@@ -3099,13 +3100,34 @@ bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)
 	return true;
 }
 
-
 bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
 {
 	if (!net)
 		return false;
 
 	net->io = io;
+	if (net->provisioned) {
+
+		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
+							beacon_recv, net);
+		mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
+							net_msg_recv, net);
+		l_queue_foreach(net->subnets, start_network_beacon, net);
+
+	} else {
+		uint8_t *uuid = node_uuid_get(net->local_node);
+
+		if (!uuid)
+			return false;
+
+		mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
+		mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_NET);
+
+		mesh_prov_listen(net, uuid, (uint8_t *) &net->prov_caps,
+					acceptor_prov_open,
+					acceptor_prov_close,
+					acceptor_prov_receive, net);
+	}
 
 	return true;
 }
@@ -4150,33 +4172,10 @@ bool mesh_net_provisioned_new(struct mesh_net *net, uint8_t device_key[16],
 
 void mesh_net_provisioned_set(struct mesh_net *net, bool provisioned)
 {
-	struct mesh_io *io;
-
 	if (!net)
 		return;
 
 	net->provisioned = provisioned;
-	io = net->io;
-
-	if (provisioned) {
-		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
-							beacon_recv, net);
-		mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
-							net_msg_recv, net);
-	} else {
-		uint8_t *uuid = node_uuid_get(net->local_node);
-
-		if (!uuid)
-			return;
-
-		mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
-		mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_NET);
-
-		mesh_prov_listen(net, uuid, (uint8_t *) &net->prov_caps,
-					acceptor_prov_open,
-					acceptor_prov_close,
-					acceptor_prov_receive, net);
-	}
 }
 
 bool mesh_net_provisioned_get(struct mesh_net *net)
-- 
2.17.1




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux