linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v3 1/3] mesh: Add ImportLocalNode api documentation
@ 2019-07-05 15:22 Jakub Witowski
  2019-07-05 15:22 ` [PATCH BlueZ v3 2/3] mesh: Added ImportLocalNode call with its API Jakub Witowski
  2019-07-05 15:22 ` [PATCH BlueZ v3 3/3] mesh: Separate json type from the node.c file Jakub Witowski
  0 siblings, 2 replies; 4+ messages in thread
From: Jakub Witowski @ 2019-07-05 15:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Inga Stotland

This updates the mesh-api.txt with new ImportLocalNode() API.
---
 doc/mesh-api.txt | 104 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 93 insertions(+), 11 deletions(-)

diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
index 893a1a6c0..f2ba164a9 100644
--- a/doc/mesh-api.txt
+++ b/doc/mesh-api.txt
@@ -151,16 +151,36 @@ Methods:
 			org.bluez.mesh.Error.InvalidArguments
 			org.bluez.mesh.Error.AlreadyExists,
 
-	 uint64 token ImportLocalNode(string json_data)
+	uint64 token ImportLocalNode(object app_root, array{byte}[16] uuid,
+							string data_type, array{byte} import_data)
 
 		This method creates a local mesh node based on node
 		configuration that has been generated outside bluetooth-meshd.
 
-		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
-		included token will be ignored in favor of a locally generated
-		token value.
+		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 data_type parameter defines the import_data type. Supported
+		data_type parameters:
+			- “json”
+
+		The import_data parameter can be either:
+			- Simplified representation of node configuration with
+			  provisioning data only
+			- Full representation of node configuration with both
+			  provisioning and composition data
+
+		sequenceNumber parameter int the import_data is optional.
+
+		The format must conform to the schema defined in
+		"Mesh Node Configuration Examples" section. Any included token will
+		be ignored in favor of a locally generated token value. If
+		import_data contains composition data (determined by the presence of
+		Elements) it is validated against composition data provided by
+		the application. Otherwise, new node is created based on
+		composition data provided by the application using provisioning data
+		from import_data parameter.
 
 		The returned token must be preserved by the application in
 		order to authenticate itself to the mesh daemon and attach to
@@ -173,8 +193,8 @@ Methods:
 
 		PossibleErrors:
 			org.bluez.mesh.Error.InvalidArguments,
-			org.bluez.mesh.Error.AlreadyExists
-			org.bluez.mesh.Error.NotFound,
+			org.bluez.mesh.Error.AlreadyExists,
+			org.bluez.mesh.Error.NotSupported,
 			org.bluez.mesh.Error.Failed
 
 Mesh Node Hierarchy
@@ -1061,6 +1081,68 @@ Properties:
 		Uniform Resource Identifier points to out-of-band (OOB)
 		information (e.g., a public key)
 
-Mesh Node Configuration Schema
-==============================
-<TBD>
+Mesh Node Configuration Examples
+================================
+Example of Json format for ImportLocalNode():
+
+	Import simplified node operation:
+	{
+		"IVindex":0,
+		"IVupdate":0,
+		"unicastAddress":"0012",
+		"deviceKey":"7daa45cd1e9e11a4b86eeef7d01efa11",
+		"sequenceNumber":15
+		"netKeys":[
+		{
+			"index":"0000",
+			"key":"2ddfef86d67144c394428ea3078f86f9",
+			"keyRefresh":0
+		}],
+	}
+
+	Import full node operation:
+	{
+		"cid":"fee5",
+		"pid":"0042",
+		"vid":"0001",
+		"crpl":"2710",
+		"relay":{
+			"mode":"disabled",
+			"count":0,
+			"interval":0
+		},
+		"lowPower":"unsupported",
+		"friend":"unsupported",
+		"proxy":"unsupported",
+		"beacon":"disabled",
+		"defaultTTL":255,
+		"elements":[
+		{
+			"elementIndex":0,
+			"location":"002a",
+			"models":[
+			{
+				"modelId":"0008",
+				"bind":[
+				"0000"]
+			}]
+		}],
+		"IVindex":0,
+		"IVupdate":0,
+		"unicastAddress":"0010",
+		"token":"bba7c60afaa85fc1",
+		"deviceKey":"56325fd145f3d5eee1b82136dc3e1454",
+		"netKeys":[
+		{
+			"index":"0000",
+			"key":"2ddfef86d67144c394428ea3078f86f9",
+			"keyRefresh":0
+		}],
+		"appKeys":[
+		{
+			"index":"0000",
+			"boundNetKey":"0000",
+			"key":"43886b02ca4343beaae26dc4b6773ba4"
+		}],
+		"sequenceNumber":15
+	}
-- 
2.20.1


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

* [PATCH BlueZ v3 2/3] mesh: Added ImportLocalNode call with its API
  2019-07-05 15:22 [PATCH BlueZ v3 1/3] mesh: Add ImportLocalNode api documentation Jakub Witowski
@ 2019-07-05 15:22 ` Jakub Witowski
  2019-07-05 15:22 ` [PATCH BlueZ v3 3/3] mesh: Separate json type from the node.c file Jakub Witowski
  1 sibling, 0 replies; 4+ messages in thread
From: Jakub Witowski @ 2019-07-05 15:22 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
---
 mesh/mesh.c |  90 +++++++++++++++++--
 mesh/node.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++----
 mesh/node.h |   2 +
 3 files changed, 317 insertions(+), 22 deletions(-)

diff --git a/mesh/mesh.c b/mesh/mesh.c
index 26acfd4dc..b3def7817 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -22,6 +22,8 @@
 #endif
 
 #define _GNU_SOURCE
+#include <json-c/json.h>
+#include <string.h>
 #include <ell/ell.h>
 
 #include "mesh/mesh-io.h"
@@ -60,7 +62,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;
@@ -70,6 +72,10 @@ struct join_data{
 	uint8_t *uuid;
 };
 
+static const char * const supported_import_data_types[] = {
+	"json"
+};
+
 static struct bt_mesh mesh;
 
 /* We allow only one outstanding Join request */
@@ -365,8 +371,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;
@@ -383,6 +389,18 @@ fail:
 	free_pending_join_call(true);
 }
 
+static bool validate_data_type(const char *data_type)
+{
+	uint8_t len = sizeof(supported_import_data_types) /
+					sizeof(supported_import_data_types[0]);
+
+	for (uint8_t idx = 0; idx < len; idx++) {
+		if (strcmp(data_type, supported_import_data_types[idx]) == 0)
+			return true;
+	}
+	return false;
+}
+
 static struct l_dbus_message *join_network_call(struct l_dbus *dbus,
 						struct l_dbus_message *msg,
 						void *user_data)
@@ -536,7 +554,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 +611,67 @@ 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, iter_import_data;
+	const char *data_type, *import_data;
+	uint8_t *uuid;
+	uint32_t n;
+	struct json_object *jnode;
+
+	l_debug("Import local node request");
+
+	if (!l_dbus_message_get_arguments(msg, "oaysay", &app_path, &iter_uuid,
+						&data_type, &iter_import_data))
+		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+	if (!validate_data_type(data_type))
+		return dbus_error(msg, MESH_ERROR_NOT_IMPLEMENTED,
+						"Unsupported data type");
+
+	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");
+
+	if (!l_dbus_message_iter_get_fixed_array(&iter_import_data,
+							&import_data, &n))
+		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+							"Bad import_data");
+
+	jnode = json_tokener_parse(import_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 +685,15 @@ 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", "oaysay", "token",
+					"app", "uuid", "data_type",
+					"import_data");
 }
 
 bool mesh_dbus_init(struct l_dbus *dbus)
diff --git a/mesh/node.c b/mesh/node.c
index 1f781cfe9..00c3270fd 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"
@@ -57,9 +58,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;
@@ -110,7 +114,19 @@ 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];
+	uint16_t net_idx;
+	uint16_t unicast;
+	uint32_t iv_idx;
+	bool iv_update;
+	uint32_t sequence;
+	void *user_data;
 };
 
 static struct l_queue *nodes;
@@ -870,7 +886,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;
@@ -965,7 +981,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;
@@ -996,7 +1012,6 @@ fail:
 
 	return false;
 }
-
 static void attach_io(void *a, void *b)
 {
 	struct mesh_node *node = a;
@@ -1385,17 +1400,86 @@ 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_unicast_addr(json_object *jobj, uint16_t *unicast)
 {
-	node->net = mesh_net_new(node);
+	char *str;
 
-	if (!nodes)
-		nodes = l_queue_new();
+	str = (char *)json_object_get_string(jobj);
 
-	l_queue_push_tail(nodes, node);
+	if (sscanf(str, "%04hx", unicast) != 1)
+		return false;
+
+	return true;
+}
+
+static bool parse_imported_device_key(json_object *jobj, uint8_t key_buf[16])
+{
+	char *str;
+
+	if (!key_buf)
+		return false;
 
+	str = (char *)json_object_get_string(jobj);
+
+	if (!str2hex(str, strlen(str), key_buf, 16))
+		return false;
+
+	return true;
+}
+
+static void parse_imported_sequence_nr(json_object *jobj, uint32_t *seq)
+{
+	json_object *jvalue;
+
+	if (json_object_object_get_ex(jobj, "sequenceNumber", &jvalue))
+		*seq = (uint32_t) json_object_get_int(jvalue);
+	else
+		*seq = DEFAULT_SEQUENCE_NUMBER;
+}
+
+static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
+							uint16_t *net_idx)
+{
+	json_object *jtemp, *jvalue;
+	char *str;
+	uint8_t key[16];
+
+	if (json_object_get_type(jobj) != json_type_array)
+		return false;
+
+	jtemp = json_object_array_get_idx(jobj, 0);
+
+	if (!json_object_object_get_ex(jtemp, "index", &jvalue))
+		return false;
+
+	*net_idx = (uint16_t)json_object_get_int(jvalue);
+
+	if (*net_idx > 4095)
+		return false;
+
+	if (!json_object_object_get_ex(jtemp, "key", &jvalue))
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (!str2hex(str, strlen(str), key, 16))
+		return false;
+
+	memcpy(&key_buf[0], &key[0], 16);
+
+	/* Imported node shouldn't contain oldKey or keyRefresh */
+	if (json_object_object_get_ex(jtemp, "oldKey", NULL))
+		return false;
+
+	if (json_object_object_get_ex(jtemp, "keyRefresh", NULL))
+		return false;
+
+	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;
 
@@ -1463,14 +1547,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;
@@ -1566,6 +1649,48 @@ 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);
+
+		if (node->seq_number != import_data->sequence)
+			node->seq_number = import_data->sequence;
+
+		memcpy(node->uuid, import_data->uuid, 16);
+
+		if (!create_node_config(node))
+			goto fail;
+
+		if (!add_local_node(node, import_data->unicast, false,
+				import_data->iv_update, import_data->iv_idx,
+				import_data->dev_key, import_data->net_idx,
+							import_data->net_key))
+			goto fail;
+
+		memcpy(net_key.old_key, import_data->net_key, 16);
+		net_key.net_idx = import_data->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;
@@ -1614,7 +1739,7 @@ fail:
 
 		cb(req->user_data, MESH_ERROR_FAILED, node);
 	} else {
-		/* Handle failed Join and Create requests */
+		/* Handle failed Join, Create and Import requests */
 		if (node)
 			node_remove(node);
 
@@ -1622,6 +1747,14 @@ fail:
 			node_join_ready_func_t cb = req->cb;
 
 			cb(NULL, NULL);
+
+		} else if (req->type == REQUEST_TYPE_IMPORT) {
+			struct node_import_request *import_data =
+								req->user_data;
+			node_ready_func_t cb = req->cb;
+
+			cb(import_data->user_data, MESH_ERROR_FAILED, NULL);
+
 		} else {
 			node_ready_func_t cb = req->cb;
 
@@ -1686,6 +1819,86 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
 					req, l_free);
 }
 
+static bool node_import_full(const char *app_path, const char *sender,
+					void *json_data, const uint8_t *uuid,
+					node_ready_func_t cb, void *user_data)
+{
+	return false;
+}
+
+static bool node_import_simplified(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 = l_new(struct managed_obj_request, 1);
+	struct node_import_request *node = l_new(struct node_import_request, 1);
+
+	json_object_object_foreach(json_data, key, val) {
+
+		if (!strcmp(key, "deviceKey")) {
+			if (!parse_imported_device_key(val, node->dev_key)) {
+				l_error("Failed to parse imported device key");
+				goto fail;
+			}
+
+		} else if (!strcmp(key, "unicastAddress")) {
+			if (!parse_imported_unicast_addr(val, &node->unicast)) {
+				l_error("Failed to parse imported unicast");
+				goto fail;
+			}
+
+		} else if (!strcmp(key, "IVindex")) {
+			node->iv_idx = (uint32_t) json_object_get_int(val);
+
+		} else if (!strcmp(key, "IVupdate")) {
+			node->iv_update = (bool) json_object_get_int(val);
+
+		} else if (!strcmp(key, "netKeys")) {
+			if (!parse_imported_net_key(val,
+					node->net_key, &node->net_idx)) {
+				l_error("Failed to parse imported network key");
+				goto fail;
+			}
+
+		} else {
+			if (strcmp(key, "sequenceNumber"))
+				goto fail;
+		}
+	}
+
+	parse_imported_sequence_nr(json_data, &node->sequence);
+	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;
+}
+
+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)
+{
+	if (!json_object_object_get_ex(json_data, "elements", NULL))
+		return node_import_simplified(app_path, sender, json_data,
+							uuid, cb, user_data);
+	else
+		return node_import_full(app_path, sender, json_data, uuid,
+								cb, user_data);
+}
+
 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] 4+ messages in thread

* [PATCH BlueZ v3 3/3] mesh: Separate json type from the node.c file
  2019-07-05 15:22 [PATCH BlueZ v3 1/3] mesh: Add ImportLocalNode api documentation Jakub Witowski
  2019-07-05 15:22 ` [PATCH BlueZ v3 2/3] mesh: Added ImportLocalNode call with its API Jakub Witowski
@ 2019-07-05 15:22 ` Jakub Witowski
  2019-07-05 15:41   ` Michał Lowas-Rzechonek
  1 sibling, 1 reply; 4+ messages in thread
From: Jakub Witowski @ 2019-07-05 15:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Inga Stotland

This creates intermediate layer between imported node data and parser.
---
 mesh/mesh-db.c | 147 ++++++++++++++++++++++++++++++++++++-
 mesh/mesh-db.h |  11 +++
 mesh/mesh.c    |  31 +++++---
 mesh/node.c    | 193 ++++++++++---------------------------------------
 mesh/node.h    |   3 +-
 5 files changed, 215 insertions(+), 170 deletions(-)

diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
index e0a000261..0e8f40470 100644
--- a/mesh/mesh-db.c
+++ b/mesh/mesh-db.c
@@ -31,7 +31,7 @@
 
 #include "mesh/mesh-defs.h"
 #include "mesh/util.h"
-
+#include "mesh/node.h"
 #include "mesh/mesh-db.h"
 
 #define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
@@ -253,6 +253,118 @@ static json_object *jarray_key_del(json_object *jarray, int16_t idx)
 	return jarray_new;
 }
 
+static bool parse_imported_unicast_addr(json_object *jobj, uint16_t *unicast)
+{
+	char *str = (char *)json_object_get_string(jobj);
+
+	if (sscanf(str, "%04hx", unicast) != 1)
+		return false;
+
+	return true;
+}
+
+static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
+							uint16_t *net_idx)
+{
+	json_object *jtemp, *jvalue;
+	char *str;
+	uint8_t key[16];
+
+	if (json_object_get_type(jobj) != json_type_array)
+		return false;
+
+	jtemp = json_object_array_get_idx(jobj, 0);
+
+	if (!json_object_object_get_ex(jtemp, "index", &jvalue))
+		return false;
+
+	*net_idx = (uint16_t)json_object_get_int(jvalue);
+
+	if (*net_idx > 4095)
+		return false;
+
+	if (!json_object_object_get_ex(jtemp, "key", &jvalue))
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (!str2hex(str, strlen(str), key, 16))
+		return false;
+
+	memcpy(&key_buf[0], &key[0], 16);
+
+	/* Imported node shouldn't contain oldKey or keyRefresh */
+	if (json_object_object_get_ex(jtemp, "oldKey", NULL))
+		return false;
+
+	if (json_object_object_get_ex(jtemp, "keyRefresh", NULL))
+		return false;
+
+	return true;
+}
+
+static uint32_t parse_imported_sequence(json_object *jobj,
+							uint32_t default_seq_nr)
+{
+	json_object *jvalue;
+
+	if (json_object_object_get_ex(jobj, "sequenceNumber", &jvalue))
+		return (uint32_t) json_object_get_int(jvalue);
+	else
+		return default_seq_nr;
+}
+
+static bool json_iter(json_object *jobj, struct mesh_db_import *db_node)
+{
+	bool dev_key = false, unicast = false;
+	bool iv_index = false, net_key = false;
+
+	json_object_object_foreach(jobj, key, val) {
+
+		if (!strcmp(key, "deviceKey")) {
+
+			dev_key = true;
+			if (!mesh_db_read_device_key(jobj, db_node->dev_key)) {
+				l_error("Failed to parse imported device key");
+				return false;
+			}
+
+		} else if (!strcmp(key, "unicastAddress")) {
+
+			unicast = true;
+			if (!parse_imported_unicast_addr(val,
+						&db_node->node->unicast)) {
+				l_error("Failed to parse imported unicast");
+				return false;
+			}
+
+		} else if (!strcmp(key, "IVindex")) {
+
+			iv_index = true;
+			if (!mesh_db_read_iv_index(jobj, &db_node->iv_index,
+							&db_node->iv_update)) {
+				l_error("Failed to parse iv_index");
+				return false;
+			}
+
+		} else if (!strcmp(key, "netKeys")) {
+
+			net_key = true;
+			if (!parse_imported_net_key(val, db_node->net_key,
+							&db_node->net_idx)) {
+				l_error("Failed to parse imported network key");
+				return false;
+			}
+
+		} else {
+			if (strcmp(key, "sequenceNumber") &&
+							strcmp(key, "IVupdate"))
+				return false;
+		}
+	}
+
+	return dev_key && unicast && net_key && iv_index;
+}
+
 bool mesh_db_read_iv_index(json_object *jobj, uint32_t *idx, bool *update)
 {
 	int tmp;
@@ -1438,7 +1550,8 @@ static void add_model(void *a, void *b)
 }
 
 /* Add unprovisioned node (local) */
-bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {
+bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node)
+{
 
 	struct mesh_db_modes *modes = &node->modes;
 	const struct l_queue_entry *entry;
@@ -1783,3 +1896,33 @@ bool mesh_db_model_sub_del_all(json_object *jnode, uint16_t addr,
 
 	return delete_model_property(jnode, addr, mod_id, vendor, "subscribe");
 }
+
+
+
+struct mesh_db_import *mesh_db_parse_import_data(const char *import_data)
+{
+	json_object *jobj = json_tokener_parse(import_data);
+	struct mesh_db_import *db_node = l_new(struct mesh_db_import, 1);
+
+	if (!jobj)
+		goto fail;
+
+	db_node->node = l_new(struct mesh_db_node, 1);
+
+	if (!json_iter(jobj, db_node))
+		goto fail;
+
+	db_node->node->seq_number =
+			parse_imported_sequence(jobj, DEFAULT_SEQUENCE_NUMBER);
+
+	return db_node;
+fail:
+	if (jobj)
+		json_object_put(jobj);
+
+	if (db_node->node)
+		l_free(db_node->node);
+
+	l_free(db_node);
+	return NULL;
+}
diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
index da5efa12a..a227319ca 100644
--- a/mesh/mesh-db.h
+++ b/mesh/mesh-db.h
@@ -16,6 +16,7 @@
  *  Lesser General Public License for more details.
  *
  */
+#include <json-c/json.h>
 
 struct mesh_db_sub {
 	bool virt;
@@ -93,6 +94,15 @@ struct mesh_db_prov {
 	uint8_t priv_key[32];
 };
 
+struct mesh_db_import {
+	struct mesh_db_node *node;
+	uint8_t dev_key[16];
+	uint8_t net_key[16];
+	uint16_t net_idx;
+	uint32_t iv_index;
+	bool iv_update;
+};
+
 typedef bool (*mesh_db_net_key_cb)(uint16_t idx, uint8_t key[16],
 			uint8_t new_key[16], int phase, void *user_data);
 typedef bool (*mesh_db_app_key_cb)(uint16_t idx, uint16_t net_idx,
@@ -155,3 +165,4 @@ bool mesh_db_net_key_set_phase(json_object *jobj, uint16_t idx, uint8_t phase);
 bool mesh_db_write_address(json_object *jobj, uint16_t address);
 bool mesh_db_write_iv_index(json_object *jobj, uint32_t idx, bool update);
 void mesh_db_remove_property(json_object *jobj, const char *desc);
+struct mesh_db_import *mesh_db_parse_import_data(const char *import_data);
diff --git a/mesh/mesh.c b/mesh/mesh.c
index b3def7817..6234121c9 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -22,7 +22,6 @@
 #endif
 
 #define _GNU_SOURCE
-#include <json-c/json.h>
 #include <string.h>
 #include <ell/ell.h>
 
@@ -36,6 +35,7 @@
 #include "mesh/error.h"
 #include "mesh/agent.h"
 #include "mesh/mesh.h"
+#include "mesh/mesh-db.h"
 
 /*
  * The default values for mesh configuration. Can be
@@ -391,10 +391,10 @@ fail:
 
 static bool validate_data_type(const char *data_type)
 {
-	uint8_t len = sizeof(supported_import_data_types) /
-					sizeof(supported_import_data_types[0]);
+	uint8_t idx = 0;
+	uint8_t len = L_ARRAY_SIZE(supported_import_data_types);
 
-	for (uint8_t idx = 0; idx < len; idx++) {
+	for (idx = 0; idx < len; idx++) {
 		if (strcmp(data_type, supported_import_data_types[idx]) == 0)
 			return true;
 	}
@@ -624,10 +624,10 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
 	const char *app_path, *sender;
 	struct l_dbus_message *pending_msg;
 	struct l_dbus_message_iter iter_uuid, iter_import_data;
+	struct mesh_db_import *p_node;
 	const char *data_type, *import_data;
 	uint8_t *uuid;
 	uint32_t n;
-	struct json_object *jnode;
 
 	l_debug("Import local node request");
 
@@ -652,7 +652,11 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 							"Bad import_data");
 
-	jnode = json_tokener_parse(import_data);
+	p_node = mesh_db_parse_import_data(import_data);
+
+	if (!p_node)
+		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+						"Failed to parse import_data");
 
 	sender = l_dbus_message_get_sender(msg);
 	pending_msg = l_dbus_message_ref(msg);
@@ -662,14 +666,17 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
 
 	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");
-	}
+	if (!node_import(app_path, sender, p_node, uuid, create_node_ready_cb,
+								pending_msg))
+		goto fail;
 
 	return NULL;
+
+fail:
+	l_free(p_node);
+	l_dbus_message_unref(msg);
+	l_queue_remove(pending_queue, pending_msg);
+	return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Node import failed");
 }
 
 static void setup_network_interface(struct l_dbus_interface *iface)
diff --git a/mesh/node.c b/mesh/node.c
index 00c3270fd..db04c0c87 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -26,8 +26,6 @@
 #include <sys/time.h>
 
 #include <ell/ell.h>
-#include <json-c/json.h>
-#include <stdio.h>
 
 #include "mesh/mesh-defs.h"
 #include "mesh/mesh.h"
@@ -56,7 +54,6 @@
 #define DEFAULT_LOCATION 0x0000
 
 #define DEFAULT_CRPL 10
-#define DEFAULT_SEQUENCE_NUMBER 0
 
 enum request_type {
 	REQUEST_TYPE_JOIN = 0,
@@ -119,13 +116,7 @@ struct managed_obj_request {
 
 struct node_import_request {
 	uint8_t uuid[16];
-	uint8_t dev_key[16];
-	uint8_t net_key[16];
-	uint16_t net_idx;
-	uint16_t unicast;
-	uint32_t iv_idx;
-	bool iv_update;
-	uint32_t sequence;
+	struct mesh_db_import *import;
 	void *user_data;
 };
 
@@ -885,8 +876,7 @@ element_done:
 
 #define MIN_COMPOSITION_LEN 16
 
-bool node_parse_composition(struct mesh_node *node, uint8_t *data,
-			    uint16_t len)
+bool node_parse_composition(struct mesh_node *node, uint8_t *data, uint16_t len)
 {
 	struct node_composition *comp;
 	uint16_t features;
@@ -981,7 +971,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;
@@ -1012,6 +1002,7 @@ fail:
 
 	return false;
 }
+
 static void attach_io(void *a, void *b)
 {
 	struct mesh_node *node = a;
@@ -1400,82 +1391,6 @@ static bool get_app_properties(struct mesh_node *node, const char *path,
 	return true;
 }
 
-static bool parse_imported_unicast_addr(json_object *jobj, uint16_t *unicast)
-{
-	char *str;
-
-	str = (char *)json_object_get_string(jobj);
-
-	if (sscanf(str, "%04hx", unicast) != 1)
-		return false;
-
-	return true;
-}
-
-static bool parse_imported_device_key(json_object *jobj, uint8_t key_buf[16])
-{
-	char *str;
-
-	if (!key_buf)
-		return false;
-
-	str = (char *)json_object_get_string(jobj);
-
-	if (!str2hex(str, strlen(str), key_buf, 16))
-		return false;
-
-	return true;
-}
-
-static void parse_imported_sequence_nr(json_object *jobj, uint32_t *seq)
-{
-	json_object *jvalue;
-
-	if (json_object_object_get_ex(jobj, "sequenceNumber", &jvalue))
-		*seq = (uint32_t) json_object_get_int(jvalue);
-	else
-		*seq = DEFAULT_SEQUENCE_NUMBER;
-}
-
-static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
-							uint16_t *net_idx)
-{
-	json_object *jtemp, *jvalue;
-	char *str;
-	uint8_t key[16];
-
-	if (json_object_get_type(jobj) != json_type_array)
-		return false;
-
-	jtemp = json_object_array_get_idx(jobj, 0);
-
-	if (!json_object_object_get_ex(jtemp, "index", &jvalue))
-		return false;
-
-	*net_idx = (uint16_t)json_object_get_int(jvalue);
-
-	if (*net_idx > 4095)
-		return false;
-
-	if (!json_object_object_get_ex(jtemp, "key", &jvalue))
-		return false;
-
-	str = (char *)json_object_get_string(jvalue);
-	if (!str2hex(str, strlen(str), key, 16))
-		return false;
-
-	memcpy(&key_buf[0], &key[0], 16);
-
-	/* Imported node shouldn't contain oldKey or keyRefresh */
-	if (json_object_object_get_ex(jtemp, "oldKey", NULL))
-		return false;
-
-	if (json_object_object_get_ex(jtemp, "keyRefresh", NULL))
-		return false;
-
-	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])
@@ -1652,7 +1567,8 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 	} else if (req->type == REQUEST_TYPE_IMPORT) {
 
 		node_ready_func_t cb = req->cb;
-		struct node_import_request *import_data = req->user_data;
+		struct node_import_request *import_req = req->user_data;
+		struct mesh_db_import *db_node = import_req->import;
 		struct keyring_net_key net_key;
 
 		if (!agent) {
@@ -1664,32 +1580,32 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 		node->num_ele = num_ele;
 		set_defaults(node);
 
-		if (node->seq_number != import_data->sequence)
-			node->seq_number = import_data->sequence;
+		if (node->seq_number != db_node->node->seq_number)
+			node->seq_number = db_node->node->seq_number;
 
-		memcpy(node->uuid, import_data->uuid, 16);
+		memcpy(node->uuid, import_req->uuid, 16);
 
 		if (!create_node_config(node))
 			goto fail;
 
-		if (!add_local_node(node, import_data->unicast, false,
-				import_data->iv_update, import_data->iv_idx,
-				import_data->dev_key, import_data->net_idx,
-							import_data->net_key))
+		if (!add_local_node(node, db_node->node->unicast, false,
+					db_node->iv_update, db_node->iv_index,
+					db_node->dev_key, db_node->net_idx,
+					db_node->net_key))
 			goto fail;
 
-		memcpy(net_key.old_key, import_data->net_key, 16);
-		net_key.net_idx = import_data->net_idx;
+		memcpy(net_key.old_key, db_node->net_key, 16);
+		net_key.net_idx = db_node->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))
+		if (!keyring_put_remote_dev_key(node, db_node->node->unicast,
+						num_ele, db_node->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);
+		cb(import_req->user_data, MESH_ERROR_NONE, node);
 
 	} else {
 		/* Callback for create node request */
@@ -1749,11 +1665,10 @@ fail:
 			cb(NULL, NULL);
 
 		} else if (req->type == REQUEST_TYPE_IMPORT) {
-			struct node_import_request *import_data =
-								req->user_data;
+			struct node_import_request *import_req = req->user_data;
 			node_ready_func_t cb = req->cb;
 
-			cb(import_data->user_data, MESH_ERROR_FAILED, NULL);
+			cb(import_req->user_data, MESH_ERROR_FAILED, NULL);
 
 		} else {
 			node_ready_func_t cb = req->cb;
@@ -1820,58 +1735,29 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
 }
 
 static bool node_import_full(const char *app_path, const char *sender,
-					void *json_data, const uint8_t *uuid,
+					struct mesh_db_import *db_node,
+					const uint8_t *uuid,
 					node_ready_func_t cb, void *user_data)
 {
 	return false;
 }
 
 static bool node_import_simplified(const char *app_path, const char *sender,
-					void *json_data, const uint8_t *uuid,
+					struct mesh_db_import *db_node,
+					const uint8_t *uuid,
 					node_ready_func_t cb, void *user_data)
 {
 	struct managed_obj_request *req = l_new(struct managed_obj_request, 1);
-	struct node_import_request *node = l_new(struct node_import_request, 1);
-
-	json_object_object_foreach(json_data, key, val) {
-
-		if (!strcmp(key, "deviceKey")) {
-			if (!parse_imported_device_key(val, node->dev_key)) {
-				l_error("Failed to parse imported device key");
-				goto fail;
-			}
-
-		} else if (!strcmp(key, "unicastAddress")) {
-			if (!parse_imported_unicast_addr(val, &node->unicast)) {
-				l_error("Failed to parse imported unicast");
-				goto fail;
-			}
+	struct node_import_request *import_req =
+					l_new(struct node_import_request, 1);
 
-		} else if (!strcmp(key, "IVindex")) {
-			node->iv_idx = (uint32_t) json_object_get_int(val);
-
-		} else if (!strcmp(key, "IVupdate")) {
-			node->iv_update = (bool) json_object_get_int(val);
-
-		} else if (!strcmp(key, "netKeys")) {
-			if (!parse_imported_net_key(val,
-					node->net_key, &node->net_idx)) {
-				l_error("Failed to parse imported network key");
-				goto fail;
-			}
-
-		} else {
-			if (strcmp(key, "sequenceNumber"))
-				goto fail;
-		}
-	}
-
-	parse_imported_sequence_nr(json_data, &node->sequence);
-	node->user_data = user_data;
+	l_debug("");
+	import_req->user_data = user_data;
+	import_req->import = db_node;
+	memcpy(import_req->uuid, uuid, 16);
 
-	memcpy(node->uuid, uuid, 16);
 	req->data = (void *) uuid;
-	req->user_data = node;
+	req->user_data = import_req;
 	req->cb = cb;
 	req->type = REQUEST_TYPE_IMPORT;
 
@@ -1881,21 +1767,18 @@ static bool node_import_simplified(const char *app_path, const char *sender,
 						get_managed_objects_cb,
 						req, l_free);
 	return true;
-
-fail:
-	json_object_put(json_data);
-	l_free(node);
-	return false;
 }
 
-bool node_import(const char *app_path, const char *sender, void *json_data,
+bool node_import(const char *app_path, const char *sender, void *import,
 		const uint8_t *uuid, node_ready_func_t cb, void *user_data)
 {
-	if (!json_object_object_get_ex(json_data, "elements", NULL))
-		return node_import_simplified(app_path, sender, json_data,
-							uuid, cb, user_data);
+	struct mesh_db_import *db_node = (struct mesh_db_import *)import;
+
+	if (!db_node->node->elements)
+		return node_import_simplified(app_path, sender, db_node, uuid,
+								cb, user_data);
 	else
-		return node_import_full(app_path, sender, json_data, uuid,
+		return node_import_full(app_path, sender, db_node, uuid,
 								cb, user_data);
 }
 
diff --git a/mesh/node.h b/mesh/node.h
index 9559f9178..7f1093df7 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -26,6 +26,7 @@ struct mesh_agent;
 #define MIN_SEQ_TRIGGER	32
 #define MIN_SEQ_CACHE		(2*MIN_SEQ_TRIGGER)
 #define MIN_SEQ_CACHE_TIME	(5*60)
+#define DEFAULT_SEQUENCE_NUMBER 0
 
 typedef void (*node_ready_func_t) (void *user_data, int status,
 							struct mesh_node *node);
@@ -91,7 +92,7 @@ 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,
+bool node_import(const char *app_path, const char *sender, void *import,
 		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);
-- 
2.20.1


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

* Re: [PATCH BlueZ v3 3/3] mesh: Separate json type from the node.c file
  2019-07-05 15:22 ` [PATCH BlueZ v3 3/3] mesh: Separate json type from the node.c file Jakub Witowski
@ 2019-07-05 15:41   ` Michał Lowas-Rzechonek
  0 siblings, 0 replies; 4+ messages in thread
From: Michał Lowas-Rzechonek @ 2019-07-05 15:41 UTC (permalink / raw)
  To: Jakub Witowski; +Cc: linux-bluetooth, Inga Stotland

On 07/05, Jakub Witowski wrote:
> This creates intermediate layer between imported node data and parser.

I don't think it's worth having a separate patch for this, please squash
it with 2/3.

> ---
>  mesh/mesh-db.c | 147 ++++++++++++++++++++++++++++++++++++-
>  mesh/mesh-db.h |  11 +++
>  mesh/mesh.c    |  31 +++++---
>  mesh/node.c    | 193 ++++++++++---------------------------------------
>  mesh/node.h    |   3 +-
>  5 files changed, 215 insertions(+), 170 deletions(-)
> 
> diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
> index e0a000261..0e8f40470 100644
> --- a/mesh/mesh-db.c
> +++ b/mesh/mesh-db.c
> @@ -31,7 +31,7 @@
>  
>  #include "mesh/mesh-defs.h"
>  #include "mesh/util.h"
> -
> +#include "mesh/node.h"
>  #include "mesh/mesh-db.h"
>  
>  #define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
> @@ -253,6 +253,118 @@ static json_object *jarray_key_del(json_object *jarray, int16_t idx)
>  	return jarray_new;
>  }
>  
> +static bool parse_imported_unicast_addr(json_object *jobj, uint16_t *unicast)
> +{
> +	char *str = (char *)json_object_get_string(jobj);
> +
> +	if (sscanf(str, "%04hx", unicast) != 1)
> +		return false;
> +
> +	return true;
> +}
> +
> +static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
> +							uint16_t *net_idx)
> +{
> +	json_object *jtemp, *jvalue;
> +	char *str;
> +	uint8_t key[16];
> +
> +	if (json_object_get_type(jobj) != json_type_array)
> +		return false;
> +
> +	jtemp = json_object_array_get_idx(jobj, 0);
> +
> +	if (!json_object_object_get_ex(jtemp, "index", &jvalue))
> +		return false;
> +
> +	*net_idx = (uint16_t)json_object_get_int(jvalue);
> +
> +	if (*net_idx > 4095)
> +		return false;
> +
> +	if (!json_object_object_get_ex(jtemp, "key", &jvalue))
> +		return false;
> +
> +	str = (char *)json_object_get_string(jvalue);
> +	if (!str2hex(str, strlen(str), key, 16))
> +		return false;
> +
> +	memcpy(&key_buf[0], &key[0], 16);
> +
> +	/* Imported node shouldn't contain oldKey or keyRefresh */
> +	if (json_object_object_get_ex(jtemp, "oldKey", NULL))
> +		return false;
> +
> +	if (json_object_object_get_ex(jtemp, "keyRefresh", NULL))
> +		return false;
> +
> +	return true;
> +}
> +
> +static uint32_t parse_imported_sequence(json_object *jobj,
> +							uint32_t default_seq_nr)
> +{
> +	json_object *jvalue;
> +
> +	if (json_object_object_get_ex(jobj, "sequenceNumber", &jvalue))
> +		return (uint32_t) json_object_get_int(jvalue);
> +	else
> +		return default_seq_nr;
> +}
> +
> +static bool json_iter(json_object *jobj, struct mesh_db_import *db_node)
> +{
> +	bool dev_key = false, unicast = false;
> +	bool iv_index = false, net_key = false;
> +
> +	json_object_object_foreach(jobj, key, val) {
> +
> +		if (!strcmp(key, "deviceKey")) {
> +
> +			dev_key = true;
> +			if (!mesh_db_read_device_key(jobj, db_node->dev_key)) {
> +				l_error("Failed to parse imported device key");
> +				return false;
> +			}
> +
> +		} else if (!strcmp(key, "unicastAddress")) {
> +
> +			unicast = true;
> +			if (!parse_imported_unicast_addr(val,
> +						&db_node->node->unicast)) {
> +				l_error("Failed to parse imported unicast");
> +				return false;
> +			}
> +
> +		} else if (!strcmp(key, "IVindex")) {
> +
> +			iv_index = true;
> +			if (!mesh_db_read_iv_index(jobj, &db_node->iv_index,
> +							&db_node->iv_update)) {
> +				l_error("Failed to parse iv_index");
> +				return false;
> +			}
> +
> +		} else if (!strcmp(key, "netKeys")) {
> +
> +			net_key = true;
> +			if (!parse_imported_net_key(val, db_node->net_key,
> +							&db_node->net_idx)) {
> +				l_error("Failed to parse imported network key");
> +				return false;
> +			}
> +
> +		} else {
> +			if (strcmp(key, "sequenceNumber") &&
> +							strcmp(key, "IVupdate"))
> +				return false;
> +		}
> +	}
> +
> +	return dev_key && unicast && net_key && iv_index;
> +}
> +
>  bool mesh_db_read_iv_index(json_object *jobj, uint32_t *idx, bool *update)
>  {
>  	int tmp;
> @@ -1438,7 +1550,8 @@ static void add_model(void *a, void *b)
>  }
>  
>  /* Add unprovisioned node (local) */
> -bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {
> +bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node)
> +{
>  
>  	struct mesh_db_modes *modes = &node->modes;
>  	const struct l_queue_entry *entry;
> @@ -1783,3 +1896,33 @@ bool mesh_db_model_sub_del_all(json_object *jnode, uint16_t addr,
>  
>  	return delete_model_property(jnode, addr, mod_id, vendor, "subscribe");
>  }
> +
> +
> +
> +struct mesh_db_import *mesh_db_parse_import_data(const char *import_data)
> +{
> +	json_object *jobj = json_tokener_parse(import_data);
> +	struct mesh_db_import *db_node = l_new(struct mesh_db_import, 1);
> +
> +	if (!jobj)
> +		goto fail;
> +
> +	db_node->node = l_new(struct mesh_db_node, 1);
> +
> +	if (!json_iter(jobj, db_node))
> +		goto fail;
> +
> +	db_node->node->seq_number =
> +			parse_imported_sequence(jobj, DEFAULT_SEQUENCE_NUMBER);
> +
> +	return db_node;
> +fail:
> +	if (jobj)
> +		json_object_put(jobj);
> +
> +	if (db_node->node)
> +		l_free(db_node->node);
> +
> +	l_free(db_node);
> +	return NULL;
> +}
> diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
> index da5efa12a..a227319ca 100644
> --- a/mesh/mesh-db.h
> +++ b/mesh/mesh-db.h
> @@ -16,6 +16,7 @@
>   *  Lesser General Public License for more details.
>   *
>   */
> +#include <json-c/json.h>
>  
>  struct mesh_db_sub {
>  	bool virt;
> @@ -93,6 +94,15 @@ struct mesh_db_prov {
>  	uint8_t priv_key[32];
>  };
>  
> +struct mesh_db_import {
> +	struct mesh_db_node *node;
> +	uint8_t dev_key[16];
> +	uint8_t net_key[16];
> +	uint16_t net_idx;
> +	uint32_t iv_index;
> +	bool iv_update;
> +};
> +
>  typedef bool (*mesh_db_net_key_cb)(uint16_t idx, uint8_t key[16],
>  			uint8_t new_key[16], int phase, void *user_data);
>  typedef bool (*mesh_db_app_key_cb)(uint16_t idx, uint16_t net_idx,
> @@ -155,3 +165,4 @@ bool mesh_db_net_key_set_phase(json_object *jobj, uint16_t idx, uint8_t phase);
>  bool mesh_db_write_address(json_object *jobj, uint16_t address);
>  bool mesh_db_write_iv_index(json_object *jobj, uint32_t idx, bool update);
>  void mesh_db_remove_property(json_object *jobj, const char *desc);
> +struct mesh_db_import *mesh_db_parse_import_data(const char *import_data);
> diff --git a/mesh/mesh.c b/mesh/mesh.c
> index b3def7817..6234121c9 100644
> --- a/mesh/mesh.c
> +++ b/mesh/mesh.c
> @@ -22,7 +22,6 @@
>  #endif
>  
>  #define _GNU_SOURCE
> -#include <json-c/json.h>
>  #include <string.h>
>  #include <ell/ell.h>
>  
> @@ -36,6 +35,7 @@
>  #include "mesh/error.h"
>  #include "mesh/agent.h"
>  #include "mesh/mesh.h"
> +#include "mesh/mesh-db.h"
>  
>  /*
>   * The default values for mesh configuration. Can be
> @@ -391,10 +391,10 @@ fail:
>  
>  static bool validate_data_type(const char *data_type)
>  {
> -	uint8_t len = sizeof(supported_import_data_types) /
> -					sizeof(supported_import_data_types[0]);
> +	uint8_t idx = 0;
> +	uint8_t len = L_ARRAY_SIZE(supported_import_data_types);
>  
> -	for (uint8_t idx = 0; idx < len; idx++) {
> +	for (idx = 0; idx < len; idx++) {
>  		if (strcmp(data_type, supported_import_data_types[idx]) == 0)
>  			return true;
>  	}
> @@ -624,10 +624,10 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
>  	const char *app_path, *sender;
>  	struct l_dbus_message *pending_msg;
>  	struct l_dbus_message_iter iter_uuid, iter_import_data;
> +	struct mesh_db_import *p_node;
>  	const char *data_type, *import_data;
>  	uint8_t *uuid;
>  	uint32_t n;
> -	struct json_object *jnode;
>  
>  	l_debug("Import local node request");
>  
> @@ -652,7 +652,11 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
>  		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
>  							"Bad import_data");
>  
> -	jnode = json_tokener_parse(import_data);
> +	p_node = mesh_db_parse_import_data(import_data);
> +
> +	if (!p_node)
> +		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
> +						"Failed to parse import_data");
>  
>  	sender = l_dbus_message_get_sender(msg);
>  	pending_msg = l_dbus_message_ref(msg);
> @@ -662,14 +666,17 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,
>  
>  	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");
> -	}
> +	if (!node_import(app_path, sender, p_node, uuid, create_node_ready_cb,
> +								pending_msg))
> +		goto fail;
>  
>  	return NULL;
> +
> +fail:
> +	l_free(p_node);
> +	l_dbus_message_unref(msg);
> +	l_queue_remove(pending_queue, pending_msg);
> +	return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Node import failed");
>  }
>  
>  static void setup_network_interface(struct l_dbus_interface *iface)
> diff --git a/mesh/node.c b/mesh/node.c
> index 00c3270fd..db04c0c87 100644
> --- a/mesh/node.c
> +++ b/mesh/node.c
> @@ -26,8 +26,6 @@
>  #include <sys/time.h>
>  
>  #include <ell/ell.h>
> -#include <json-c/json.h>
> -#include <stdio.h>
>  
>  #include "mesh/mesh-defs.h"
>  #include "mesh/mesh.h"
> @@ -56,7 +54,6 @@
>  #define DEFAULT_LOCATION 0x0000
>  
>  #define DEFAULT_CRPL 10
> -#define DEFAULT_SEQUENCE_NUMBER 0
>  
>  enum request_type {
>  	REQUEST_TYPE_JOIN = 0,
> @@ -119,13 +116,7 @@ struct managed_obj_request {
>  
>  struct node_import_request {
>  	uint8_t uuid[16];
> -	uint8_t dev_key[16];
> -	uint8_t net_key[16];
> -	uint16_t net_idx;
> -	uint16_t unicast;
> -	uint32_t iv_idx;
> -	bool iv_update;
> -	uint32_t sequence;
> +	struct mesh_db_import *import;
>  	void *user_data;
>  };
>  
> @@ -885,8 +876,7 @@ element_done:
>  
>  #define MIN_COMPOSITION_LEN 16
>  
> -bool node_parse_composition(struct mesh_node *node, uint8_t *data,
> -			    uint16_t len)
> +bool node_parse_composition(struct mesh_node *node, uint8_t *data, uint16_t len)
>  {
>  	struct node_composition *comp;
>  	uint16_t features;
> @@ -981,7 +971,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;
> @@ -1012,6 +1002,7 @@ fail:
>  
>  	return false;
>  }
> +
>  static void attach_io(void *a, void *b)
>  {
>  	struct mesh_node *node = a;
> @@ -1400,82 +1391,6 @@ static bool get_app_properties(struct mesh_node *node, const char *path,
>  	return true;
>  }
>  
> -static bool parse_imported_unicast_addr(json_object *jobj, uint16_t *unicast)
> -{
> -	char *str;
> -
> -	str = (char *)json_object_get_string(jobj);
> -
> -	if (sscanf(str, "%04hx", unicast) != 1)
> -		return false;
> -
> -	return true;
> -}
> -
> -static bool parse_imported_device_key(json_object *jobj, uint8_t key_buf[16])
> -{
> -	char *str;
> -
> -	if (!key_buf)
> -		return false;
> -
> -	str = (char *)json_object_get_string(jobj);
> -
> -	if (!str2hex(str, strlen(str), key_buf, 16))
> -		return false;
> -
> -	return true;
> -}
> -
> -static void parse_imported_sequence_nr(json_object *jobj, uint32_t *seq)
> -{
> -	json_object *jvalue;
> -
> -	if (json_object_object_get_ex(jobj, "sequenceNumber", &jvalue))
> -		*seq = (uint32_t) json_object_get_int(jvalue);
> -	else
> -		*seq = DEFAULT_SEQUENCE_NUMBER;
> -}
> -
> -static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
> -							uint16_t *net_idx)
> -{
> -	json_object *jtemp, *jvalue;
> -	char *str;
> -	uint8_t key[16];
> -
> -	if (json_object_get_type(jobj) != json_type_array)
> -		return false;
> -
> -	jtemp = json_object_array_get_idx(jobj, 0);
> -
> -	if (!json_object_object_get_ex(jtemp, "index", &jvalue))
> -		return false;
> -
> -	*net_idx = (uint16_t)json_object_get_int(jvalue);
> -
> -	if (*net_idx > 4095)
> -		return false;
> -
> -	if (!json_object_object_get_ex(jtemp, "key", &jvalue))
> -		return false;
> -
> -	str = (char *)json_object_get_string(jvalue);
> -	if (!str2hex(str, strlen(str), key, 16))
> -		return false;
> -
> -	memcpy(&key_buf[0], &key[0], 16);
> -
> -	/* Imported node shouldn't contain oldKey or keyRefresh */
> -	if (json_object_object_get_ex(jtemp, "oldKey", NULL))
> -		return false;
> -
> -	if (json_object_object_get_ex(jtemp, "keyRefresh", NULL))
> -		return false;
> -
> -	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])
> @@ -1652,7 +1567,8 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
>  	} else if (req->type == REQUEST_TYPE_IMPORT) {
>  
>  		node_ready_func_t cb = req->cb;
> -		struct node_import_request *import_data = req->user_data;
> +		struct node_import_request *import_req = req->user_data;
> +		struct mesh_db_import *db_node = import_req->import;
>  		struct keyring_net_key net_key;
>  
>  		if (!agent) {
> @@ -1664,32 +1580,32 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
>  		node->num_ele = num_ele;
>  		set_defaults(node);
>  
> -		if (node->seq_number != import_data->sequence)
> -			node->seq_number = import_data->sequence;
> +		if (node->seq_number != db_node->node->seq_number)
> +			node->seq_number = db_node->node->seq_number;
>  
> -		memcpy(node->uuid, import_data->uuid, 16);
> +		memcpy(node->uuid, import_req->uuid, 16);
>  
>  		if (!create_node_config(node))
>  			goto fail;
>  
> -		if (!add_local_node(node, import_data->unicast, false,
> -				import_data->iv_update, import_data->iv_idx,
> -				import_data->dev_key, import_data->net_idx,
> -							import_data->net_key))
> +		if (!add_local_node(node, db_node->node->unicast, false,
> +					db_node->iv_update, db_node->iv_index,
> +					db_node->dev_key, db_node->net_idx,
> +					db_node->net_key))
>  			goto fail;
>  
> -		memcpy(net_key.old_key, import_data->net_key, 16);
> -		net_key.net_idx = import_data->net_idx;
> +		memcpy(net_key.old_key, db_node->net_key, 16);
> +		net_key.net_idx = db_node->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))
> +		if (!keyring_put_remote_dev_key(node, db_node->node->unicast,
> +						num_ele, db_node->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);
> +		cb(import_req->user_data, MESH_ERROR_NONE, node);
>  
>  	} else {
>  		/* Callback for create node request */
> @@ -1749,11 +1665,10 @@ fail:
>  			cb(NULL, NULL);
>  
>  		} else if (req->type == REQUEST_TYPE_IMPORT) {
> -			struct node_import_request *import_data =
> -								req->user_data;
> +			struct node_import_request *import_req = req->user_data;
>  			node_ready_func_t cb = req->cb;
>  
> -			cb(import_data->user_data, MESH_ERROR_FAILED, NULL);
> +			cb(import_req->user_data, MESH_ERROR_FAILED, NULL);
>  
>  		} else {
>  			node_ready_func_t cb = req->cb;
> @@ -1820,58 +1735,29 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
>  }
>  
>  static bool node_import_full(const char *app_path, const char *sender,
> -					void *json_data, const uint8_t *uuid,
> +					struct mesh_db_import *db_node,
> +					const uint8_t *uuid,
>  					node_ready_func_t cb, void *user_data)
>  {
>  	return false;
>  }
>  
>  static bool node_import_simplified(const char *app_path, const char *sender,
> -					void *json_data, const uint8_t *uuid,
> +					struct mesh_db_import *db_node,
> +					const uint8_t *uuid,
>  					node_ready_func_t cb, void *user_data)
>  {
>  	struct managed_obj_request *req = l_new(struct managed_obj_request, 1);
> -	struct node_import_request *node = l_new(struct node_import_request, 1);
> -
> -	json_object_object_foreach(json_data, key, val) {
> -
> -		if (!strcmp(key, "deviceKey")) {
> -			if (!parse_imported_device_key(val, node->dev_key)) {
> -				l_error("Failed to parse imported device key");
> -				goto fail;
> -			}
> -
> -		} else if (!strcmp(key, "unicastAddress")) {
> -			if (!parse_imported_unicast_addr(val, &node->unicast)) {
> -				l_error("Failed to parse imported unicast");
> -				goto fail;
> -			}
> +	struct node_import_request *import_req =
> +					l_new(struct node_import_request, 1);
>  
> -		} else if (!strcmp(key, "IVindex")) {
> -			node->iv_idx = (uint32_t) json_object_get_int(val);
> -
> -		} else if (!strcmp(key, "IVupdate")) {
> -			node->iv_update = (bool) json_object_get_int(val);
> -
> -		} else if (!strcmp(key, "netKeys")) {
> -			if (!parse_imported_net_key(val,
> -					node->net_key, &node->net_idx)) {
> -				l_error("Failed to parse imported network key");
> -				goto fail;
> -			}
> -
> -		} else {
> -			if (strcmp(key, "sequenceNumber"))
> -				goto fail;
> -		}
> -	}
> -
> -	parse_imported_sequence_nr(json_data, &node->sequence);
> -	node->user_data = user_data;
> +	l_debug("");
> +	import_req->user_data = user_data;
> +	import_req->import = db_node;
> +	memcpy(import_req->uuid, uuid, 16);
>  
> -	memcpy(node->uuid, uuid, 16);
>  	req->data = (void *) uuid;
> -	req->user_data = node;
> +	req->user_data = import_req;
>  	req->cb = cb;
>  	req->type = REQUEST_TYPE_IMPORT;
>  
> @@ -1881,21 +1767,18 @@ static bool node_import_simplified(const char *app_path, const char *sender,
>  						get_managed_objects_cb,
>  						req, l_free);
>  	return true;
> -
> -fail:
> -	json_object_put(json_data);
> -	l_free(node);
> -	return false;
>  }
>  
> -bool node_import(const char *app_path, const char *sender, void *json_data,
> +bool node_import(const char *app_path, const char *sender, void *import,
>  		const uint8_t *uuid, node_ready_func_t cb, void *user_data)
>  {
> -	if (!json_object_object_get_ex(json_data, "elements", NULL))
> -		return node_import_simplified(app_path, sender, json_data,
> -							uuid, cb, user_data);
> +	struct mesh_db_import *db_node = (struct mesh_db_import *)import;
> +
> +	if (!db_node->node->elements)
> +		return node_import_simplified(app_path, sender, db_node, uuid,
> +								cb, user_data);
>  	else
> -		return node_import_full(app_path, sender, json_data, uuid,
> +		return node_import_full(app_path, sender, db_node, uuid,
>  								cb, user_data);
>  }
>  
> diff --git a/mesh/node.h b/mesh/node.h
> index 9559f9178..7f1093df7 100644
> --- a/mesh/node.h
> +++ b/mesh/node.h
> @@ -26,6 +26,7 @@ struct mesh_agent;
>  #define MIN_SEQ_TRIGGER	32
>  #define MIN_SEQ_CACHE		(2*MIN_SEQ_TRIGGER)
>  #define MIN_SEQ_CACHE_TIME	(5*60)
> +#define DEFAULT_SEQUENCE_NUMBER 0
>  
>  typedef void (*node_ready_func_t) (void *user_data, int status,
>  							struct mesh_node *node);
> @@ -91,7 +92,7 @@ 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,
> +bool node_import(const char *app_path, const char *sender, void *import,
>  		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);
> -- 
> 2.20.1
> 

-- 
Michał Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com>
Silvair http://silvair.com
Jasnogórska 44, 31-358 Krakow, POLAND

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

end of thread, other threads:[~2019-07-05 15:42 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-05 15:22 [PATCH BlueZ v3 1/3] mesh: Add ImportLocalNode api documentation Jakub Witowski
2019-07-05 15:22 ` [PATCH BlueZ v3 2/3] mesh: Added ImportLocalNode call with its API Jakub Witowski
2019-07-05 15:22 ` [PATCH BlueZ v3 3/3] mesh: Separate json type from the node.c file Jakub Witowski
2019-07-05 15:41   ` Michał Lowas-Rzechonek

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).