linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] mesh: Added ImportLocalNode call with its API
@ 2019-06-25 14:38 Jakub Witowski
  2019-06-26 17:01 ` Gix, Brian
  0 siblings, 1 reply; 9+ messages in thread
From: Jakub Witowski @ 2019-06-25 14:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Inga Stotland

This implements ImportLocalNode() method on org.bluez.mesh.Network1
interface. Invoking this method creates a self-provisioned node based on
passed JSON definition. Also full functionality of import local node has
been implemented
---
 doc/mesh-api.txt |  22 ++++-
 mesh/mesh.c      |  63 ++++++++++++--
 mesh/node.c      | 212 +++++++++++++++++++++++++++++++++++++++++++----
 mesh/node.h      |   2 +
 4 files changed, 276 insertions(+), 23 deletions(-)

diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
index 4e0a8bff1..539fc3e4f 100644
--- a/doc/mesh-api.txt
+++ b/doc/mesh-api.txt
@@ -151,11 +151,21 @@ Methods:
 			org.bluez.mesh.Error.InvalidArguments
 			org.bluez.mesh.Error.AlreadyExists,
 
-	 uint64 token ImportLocalNode(string json_data)
+	 uint64 token ImportLocalNode(object app_root, string json_data, array{byte}[16] uuid)
 
 		This method creates a local mesh node based on node
 		configuration that has been generated outside bluetooth-meshd.
 
+		The app_root parameter is a D-Bus object root path of the
+		application that implements org.bluez.mesh.Application1
+		interface, and a org.bluez.mesh.Provisioner1 interface. The
+		application represents a node where child mesh elements have
+		their own objects that implement org.bluez.mesh.Element1
+		interface. The application hierarchy also contains a provision
+		agent object that implements org.bluez.mesh.ProvisionAgent1
+		interface. The standard DBus.ObjectManager interface must be
+		available on the app_root path.
+
 		The json_data parameter is a full JSON representation of a node
 		configuration file. The format must conform to the schema
 		defined in "Mesh Node Configuration Schema" section. Any
@@ -1059,4 +1069,12 @@ Properties:
 
 Mesh Node Configuration Schema
 ==============================
-<TBD>
+Example of Json format for ImportLocalNode():
+{
+  "IVindex":0,
+  "IVupdate":0,
+  "unicastAddress":"0012",
+  "deviceKey":"7daa45cd1e9e11a4b86eeef7d01efa11",
+  "netKey":"1234567890abcdef1234567890abcdef",
+  "keyRefresh":0
+}
diff --git a/mesh/mesh.c b/mesh/mesh.c
index 26acfd4dc..e0f0e4bf9 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -22,6 +22,7 @@
 #endif
 
 #define _GNU_SOURCE
+#include <json-c/json.h>
 #include <ell/ell.h>
 
 #include "mesh/mesh-io.h"
@@ -60,7 +61,7 @@ struct bt_mesh {
 	uint8_t max_filters;
 };
 
-struct join_data{
+struct join_data {
 	struct l_dbus_message *msg;
 	struct mesh_agent *agent;
 	const char *sender;
@@ -365,8 +366,8 @@ static void node_init_cb(struct mesh_node *node, struct mesh_agent *agent)
 
 	if (!acceptor_start(num_ele, join_pending->uuid, mesh.algorithms,
 				mesh.prov_timeout, agent, prov_complete_cb,
-				&mesh))
-	{
+				&mesh)) {
+
 		reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
 				"Failed to start provisioning acceptor");
 		goto fail;
@@ -536,7 +537,7 @@ static struct l_dbus_message *leave_call(struct l_dbus *dbus,
 	return l_dbus_message_new_method_return(msg);
 }
 
-static void create_network_ready_cb(void *user_data, int status,
+static void create_node_ready_cb(void *user_data, int status,
 							struct mesh_node *node)
 {
 	struct l_dbus_message *reply;
@@ -593,12 +594,58 @@ static struct l_dbus_message *create_network_call(struct l_dbus *dbus,
 
 	l_queue_push_tail(pending_queue, pending_msg);
 
-	node_create(app_path, sender, uuid, create_network_ready_cb,
+	node_create(app_path, sender, uuid, create_node_ready_cb,
 								pending_msg);
 
 	return NULL;
 }
 
+static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
+						struct l_dbus_message *msg,
+						void *user_data)
+{
+	const char *app_path, *sender;
+	struct l_dbus_message *pending_msg;
+	struct l_dbus_message_iter iter_uuid;
+	const char *json_data;
+	uint8_t *uuid;
+	uint32_t n;
+	struct json_object *jnode;
+
+	l_debug("Import local node request");
+
+	if (!l_dbus_message_get_arguments(msg, "osay", &app_path,
+							&json_data, &iter_uuid))
+		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+	if (!l_dbus_message_iter_get_fixed_array(&iter_uuid, &uuid, &n) ||
+									n != 16)
+		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad dev UUID");
+
+	if (node_find_by_uuid(uuid))
+		return dbus_error(msg, MESH_ERROR_ALREADY_EXISTS,
+							"Node already exists");
+
+	jnode = json_tokener_parse(json_data);
+
+	sender = l_dbus_message_get_sender(msg);
+	pending_msg = l_dbus_message_ref(msg);
+
+	if (!pending_queue)
+		pending_queue = l_queue_new();
+
+	l_queue_push_tail(pending_queue, pending_msg);
+
+	if (!node_import(app_path, sender, jnode, uuid, create_node_ready_cb,
+								pending_msg)) {
+		l_dbus_message_unref(msg);
+		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+							"Node import failed");
+	}
+
+	return NULL;
+}
+
 static void setup_network_interface(struct l_dbus_interface *iface)
 {
 	l_dbus_interface_method(iface, "Join", 0, join_network_call, "",
@@ -612,8 +659,14 @@ static void setup_network_interface(struct l_dbus_interface *iface)
 
 	l_dbus_interface_method(iface, "Leave", 0, leave_call, "", "t",
 								"token");
+
 	l_dbus_interface_method(iface, "CreateNetwork", 0, create_network_call,
 					"t", "oay", "token", "app", "uuid");
+
+	l_dbus_interface_method(iface, "ImportLocalNode", 0,
+					import_local_node_call,
+					"t", "osay", "token",
+					"app", "json_data", "uuid");
 }
 
 bool mesh_dbus_init(struct l_dbus *dbus)
diff --git a/mesh/node.c b/mesh/node.c
index e99858623..991802a6f 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -27,6 +27,7 @@
 
 #include <ell/ell.h>
 #include <json-c/json.h>
+#include <stdio.h>
 
 #include "mesh/mesh-defs.h"
 #include "mesh/mesh.h"
@@ -58,9 +59,12 @@
 #define DEFAULT_CRPL 10
 #define DEFAULT_SEQUENCE_NUMBER 0
 
-#define REQUEST_TYPE_JOIN 0
-#define REQUEST_TYPE_ATTACH 1
-#define REQUEST_TYPE_CREATE 2
+enum request_type {
+	REQUEST_TYPE_JOIN = 0,
+	REQUEST_TYPE_ATTACH,
+	REQUEST_TYPE_CREATE,
+	REQUEST_TYPE_IMPORT,
+};
 
 struct node_element {
 	char *path;
@@ -111,7 +115,18 @@ struct managed_obj_request {
 	void *data;
 	void *cb;
 	void *user_data;
-	uint8_t type;
+	enum request_type type;
+};
+
+struct node_import_request {
+	uint8_t uuid[16];
+	uint8_t dev_key[16];
+	uint8_t net_key[16];
+	bool kr;
+	uint16_t unicast;
+	uint32_t iv_idx;
+	bool iv_update;
+	void *user_data;
 };
 
 static struct l_queue *nodes;
@@ -851,7 +866,7 @@ element_done:
 #define MIN_COMPOSITION_LEN 16
 
 bool node_parse_composition(struct mesh_node *node, uint8_t *data,
-								uint16_t len)
+			    uint16_t len)
 {
 	struct node_composition *comp;
 	uint16_t features;
@@ -946,7 +961,7 @@ bool node_parse_composition(struct mesh_node *node, uint8_t *data,
 			vendor_id = l_get_le16(data);
 			mod_id |= (vendor_id << 16);
 			mod = mesh_model_vendor_new(ele->idx, vendor_id,
-									mod_id);
+						    mod_id);
 			if (!mod) {
 				element_free(ele);
 				goto fail;
@@ -977,7 +992,6 @@ fail:
 
 	return false;
 }
-
 static void attach_io(void *a, void *b)
 {
 	struct mesh_node *node = a;
@@ -1078,6 +1092,7 @@ static bool validate_model_property(struct node_element *ele,
 		while (l_dbus_message_iter_next_entry(&ids, &vendor_id,
 								&mod_id)) {
 			struct mesh_model *mod;
+
 			mod = l_queue_find(ele->models, match_model_id,
 				L_UINT_TO_PTR((vendor_id << 16) | mod_id));
 			if (!mod)
@@ -1366,17 +1381,92 @@ static bool get_app_properties(struct mesh_node *node, const char *path,
 	return true;
 }
 
-static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr,
-				bool ivu, uint32_t iv_idx, uint8_t dev_key[16],
-				uint16_t net_key_idx, uint8_t net_key[16])
+static bool parse_imported_iv_index(json_object *jobj, uint32_t *idx,
+								bool *update)
 {
-	node->net = mesh_net_new(node);
+	int tmp;
+	json_object *jvalue;
 
-	if (!nodes)
-		nodes = l_queue_new();
+	if (!json_object_object_get_ex(jobj, "IVindex", &jvalue))
+		return false;
 
-	l_queue_push_tail(nodes, node);
+	tmp = json_object_get_int(jvalue);
+	*idx = (uint32_t) tmp;
+
+	if (!json_object_object_get_ex(jobj, "IVupdate", &jvalue))
+		return false;
+
+	tmp = json_object_get_int(jvalue);
+	*update = (bool)tmp;
+
+	return true;
+}
+
+static bool parse_imported_unicast_addr(json_object *jobj, uint16_t *unicast)
+{
+	json_object *jvalue;
+	char *str;
+
+	if (!json_object_object_get_ex(jobj, "unicastAddress", &jvalue))
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+
+	if (sscanf(str, "%04hx", unicast) != 1)
+		return false;
+
+	return true;
+}
 
+static bool parse_imported_device_key(json_object *jobj, uint8_t key_buf[16])
+{
+	json_object *jvalue;
+	char *str;
+
+	if (!key_buf)
+		return false;
+
+	if (!json_object_object_get_ex(jobj, "deviceKey", &jvalue))
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+
+	if (!str2hex(str, strlen(str), key_buf, 16))
+		return false;
+
+	return true;
+}
+
+static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
+								bool *kr)
+{
+	json_object *jvalue;
+	char *str;
+
+	if (!key_buf)
+		return false;
+
+	if (!json_object_object_get_ex(jobj, "netKey", &jvalue))
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+
+	if (!str2hex(str, strlen(str), key_buf, 16))
+		return false;
+
+	/* Get key refresh */
+	if (!json_object_object_get_ex(jobj, "keyRefresh", &jvalue))
+		return false;
+
+	*kr = (bool)json_object_get_boolean(jvalue);
+	return true;
+}
+
+
+static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr,
+				bool ivu, uint32_t iv_idx, uint8_t dev_key[16],
+				uint16_t net_key_idx, uint8_t net_key[16])
+{
 	if (!storage_set_iv_index(node->net, iv_idx, ivu))
 		return false;
 
@@ -1444,14 +1534,13 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 	}
 
 	if (is_new) {
-		node = l_new(struct mesh_node, 1);
+		node = node_new(req->data);
 		node->elements = l_queue_new();
 	} else {
 		node = req->data;
 	}
 
 	num_ele = 0;
-
 	while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
 		struct l_dbus_message_iter properties;
 		const char *interface;
@@ -1547,6 +1636,44 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 
 		cb(node, agent);
 
+	} else if (req->type == REQUEST_TYPE_IMPORT) {
+
+		node_ready_func_t cb = req->cb;
+		struct node_import_request *import_data = req->user_data;
+		struct keyring_net_key net_key;
+
+		if (!agent) {
+			l_error("Interface %s not found",
+						MESH_PROVISION_AGENT_INTERFACE);
+			goto fail;
+		}
+
+		node->num_ele = num_ele;
+		set_defaults(node);
+		memcpy(node->uuid, import_data->uuid, 16);
+
+		if (!create_node_config(node))
+			goto fail;
+
+		if (!add_local_node(node, import_data->unicast, import_data->kr,
+				import_data->iv_update, import_data->iv_idx,
+				import_data->dev_key, PRIMARY_NET_IDX,
+							import_data->net_key))
+			goto fail;
+
+		memcpy(net_key.old_key, import_data->net_key, 16);
+		net_key.net_idx = PRIMARY_NET_IDX;
+		net_key.phase = KEY_REFRESH_PHASE_NONE;
+
+		if (!keyring_put_remote_dev_key(node, import_data->unicast,
+						num_ele, import_data->dev_key))
+			goto fail;
+
+		if (!keyring_put_net_key(node, PRIMARY_NET_IDX, &net_key))
+			goto fail;
+
+		cb(import_data->user_data, MESH_ERROR_NONE, node);
+
 	} else {
 		/* Callback for create node request */
 		node_ready_func_t cb = req->cb;
@@ -1672,6 +1799,59 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
 					req, l_free);
 }
 
+
+bool node_import(const char *app_path, const char *sender, void *json_data,
+		const uint8_t *uuid, node_ready_func_t cb, void *user_data)
+{
+	struct managed_obj_request *req;
+	struct node_import_request *node;
+
+	l_debug("");
+	node = l_new(struct node_import_request, 1);
+	req = l_new(struct managed_obj_request, 1);
+
+	if (!parse_imported_device_key(json_data, node->dev_key)) {
+		l_error("Failed to parse imported device key");
+		goto fail;
+	}
+
+	if (!parse_imported_unicast_addr(json_data, &node->unicast)) {
+		l_error("Failed to parse imported unicast address");
+		goto fail;
+	}
+
+	if (!parse_imported_iv_index(json_data, &node->iv_idx,
+							&node->iv_update)) {
+		l_error("Failed to parse imported iv idx");
+		goto fail;
+	}
+
+
+	if (!parse_imported_net_key(json_data, node->net_key, &node->kr)) {
+		l_error("Failed to parse imported network key");
+		goto fail;
+	}
+
+	node->user_data = user_data;
+
+	memcpy(node->uuid, uuid, 16);
+	req->data = (void *) uuid;
+	req->user_data = node;
+	req->cb = cb;
+	req->type = REQUEST_TYPE_IMPORT;
+
+	l_dbus_method_call(dbus_get_bus(), sender, app_path,
+					L_DBUS_INTERFACE_OBJECT_MANAGER,
+					"GetManagedObjects", NULL,
+					get_managed_objects_cb,
+					req, l_free);
+	return true;
+fail:
+	json_object_put(json_data);
+	l_free(node);
+	return false;
+}
+
 void node_create(const char *app_path, const char *sender, const uint8_t *uuid,
 					node_ready_func_t cb, void *user_data)
 {
diff --git a/mesh/node.h b/mesh/node.h
index 142527b30..9559f9178 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -91,6 +91,8 @@ void node_build_attach_reply(struct mesh_node *node,
 						struct l_dbus_message *reply);
 void node_create(const char *app_path, const char *sender, const uint8_t *uuid,
 					node_ready_func_t cb, void *user_data);
+bool node_import(const char *app_path, const char *sender, void *jnode,
+		const uint8_t *uuid, node_ready_func_t cb, void *user_data);
 void node_id_set(struct mesh_node *node, uint16_t node_id);
 uint16_t node_id_get(struct mesh_node *node);
 bool node_dbus_init(struct l_dbus *bus);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-07-02  5:44 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-25 14:38 [PATCH v2] mesh: Added ImportLocalNode call with its API Jakub Witowski
2019-06-26 17:01 ` Gix, Brian
2019-06-26 17:53   ` Stotland, Inga
2019-06-26 18:37     ` Jakub Witowski
     [not found]     ` <CAMCw4t3pXTbtt05RD694jzF_MNT_J9dcFMtA7iuD4ujZT9FDbg@mail.gmail.com>
     [not found]       ` <1561660267.7802.29.camel@intel.com>
2019-06-27 19:51         ` Was: mesh: Added ImportLocalNode call with its API --> Multiple Methods? michal.lowas-rzechonek
2019-06-28 14:29           ` Gix, Brian
2019-07-01  9:20             ` michal.lowas-rzechonek
2019-07-01 15:57               ` Gix, Brian
2019-07-02  5:43                 ` Stotland, Inga

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).