2019-06-14 12:45:55

by Jakub Witowski

[permalink] [raw]
Subject: [RFC 0/3] Import local node

Hello,
I have implemented importing local node functionality.
Please comment what do You think about this solution.

I'm still working on it but for now I didn't noticed any side effects.

BR,
Jakub Witowski

Jakub Witowski (2):
mesh: Added functionality of import local node
mesh: Allow to import multiple network keys

Michał Lowas-Rzechonek (1):
mesh: Added ImportLocalNode call

doc/mesh-api.txt | 2 +-
mesh/keyring.h | 1 +
mesh/mesh.c | 55 ++++-
mesh/model.c | 5 +-
mesh/node.c | 543 +++++++++++++++++++++++++++++++++++++++++++----
mesh/node.h | 4 +-
6 files changed, 566 insertions(+), 44 deletions(-)

--
2.20.1


2019-06-14 12:45:54

by Jakub Witowski

[permalink] [raw]
Subject: [PATCH 1/3] mesh: Added ImportLocalNode call

From: Michał Lowas-Rzechonek <[email protected]>

This implements ImportLocalNode() method on org.bluez.mesh.Network1
interface. Invoking this method creates a self-provisioned node based on
passed JSON definition.
---
doc/mesh-api.txt | 2 +-
mesh/mesh.c | 49 ++++++++++++++++++++++++++++++++--
mesh/net.c | 2 +-
mesh/node.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
mesh/node.h | 4 ++-
5 files changed, 121 insertions(+), 5 deletions(-)

diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
index 2a800468b..aeb3167fc 100644
--- a/doc/mesh-api.txt
+++ b/doc/mesh-api.txt
@@ -151,7 +151,7 @@ Methods:
org.bluez.mesh.Error.InvalidArguments
org.bluez.mesh.Error.AlreadyExists,

- uint64 token ImportLocalNode(string json_data)
+ uint64 token ImportLocalNode(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.
diff --git a/mesh/mesh.c b/mesh/mesh.c
index 231a6bca4..bcbd9ada4 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 "lib/bluetooth.h"
@@ -701,7 +702,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;
@@ -758,7 +759,45 @@ 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(sender, app_path, 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 *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, "say",
+ &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 device UUID");
+
+ 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);
+
+ node_import(sender, jnode, uuid, create_node_ready_cb,
pending_msg);

return NULL;
@@ -777,8 +816,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", "say", "token",
+ "json_data", "uuid");
}

bool mesh_dbus_init(struct l_dbus *dbus)
diff --git a/mesh/net.c b/mesh/net.c
index a597b8794..1cb29e1e8 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -56,7 +56,7 @@
#define DEFAULT_MIN_DELAY 0
#define DEFAULT_MAX_DELAY 25

-#define DEFAULT_TRANSMIT_COUNT 1
+#define DEFAULT_TRANSMIT_COUNT 3
#define DEFAULT_TRANSMIT_INTERVAL 100

#define BEACON_INTERVAL_MIN 10
diff --git a/mesh/node.c b/mesh/node.c
index e99858623..b55e2b72a 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -1672,6 +1672,75 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
req, l_free);
}

+void node_import(const char *sender, void *json_data, const uint8_t *uuid,
+ node_ready_func_t cb, void *user_data)
+{
+ json_object *jnode = json_data;
+ struct mesh_node *node = NULL;
+ struct keyring_net_key net_key;
+ uint8_t dev_key[16];
+
+ node = l_new(struct mesh_node, 1);
+ node->elements = l_queue_new();
+
+ (void)jnode;
+ /*
+ * TODO:
+ * add elements from json
+ */
+ node->num_ele = l_queue_length(node->elements);
+ set_defaults(node);
+ memcpy(node->uuid, uuid, 16);
+
+ if (!create_node_config(node)) {
+ l_error("create config");
+ goto fail;
+ }
+
+ /*
+ * TODO:
+ * get primary (dev and net) keys from jnode
+ */
+ l_getrandom(dev_key, sizeof(dev_key));
+ l_getrandom(net_key.old_key, sizeof(net_key.old_key));
+
+ net_key.net_idx = PRIMARY_NET_IDX;
+ net_key.phase = KEY_REFRESH_PHASE_NONE;
+
+ if (!add_local_node(node, DEFAULT_NEW_UNICAST, false, false,
+ DEFAULT_IV_INDEX, dev_key,
+ PRIMARY_NET_IDX,
+ net_key.old_key)) {
+ l_error("add local node");
+ goto fail;
+ }
+
+ if (!keyring_put_remote_dev_key(node, node->primary,
+ node->num_ele, dev_key)) {
+ l_error("put remote key");
+ goto fail;
+ }
+
+ /*
+ * TODO:
+ * add remaining keys from json
+ */
+ if (!keyring_put_net_key(node, PRIMARY_NET_IDX, &net_key)) {
+ l_error("put net key");
+ goto fail;
+ }
+
+ cb(user_data, MESH_ERROR_NONE, node);
+ return;
+
+fail:
+ if (node)
+ free_node_resources(node);
+
+ cb(user_data, MESH_ERROR_FAILED, NULL);
+
+}
+
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..991adae3a 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -89,7 +89,9 @@ int node_attach(const char *app_path, const char *sender, uint64_t token,
node_ready_func_t cb, void *user_data);
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,
+void node_create(const char *sender, const char *app_path, const uint8_t *uuid,
+ node_ready_func_t cb, void *user_data);
+void node_import(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);
--
2.20.1

2019-06-14 12:45:55

by Jakub Witowski

[permalink] [raw]
Subject: [PATCH 3/3] mesh: Allow to import multiple network keys

This implements allows to import local node with
multiple network keys
---
mesh/keyring.h | 1 +
mesh/net.c | 2 +-
mesh/node.c | 264 ++++++++++++++++++++++++++-----------------------
3 files changed, 144 insertions(+), 123 deletions(-)

diff --git a/mesh/keyring.h b/mesh/keyring.h
index 167191013..8607f6497 100644
--- a/mesh/keyring.h
+++ b/mesh/keyring.h
@@ -22,6 +22,7 @@ struct keyring_net_key {
uint8_t phase;
uint8_t old_key[16];
uint8_t new_key[16];
+ bool key_refresh;
};

struct keyring_app_key {
diff --git a/mesh/net.c b/mesh/net.c
index 1cb29e1e8..a597b8794 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -56,7 +56,7 @@
#define DEFAULT_MIN_DELAY 0
#define DEFAULT_MAX_DELAY 25

-#define DEFAULT_TRANSMIT_COUNT 3
+#define DEFAULT_TRANSMIT_COUNT 1
#define DEFAULT_TRANSMIT_INTERVAL 100

#define BEACON_INTERVAL_MIN 10
diff --git a/mesh/node.c b/mesh/node.c
index fab5780cb..40def0fba 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -1457,77 +1457,92 @@ static bool parse_imported_device_key(json_object *jobj, uint8_t key_buf[16])
return true;
}

-static bool parse_imported_net_key(json_object *jobj, uint8_t key_buf[16],
- bool *kr, uint16_t *net_idx, uint8_t *ph)
+static struct l_queue *parse_imported_net_key(json_object *jobj)
{
json_object *jobject;
struct json_object_iterator iter, iend;
const char *jidx;
json_object *jtemp, *jvalue;
+ struct l_queue *keys;
+ struct keyring_net_key *net_keyring;

if (!json_object_object_get_ex(jobj, "netKeys", &jobject))
- return false;
+ return NULL;

if (json_object_get_type(jobject) != json_type_object)
- return false;
+ return NULL;
+
+ keys = l_queue_new();

iter = json_object_iter_begin(jobject);
iend = json_object_iter_end(jobject);

while (!json_object_iter_equal(&iter, &iend)) {
+
uint16_t idx;
char *str, *end;
- bool key_refresh = false;
- uint8_t phase;
- uint8_t key[16];
uint8_t new_key[16];
+ uint8_t old_key[16];
+
+ net_keyring = l_new(struct keyring_net_key, 1);

+ net_keyring->key_refresh = false;
jidx = json_object_iter_peek_name(&iter);
jtemp = json_object_iter_peek_value(&iter);

if (!*jidx)
- return false;
+ goto fail;

idx = (uint16_t)strtol(jidx, &end, 10);
if (*end || (idx > 4095))
- return false;
+ goto fail;

- *net_idx = idx;
+ net_keyring->net_idx = idx;
if (json_object_get_type(jtemp) != json_type_object)
- return false;
+ goto fail;

json_object_object_get_ex(jtemp, "oldKey", &jvalue);

if (jvalue) {
str = (char *)json_object_get_string(jvalue);
- if (!str2hex(str, strlen(str), key, 16))
- return false;
- key_refresh = true;
+ if (!str2hex(str, strlen(str), old_key, 16))
+ goto fail;
+
+ net_keyring->key_refresh = true;
}

if (!json_object_object_get_ex(jtemp, "key", &jvalue))
- return false;
+ goto fail;

str = (char *)json_object_get_string(jvalue);
- if (!str2hex(str, strlen(str), key_refresh ? new_key : key, 16))
- return false;

- memcpy(&key_buf[0], key_refresh ? new_key : key, 16);
+ if (!str2hex(str, strlen(str), net_keyring->key_refresh ?
+ new_key : old_key, 16))
+ goto fail;
+
+ memcpy(net_keyring->old_key, old_key, 16);
+
+ if (net_keyring->key_refresh)
+ memcpy(net_keyring->new_key, new_key, 16);

if (!json_object_object_get_ex(jtemp, "keyRefresh", &jvalue))
- return false;
+ goto fail;

if (!jvalue)
- phase = KEY_REFRESH_PHASE_NONE;
+ net_keyring->phase = KEY_REFRESH_PHASE_NONE;
else
- phase = (uint8_t)json_object_get_int(jvalue);
+ net_keyring->phase =
+ (uint8_t)json_object_get_int(jvalue);

- *ph = phase;
- *kr = key_refresh;
+ l_queue_push_tail(keys, net_keyring);
json_object_iter_next(&iter);
}

- return true;
+ return keys;
+fail:
+ l_queue_destroy(keys, l_free);
+ l_free(net_keyring);
+ return NULL;
}

static bool parse_imported_models(json_object *jmodels,
@@ -1548,7 +1563,7 @@ static bool parse_imported_models(json_object *jmodels,

mod = l_new(struct mesh_db_model, 1);
if (!mod)
- goto fail;
+ return false;

jidx = json_object_iter_peek_name(&iter);

@@ -1557,35 +1572,30 @@ static bool parse_imported_models(json_object *jmodels,

switch (strlen(jidx)) {

- case 4: {
+ case 4:
if (sscanf(jidx, "%04x", &id) != 1)
- goto fail;
+ return false;

id |= VENDOR_ID_MASK;
break;
- }

- case 8: {
+ case 8:
if (sscanf(jidx, "%08x", &id) != 1)
- goto fail;
+ return false;

mod->vendor = true;
break;
- }

default:
- goto fail;
+ return false;
}

mod->id = id;
l_queue_push_tail(ele->models, mod);
json_object_iter_next(&iter);
}
- return true;

-fail:
- l_queue_destroy(ele->models, l_free);
- return false;
+ return true;
}

static bool parse_imported_elements(json_object *jelements,
@@ -1638,54 +1648,54 @@ static bool parse_imported_elements(json_object *jelements,
ele = l_new(struct mesh_db_element, 1);

if (!ele)
- goto fail;
+ return false;

ele->index = idx;
ele->models = l_queue_new();

if (!ele->models)
- goto fail;
+ return false;

if (!json_object_object_get_ex(jtemp, "location", &jlocation))
- goto fail;
+ return false;

str = (char *)json_object_get_string(jlocation);

if (sscanf(str, "%04hx", &(ele->location)) != 1)
- goto fail;
+ return false;

if (json_object_object_get_ex(jtemp, "models", &jmodels)) {

if (json_object_get_type(jmodels) != json_type_object)
- goto fail;
+ return false;

if (!parse_imported_models(jmodels, ele))
- goto fail;
+ return false;
}

l_queue_push_tail(db_node->elements, ele);
json_object_iter_next(&iter);
}
+
return true;
+}

-fail:
- l_queue_destroy(db_node->elements, l_free);
- db_node->elements = NULL;
+static void put_net_keyrings(void *net_keys, void *_node)
+{
+ struct mesh_node *node = _node;
+ struct keyring_net_key *net_key = net_keys;

- if (ele->models) {
- l_queue_destroy(ele->models, l_free);
- ele->models = NULL;
- }
+ if (!node || !net_key)
+ return;

- return false;
+ if (!keyring_put_net_key(node, net_key->net_idx, net_key))
+ return;
}

static bool parse_imported_finalize(struct mesh_db_node *db_node,
struct mesh_node *node)
{
struct mesh_net *net;
- uint8_t mode, cnt;
- uint16_t interval;

if (!node_init_from_storage(node, db_node)) {
node_remove(node);
@@ -1693,42 +1703,48 @@ static bool parse_imported_finalize(struct mesh_db_node *db_node,
}

net = node_get_net(node);
- mesh_net_set_seq_num(net, node_get_sequence_number(node));
- mesh_net_set_default_ttl(net, node_default_ttl_get(node));
-
- mode = node_proxy_mode_get(node);
- if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
- mesh_net_set_proxy_mode(net, mode == MESH_MODE_ENABLED);
-
- mode = node_friend_mode_get(node);
- if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
- mesh_net_set_friend_mode(net, mode == MESH_MODE_ENABLED);
-
- mode = node_relay_mode_get(node, &cnt, &interval);
- if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
- mesh_net_set_relay_mode(net, mode == MESH_MODE_ENABLED, cnt,
- interval);
-
- mode = node_beacon_mode_get(node);
- if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
- mesh_net_set_beacon_mode(net, mode == MESH_MODE_ENABLED);

if (!IS_UNASSIGNED(db_node->unicast) &&
!mesh_net_register_unicast(net, db_node->unicast,
node_get_num_elements(node))) {
+
node_remove(node);
return false;
}

- if (node_uuid_get(node))
- mesh_net_id_uuid_set(net, node_uuid_get(node));
-
+ mesh_net_id_uuid_set(net, node_uuid_get(node));
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 void add_keys(void *net_keys, void *_node)
+{
+ struct mesh_node *node = _node;
+ struct keyring_net_key *net_key = net_keys;
+
+ if (!node || !net_key) {
+ l_info("Add network key error");
+ return;
+ }
+
+ if (mesh_net_add_key(node->net, net_key->net_idx, net_key->old_key) !=
+ MESH_STATUS_SUCCESS)
+ return;
+
+ if (net_key->key_refresh) {
+ /* Duplicate net key, if the key refresh is on */
+ if (mesh_net_update_key(node->net, net_key->net_idx,
+ net_key->old_key) != MESH_STATUS_SUCCESS)
+ return;
+
+ if (!mesh_db_net_key_set_phase(node->jconfig, net_key->net_idx,
+ KEY_REFRESH_PHASE_TWO))
+ return;
+ }
+}
+
+static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool ivu,
+ uint32_t iv_idx, uint8_t dev_key[16],
+ struct l_queue *net_keys)
{
if (!storage_set_iv_index(node->net, iv_idx, ivu))
return false;
@@ -1750,21 +1766,7 @@ static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr,
node->primary = unicast;
mesh_net_register_unicast(node->net, unicast, node->num_ele);

- if (mesh_net_add_key(node->net, net_key_idx, net_key) !=
- MESH_STATUS_SUCCESS)
- return false;
-
- if (kr) {
- /* Duplicate net key, if the key refresh is on */
- if (mesh_net_update_key(node->net, net_key_idx, net_key) !=
- MESH_STATUS_SUCCESS)
- return false;
-
- if (!mesh_db_net_key_set_phase(node->jconfig, net_key_idx,
- KEY_REFRESH_PHASE_TWO))
- return false;
- }
-
+ l_queue_foreach(net_keys, add_keys, node);
storage_save_config(node, true, NULL, NULL);

/* Initialize configuration server model */
@@ -1779,6 +1781,8 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
struct managed_obj_request *req = user_data;
const char *path;
struct mesh_node *node = NULL;
+ struct l_queue *net_keys = NULL;
+ struct keyring_net_key *net_key = NULL;
void *agent = NULL;
bool have_app = false;
bool is_new;
@@ -1902,9 +1906,10 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)

} else {
/* Callback for create node request */
- node_ready_func_t cb = req->cb;
- struct keyring_net_key net_key;
uint8_t dev_key[16];
+ node_ready_func_t cb = req->cb;
+
+ net_key = l_new(struct keyring_net_key, 1);

node->num_ele = num_ele;
set_defaults(node);
@@ -1915,21 +1920,22 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)

/* Generate device and primary network keys */
l_getrandom(dev_key, sizeof(dev_key));
- l_getrandom(net_key.old_key, sizeof(net_key.old_key));
- net_key.net_idx = PRIMARY_NET_IDX;
- net_key.phase = KEY_REFRESH_PHASE_NONE;
-
- if (!add_local_node(node, DEFAULT_NEW_UNICAST, false, false,
- DEFAULT_IV_INDEX, dev_key,
- PRIMARY_NET_IDX,
- net_key.old_key))
+ l_getrandom(net_key->old_key, sizeof(net_key->old_key));
+ net_key->net_idx = PRIMARY_NET_IDX;
+ net_key->phase = KEY_REFRESH_PHASE_NONE;
+
+ net_keys = l_queue_new();
+ l_queue_push_tail(net_keys, net_key);
+
+ if (!add_local_node(node, DEFAULT_NEW_UNICAST, false,
+ DEFAULT_IV_INDEX, dev_key, net_keys))
goto fail;

if (!keyring_put_remote_dev_key(node, DEFAULT_NEW_UNICAST,
num_ele, dev_key))
goto fail;

- if (!keyring_put_net_key(node, PRIMARY_NET_IDX, &net_key))
+ if (!keyring_put_net_key(node, PRIMARY_NET_IDX, net_key))
goto fail;

cb(req->user_data, MESH_ERROR_NONE, node);
@@ -1937,6 +1943,12 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)

return;
fail:
+ if (net_keys)
+ l_queue_destroy(net_keys, l_free);
+
+ if (net_key)
+ l_free(net_key);
+
if (agent)
mesh_agent_remove(agent);

@@ -2031,15 +2043,12 @@ void node_import(const char *sender, void *json_data, const uint8_t *uuid,
struct mesh_node *node;
struct mesh_net *net;
struct mesh_db_node db_node;
- struct keyring_net_key network_key;
+ struct l_queue *net_keys = NULL;

json_object *jnode = json_data;
+
uint16_t unicast;
uint8_t dev_key[16];
- uint8_t net_key[16];
- bool key_refresh;
- uint16_t net_idx;
- uint8_t phase;
uint32_t iv_idx;
bool iv_update;

@@ -2073,8 +2082,9 @@ void node_import(const char *sender, void *json_data, const uint8_t *uuid,
goto fail;
}

- if (!parse_imported_net_key(jnode, &net_key[0], &key_refresh,
- &net_idx, &phase)) {
+ net_keys = parse_imported_net_key(jnode);
+
+ if (!net_keys) {
l_error("Failed to parse imported network key");
goto fail;
}
@@ -2094,22 +2104,17 @@ void node_import(const char *sender, void *json_data, const uint8_t *uuid,
goto fail;
}

- if (!add_local_node(node, unicast, key_refresh, iv_update, iv_idx,
- dev_key, net_idx, &net_key[0])) {
+ if (!add_local_node(node, unicast, iv_update, iv_idx, dev_key,
+ net_keys)) {
l_error("Failed to add local node");
goto fail;
}

- memcpy(network_key.old_key, net_key, 16);
- network_key.net_idx = net_idx;
- network_key.phase = phase;
+ l_queue_foreach(net_keys, put_net_keyrings, node);

if (!keyring_put_remote_dev_key(node, unicast, node->num_ele, dev_key))
goto fail;

- if (!keyring_put_net_key(node, net_idx, &network_key))
- goto fail;
-
cb(user_data, MESH_ERROR_NONE, node);
return;

@@ -2117,6 +2122,9 @@ fail:
cb(user_data, MESH_ERROR_FAILED, NULL);
json_object_put(jnode);

+ if (net_keys)
+ l_queue_destroy(net_keys, l_free);
+
if (node)
node_remove(node);
}
@@ -2125,11 +2133,9 @@ void node_create(const char *app_path, const char *sender, const uint8_t *uuid,
node_ready_func_t cb, void *user_data)
{
struct managed_obj_request *req;
- struct mesh_node *node;

l_debug("");

- node = node_new(uuid);
req = l_new(struct managed_obj_request, 1);
req->data = (void *) uuid;
req->cb = cb;
@@ -2377,11 +2383,25 @@ const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx)
bool node_add_pending_local(struct mesh_node *node, void *prov_node_info)
{
struct mesh_prov_node_info *info = prov_node_info;
+ struct l_queue *net_keys = l_queue_new();
+ struct keyring_net_key *net_keyring = l_new(struct keyring_net_key, 1);
+
bool kr = !!(info->flags & PROV_FLAG_KR);
bool ivu = !!(info->flags & PROV_FLAG_IVU);

- return add_local_node(node, info->unicast, kr, ivu, info->iv_index,
- info->device_key, info->net_index, info->net_key);
+ net_keyring->net_idx = info->net_index;
+ net_keyring->key_refresh = kr;
+ memcpy(net_keyring->old_key, info->net_key, 16);
+
+ l_queue_push_tail(net_keys, net_keyring);
+
+ if (add_local_node(node, info->unicast, ivu, info->iv_index,
+ info->device_key, net_keys))
+ return true;
+
+ l_free(net_keyring);
+ l_queue_destroy(net_keys, l_free);
+ return false;
}

void node_jconfig_set(struct mesh_node *node, void *jconfig)
--
2.20.1

2019-06-14 12:45:55

by Jakub Witowski

[permalink] [raw]
Subject: [PATCH 2/3] mesh: Added functionality of import local node

This implements node_import() which provides full functionality
of importing node via dbus from json format
---
mesh/mesh.c | 10 +-
mesh/model.c | 5 +-
mesh/node.c | 474 ++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 437 insertions(+), 52 deletions(-)

diff --git a/mesh/mesh.c b/mesh/mesh.c
index bcbd9ada4..a3f44bc8e 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -66,7 +66,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;
@@ -531,8 +531,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;
@@ -792,13 +792,13 @@ static struct l_dbus_message *import_local_node_call(struct l_dbus *dbus,

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

- node_import(sender, jnode, uuid, create_node_ready_cb,
- pending_msg);
+ node_import(sender, jnode, uuid, create_node_ready_cb, pending_msg);

return NULL;
}
diff --git a/mesh/model.c b/mesh/model.c
index f29ad9af2..1d69236ca 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -228,6 +228,7 @@ static struct l_dbus_message *create_config_update_msg(struct mesh_node *node,

if ((id & VENDOR_ID_MASK) != VENDOR_ID_MASK) {
uint16_t vendor = id >> 16;
+
dbus_append_dict_entry_basic(*builder, "Vendor", "q", &vendor);
}

@@ -269,7 +270,7 @@ static void append_dict_uint16_array(struct l_dbus_message_builder *builder,
for (entry = l_queue_get_entries(q); entry; entry = entry->next) {
uint16_t value = (uint16_t) L_PTR_TO_UINT(entry->data);

- l_dbus_message_builder_append_basic(builder,'q', &value);
+ l_dbus_message_builder_append_basic(builder, 'q', &value);
}

l_dbus_message_builder_leave_array(builder);
@@ -1597,6 +1598,7 @@ void model_build_config(void *model, void *msg_builder)
/* For vendor models, add vendor id */
if ((mod->id & VENDOR_ID_MASK) != VENDOR_ID_MASK) {
uint16_t vendor = mod->id >> 16;
+
dbus_append_dict_entry_basic(builder, "Vendor", "q", &vendor);
}

@@ -1607,6 +1609,7 @@ void model_build_config(void *model, void *msg_builder)
/* Model periodic publication interval, if present */
if (mod->pub) {
uint32_t period = pub_period_to_ms(mod->pub->period);
+
dbus_append_dict_entry_basic(builder, "PublicationPeriod", "u",
&period);
}
diff --git a/mesh/node.c b/mesh/node.c
index b55e2b72a..fab5780cb 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -27,6 +27,9 @@

#include <ell/ell.h>
#include <json-c/json.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>

#include "mesh/mesh-defs.h"
#include "mesh/mesh.h"
@@ -1078,6 +1081,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 +1370,366 @@ 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_composition(json_object *jcomp,
+ struct mesh_db_node *node)
{
- node->net = mesh_net_new(node);
+ json_object *jvalue;
+ char *str;

- if (!nodes)
- nodes = l_queue_new();
+ /* All the fields in node composition are mandatory */
+ if (!json_object_object_get_ex(jcomp, "cid", &jvalue))
+ return false;

- l_queue_push_tail(nodes, node);
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &node->cid) != 1)
+ return false;
+
+ if (!json_object_object_get_ex(jcomp, "pid", &jvalue))
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &node->pid) != 1)
+ return false;
+
+ if (!json_object_object_get_ex(jcomp, "vid", &jvalue))
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &node->vid) != 1)
+ return false;
+
+ return true;
+}
+
+static bool parse_imported_iv_index(json_object *jobj, uint32_t *idx,
+ bool *update)
+{
+ int tmp;
+ json_object *jvalue;
+
+ if (!json_object_object_get_ex(jobj, "IVindex", &jvalue))
+ return false;
+
+ 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, uint16_t *net_idx, uint8_t *ph)
+{
+ json_object *jobject;
+ struct json_object_iterator iter, iend;
+ const char *jidx;
+ json_object *jtemp, *jvalue;
+
+ if (!json_object_object_get_ex(jobj, "netKeys", &jobject))
+ return false;
+
+ if (json_object_get_type(jobject) != json_type_object)
+ return false;
+
+ iter = json_object_iter_begin(jobject);
+ iend = json_object_iter_end(jobject);
+
+ while (!json_object_iter_equal(&iter, &iend)) {
+ uint16_t idx;
+ char *str, *end;
+ bool key_refresh = false;
+ uint8_t phase;
+ uint8_t key[16];
+ uint8_t new_key[16];
+
+ jidx = json_object_iter_peek_name(&iter);
+ jtemp = json_object_iter_peek_value(&iter);
+
+ if (!*jidx)
+ return false;
+
+ idx = (uint16_t)strtol(jidx, &end, 10);
+ if (*end || (idx > 4095))
+ return false;
+
+ *net_idx = idx;
+ if (json_object_get_type(jtemp) != json_type_object)
+ return false;
+
+ json_object_object_get_ex(jtemp, "oldKey", &jvalue);
+
+ if (jvalue) {
+ str = (char *)json_object_get_string(jvalue);
+ if (!str2hex(str, strlen(str), key, 16))
+ return false;
+ key_refresh = true;
+ }
+
+ if (!json_object_object_get_ex(jtemp, "key", &jvalue))
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+ if (!str2hex(str, strlen(str), key_refresh ? new_key : key, 16))
+ return false;
+
+ memcpy(&key_buf[0], key_refresh ? new_key : key, 16);

+ if (!json_object_object_get_ex(jtemp, "keyRefresh", &jvalue))
+ return false;
+
+ if (!jvalue)
+ phase = KEY_REFRESH_PHASE_NONE;
+ else
+ phase = (uint8_t)json_object_get_int(jvalue);
+
+ *ph = phase;
+ *kr = key_refresh;
+ json_object_iter_next(&iter);
+ }
+
+ return true;
+}
+
+static bool parse_imported_models(json_object *jmodels,
+ struct mesh_db_element *ele)
+{
+ struct json_object_iterator iter, end;
+
+ if (json_object_get_type(jmodels) != json_type_object)
+ return false;
+
+ iter = json_object_iter_begin(jmodels);
+ end = json_object_iter_end(jmodels);
+
+ while (!json_object_iter_equal(&iter, &end)) {
+ uint32_t id;
+ const char *jidx;
+ struct mesh_db_model *mod;
+
+ mod = l_new(struct mesh_db_model, 1);
+ if (!mod)
+ goto fail;
+
+ jidx = json_object_iter_peek_name(&iter);
+
+ if (!*jidx)
+ return false;
+
+ switch (strlen(jidx)) {
+
+ case 4: {
+ if (sscanf(jidx, "%04x", &id) != 1)
+ goto fail;
+
+ id |= VENDOR_ID_MASK;
+ break;
+ }
+
+ case 8: {
+ if (sscanf(jidx, "%08x", &id) != 1)
+ goto fail;
+
+ mod->vendor = true;
+ break;
+ }
+
+ default:
+ goto fail;
+ }
+
+ mod->id = id;
+ l_queue_push_tail(ele->models, mod);
+ json_object_iter_next(&iter);
+ }
+ return true;
+
+fail:
+ l_queue_destroy(ele->models, l_free);
+ return false;
+}
+
+static bool parse_imported_elements(json_object *jelements,
+ struct mesh_db_node *db_node)
+{
+ json_object *jvalue;
+ json_object *jtemp;
+ struct json_object_iterator iter, end;
+ struct mesh_db_element *ele;
+ const char *jidx;
+
+ if (!json_object_object_get_ex(jelements, "elements", &jvalue))
+ return false;
+
+ if (json_object_get_type(jelements) != json_type_object)
+ return false;
+
+ if (jvalue && json_object_get_type(jvalue) != json_type_object)
+ return false;
+
+ db_node->elements = l_queue_new();
+
+ if (!db_node->elements)
+ return false;
+
+ iter = json_object_iter_begin(jvalue);
+ end = json_object_iter_end(jvalue);
+
+ while (!json_object_iter_equal(&iter, &end)) {
+
+ json_object *jmodels, *jlocation;
+
+ char *str_end, *str;
+ uint8_t idx;
+
+ jidx = json_object_iter_peek_name(&iter);
+ jtemp = json_object_iter_peek_value(&iter);
+
+ if (!*jidx)
+ return false;
+
+ idx = (uint8_t)strtol(jidx, &str_end, 10);
+
+ if (*str_end)
+ return false;
+
+ if (json_object_get_type(jtemp) != json_type_object)
+ return false;
+
+ ele = l_new(struct mesh_db_element, 1);
+
+ if (!ele)
+ goto fail;
+
+ ele->index = idx;
+ ele->models = l_queue_new();
+
+ if (!ele->models)
+ goto fail;
+
+ if (!json_object_object_get_ex(jtemp, "location", &jlocation))
+ goto fail;
+
+ str = (char *)json_object_get_string(jlocation);
+
+ if (sscanf(str, "%04hx", &(ele->location)) != 1)
+ goto fail;
+
+ if (json_object_object_get_ex(jtemp, "models", &jmodels)) {
+
+ if (json_object_get_type(jmodels) != json_type_object)
+ goto fail;
+
+ if (!parse_imported_models(jmodels, ele))
+ goto fail;
+ }
+
+ l_queue_push_tail(db_node->elements, ele);
+ json_object_iter_next(&iter);
+ }
+ return true;
+
+fail:
+ l_queue_destroy(db_node->elements, l_free);
+ db_node->elements = NULL;
+
+ if (ele->models) {
+ l_queue_destroy(ele->models, l_free);
+ ele->models = NULL;
+ }
+
+ return false;
+}
+
+static bool parse_imported_finalize(struct mesh_db_node *db_node,
+ struct mesh_node *node)
+{
+ struct mesh_net *net;
+ uint8_t mode, cnt;
+ uint16_t interval;
+
+ if (!node_init_from_storage(node, db_node)) {
+ node_remove(node);
+ return false;
+ }
+
+ net = node_get_net(node);
+ mesh_net_set_seq_num(net, node_get_sequence_number(node));
+ mesh_net_set_default_ttl(net, node_default_ttl_get(node));
+
+ mode = node_proxy_mode_get(node);
+ if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
+ mesh_net_set_proxy_mode(net, mode == MESH_MODE_ENABLED);
+
+ mode = node_friend_mode_get(node);
+ if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
+ mesh_net_set_friend_mode(net, mode == MESH_MODE_ENABLED);
+
+ mode = node_relay_mode_get(node, &cnt, &interval);
+ if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
+ mesh_net_set_relay_mode(net, mode == MESH_MODE_ENABLED, cnt,
+ interval);
+
+ mode = node_beacon_mode_get(node);
+ if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
+ mesh_net_set_beacon_mode(net, mode == MESH_MODE_ENABLED);
+
+ if (!IS_UNASSIGNED(db_node->unicast) &&
+ !mesh_net_register_unicast(net, db_node->unicast,
+ node_get_num_elements(node))) {
+ node_remove(node);
+ return false;
+ }
+
+ if (node_uuid_get(node))
+ mesh_net_id_uuid_set(net, node_uuid_get(node));
+
+ 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,7 +1797,7 @@ 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;
@@ -1675,79 +2028,108 @@ void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
void node_import(const char *sender, void *json_data, const uint8_t *uuid,
node_ready_func_t cb, void *user_data)
{
+ struct mesh_node *node;
+ struct mesh_net *net;
+ struct mesh_db_node db_node;
+ struct keyring_net_key network_key;
+
json_object *jnode = json_data;
- struct mesh_node *node = NULL;
- struct keyring_net_key net_key;
+ uint16_t unicast;
uint8_t dev_key[16];
+ uint8_t net_key[16];
+ bool key_refresh;
+ uint16_t net_idx;
+ uint8_t phase;
+ uint32_t iv_idx;
+ bool iv_update;

- node = l_new(struct mesh_node, 1);
- node->elements = l_queue_new();
+ l_info("Node import method call");
+
+ node = node_new(uuid);
+ memset(&db_node, 0, sizeof(db_node));
+
+ net = node_get_net(node);
+ assert(net);

- (void)jnode;
- /*
- * TODO:
- * add elements from json
- */
- node->num_ele = l_queue_length(node->elements);
set_defaults(node);
- memcpy(node->uuid, uuid, 16);

- if (!create_node_config(node)) {
- l_error("create config");
+ if (!parse_imported_iv_index(jnode, &iv_idx, &iv_update)) {
+ l_error("Failed to parse imported iv idx");
goto fail;
}

- /*
- * TODO:
- * get primary (dev and net) keys from jnode
- */
- l_getrandom(dev_key, sizeof(dev_key));
- l_getrandom(net_key.old_key, sizeof(net_key.old_key));
+ if (!parse_imported_composition(jnode, &db_node)) {
+ l_error("Failed to parse composition data");
+ goto fail;
+ }

- net_key.net_idx = PRIMARY_NET_IDX;
- net_key.phase = KEY_REFRESH_PHASE_NONE;
+ if (!parse_imported_unicast_addr(jnode, &unicast)) {
+ l_error("Failed to parse unicast address");
+ goto fail;
+ }

- if (!add_local_node(node, DEFAULT_NEW_UNICAST, false, false,
- DEFAULT_IV_INDEX, dev_key,
- PRIMARY_NET_IDX,
- net_key.old_key)) {
- l_error("add local node");
+ if (!parse_imported_device_key(jnode, &dev_key[0])) {
+ l_error("Failed to parse device key");
goto fail;
}

- if (!keyring_put_remote_dev_key(node, node->primary,
- node->num_ele, dev_key)) {
- l_error("put remote key");
+ if (!parse_imported_net_key(jnode, &net_key[0], &key_refresh,
+ &net_idx, &phase)) {
+ l_error("Failed to parse imported network key");
goto fail;
}

- /*
- * TODO:
- * add remaining keys from json
- */
- if (!keyring_put_net_key(node, PRIMARY_NET_IDX, &net_key)) {
- l_error("put net key");
+ if (!parse_imported_elements(jnode, &db_node)) {
+ l_error("Failed to parse elements");
goto fail;
}

+ if (!parse_imported_finalize(&db_node, node)) {
+ l_error("Failed to finalize imported node");
+ goto fail;
+ }
+
+ if (!create_node_config(node)) {
+ l_error("Failed to create config");
+ goto fail;
+ }
+
+ if (!add_local_node(node, unicast, key_refresh, iv_update, iv_idx,
+ dev_key, net_idx, &net_key[0])) {
+ l_error("Failed to add local node");
+ goto fail;
+ }
+
+ memcpy(network_key.old_key, net_key, 16);
+ network_key.net_idx = net_idx;
+ network_key.phase = phase;
+
+ if (!keyring_put_remote_dev_key(node, unicast, node->num_ele, dev_key))
+ goto fail;
+
+ if (!keyring_put_net_key(node, net_idx, &network_key))
+ goto fail;
+
cb(user_data, MESH_ERROR_NONE, node);
return;

fail:
- if (node)
- free_node_resources(node);
-
cb(user_data, MESH_ERROR_FAILED, NULL);
+ json_object_put(jnode);

+ if (node)
+ node_remove(node);
}

void node_create(const char *app_path, const char *sender, const uint8_t *uuid,
node_ready_func_t cb, void *user_data)
{
struct managed_obj_request *req;
+ struct mesh_node *node;

l_debug("");

+ node = node_new(uuid);
req = l_new(struct managed_obj_request, 1);
req->data = (void *) uuid;
req->cb = cb;
--
2.20.1