2019-07-17 08:37:37

by Michał Lowas-Rzechonek

[permalink] [raw]
Subject: [PATCH BlueZ v5 3/4] mesh: Implement ImportLocalNode() method

This implements ImportLocalNode() method of org.bluez.mesh.Network1
interface, allowing applications to create provisioned nodes based on
passed import data, without relying on external provisioner.
---
mesh/mesh-config-json.c | 85 ++++++++++++++++++++++++++++++++
mesh/mesh-config.h | 10 ++++
mesh/mesh-defs.h | 3 ++
mesh/mesh.c | 90 +++++++++++++++++++++++++++++++++-
mesh/net.h | 2 -
mesh/node.c | 106 ++++++++++++++++++++++++++++++++++------
mesh/node.h | 5 ++
7 files changed, 282 insertions(+), 19 deletions(-)

diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c
index 6df7f7b3f..e80df19a5 100644
--- a/mesh/mesh-config-json.c
+++ b/mesh/mesh-config-json.c
@@ -472,6 +472,25 @@ static bool read_net_key(struct mesh_config_netkey *net_key,
return true;
}

+static bool import_net_key(struct mesh_config_netkey *net_key,
+ void *user_data)
+{
+ struct mesh_config_import *import = user_data;
+
+ if (!net_key)
+ return false;
+
+ if (import->net_key.idx != UNUSED_KEY_IDX)
+ return false;
+
+ if (net_key->phase != KEY_REFRESH_PHASE_NONE)
+ return false;
+
+ memcpy(&import->net_key, net_key, sizeof(import->net_key));
+
+ return true;
+}
+
static bool read_net_keys(json_object *jobj, read_net_key_cb cb,
void *user_data)
{
@@ -2256,3 +2275,69 @@ void mesh_config_destroy(struct mesh_config *cfg)
/* Release node config object */
mesh_config_release(cfg);
}
+
+
+struct mesh_config_import *mesh_config_import_create(const char *import_data)
+{
+ json_object *jobj = json_tokener_parse(import_data);
+ struct mesh_config_import *import = NULL;
+
+ if (!jobj || json_object_get_type(jobj) != json_type_object)
+ goto fail;
+
+ import = l_new(struct mesh_config_import, 1);
+ import->node = l_new(struct mesh_config_node, 1);
+ import->net_key.idx = UNUSED_KEY_IDX;
+
+ if (!read_device_key(jobj, import->dev_key)) {
+ l_error("Failed to parse imported device key");
+ goto fail;
+ }
+
+ json_object_object_del(jobj, "deviceKey");
+
+ if (!read_unicast_address(jobj, &import->node->unicast)) {
+ l_error("Failed to parse imported unicast");
+ goto fail;
+ }
+
+ json_object_object_del(jobj, "unicastAddress");
+
+ if (!read_iv_index(jobj, &import->iv_index,
+ &import->iv_update)) {
+ l_error("Failed to parse iv_index");
+ goto fail;
+ }
+
+ json_object_object_del(jobj, "IVindex");
+ json_object_object_del(jobj, "IVupdate");
+
+ if (!read_net_keys(jobj, import_net_key, import)) {
+ l_error("Failed to parse imported network key");
+ goto fail;
+ }
+
+ json_object_object_del(jobj, "netKeys");
+
+ if (!read_seq_number(jobj, &import->node->seq_number))
+ import->node->seq_number = DEFAULT_SEQUENCE_NUMBER;
+
+ json_object_object_del(jobj, "sequenceNumber");
+
+ if (json_object_object_length(jobj) != 0) {
+ l_error("Unexpected keys in import data");
+ goto fail;
+ }
+
+ return import;
+fail:
+ if (jobj)
+ json_object_put(jobj);
+
+ if (import) {
+ l_free(import->node);
+ l_free(import);
+ }
+
+ return NULL;
+}
diff --git a/mesh/mesh-config.h b/mesh/mesh-config.h
index 44e3b3ad6..0061862b5 100644
--- a/mesh/mesh-config.h
+++ b/mesh/mesh-config.h
@@ -104,6 +104,15 @@ struct mesh_config_node {
uint8_t dev_key[16];
uint8_t token[8];
};
+
+struct mesh_config_import {
+ struct mesh_config_node *node;
+ struct mesh_config_netkey net_key;
+ uint8_t dev_key[16];
+ uint32_t iv_index;
+ bool iv_update;
+};
+
typedef void (*mesh_config_status_func_t)(void *user_data, bool result);
typedef bool (*mesh_config_node_func_t)(struct mesh_config_node *node,
const uint8_t uuid[16],
@@ -119,6 +128,7 @@ bool mesh_config_save(struct mesh_config *cfg, bool no_wait,
struct mesh_config *mesh_config_create(const char *cfg_path,
const uint8_t uuid[16],
struct mesh_config_node *node);
+struct mesh_config_import *mesh_config_import_create(const char *import_data);

bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt,
uint16_t interval);
diff --git a/mesh/mesh-defs.h b/mesh/mesh-defs.h
index 1a199f156..79b38c56c 100644
--- a/mesh/mesh-defs.h
+++ b/mesh/mesh-defs.h
@@ -37,6 +37,7 @@
#define KEY_REFRESH_PHASE_THREE 0x03

#define DEFAULT_TTL 0xff
+#define DEFAULT_SEQUENCE_NUMBER 0

/* Supported algorithms for provisioning */
#define ALG_FIPS_256_ECC 0x0001
@@ -76,6 +77,8 @@

#define PRIMARY_NET_IDX 0x0000
#define MAX_KEY_IDX 0x0fff
+#define UNUSED_KEY_IDX 0xffff
+
#define MAX_MODEL_COUNT 0xff
#define MAX_ELE_COUNT 0xff

diff --git a/mesh/mesh.c b/mesh/mesh.c
index 9c6b9a70e..ca268e4c9 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -33,6 +33,7 @@
#include "mesh/error.h"
#include "mesh/agent.h"
#include "mesh/mesh.h"
+#include "mesh/mesh-config.h"

/*
* The default values for mesh configuration. Can be
@@ -69,6 +70,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 */
@@ -383,6 +388,18 @@ fail:
free_pending_join_call(true);
}

+static bool validate_data_type(const char *data_type)
+{
+ uint8_t idx = 0;
+ uint8_t len = L_ARRAY_SIZE(supported_import_data_types);
+
+ for (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 +553,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 +610,74 @@ 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;
+ struct mesh_config_import *import;
+ const char *data_type, *import_data;
+ uint8_t *uuid;
+ uint32_t n;
+
+ 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");
+
+ import = mesh_config_import_create(import_data);
+
+ if (!import)
+ 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);
+
+ if (!pending_queue)
+ pending_queue = l_queue_new();
+
+ l_queue_push_tail(pending_queue, pending_msg);
+
+ if (!node_import(app_path, sender, import, uuid, create_node_ready_cb,
+ pending_msg))
+ goto fail;
+
+ return NULL;
+
+fail:
+ l_free(import);
+ 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)
{
l_dbus_interface_method(iface, "Join", 0, join_network_call, "",
@@ -612,8 +691,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/net.h b/mesh/net.h
index 8848e6df0..7e6af8714 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -26,8 +26,6 @@ struct mesh_node;

#define DEV_ID 0

-#define UNUSED_KEY_IDX 0xffff
-
#define APP_ID_DEV 0
#define APP_ID_ANY ((unsigned int) -1)
#define NET_ID_ANY (APP_ID_ANY - 1)
diff --git a/mesh/node.c b/mesh/node.c
index 652551756..d1b37a5da 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -56,11 +56,13 @@
#define DEFAULT_LOCATION 0x0000

#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;
@@ -112,8 +114,9 @@ struct mesh_node {
struct managed_obj_request {
void *data;
void *cb;
- void *user_data;
- uint8_t type;
+ struct l_dbus_message *pending_msg;
+ enum request_type type;
+ struct mesh_config_import *import;
};

static struct l_queue *nodes;
@@ -1568,14 +1571,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;
@@ -1652,7 +1654,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)

node->disc_watch = l_dbus_add_disconnect_watch(bus,
node->owner, app_disc_cb, node, NULL);
- cb(req->user_data, MESH_ERROR_NONE, node);
+ cb(req->pending_msg, MESH_ERROR_NONE, node);
} else
goto fail;

@@ -1674,6 +1676,51 @@ 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 mesh_config_import *import = req->import;
+ 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->node->seq_number)
+ node->seq_number = import->node->seq_number;
+
+ memcpy(node->uuid, req->data, 16);
+
+ if (!create_node_config(node, node->uuid))
+ goto fail;
+
+ if (!add_local_node(node, import->node->unicast, false,
+ import->iv_update, import->iv_index,
+ import->dev_key, import->net_key.idx,
+ import->net_key.key))
+ goto fail;
+
+ memcpy(net_key.old_key, import->net_key.key, 16);
+ net_key.net_idx = import->net_key.idx;
+ net_key.phase = KEY_REFRESH_PHASE_NONE;
+
+ /* Initialize directory for storing keyring info */
+ init_storage_dir(node);
+
+ if (!keyring_put_remote_dev_key(node, import->node->unicast,
+ num_ele, import->dev_key))
+ goto fail;
+
+ if (!keyring_put_net_key(node, import->net_key.idx, &net_key))
+ goto fail;
+
+ cb(req->pending_msg, MESH_ERROR_NONE, node);
+
} else {
/* Callback for create node request */
node_ready_func_t cb = req->cb;
@@ -1709,7 +1756,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
if (!keyring_put_net_key(node, PRIMARY_NET_IDX, &net_key))
goto fail;

- cb(req->user_data, MESH_ERROR_NONE, node);
+ cb(req->pending_msg, MESH_ERROR_NONE, node);
}

return;
@@ -1723,9 +1770,9 @@ fail:

free_node_dbus_resources(node);

- cb(req->user_data, MESH_ERROR_FAILED, node);
+ cb(req->pending_msg, MESH_ERROR_FAILED, node);
} else {
- /* Handle failed Join and Create requests */
+ /* Handle failed Join, Create and Import requests */
if (node)
node_remove(node);

@@ -1736,7 +1783,7 @@ fail:
} else {
node_ready_func_t cb = req->cb;

- cb(req->user_data, MESH_ERROR_FAILED, NULL);
+ cb(req->pending_msg, MESH_ERROR_FAILED, NULL);
}
}
}
@@ -1764,7 +1811,7 @@ int node_attach(const char *app_path, const char *sender, uint64_t token,
req = l_new(struct managed_obj_request, 1);
req->data = node;
req->cb = cb;
- req->user_data = user_data;
+ req->pending_msg = user_data;
req->type = REQUEST_TYPE_ATTACH;

l_dbus_method_call(dbus_get_bus(), sender, app_path,
@@ -1797,6 +1844,35 @@ 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,
+ struct mesh_config_import *import,
+ const uint8_t *uuid, node_ready_func_t cb,
+ void *user_data)
+{
+ struct managed_obj_request *req;
+
+ l_debug("");
+
+ /* TODO: implement full import */
+ if (import->node->elements)
+ return false;
+
+ req = l_new(struct managed_obj_request, 1);
+
+ req->data = (void *) uuid;
+ req->cb = cb;
+ req->pending_msg = user_data;
+ req->import = import;
+ 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;
+}
+
void node_create(const char *app_path, const char *sender, const uint8_t *uuid,
node_ready_func_t cb, void *user_data)
{
@@ -1807,7 +1883,7 @@ void node_create(const char *app_path, const char *sender, const uint8_t *uuid,
req = l_new(struct managed_obj_request, 1);
req->data = (void *) uuid;
req->cb = cb;
- req->user_data = user_data;
+ req->pending_msg = user_data;
req->type = REQUEST_TYPE_CREATE;

l_dbus_method_call(dbus_get_bus(), sender, app_path,
diff --git a/mesh/node.h b/mesh/node.h
index 56ca796cd..fad034f42 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -23,6 +23,7 @@ struct mesh_io;
struct mesh_agent;
struct mesh_config;
struct mesh_config_node;
+struct mesh_config_import;

/* To prevent local node JSON cache thrashing, minimum update times */
#define MIN_SEQ_TRIGGER 32
@@ -95,6 +96,10 @@ 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,
+ struct mesh_config_import *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);
bool node_dbus_init(struct l_dbus *bus);
--
2.19.1