From: Brian Gix <brian.gix@intel.com>
To: linux-bluetooth@vger.kernel.org
Cc: johan.hedberg@gmail.com, inga.stotland@intel.com,
marcel@holtmann.org, brian.gix@intel.com
Subject: [PATCH BlueZ v5 06/30] mesh: Rewrite Node handling for multiple nodes
Date: Tue, 18 Dec 2018 20:19:52 -0800 [thread overview]
Message-ID: <20181219042016.25538-7-brian.gix@intel.com> (raw)
In-Reply-To: <20181219042016.25538-1-brian.gix@intel.com>
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/node.c | 1338 +++++++++++++++++++++++++++++++++++++++++++++++++----------
mesh/node.h | 42 +-
2 files changed, 1158 insertions(+), 222 deletions(-)
diff --git a/mesh/node.c b/mesh/node.c
index 501ab8eea..d966f188c 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -22,21 +22,40 @@
#include <config.h>
#endif
+#include <stdio.h>
#include <sys/time.h>
#include <ell/ell.h>
#include "mesh/mesh-defs.h"
#include "mesh/mesh.h"
+#include "mesh/mesh-io.h"
#include "mesh/net.h"
-#include "mesh/node.h"
+#include "mesh/mesh-db.h"
+#include "mesh/provision.h"
#include "mesh/storage.h"
#include "mesh/appkey.h"
#include "mesh/model.h"
+#include "mesh/cfgmod.h"
+#include "mesh/util.h"
+#include "mesh/error.h"
+#include "mesh/dbus.h"
+#include "mesh/agent.h"
+#include "mesh/node.h"
#define MIN_COMP_SIZE 14
+#define MESH_NODE_PATH_PREFIX "/node"
+#define MESH_ELEMENT_PATH_PREFIX "/ele"
+
+/* Default element location: unknown */
+#define DEFAULT_LOCATION 0x0000
+
+#define DEFAULT_CRPL 10
+#define DEFAULT_SEQUENCE_NUMBER 0
+
struct node_element {
+ char *path;
struct l_queue *models;
uint16_t location;
uint8_t idx;
@@ -51,30 +70,45 @@ struct node_composition {
struct mesh_node {
struct mesh_net *net;
- struct l_queue *net_keys;
- struct l_queue *app_keys;
struct l_queue *elements;
+ char *app_path;
+ char *owner;
+ char *path;
+ void *jconfig;
+ char *cfg_file;
+ uint32_t disc_watch;
time_t upd_sec;
uint32_t seq_number;
uint32_t seq_min_cache;
- uint16_t primary;
- uint16_t num_ele;
- uint8_t dev_uuid[16];
- uint8_t dev_key[16];
- uint8_t ttl;
+ uint16_t id;
bool provisioner;
+ uint16_t primary;
struct node_composition *comp;
struct {
uint16_t interval;
uint8_t cnt;
uint8_t mode;
} relay;
+ uint8_t dev_uuid[16];
+ uint8_t dev_key[16];
+ uint8_t num_ele;
+ uint8_t ttl;
uint8_t lpn;
uint8_t proxy;
uint8_t friend;
uint8_t beacon;
};
+struct attach_obj_request {
+ node_attach_ready_func_t cb;
+ struct mesh_node *node;
+};
+
+struct join_obj_request {
+ node_join_ready_func_t cb;
+ const uint8_t *uuid;
+};
+
static struct l_queue *nodes;
static bool match_node_unicast(const void *a, const void *b)
@@ -94,6 +128,14 @@ static bool match_device_uuid(const void *a, const void *b)
return (memcmp(node->dev_uuid, uuid, 16) == 0);
}
+static bool match_token(const void *a, const void *b)
+{
+ const struct mesh_node *node = a;
+ const uint64_t *token = b;
+ const uint64_t tmp = l_get_u64(node->dev_key);
+ return *token == tmp;
+}
+
static bool match_element_idx(const void *a, const void *b)
{
const struct node_element *element = a;
@@ -102,17 +144,15 @@ static bool match_element_idx(const void *a, const void *b)
return (element->idx == index);
}
-static bool match_key_idx(const void *a, const void *b)
+static bool match_element_path(const void *a, const void *b)
{
- return (L_PTR_TO_UINT(a) == L_PTR_TO_UINT(b));
-}
+ const struct node_element *element = a;
+ const char *path = b;
-static bool match_model_id(const void *a, const void *b)
-{
- const struct mesh_model *model = a;
- uint32_t id = L_PTR_TO_UINT(b);
+ if (!element->path)
+ return false;
- return (mesh_model_get_model_id(model) == id);
+ return (!strcmp(element->path, path));
}
struct mesh_node *node_find_by_addr(uint16_t addr)
@@ -140,20 +180,30 @@ struct mesh_node *node_new(void)
struct mesh_node *node;
node = l_new(struct mesh_node, 1);
+ node->net = mesh_net_new(node);
- if (!node)
- return NULL;
+ if (!nodes)
+ nodes = l_queue_new();
l_queue_push_tail(nodes, node);
return node;
}
+static void free_element_path(void *a, void *b)
+{
+ struct node_element *element = a;
+
+ l_free(element->path);
+ element->path = NULL;
+}
+
static void element_free(void *data)
{
struct node_element *element = data;
l_queue_destroy(element->models, mesh_model_free);
+ l_free(element->path);
l_free(element);
}
@@ -161,13 +211,20 @@ static void free_node_resources(void *data)
{
struct mesh_node *node = data;
- l_queue_destroy(node->net_keys, NULL);
- l_queue_destroy(node->app_keys, NULL);
+ /* Unregister io callbacks */
+ if(node->net)
+ mesh_net_detach(node->net);
+ mesh_net_free(node->net);
+
l_queue_destroy(node->elements, element_free);
l_free(node->comp);
+ l_free(node->app_path);
+ l_free(node->owner);
- if (node->net)
- mesh_net_unref(node->net);
+ if (node->path)
+ l_dbus_object_remove_interface(dbus_get_bus(), node->path,
+ MESH_NODE_INTERFACE);
+ l_free(node->path);
l_free(node);
}
@@ -176,19 +233,18 @@ void node_free(struct mesh_node *node)
{
if (!node)
return;
+
l_queue_remove(nodes, node);
free_node_resources(node);
}
-static bool add_models(struct mesh_net *net, struct node_element *ele,
+static bool add_models(struct mesh_node *node, struct node_element *ele,
struct mesh_db_element *db_ele)
{
const struct l_queue_entry *entry;
if (!ele->models)
ele->models = l_queue_new();
- if (!ele->models)
- return false;
entry = l_queue_get_entries(db_ele->models);
for (; entry; entry = entry->next) {
@@ -196,7 +252,7 @@ static bool add_models(struct mesh_net *net, struct node_element *ele,
struct mesh_db_model *db_mod;
db_mod = entry->data;
- mod = mesh_model_init(net, ele->idx, db_mod);
+ mod = mesh_model_setup(node, ele->idx, db_mod);
if (!mod)
return false;
@@ -206,6 +262,32 @@ static bool add_models(struct mesh_net *net, struct node_element *ele,
return true;
}
+static void add_internal_model(struct mesh_node *node, uint32_t mod_id,
+ uint8_t ele_idx)
+{
+ struct node_element *ele;
+ struct mesh_model *mod;
+ struct mesh_db_model db_mod;
+
+ ele = l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(ele_idx));
+
+ if (!ele)
+ return;
+
+ memset(&db_mod, 0, sizeof(db_mod));
+ db_mod.id = mod_id;
+
+ mod = mesh_model_setup(node, ele_idx, &db_mod);
+ if (!mod)
+ return;
+
+ if (!ele->models)
+ ele->models = l_queue_new();
+
+ l_queue_push_tail(ele->models, mod);
+}
+
static bool add_element(struct mesh_node *node, struct mesh_db_element *db_ele)
{
struct node_element *ele;
@@ -217,7 +299,7 @@ static bool add_element(struct mesh_node *node, struct mesh_db_element *db_ele)
ele->idx = db_ele->index;
ele->location = db_ele->location;
- if (!db_ele->models || !add_models(node->net, ele, db_ele))
+ if (!db_ele->models || !add_models(node, ele, db_ele))
return false;
l_queue_push_tail(node->elements, ele);
@@ -231,9 +313,6 @@ static bool add_elements(struct mesh_node *node, struct mesh_db_node *db_node)
if (!node->elements)
node->elements = l_queue_new();
- if (!node->elements)
- return false;
-
entry = l_queue_get_entries(db_node->elements);
for (; entry; entry = entry->next)
if (!add_element(node, entry->data))
@@ -242,26 +321,12 @@ static bool add_elements(struct mesh_node *node, struct mesh_db_node *db_node)
return true;
}
-struct mesh_node *node_create_from_storage(struct mesh_net *net,
- struct mesh_db_node *db_node,
- bool local)
+bool node_init_from_storage(struct mesh_node *node, void *data)
{
- struct mesh_node *node;
+ struct mesh_db_node *db_node = data;
unsigned int num_ele;
- if (local && !net)
- return NULL;
-
- node = node_new();
- if (!node)
- return NULL;
-
node->comp = l_new(struct node_composition, 1);
- if (!node->comp) {
- node_free(node);
- return NULL;
- }
-
node->comp->cid = db_node->cid;
node->comp->pid = db_node->pid;
node->comp->vid = db_node->vid;
@@ -276,107 +341,77 @@ struct mesh_node *node_create_from_storage(struct mesh_net *net,
node->relay.interval = db_node->modes.relay.interval;
node->beacon = db_node->modes.beacon;
- l_info("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x",
- node->relay.mode, node->proxy, node->friend, node->lpn);
+ l_debug("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x",
+ node->relay.mode, node->proxy, node->friend, node->lpn);
node->ttl = db_node->ttl;
node->seq_number = db_node->seq_number;
num_ele = l_queue_length(db_node->elements);
- if (num_ele > 0xff) {
- node_free(node);
- return NULL;
- }
+ if (num_ele > 0xff)
+ return false;
node->num_ele = num_ele;
- if (num_ele != 0 && !add_elements(node, db_node)) {
- node_free(node);
- return NULL;
- }
+ if (num_ele != 0 && !add_elements(node, db_node))
+ return false;
node->primary = db_node->unicast;
memcpy(node->dev_uuid, db_node->uuid, 16);
- if (local)
- node->net = mesh_net_ref(net);
+ /* Initialize configuration server model */
+ mesh_config_srv_init(node, PRIMARY_ELE_IDX);
- return node;
+ return true;
}
-void node_cleanup(struct mesh_net *net)
+void node_cleanup(void *data)
{
- struct mesh_node *node;
+ struct mesh_node *node = data;
+ struct mesh_net *net = node->net;
- if (!net)
- return;
- node = mesh_net_local_node_get(net);
- if (node)
- node_free(node);
+ /* Save local node configuration */
+ if (node->cfg_file) {
+
+ /* Preserve the last sequence number */
+ storage_write_sequence_number(net, mesh_net_get_seq_num(net));
- l_queue_destroy(nodes, free_node_resources);
+ if (storage_save_config(node, true, NULL, NULL))
+ l_info("Saved final config to %s", node->cfg_file);
+ }
+
+ if (node->disc_watch)
+ l_dbus_remove_watch(dbus_get_bus(), node->disc_watch);
+ free_node_resources(node);
}
-bool node_is_provisioned(struct mesh_node *node)
+void node_cleanup_all(void)
{
- return (!IS_UNASSIGNED(node->primary));
+ l_queue_destroy(nodes, node_cleanup);
+ l_dbus_unregister_interface(dbus_get_bus(), MESH_NODE_INTERFACE);
}
-bool node_net_key_delete(struct mesh_node *node, uint16_t idx)
+bool node_is_provisioned(struct mesh_node *node)
{
- if (!node)
- return false;
-
- if (!l_queue_find(node->net_keys, match_key_idx, L_UINT_TO_PTR(idx)))
- return false;
-
- l_queue_remove(node->net_keys, L_UINT_TO_PTR(idx));
- /* TODO: remove all associated app keys and bindings */
- return true;
+ return (!IS_UNASSIGNED(node->primary));
}
bool node_app_key_delete(struct mesh_net *net, uint16_t addr,
uint16_t net_idx, uint16_t app_idx)
{
struct mesh_node *node;
- uint32_t index;
const struct l_queue_entry *entry;
node = node_find_by_addr(addr);
if (!node)
return false;
- index = (net_idx << 16) + app_idx;
-
- if (!l_queue_find(node->app_keys, match_key_idx, L_UINT_TO_PTR(index)))
- return false;
-
- l_queue_remove(node->app_keys, L_UINT_TO_PTR(index));
-
- storage_local_app_key_del(net, net_idx, app_idx);
-
entry = l_queue_get_entries(node->elements);
for (; entry; entry = entry->next) {
struct node_element *ele = entry->data;
- mesh_model_app_key_delete(net, ele->models, app_idx);
+ mesh_model_app_key_delete(node, ele->models, app_idx);
}
-
- return true;
-}
-
-bool node_set_primary(struct mesh_node *node, uint16_t unicast)
-{
- if (!node)
- return false;
-
- node->primary = unicast;
-
- /* If local node, save to storage */
- if (node->net)
- return storage_local_set_unicast(node->net, unicast);
-
- /* TODO: for provisioner, store remote node info */
return true;
}
@@ -388,20 +423,9 @@ uint16_t node_get_primary(struct mesh_node *node)
return node->primary;
}
-bool node_set_device_key(struct mesh_node *node, uint8_t key[16])
-
+void node_set_device_key(struct mesh_node *node, uint8_t key[16])
{
- if (!node || !key)
- return false;
-
memcpy(node->dev_key, key, 16);
-
- /* If local node, save to storage */
- if (node->net)
- return storage_local_set_device_key(node->net, key);
-
- /* TODO: for provisioner, store remote node info */
- return true;
}
const uint8_t *node_get_device_key(struct mesh_node *node)
@@ -417,22 +441,6 @@ uint8_t node_get_num_elements(struct mesh_node *node)
return node->num_ele;
}
-struct l_queue *node_get_net_keys(struct mesh_node *node)
-{
- if (!node)
- return NULL;
- else
- return node->net_keys;
-}
-
-struct l_queue *node_get_app_keys(struct mesh_node *node)
-{
- if (!node)
- return NULL;
- else
- return node->app_keys;
-}
-
struct l_queue *node_get_element_models(struct mesh_node *node,
uint8_t ele_idx, int *status)
{
@@ -458,31 +466,6 @@ struct l_queue *node_get_element_models(struct mesh_node *node,
return ele->models;
}
-struct mesh_model *node_get_model(struct mesh_node *node, uint8_t ele_idx,
- uint32_t id, int *status)
-{
- struct l_queue *models;
- struct mesh_model *model;
-
- if (!node) {
- if (status)
- *status = MESH_STATUS_INVALID_ADDRESS;
- return NULL;
- }
-
- models = node_get_element_models(node, ele_idx, status);
- if (!models)
- return NULL;
-
- model = l_queue_find(models, match_model_id, L_UINT_TO_PTR(id));
-
- if (status)
- *status = (model) ? MESH_STATUS_SUCCESS :
- MESH_STATUS_INVALID_MODEL;
-
- return model;
-}
-
uint8_t node_default_ttl_get(struct mesh_node *node)
{
if (!node)
@@ -492,20 +475,16 @@ uint8_t node_default_ttl_get(struct mesh_node *node)
bool node_default_ttl_set(struct mesh_node *node, uint8_t ttl)
{
- bool res, is_local;
+ bool res;
if (!node)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
- res = storage_local_set_ttl(node->net, ttl);
+ res = storage_set_ttl(node->jconfig, ttl);
if (res) {
node->ttl = ttl;
- if (is_local)
- mesh_net_set_default_ttl(node->net, ttl);
+ mesh_net_set_default_ttl(node->net, ttl);
}
return res;
@@ -513,21 +492,13 @@ bool node_default_ttl_set(struct mesh_node *node, uint8_t ttl)
bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
{
- bool is_local;
struct timeval write_time;
-
if (!node)
return false;
node->seq_number = seq;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
- if (!is_local)
- return true;
-
/*
* Holistically determine worst case 5 minute sequence consumption
* so that we typically (once we reach a steady state) rewrite the
@@ -541,7 +512,7 @@ bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
if (elapsed < MIN_SEQ_CACHE_TIME) {
uint32_t ideal = node->seq_min_cache;
- l_info("Old Seq Cache: %d", node->seq_min_cache);
+ l_debug("Old Seq Cache: %d", node->seq_min_cache);
ideal *= (MIN_SEQ_CACHE_TIME / elapsed);
@@ -550,14 +521,13 @@ bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
else
node->seq_min_cache += MIN_SEQ_CACHE;
- l_info("New Seq Cache: %d", node->seq_min_cache);
+ l_debug("New Seq Cache: %d", node->seq_min_cache);
}
}
node->upd_sec = write_time.tv_sec;
- l_info("Storage-Write");
- return storage_local_write_sequence_number(node->net, seq);
+ return storage_write_sequence_number(node->net, seq);
}
uint32_t node_get_sequence_number(struct mesh_node *node)
@@ -629,24 +599,19 @@ uint8_t node_lpn_mode_get(struct mesh_node *node)
bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
uint16_t interval)
{
- bool res, is_local;
+ bool res;
if (!node || node->relay.mode == MESH_MODE_UNSUPPORTED)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
- res = storage_local_set_relay(node->net, enable, cnt, interval);
+ res = storage_set_relay(node->jconfig, enable, cnt, interval);
if (res) {
node->relay.mode = enable ? MESH_MODE_ENABLED :
MESH_MODE_DISABLED;
node->relay.cnt = cnt;
node->relay.interval = interval;
- if (is_local)
- mesh_net_set_relay_mode(node->net, enable, cnt,
- interval);
+ mesh_net_set_relay_mode(node->net, enable, cnt, interval);
}
return res;
@@ -654,22 +619,18 @@ bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
bool node_proxy_mode_set(struct mesh_node *node, bool enable)
{
- bool res, is_local;
+ bool res;
uint8_t proxy;
if (!node || node->proxy == MESH_MODE_UNSUPPORTED)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
proxy = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
- res = storage_local_set_mode(node->net, proxy, "proxy");
+ res = storage_set_mode(node->jconfig, proxy, "proxy");
if (res) {
node->proxy = proxy;
- if (is_local)
- mesh_net_set_proxy_mode(node->net, enable);
+ mesh_net_set_proxy_mode(node->net, enable);
}
return res;
@@ -685,22 +646,18 @@ uint8_t node_proxy_mode_get(struct mesh_node *node)
bool node_beacon_mode_set(struct mesh_node *node, bool enable)
{
- bool res, is_local;
+ bool res;
uint8_t beacon;
if (!node)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
beacon = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
- res = storage_local_set_mode(node->net, beacon, "beacon");
+ res = storage_set_mode(node->jconfig, beacon, "beacon");
if (res) {
node->beacon = beacon;
- if (is_local)
- mesh_net_set_beacon_mode(node->net, enable);
+ mesh_net_set_beacon_mode(node->net, enable);
}
return res;
@@ -716,22 +673,18 @@ uint8_t node_beacon_mode_get(struct mesh_node *node)
bool node_friend_mode_set(struct mesh_node *node, bool enable)
{
- bool res, is_local;
+ bool res;
uint8_t friend;
if (!node || node->friend == MESH_MODE_UNSUPPORTED)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
friend = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
- res = storage_local_set_mode(node->net, friend, "friend");
+ res = storage_set_mode(node->jconfig, friend, "friend");
if (res) {
node->friend = friend;
- if (is_local)
- mesh_net_set_friend_mode(node->net, enable);
+ mesh_net_set_friend_mode(node->net, enable);
}
return res;
@@ -788,7 +741,7 @@ uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz)
/* At least fit location and zeros for number of models */
if ((n + 4) > sz)
return n;
- l_info("ele->location %d", ele->location);
+
l_put_le16(ele->location, buf + n);
n += 2;
@@ -805,7 +758,7 @@ uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz)
mod_id = mesh_model_get_model_id(
(const struct mesh_model *) mod);
- if ((mod_id >> 16) == 0xffff) {
+ if ((mod_id & VENDOR_ID_MASK) == VENDOR_ID_MASK) {
if (n + 2 > sz)
goto element_done;
@@ -849,3 +802,970 @@ element_done:
return n;
}
+
+
+#define MIN_COMPOSITION_LEN 16
+
+bool node_parse_composition(struct mesh_node *node, uint8_t *data,
+ uint16_t len)
+{
+ struct node_composition *comp;
+ uint16_t features;
+ uint8_t num_ele;
+ bool mode;
+
+ if (!len)
+ return false;
+
+ /* Skip page -- We only support Page Zero */
+ data++;
+ len--;
+
+ if (len < MIN_COMPOSITION_LEN)
+ return false;
+
+ comp = l_new(struct node_composition, 1);
+ if (!comp)
+ return false;
+
+ node->elements = l_queue_new();
+ if (!node->elements) {
+ l_free(comp);
+ return false;
+ }
+
+ node->comp = l_new(struct node_composition, 1);
+ comp->cid = l_get_le16(&data[0]);
+ comp->pid = l_get_le16(&data[2]);
+ comp->vid = l_get_le16(&data[4]);
+ comp->crpl = l_get_le16(&data[6]);
+ features = l_get_le16(&data[8]);
+ data += 10;
+ len -= 10;
+
+ mode = !!(features & FEATURE_PROXY);
+ node->proxy = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ mode = !!(features & FEATURE_LPN);
+ node->lpn = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ mode = !!(features & FEATURE_FRIEND);
+ node->friend = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ mode = !!(features & FEATURE_RELAY);
+ node->relay.mode = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ num_ele = 0;
+
+ do {
+ uint8_t m, v;
+ uint16_t mod_id;
+ uint16_t vendor_id;
+ struct node_element *ele;
+ struct mesh_model *mod;
+
+ ele = l_new(struct node_element, 1);
+ if (!ele)
+ return false;
+
+ ele->idx = num_ele;
+ ele->location = l_get_le16(data);
+ len -= 2;
+ data += 2;
+
+ m = *data++;
+ v = *data++;
+ len -= 2;
+
+ /* Parse SIG models */
+ while (len >= 2 && m--) {
+ mod_id = l_get_le16(data);
+ mod = mesh_model_new(ele->idx, mod_id);
+ if (!mod) {
+ element_free(ele);
+ goto fail;
+ }
+
+ l_queue_push_tail(ele->models, mod);
+ data += 2;
+ len -= 2;
+ }
+
+ if (v && len < 4) {
+ element_free(ele);
+ goto fail;
+ }
+
+ /* Parse vendor models */
+ while (len >= 4 && v--) {
+ mod_id = l_get_le16(data + 2);
+ vendor_id = l_get_le16(data);
+ mod_id |= (vendor_id << 16);
+ mod = mesh_model_vendor_new(ele->idx, vendor_id,
+ mod_id);
+ if (!mod) {
+ element_free(ele);
+ goto fail;
+ }
+
+ l_queue_push_tail(ele->models, mod);
+ data += 4;
+ len -= 4;
+ }
+
+ num_ele++;
+ l_queue_push_tail(node->elements, ele);
+
+ } while (len >= 6);
+
+ /* Check the consistency for the remote node */
+ if (node->num_ele > num_ele)
+ goto fail;
+
+ node->comp = comp;
+ node->num_ele = num_ele;
+
+ return true;
+
+fail:
+ l_queue_destroy(node->elements, element_free);
+ l_free(comp);
+
+ return false;
+}
+
+void node_id_set(struct mesh_node *node, uint16_t id)
+{
+ if (node)
+ node->id = id;
+}
+
+static void attach_io(void *a, void *b)
+{
+ struct mesh_node *node = a;
+ struct mesh_io *io = b;
+
+ if (node->net)
+ mesh_net_attach(node->net, io);
+}
+
+/* Register callbacks for io */
+void node_attach_io(struct mesh_io *io)
+{
+ l_queue_foreach(nodes, attach_io, io);
+}
+
+static bool register_node_object(struct mesh_node *node)
+{
+ node->path = l_malloc(strlen(MESH_NODE_PATH_PREFIX) + 5);
+
+ snprintf(node->path, 10, MESH_NODE_PATH_PREFIX "%4.4x", node->id);
+
+ if (!l_dbus_object_add_interface(dbus_get_bus(), node->path,
+ MESH_NODE_INTERFACE, node))
+ return false;
+
+ return true;
+}
+
+static void app_disc_cb(struct l_dbus *bus, void *user_data)
+{
+ struct mesh_node *node = user_data;
+
+ l_info("App %s disconnected (%u)", node->owner, node->disc_watch);
+
+ node->disc_watch = 0;
+
+ l_queue_foreach(node->elements, free_element_path, NULL);
+
+ l_free(node->owner);
+ node->owner = NULL;
+
+ l_free(node->app_path);
+ node->app_path = NULL;
+}
+
+static bool validate_element_properties(struct mesh_node *node,
+ const char *path,
+ struct l_dbus_message_iter *properties)
+{
+ uint8_t ele_idx;
+ struct node_element *ele;
+ const char *key;
+ struct l_dbus_message_iter variant;
+ bool have_index = false;
+
+ l_debug("path %s", path);
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+ if (!strcmp(key, "Index")) {
+ have_index = true;
+ break;
+ }
+ }
+
+ if (!have_index) {
+ l_debug("Mandatory property \"Index\" not found");
+ return false;
+ }
+
+ if (!l_dbus_message_iter_get_variant(&variant, "y", &ele_idx))
+ return false;
+
+ ele = l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(ele_idx));
+
+ if (!ele) {
+ l_debug("Element with index %u not found", ele_idx);
+ return false;
+ }
+
+ /* TODO: validate models */
+
+ ele->path = l_strdup(path);
+
+ return true;
+}
+
+static void get_managed_objects_attach_cb(struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct l_dbus_message_iter objects, interfaces;
+ struct attach_obj_request *req = user_data;
+ struct mesh_node *node = req->node;
+ const char *path;
+ uint64_t token = l_get_u64(node->dev_key);
+ uint8_t num_ele;
+
+ if (l_dbus_message_is_error(msg)) {
+ l_error("Failed to get app's dbus objects");
+ goto fail;
+ }
+
+ if (!l_dbus_message_get_arguments(msg, "a{oa{sa{sv}}}", &objects)) {
+ l_error("Failed to parse app's dbus objects");
+ goto fail;
+ }
+
+ num_ele = 0;
+
+ while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
+ struct l_dbus_message_iter properties;
+ const char *interface;
+
+ while (l_dbus_message_iter_next_entry(&interfaces, &interface,
+ &properties)) {
+ if (strcmp(MESH_ELEMENT_INTERFACE, interface))
+ continue;
+
+ if (!validate_element_properties(node, path,
+ &properties))
+ goto fail;
+
+ num_ele++;
+ }
+ }
+
+ /*
+ * Check that the number of element objects matches the expected number
+ * of elements on the node
+ */
+ if (num_ele != node->num_ele)
+ goto fail;
+
+ /* Register node object with D-Bus */
+ register_node_object(node);
+
+ if (node->path) {
+ struct l_dbus *bus = dbus_get_bus();
+
+ node->disc_watch = l_dbus_add_disconnect_watch(bus, node->owner,
+ app_disc_cb, node, NULL);
+ req->cb(MESH_ERROR_NONE, node->path, token);
+
+ return;
+ }
+fail:
+ req->cb(MESH_ERROR_FAILED, NULL, token);
+
+ l_queue_foreach(node->elements, free_element_path, NULL);
+ l_free(node->app_path);
+ node->app_path = NULL;
+
+ l_free(node->owner);
+ node->owner = NULL;
+}
+
+/* Establish relationship between application and mesh node */
+int node_attach(const char *app_path, const char *sender, uint64_t token,
+ node_attach_ready_func_t cb)
+{
+ struct attach_obj_request *req;
+ struct mesh_node *node;
+
+ l_debug("");
+
+ node = l_queue_find(nodes, match_token, &token);
+ if (!node)
+ return MESH_ERROR_NOT_FOUND;
+
+ /* TODO: decide what to do if previous node->app_path is not NULL */
+ node->app_path = l_strdup(app_path);
+
+ node->owner = l_strdup(sender);
+
+ req = l_new(struct attach_obj_request, 1);
+ req->node = node;
+ req->cb = cb;
+
+ l_dbus_method_call(dbus_get_bus(), sender, app_path,
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "GetManagedObjects", NULL,
+ get_managed_objects_attach_cb,
+ req, l_free);
+ return MESH_ERROR_NONE;
+
+}
+
+static void add_model_from_properties(struct node_element *ele,
+ struct l_dbus_message_iter *property)
+{
+ struct l_dbus_message_iter ids;
+ uint16_t model_id;
+ int i = 0;
+
+ if (!ele->models)
+ ele->models = l_queue_new();
+
+ if (!l_dbus_message_iter_get_variant(property, "aq", &ids))
+ return;
+
+ while (l_dbus_message_iter_next_entry(&ids, &model_id)) {
+ struct mesh_model *mod;
+ l_debug("model_id %4.4x", model_id);
+ mod = mesh_model_new(ele->idx, model_id);
+ l_queue_push_tail(ele->models, mod);
+ i++;
+ if (i > 3)
+ break;
+ }
+}
+
+static void add_vendor_model_from_properties(struct node_element *ele,
+ struct l_dbus_message_iter *property)
+{
+ struct {
+ uint16_t v;
+ uint16_t m;
+ } id_pair;
+
+ if (!ele->models)
+ ele->models = l_queue_new();
+
+ while (l_dbus_message_iter_next_entry(property, &id_pair)) {
+ struct mesh_model *mod;
+ mod = mesh_model_vendor_new(ele->idx, id_pair.v, id_pair.m);
+ l_queue_push_tail(ele->models, mod);
+ }
+}
+
+static bool get_element_properties(struct mesh_node *node, const char *path,
+ struct l_dbus_message_iter *properties)
+{
+ struct node_element *ele;
+ const char *key;
+ struct l_dbus_message_iter variant;
+ bool have_index = false;
+
+ l_debug("path %s", path);
+
+ ele = l_new(struct node_element, 1);
+ ele->location = DEFAULT_LOCATION;
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+ if (!strcmp(key, "Index")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "y",
+ &ele->idx))
+ return false;
+ have_index = true;
+ } else if (!strcmp(key, "Location")) {
+ l_dbus_message_iter_get_variant(&variant, "q",
+ &ele->location);
+ } else if (!strcmp(key, "Models")) {
+ add_model_from_properties(ele, &variant);
+ } else if (!strcmp(key, "VendorModels")) {
+ add_vendor_model_from_properties(ele, &variant);
+ }
+ }
+
+ if (!have_index) {
+ l_debug("Mandatory property \"Index\" not found");
+ return false;
+ }
+
+ l_queue_push_tail(node->elements, ele);
+
+ return true;
+}
+
+static bool get_app_properties(struct mesh_node *node, const char *path,
+ struct l_dbus_message_iter *properties)
+{
+ const char *key;
+ struct l_dbus_message_iter variant;
+
+ l_debug("path %s", path);
+
+ if (!node->comp)
+ node->comp = l_new(struct node_composition, 1);
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+
+ if (!strcmp(key, "CompanyID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &node->comp->cid))
+ return false;
+ } else if (!strcmp(key, "ProductID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &node->comp->pid))
+ return false;
+ } else if (!strcmp(key, "VersionID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &node->comp->vid))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void convert_node_to_storage(struct mesh_node *node,
+ struct mesh_db_node *db_node)
+{
+ const struct l_queue_entry *entry;
+
+ db_node->cid = node->comp->cid;
+ db_node->pid = node->comp->pid;
+ db_node->vid = node->comp->vid;
+ db_node->crpl = node->comp->crpl;
+ db_node->modes.lpn = node->lpn;
+ db_node->modes.proxy = node->proxy;
+
+ memcpy(db_node->uuid, node->dev_uuid, 16);
+
+ node->friend = db_node->modes.friend;
+ db_node->modes.relay.state = node->relay.mode;
+ db_node->modes.relay.cnt = node->relay.cnt;
+ db_node->modes.relay.interval = node->relay.interval;
+ db_node->modes.beacon = node->beacon;
+
+ db_node->ttl = node->ttl;
+ db_node->seq_number = node->seq_number;
+
+ db_node->elements = l_queue_new();
+
+ entry = l_queue_get_entries(node->elements);
+
+ for (; entry; entry = entry->next) {
+ struct node_element *ele = entry->data;
+ struct mesh_db_element *db_ele;
+ const struct l_queue_entry *mod_entry;
+
+ db_ele = l_new(struct mesh_db_element, 1);
+
+ db_ele->index = ele->idx;
+ db_ele->location = ele->location;
+ db_ele->models = l_queue_new();
+
+ mod_entry = l_queue_get_entries(ele->models);
+
+ for (; mod_entry; mod_entry = mod_entry->next) {
+ struct mesh_model *mod = mod_entry->data;
+ struct mesh_db_model *db_mod;
+ uint32_t mod_id = mesh_model_get_model_id(mod);
+
+ db_mod = l_new(struct mesh_db_model, 1);
+ db_mod->id = mod_id;
+ db_mod->vendor = ((mod_id & VENDOR_ID_MASK)
+ != VENDOR_ID_MASK);
+
+ l_queue_push_tail(db_ele->models, db_mod);
+ }
+ l_queue_push_tail(db_node->elements, db_ele);
+ }
+
+}
+
+static bool create_node_config(struct mesh_node *node)
+{
+ struct mesh_db_node db_node;
+ const struct l_queue_entry *entry;
+ bool res;
+
+ convert_node_to_storage(node, &db_node);
+ res = storage_create_node_config(node, &db_node);
+
+ /* Free temporarily allocated resources */
+ entry = l_queue_get_entries(db_node.elements);
+ for (; entry; entry = entry->next) {
+ struct mesh_db_element *db_ele = entry->data;
+
+ l_queue_destroy(db_ele->models, l_free);
+ }
+
+ l_queue_destroy(db_node.elements, l_free);
+
+ return res;
+}
+
+static void set_defaults(struct mesh_node *node)
+{
+ /* TODO: these values should come from mesh.conf */
+ if (!node->comp)
+ node->comp = l_new(struct node_composition, 1);
+
+ node->comp->crpl = DEFAULT_CRPL;
+ node->lpn = MESH_MODE_UNSUPPORTED;
+ node->proxy = MESH_MODE_UNSUPPORTED;
+ node->friend = MESH_MODE_UNSUPPORTED;
+ node->beacon = MESH_MODE_DISABLED;
+ node->relay.mode = MESH_MODE_DISABLED;
+ node->ttl = DEFAULT_TTL;
+ node->seq_number = DEFAULT_SEQUENCE_NUMBER;
+
+ /* Add configuration server model on primary element */
+ add_internal_model(node, CONFIG_SRV_MODEL, PRIMARY_ELE_IDX);
+}
+
+static void get_managed_objects_join_cb(struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct l_dbus_message_iter objects, interfaces;
+ struct join_obj_request *req = user_data;
+ const char *path;
+ struct mesh_node *node = NULL;
+ void *agent = NULL;
+
+ if (l_dbus_message_is_error(msg)) {
+ l_error("Failed to get app's dbus objects");
+ goto fail;
+ }
+
+ if (!l_dbus_message_get_arguments(msg, "a{oa{sa{sv}}}", &objects)) {
+ l_error("Failed to parse app's dbus objects");
+ goto fail;
+ }
+
+ node = l_new(struct mesh_node, 1);
+ node->elements = l_queue_new();
+
+ while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
+ struct l_dbus_message_iter properties;
+ const char *interface;
+
+ while (l_dbus_message_iter_next_entry(&interfaces, &interface,
+ &properties)) {
+ bool res;
+
+ if (!strcmp(MESH_ELEMENT_INTERFACE, interface)) {
+ res = get_element_properties(node, path,
+ &properties);
+ if (!res)
+ goto fail;
+
+ node->num_ele++;
+ continue;
+
+ }
+
+ if (!strcmp(MESH_APPLICATION_INTERFACE, interface)) {
+ res = get_app_properties(node, path,
+ &properties);
+ if (!res)
+ goto fail;
+
+ continue;
+ }
+
+ if (!strcmp(MESH_PROVISION_AGENT_INTERFACE,
+ interface)) {
+ const char *sender;
+
+ sender = l_dbus_message_get_sender(msg);
+ agent = mesh_agent_create(path, sender,
+ &properties);
+ if (!agent)
+ goto fail;
+ }
+ }
+ }
+
+ if (!node->comp){
+ l_error("Interface %s not found", MESH_APPLICATION_INTERFACE);
+ goto fail;
+ }
+
+ if (!agent) {
+ l_error("Interface %s not found",
+ MESH_PROVISION_AGENT_INTERFACE);
+ goto fail;
+ }
+
+ if (!node->num_ele) {
+ l_error("Interface %s not found", MESH_ELEMENT_INTERFACE);
+ goto fail;
+ }
+
+ if (!l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(PRIMARY_ELE_IDX))) {
+
+ l_debug("Primary element not detected");
+ goto fail;
+ }
+
+ set_defaults(node);
+ memcpy(node->dev_uuid, req->uuid, 16);
+
+ if (!create_node_config(node))
+ goto fail;
+
+ req->cb(node, agent);
+
+ return;
+fail:
+ if (agent)
+ free_node_resources(node);
+
+ if (node)
+ mesh_agent_remove(agent);
+
+ req->cb(NULL, NULL);
+}
+
+/* Create a temporary pre-provisioned node */
+void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
+ node_join_ready_func_t cb)
+{
+ struct join_obj_request *req;
+
+ l_debug("");
+
+ req = l_new(struct join_obj_request, 1);
+ req->uuid = uuid;
+ req->cb = cb;
+
+ l_dbus_method_call(dbus_get_bus(), sender, app_path,
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "GetManagedObjects", NULL,
+ get_managed_objects_join_cb,
+ req, l_free);
+}
+
+static void build_element_config(void *a, void *b)
+{
+ struct node_element *ele = a;
+ struct l_dbus_message_builder *builder = b;
+
+ l_debug("Element %u", ele->idx);
+
+ l_dbus_message_builder_enter_struct(builder, "ya(qa{sv})");
+
+ /* Element index */
+ l_dbus_message_builder_append_basic(builder, 'y', &ele->idx);
+
+ l_dbus_message_builder_enter_array(builder, "(qa{sv})");
+
+ /* Iterate over models */
+ l_queue_foreach(ele->models, model_build_config, builder);
+
+ l_dbus_message_builder_leave_array(builder);
+
+ l_dbus_message_builder_leave_struct(builder);
+}
+
+void node_build_attach_reply(struct l_dbus_message *reply, uint64_t token)
+{
+ struct mesh_node *node;
+ struct l_dbus_message_builder *builder;
+
+ node = l_queue_find(nodes, match_token, &token);
+ if (!node)
+ return;
+
+ builder = l_dbus_message_builder_new(reply);
+
+ /* Node object path */
+ l_dbus_message_builder_append_basic(builder, 'o', node->path);
+
+ /* Array of element configurations "a*/
+ l_dbus_message_builder_enter_array(builder, "(ya(qa{sv}))");
+ l_queue_foreach(node->elements, build_element_config, builder);
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+}
+
+static struct l_dbus_message *send_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct mesh_node *node = user_data;
+ const char *sender, *ele_path;
+ struct l_dbus_message_iter iter_data;
+ struct node_element *ele;
+ uint16_t dst, app_idx, src;
+ uint8_t data[MESH_MAX_ACCESS_PAYLOAD];
+ uint32_t len;
+ struct l_dbus_message *reply;
+
+ l_debug("Send");
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (strcmp(sender, node->owner))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ if (!l_dbus_message_get_arguments(msg, "oqqay", &ele_path, &dst,
+ &app_idx, &iter_data))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ ele = l_queue_find(node->elements, match_element_path, ele_path);
+ if (!ele)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Element not found");
+
+ src = node_get_primary(node) + ele->idx;
+
+ l_dbus_message_iter_get_fixed_array(&iter_data, data, &len);
+ if (!len)
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Mesh message is empty");
+
+ if (!mesh_model_send(node, src, dst, app_idx,
+ mesh_net_get_default_ttl(node->net), data, len))
+ return dbus_error(msg, MESH_ERROR_FAILED, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *publish_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct mesh_node *node = user_data;
+ const char *sender, *ele_path;
+ struct l_dbus_message_iter iter_data;
+ uint16_t mod_id, src;
+ struct node_element *ele;
+ uint8_t data[MESH_MAX_ACCESS_PAYLOAD];
+ uint32_t len;
+ struct l_dbus_message *reply;
+ int result;
+
+ l_debug("Publish");
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (strcmp(sender, node->owner))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ if (!l_dbus_message_get_arguments(msg, "oqay", &ele_path, &mod_id,
+ &iter_data))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ ele = l_queue_find(node->elements, match_element_path, ele_path);
+ if (!ele)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Element not found");
+
+ src = node_get_primary(node) + ele->idx;
+
+ l_dbus_message_iter_get_fixed_array(&iter_data, data, &len);
+ if (!len)
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Mesh message is empty");
+
+ result = mesh_model_publish(node, VENDOR_ID_MASK | mod_id, src,
+ mesh_net_get_default_ttl(node->net), data, len);
+
+ if (result != MESH_ERROR_NONE)
+ return dbus_error(msg, result, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *vendor_publish_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct mesh_node *node = user_data;
+ const char *sender, *ele_path;
+ struct l_dbus_message_iter iter_data;
+ uint16_t src;
+ uint16_t model_id, vendor;
+ uint32_t vendor_mod_id;
+ struct node_element *ele;
+ uint8_t data[MESH_MAX_ACCESS_PAYLOAD];
+ uint32_t len;
+ struct l_dbus_message *reply;
+ int result;
+
+ l_debug("Publish");
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (strcmp(sender, node->owner))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ if (!l_dbus_message_get_arguments(msg, "oqqay", &ele_path, &vendor,
+ &model_id, &iter_data))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ ele = l_queue_find(node->elements, match_element_path, ele_path);
+ if (!ele)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Element not found");
+
+ src = node_get_primary(node) + ele->idx;
+
+ l_dbus_message_iter_get_fixed_array(&iter_data, data, &len);
+ if (!len)
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Mesh message is empty");
+
+ vendor_mod_id = (vendor << 16) | model_id;
+ result = mesh_model_publish(node, vendor_mod_id, src,
+ mesh_net_get_default_ttl(node->net), data, len);
+
+ if (result != MESH_ERROR_NONE)
+ return dbus_error(msg, result, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static void setup_node_interface(struct l_dbus_interface *iface)
+{
+ l_dbus_interface_method(iface, "Send", 0, send_call, "", "oqqay",
+ "element_path", "destination",
+ "key", "data");
+ l_dbus_interface_method(iface, "Publish", 0, publish_call, "", "oqay",
+ "element_path", "model_id", "data");
+ l_dbus_interface_method(iface, "VendorPublish", 0, vendor_publish_call,
+ "", "oqqay", "element_path",
+ "vendor", "model_id", "data");
+
+ /*TODO: Properties */
+}
+
+bool node_dbus_init(struct l_dbus *bus)
+{
+ if (!l_dbus_register_interface(bus, MESH_NODE_INTERFACE,
+ setup_node_interface,
+ NULL, false)) {
+ l_info("Unable to register %s interface", MESH_NODE_INTERFACE);
+ return false;
+ }
+
+ return true;
+}
+
+const char *node_get_owner(struct mesh_node *node)
+{
+ return node->owner;
+}
+
+const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx)
+{
+ struct node_element *ele;
+
+ ele = l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(ele_idx));
+
+ if (!ele)
+ return NULL;
+
+ return ele->path;
+}
+
+bool node_add_pending_local(struct mesh_node *node, void *prov_node_info,
+ struct mesh_io *io)
+{
+ struct mesh_prov_node_info *info = prov_node_info;
+ bool kr = !!(info->flags & PROV_FLAG_KR);
+ bool ivu = !!(info->flags & PROV_FLAG_IVU);
+
+ node->net = mesh_net_new(node);
+
+ if (!nodes)
+ nodes = l_queue_new();
+
+ l_queue_push_tail(nodes, node);
+
+ if (!storage_set_iv_index(node->net, info->iv_index, ivu))
+ return false;
+
+ mesh_net_set_iv_index(node->net, info->iv_index, ivu);
+
+ if (!mesh_db_write_uint16_hex(node->jconfig, "unicastAddress",
+ info->unicast))
+ return false;
+
+ node->primary = info->unicast;
+ mesh_net_register_unicast(node->net, info->unicast, node->num_ele);
+
+ memcpy(node->dev_key, info->device_key, 16);
+ if (!mesh_db_write_device_key(node->jconfig, info->device_key))
+ return false;
+
+ if (mesh_net_add_key(node->net, kr, info->net_index,
+ info->net_key) != MESH_STATUS_SUCCESS)
+ return false;
+
+ if (!storage_net_key_add(node->net, info->net_index, info->net_key,
+ kr ? KEY_REFRESH_PHASE_TWO : KEY_REFRESH_PHASE_NONE))
+ return false;
+
+ if (!storage_save_config(node, true, NULL, NULL))
+ return false;
+
+ /* Initialize configuration server model */
+ mesh_config_srv_init(node, PRIMARY_ELE_IDX);
+
+ mesh_net_attach(node->net, io);
+
+ return true;
+}
+
+void node_jconfig_set(struct mesh_node *node, void *jconfig)
+{
+ node->jconfig = jconfig;
+}
+
+void *node_jconfig_get(struct mesh_node *node)
+{
+ return node->jconfig;
+}
+
+void node_cfg_file_set(struct mesh_node *node, char *cfg)
+{
+ node->cfg_file = cfg;
+}
+
+char *node_cfg_file_get(struct mesh_node *node)
+{
+ return node->cfg_file;
+}
+
+struct mesh_net *node_get_net(struct mesh_node *node)
+{
+ return node->net;
+}
diff --git a/mesh/node.h b/mesh/node.h
index f417fe503..196b54c4d 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -18,35 +18,40 @@
*
*/
-#include "mesh/mesh-db.h"
-
struct mesh_net;
struct mesh_node;
+struct mesh_io;
+struct mesh_agent;
/* To prevent local node JSON cache thrashing, minimum update times */
#define MIN_SEQ_TRIGGER 32
#define MIN_SEQ_CACHE (2*MIN_SEQ_TRIGGER)
#define MIN_SEQ_CACHE_TIME (5*60)
+typedef void (*node_attach_ready_func_t) (int status, char *node_path,
+ uint64_t token);
+
+typedef void (*node_join_ready_func_t) (struct mesh_node *node,
+ struct mesh_agent *agent);
+
struct mesh_node *node_new(void);
void node_free(struct mesh_node *node);
+void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
+ node_join_ready_func_t cb);
uint8_t *node_uuid_get(struct mesh_node *node);
+struct mesh_net *node_get_net(struct mesh_node *node);
struct mesh_node *node_find_by_addr(uint16_t addr);
struct mesh_node *node_find_by_uuid(uint8_t uuid[16]);
bool node_is_provisioned(struct mesh_node *node);
bool node_app_key_delete(struct mesh_net *net, uint16_t addr,
uint16_t net_idx, uint16_t idx);
-bool node_net_key_delete(struct mesh_node *node, uint16_t index);
-bool node_set_primary(struct mesh_node *node, uint16_t unicast);
uint16_t node_get_primary(struct mesh_node *node);
uint16_t node_get_primary_net_idx(struct mesh_node *node);
-bool node_set_device_key(struct mesh_node *node, uint8_t key[16]);
+void node_set_device_key(struct mesh_node *node, uint8_t key[16]);
const uint8_t *node_get_device_key(struct mesh_node *node);
void node_set_num_elements(struct mesh_node *node, uint8_t num_ele);
uint8_t node_get_num_elements(struct mesh_node *node);
bool node_parse_composition(struct mesh_node *node, uint8_t *buf, uint16_t len);
-struct l_queue *node_get_net_keys(struct mesh_node *node);
-struct l_queue *node_get_app_keys(struct mesh_node *node);
bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
uint32_t model_id, uint16_t app_idx);
bool node_del_binding(struct mesh_node *node, uint8_t ele_idx,
@@ -58,12 +63,8 @@ uint32_t node_get_sequence_number(struct mesh_node *node);
int node_get_element_idx(struct mesh_node *node, uint16_t ele_addr);
struct l_queue *node_get_element_models(struct mesh_node *node, uint8_t ele_idx,
int *status);
-struct mesh_model *node_get_model(struct mesh_node *node, uint8_t ele_idx,
- uint32_t id, int *status);
uint16_t node_get_crpl(struct mesh_node *node);
-struct mesh_node *node_create_from_storage(struct mesh_net *net,
- struct mesh_db_node *db_node,
- bool local);
+bool node_init_from_storage(struct mesh_node *node, void *data);
uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz);
uint8_t node_lpn_mode_get(struct mesh_node *node);
bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
@@ -77,4 +78,19 @@ uint8_t node_beacon_mode_get(struct mesh_node *node);
bool node_friend_mode_set(struct mesh_node *node, bool enable);
uint8_t node_friend_mode_get(struct mesh_node *node);
uint32_t node_seq_cache(struct mesh_node *node);
-void node_cleanup(struct mesh_net *net);
+const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx);
+const char *node_get_owner(struct mesh_node *node);
+bool node_add_pending_local(struct mesh_node *node, void *info,
+ struct mesh_io *io);
+void node_attach_io(struct mesh_io *io);
+int node_attach(const char *app_path, const char *sender, uint64_t token,
+ node_attach_ready_func_t cb);
+void node_build_attach_reply(struct l_dbus_message *reply, uint64_t token);
+void node_id_set(struct mesh_node *node, uint16_t node_id);
+bool node_dbus_init(struct l_dbus *bus);
+void node_cleanup(void *node);
+void node_cleanup_all(void);
+void node_jconfig_set(struct mesh_node *node, void *jconfig);
+void *node_jconfig_get(struct mesh_node *node);
+void node_cfg_file_set(struct mesh_node *node, char *cfg);
+char *node_cfg_file_get(struct mesh_node *node);
--
2.14.5
next prev parent reply other threads:[~2018-12-19 4:20 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-19 4:19 [PATCH BlueZ v5 00/30] Major rewrite for Multi-Node and DBus Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
2018-12-24 20:56 ` Marcel Holtmann
2018-12-19 4:19 ` [PATCH BlueZ v5 02/30] mesh: Delete obsolete files Brian Gix
2018-12-24 20:57 ` Marcel Holtmann
2018-12-19 4:19 ` [PATCH BlueZ v5 03/30] mesh: Utilities for DBus support Brian Gix
2018-12-24 21:01 ` Marcel Holtmann
2018-12-19 4:19 ` [PATCH BlueZ v5 04/30] mesh: Internal errors Brian Gix
2018-12-24 21:03 ` Marcel Holtmann
2018-12-19 4:19 ` [PATCH BlueZ v5 05/30] mesh: Rewrite storage for Multiple Nodes Brian Gix
2018-12-24 21:05 ` Marcel Holtmann
2018-12-19 4:19 ` Brian Gix [this message]
2018-12-19 4:19 ` [PATCH BlueZ v5 07/30] mesh: Rewrite Network layer for multiple nodes Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 08/30] mesh: Direction agnostic PB-Adv implementation Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 09/30] mesh: Acceptor side provisioning implementation Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 10/30] mesh: Initiator " Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 11/30] mesh: Rewrite Controler interface for full init Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 12/30] mesh: Unchanged variables set to const Brian Gix
2018-12-19 4:19 ` [PATCH BlueZ v5 13/30] mesh: centralize generic utilities Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 15/30] mesh: Re-architect " Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 16/30] mesh: Make config model handle multiple nodes Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 18/30] mesh: restructure I/O for " Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 19/30] mesh: Restructure DB to support " Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 20/30] mesh: restructure model services for " Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 22/30] mesh: restructure App Key storage Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 23/30] mesh: Clean-up Comment style Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 24/30] mesh: Update for DBus API and multi-node support Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 25/30] mesh: Add default location for Mesh Node storage Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 26/30] mesh: Add structural changes for mesh Brian Gix
2018-12-19 4:20 ` [PATCH BlueZ v5 27/30] mesh: Sample Provisioning Agent Brian Gix
2018-12-24 21:09 ` Marcel Holtmann
2018-12-27 19:22 ` Gix, Brian
2018-12-19 4:20 ` [PATCH BlueZ v5 28/30] mesh: Sample On/Off Client and Server Brian Gix
2018-12-24 21:10 ` Marcel Holtmann
2018-12-19 4:20 ` [PATCH BlueZ v5 30/30] mesh: Enable building Mesh Daemon Brian Gix
2018-12-24 21:12 ` Marcel Holtmann
2018-12-23 17:54 ` [PATCH BlueZ v5 00/30] Major rewrite for Multi-Node and DBus Gix, Brian
[not found] ` <20181219042016.25538-30-brian.gix@intel.com>
2018-12-24 21:10 ` [PATCH BlueZ v5 29/30] mesh: Sample Mesh Joiner (provision acceptor) Marcel Holtmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181219042016.25538-7-brian.gix@intel.com \
--to=brian.gix@intel.com \
--cc=inga.stotland@intel.com \
--cc=johan.hedberg@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=marcel@holtmann.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).