2020-05-07 19:20:13

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ] tools/mesh-cfgclient: Save node's composition in config

Store remote node's composition after successful completion
of "composition-get" command (config menu).
Show model IDs when printing node info for "list-nodes" command
(main menu).
---
tools/mesh/cfgcli.c | 2 +
tools/mesh/mesh-db.c | 294 ++++++++++++++++++++++++++++++++++++++++---
tools/mesh/mesh-db.h | 10 +-
tools/mesh/remote.c | 93 +++++++++++++-
tools/mesh/remote.h | 2 +
5 files changed, 374 insertions(+), 27 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index b96c6c9e6..218e82c50 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -434,6 +434,8 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

print_composition(data, len);

+ if (!mesh_db_node_set_composition(src, data, len))
+ bt_shell_printf("Failed to save node composition!\n");
break;

case OP_APPKEY_STATUS:
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index d39435ca0..8973bba76 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -45,6 +45,7 @@
#include "tools/mesh/mesh-db.h"

#define KEY_IDX_INVALID NET_IDX_INVALID
+#define DEFAULT_LOCATION 0x0000

struct mesh_db {
json_object *jcfg;
@@ -217,6 +218,23 @@ static bool write_uint16_hex(json_object *jobj, const char *desc,
return true;
}

+static bool write_uint32_hex(json_object *jobj, const char *desc, uint32_t val)
+{
+ json_object *jstring;
+ char buf[9];
+
+ snprintf(buf, 9, "%8.8x", val);
+ jstring = json_object_new_string(buf);
+ if (!jstring)
+ return false;
+
+ /* Overwrite old value if present */
+ json_object_object_del(jobj, desc);
+
+ json_object_object_add(jobj, desc, jstring);
+ return true;
+}
+
static json_object *get_node_by_uuid(json_object *jcfg, uint8_t uuid[16])
{
json_object *jarray = NULL;
@@ -338,6 +356,65 @@ static int compare_group_addr(const void *a, const void *b, void *user_data)
return 0;
}

+static bool load_composition(json_object *jnode, uint16_t unicast)
+{
+ json_object *jarray;
+ int i, ele_cnt;
+
+ if (!json_object_object_get_ex(jnode, "elements", &jarray))
+ return false;
+
+ if (json_object_get_type(jarray) != json_type_array)
+ return false;
+
+ ele_cnt = json_object_array_length(jarray);
+
+ for (i = 0; i < ele_cnt; ++i) {
+ json_object *jentry, *jval, *jmods;
+ int32_t index;
+ int k, mod_cnt;
+
+ jentry = json_object_array_get_idx(jarray, i);
+ if (!json_object_object_get_ex(jentry, "index", &jval))
+ return false;
+
+ index = json_object_get_int(jval);
+ if (index > 0xff)
+ return false;
+
+ if (!json_object_object_get_ex(jentry, "models", &jmods))
+ return false;
+
+ mod_cnt = json_object_array_length(jmods);
+
+ for (k = 0; k < mod_cnt; ++k) {
+ json_object *jmod, *jid;
+ uint32_t mod_id, len;
+ const char *str;
+
+ jmod = json_object_array_get_idx(jmods, k);
+ if (!json_object_object_get_ex(jmod, "modelId", &jid))
+ return false;
+
+ str = json_object_get_string(jid);
+ len = strlen(str);
+
+ if (len != 4 && len != 8)
+ return false;
+
+ if ((len == 4) && (sscanf(str, "%04x", &mod_id) != 1))
+ return false;
+
+ if ((len == 8) && (sscanf(str, "%08x", &mod_id) != 1))
+ return false;
+
+ remote_set_model(unicast, index, mod_id, len == 8);
+ }
+ }
+
+ return true;
+}
+
static void load_remotes(json_object *jcfg)
{
json_object *jnodes;
@@ -420,6 +497,8 @@ static void load_remotes(json_object *jcfg)
remote_add_app_key(unicast, key_idx);
}

+ load_composition(jnode, unicast);
+
node_count++;

/* TODO: Add the rest of the configuration */
@@ -819,12 +898,34 @@ struct l_queue *mesh_db_load_groups(void)
return groups;
}

+static json_object *init_elements(uint8_t num_els)
+{
+ json_object *jelements;
+ uint8_t i;
+
+ jelements = json_object_new_array();
+
+ for (i = 0; i < num_els; ++i) {
+ json_object *jelement, *jmods;
+
+ jelement = json_object_new_object();
+
+ write_int(jelement, "index", i);
+ write_uint16_hex(jelement, "location", DEFAULT_LOCATION);
+ jmods = json_object_new_array();
+ json_object_object_add(jelement, "models", jmods);
+
+ json_object_array_add(jelements, jelement);
+ }
+
+ return jelements;
+}
+
bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
uint16_t net_idx)
{
json_object *jnode;
json_object *jelements, *jnodes, *jnetkeys, *jappkeys;
- int i;

if (!cfg || !cfg->jcfg)
return false;
@@ -842,22 +943,7 @@ bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
if (!add_u8_16(jnode, "uuid", uuid))
goto fail;

- jelements = json_object_new_array();
- if (!jelements)
- goto fail;
-
- for (i = 0; i < num_els; ++i) {
- json_object *jelement = json_object_new_object();
-
- if (!jelement) {
- json_object_put(jelements);
- goto fail;
- }
-
- write_int(jelement, "elementIndex", i);
- json_object_array_add(jelements, jelement);
- }
-
+ jelements = init_elements(num_els);
json_object_object_add(jnode, "elements", jelements);

jnetkeys = json_object_new_array();
@@ -932,6 +1018,180 @@ bool mesh_db_del_node(uint16_t unicast)
return save_config();
}

+static json_object *init_model(uint16_t mod_id)
+{
+ json_object *jmod, *jarray;
+
+ jmod = json_object_new_object();
+
+ if (!write_uint16_hex(jmod, "modelId", mod_id)) {
+ json_object_put(jmod);
+ return NULL;
+ }
+
+ jarray = json_object_new_array();
+ json_object_object_add(jmod, "bind", jarray);
+
+ jarray = json_object_new_array();
+ json_object_object_add(jmod, "subscribe", jarray);
+
+ return jmod;
+}
+
+static json_object *init_vendor_model(uint32_t mod_id)
+{
+ json_object *jmod, *jarray;
+
+ jmod = json_object_new_object();
+
+ if (!write_uint32_hex(jmod, "modelId", mod_id)) {
+ json_object_put(jmod);
+ return NULL;
+ }
+
+ jarray = json_object_new_array();
+ json_object_object_add(jmod, "bind", jarray);
+
+ jarray = json_object_new_array();
+ json_object_object_add(jmod, "subscribe", jarray);
+
+ return jmod;
+}
+
+bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len)
+{
+ uint16_t features;
+ int sz, i = 0;
+ json_object *jnode, *jobj, *jelements;
+ uint16_t crpl;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(unicast);
+ if (!jnode)
+ return false;
+
+ /* skip page -- We only support Page Zero */
+ data++;
+ len--;
+
+ /* If "crpl" property is present, composition is already recorded */
+ if (json_object_object_get_ex(jnode, "crpl", &jobj))
+ return true;
+
+ if (!write_uint16_hex(jnode, "cid", l_get_le16(&data[0])))
+ return false;
+
+ if (!write_uint16_hex(jnode, "pid", l_get_le16(&data[2])))
+ return false;
+
+ if (!write_uint16_hex(jnode, "vid", l_get_le16(&data[4])))
+ return false;
+
+ crpl = l_get_le16(&data[6]);
+
+ features = l_get_le16(&data[8]);
+ data += 10;
+ len -= 10;
+
+ jobj = json_object_object_get(jnode, "features");
+ if (!jobj) {
+ jobj = json_object_new_object();
+ json_object_object_add(jnode, "features", jobj);
+ }
+
+ if (!(features & FEATURE_RELAY))
+ write_int(jobj, "relay", 2);
+
+ if (!(features & FEATURE_FRIEND))
+ write_int(jobj, "friend", 2);
+
+ if (!(features & FEATURE_PROXY))
+ write_int(jobj, "proxy", 2);
+
+ if (!(features & FEATURE_LPN))
+ write_int(jobj, "lowPower", 2);
+
+ jelements = json_object_object_get(jnode, "elements");
+ if (!jelements)
+ return false;
+
+ sz = json_object_array_length(jelements);
+
+ while (len) {
+ json_object *jentry, *jmods;
+ uint32_t mod_id;
+ uint8_t m, v;
+
+ /* Mismatch in the element count */
+ if (i >= sz)
+ return false;
+
+ jentry = json_object_array_get_idx(jelements, i);
+
+ if (!write_uint16_hex(jentry, "location", l_get_le16(data)))
+ return false;
+
+ data += 2;
+ len -= 2;
+
+ m = *data++;
+ v = *data++;
+ len -= 2;
+
+ jmods = json_object_object_get(jentry, "models");
+ if (!jmods || json_object_get_type(jmods) != json_type_array)
+ return false;
+
+ while (len >= 2 && m--) {
+ mod_id = l_get_le16(data);
+
+ jobj = init_model(mod_id);
+ if (!jobj)
+ goto fail;
+
+ json_object_array_add(jmods, jobj);
+ data += 2;
+ len -= 2;
+ }
+
+ while (len >= 4 && v--) {
+ jobj = json_object_new_object();
+ mod_id = l_get_le16(data + 2);
+ mod_id = l_get_le16(data) << 16 | mod_id;
+
+ jobj = init_vendor_model(mod_id);
+ if (!jobj)
+ goto fail;
+
+ json_object_array_add(jmods, jobj);
+
+ data += 4;
+ len -= 4;
+ }
+
+ i++;
+ }
+
+ /* CRPL is written last. Will be used to check composition's presence */
+ if (!write_uint16_hex(jnode, "crpl", crpl))
+ goto fail;
+
+ /* Initiate remote's composition from storage */
+ if (!load_composition(jnode, unicast))
+ goto fail;
+
+ return save_config();
+
+fail:
+ /* Reset elements array */
+ json_object_object_del(jnode, "elements");
+ init_elements(sz);
+
+ return false;
+}
+
bool mesh_db_get_token(uint8_t token[8])
{
if (!cfg || !cfg->jcfg)
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index 1f9e4e3d3..89c644400 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -38,11 +38,11 @@ bool mesh_db_get_addr_range(uint16_t *low, uint16_t *high);
bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
uint16_t net_idx);
bool mesh_db_del_node(uint16_t unicast);
-bool mesh_db_node_set_composition(uint16_t unicast, uint16_t cid, uint16_t pid,
- uint16_t vid, uint16_t crpl,
- struct mesh_config_modes modes,
- struct l_queue *elements);
-
+bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data,
+ uint16_t len);
+bool mesh_db_add_provisioner(const char *name, uint8_t uuid[16],
+ uint16_t unicast_low, uint16_t unicast_high,
+ uint16_t group_low, uint16_t group_high);
bool mesh_db_node_set_net_transmit(uint16_t unicast, uint8_t cnt,
uint16_t interval);
bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx);
diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c
index 24bc59129..344de798b 100644
--- a/tools/mesh/remote.c
+++ b/tools/mesh/remote.c
@@ -35,12 +35,14 @@ struct remote_node {
uint16_t unicast;
struct l_queue *net_keys;
struct l_queue *app_keys;
+ struct l_queue **els;
uint8_t uuid[16];
uint8_t num_ele;
};

static struct l_queue *nodes;

+
static bool key_present(struct l_queue *keys, uint16_t app_idx)
{
const struct l_queue_entry *l;
@@ -55,6 +57,26 @@ static bool key_present(struct l_queue *keys, uint16_t app_idx)
return false;
}

+static int compare_mod_id(const void *a, const void *b, void *user_data)
+{
+ uint32_t id1 = L_PTR_TO_UINT(a);
+ uint32_t id2 = L_PTR_TO_UINT(b);
+
+ if (id1 >= VENDOR_ID_MASK)
+ id1 &= ~VENDOR_ID_MASK;
+
+ if (id2 >= VENDOR_ID_MASK)
+ id2 &= ~VENDOR_ID_MASK;
+
+ if (id1 < id2)
+ return -1;
+
+ if (id1 > id2)
+ return 1;
+
+ return 0;
+}
+
static int compare_unicast(const void *a, const void *b, void *user_data)
{
const struct remote_node *a_rmt = a;
@@ -92,7 +114,7 @@ static bool match_bound_key(const void *a, const void *b)
uint8_t remote_del_node(uint16_t unicast)
{
struct remote_node *rmt;
- uint8_t num_ele;
+ uint8_t num_ele, i;

rmt = l_queue_remove_if(nodes, match_node_addr, L_UINT_TO_PTR(unicast));
if (!rmt)
@@ -100,8 +122,13 @@ uint8_t remote_del_node(uint16_t unicast)

num_ele = rmt->num_ele;

- l_queue_destroy(rmt->net_keys, NULL);
- l_queue_destroy(rmt->app_keys, NULL);
+ for (i = 0; i < num_ele; ++i)
+ l_queue_destroy(rmt->els[i], NULL);
+
+ l_free(rmt->els);
+
+ l_queue_destroy(rmt->net_keys, l_free);
+ l_queue_destroy(rmt->app_keys, l_free);
l_free(rmt);

mesh_db_del_node(unicast);
@@ -126,6 +153,8 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,

l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));

+ rmt->els = l_new(struct l_queue *, ele_cnt);
+
if (!nodes)
nodes = l_queue_new();

@@ -133,6 +162,30 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
return true;
}

+bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
+ bool vendor)
+{
+ struct remote_node *rmt;
+
+ rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(unicast));
+ if (!rmt)
+ return false;
+
+ if (ele_idx >= rmt->num_ele)
+ return false;
+
+ if (!rmt->els[ele_idx])
+ rmt->els[ele_idx] = l_queue_new();
+
+ if (!vendor)
+ mod_id = VENDOR_ID_MASK | mod_id;
+
+ l_queue_insert(rmt->els[ele_idx], L_UINT_TO_PTR(mod_id),
+ compare_mod_id, NULL);
+
+ return true;
+}
+
bool remote_add_net_key(uint16_t addr, uint16_t net_idx)
{
struct remote_node *rmt;
@@ -224,9 +277,35 @@ static void print_key(void *key, void *user_data)
bt_shell_printf("%u (0x%3.3x), ", idx, idx);
}

+static void print_model(void *model, void *user_data)
+{
+ uint32_t mod_id = L_PTR_TO_UINT(model);
+
+ if (mod_id >= VENDOR_ID_MASK) {
+ mod_id &= ~VENDOR_ID_MASK;
+ bt_shell_printf("\t\t\t" COLOR_GREEN "SIG model: %4.4x\n"
+ COLOR_OFF, mod_id);
+ return;
+ }
+
+ bt_shell_printf("\t\t\t" COLOR_GREEN "Vendor model: %8.8x\n"
+ COLOR_OFF, mod_id);
+
+}
+
+static void print_element(struct l_queue *mods, int idx)
+{
+ if (!mods)
+ return;
+
+ bt_shell_printf("\t\t" COLOR_GREEN "element %u:\n" COLOR_OFF, idx);
+ l_queue_foreach(mods, print_model, NULL);
+}
+
static void print_node(void *rmt, void *user_data)
{
struct remote_node *node = rmt;
+ int i;
char *str;

bt_shell_printf(COLOR_YELLOW "Mesh node:\n" COLOR_OFF);
@@ -235,8 +314,6 @@ static void print_node(void *rmt, void *user_data)
l_free(str);
bt_shell_printf("\t" COLOR_GREEN "primary = %4.4x\n" COLOR_OFF,
node->unicast);
- bt_shell_printf("\t" COLOR_GREEN "elements = %u\n" COLOR_OFF,
- node->num_ele);
bt_shell_printf("\t" COLOR_GREEN "net_keys = ");
l_queue_foreach(node->net_keys, print_key, NULL);
bt_shell_printf("\n" COLOR_OFF);
@@ -246,6 +323,12 @@ static void print_node(void *rmt, void *user_data)
l_queue_foreach(node->app_keys, print_key, NULL);
bt_shell_printf("\n" COLOR_OFF);
}
+
+ bt_shell_printf("\t" COLOR_GREEN "elements (%u):\n" COLOR_OFF,
+ node->num_ele);
+
+ for (i = 0; i < node->num_ele; ++i)
+ print_element(node->els[i], i);
}

void remote_print_node(uint16_t addr)
diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h
index 63382ed90..33398c8bd 100644
--- a/tools/mesh/remote.h
+++ b/tools/mesh/remote.h
@@ -20,6 +20,8 @@
bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
uint8_t ele_cnt, uint16_t net_idx);
uint8_t remote_del_node(uint16_t unicast);
+bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
+ bool vendor);
uint16_t remote_get_next_unicast(uint16_t low, uint16_t high, uint8_t ele_cnt);
bool remote_add_net_key(uint16_t addr, uint16_t net_idx);
bool remote_del_net_key(uint16_t addr, uint16_t net_idx);
--
2.21.3


2020-05-09 14:00:53

by Gix, Brian

[permalink] [raw]
Subject: Re: [PATCH BlueZ] tools/mesh-cfgclient: Save node's composition in config

Applied
On Thu, 2020-05-07 at 12:17 -0700, Inga Stotland wrote:
> Store remote node's composition after successful completion
> of "composition-get" command (config menu).
> Show model IDs when printing node info for "list-nodes" command
> (main menu).
> ---
> tools/mesh/cfgcli.c | 2 +
> tools/mesh/mesh-db.c | 294 ++++++++++++++++++++++++++++++++++++++++---
> tools/mesh/mesh-db.h | 10 +-
> tools/mesh/remote.c | 93 +++++++++++++-
> tools/mesh/remote.h | 2 +
> 5 files changed, 374 insertions(+), 27 deletions(-)
>
> diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
> index b96c6c9e6..218e82c50 100644
> --- a/tools/mesh/cfgcli.c
> +++ b/tools/mesh/cfgcli.c
> @@ -434,6 +434,8 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
>
> print_composition(data, len);
>
> + if (!mesh_db_node_set_composition(src, data, len))
> + bt_shell_printf("Failed to save node composition!\n");
> break;
>
> case OP_APPKEY_STATUS:
> diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
> index d39435ca0..8973bba76 100644
> --- a/tools/mesh/mesh-db.c
> +++ b/tools/mesh/mesh-db.c
> @@ -45,6 +45,7 @@
> #include "tools/mesh/mesh-db.h"
>
> #define KEY_IDX_INVALID NET_IDX_INVALID
> +#define DEFAULT_LOCATION 0x0000
>
> struct mesh_db {
> json_object *jcfg;
> @@ -217,6 +218,23 @@ static bool write_uint16_hex(json_object *jobj, const char *desc,
> return true;
> }
>
> +static bool write_uint32_hex(json_object *jobj, const char *desc, uint32_t val)
> +{
> + json_object *jstring;
> + char buf[9];
> +
> + snprintf(buf, 9, "%8.8x", val);
> + jstring = json_object_new_string(buf);
> + if (!jstring)
> + return false;
> +
> + /* Overwrite old value if present */
> + json_object_object_del(jobj, desc);
> +
> + json_object_object_add(jobj, desc, jstring);
> + return true;
> +}
> +
> static json_object *get_node_by_uuid(json_object *jcfg, uint8_t uuid[16])
> {
> json_object *jarray = NULL;
> @@ -338,6 +356,65 @@ static int compare_group_addr(const void *a, const void *b, void *user_data)
> return 0;
> }
>
> +static bool load_composition(json_object *jnode, uint16_t unicast)
> +{
> + json_object *jarray;
> + int i, ele_cnt;
> +
> + if (!json_object_object_get_ex(jnode, "elements", &jarray))
> + return false;
> +
> + if (json_object_get_type(jarray) != json_type_array)
> + return false;
> +
> + ele_cnt = json_object_array_length(jarray);
> +
> + for (i = 0; i < ele_cnt; ++i) {
> + json_object *jentry, *jval, *jmods;
> + int32_t index;
> + int k, mod_cnt;
> +
> + jentry = json_object_array_get_idx(jarray, i);
> + if (!json_object_object_get_ex(jentry, "index", &jval))
> + return false;
> +
> + index = json_object_get_int(jval);
> + if (index > 0xff)
> + return false;
> +
> + if (!json_object_object_get_ex(jentry, "models", &jmods))
> + return false;
> +
> + mod_cnt = json_object_array_length(jmods);
> +
> + for (k = 0; k < mod_cnt; ++k) {
> + json_object *jmod, *jid;
> + uint32_t mod_id, len;
> + const char *str;
> +
> + jmod = json_object_array_get_idx(jmods, k);
> + if (!json_object_object_get_ex(jmod, "modelId", &jid))
> + return false;
> +
> + str = json_object_get_string(jid);
> + len = strlen(str);
> +
> + if (len != 4 && len != 8)
> + return false;
> +
> + if ((len == 4) && (sscanf(str, "%04x", &mod_id) != 1))
> + return false;
> +
> + if ((len == 8) && (sscanf(str, "%08x", &mod_id) != 1))
> + return false;
> +
> + remote_set_model(unicast, index, mod_id, len == 8);
> + }
> + }
> +
> + return true;
> +}
> +
> static void load_remotes(json_object *jcfg)
> {
> json_object *jnodes;
> @@ -420,6 +497,8 @@ static void load_remotes(json_object *jcfg)
> remote_add_app_key(unicast, key_idx);
> }
>
> + load_composition(jnode, unicast);
> +
> node_count++;
>
> /* TODO: Add the rest of the configuration */
> @@ -819,12 +898,34 @@ struct l_queue *mesh_db_load_groups(void)
> return groups;
> }
>
> +static json_object *init_elements(uint8_t num_els)
> +{
> + json_object *jelements;
> + uint8_t i;
> +
> + jelements = json_object_new_array();
> +
> + for (i = 0; i < num_els; ++i) {
> + json_object *jelement, *jmods;
> +
> + jelement = json_object_new_object();
> +
> + write_int(jelement, "index", i);
> + write_uint16_hex(jelement, "location", DEFAULT_LOCATION);
> + jmods = json_object_new_array();
> + json_object_object_add(jelement, "models", jmods);
> +
> + json_object_array_add(jelements, jelement);
> + }
> +
> + return jelements;
> +}
> +
> bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
> uint16_t net_idx)
> {
> json_object *jnode;
> json_object *jelements, *jnodes, *jnetkeys, *jappkeys;
> - int i;
>
> if (!cfg || !cfg->jcfg)
> return false;
> @@ -842,22 +943,7 @@ bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
> if (!add_u8_16(jnode, "uuid", uuid))
> goto fail;
>
> - jelements = json_object_new_array();
> - if (!jelements)
> - goto fail;
> -
> - for (i = 0; i < num_els; ++i) {
> - json_object *jelement = json_object_new_object();
> -
> - if (!jelement) {
> - json_object_put(jelements);
> - goto fail;
> - }
> -
> - write_int(jelement, "elementIndex", i);
> - json_object_array_add(jelements, jelement);
> - }
> -
> + jelements = init_elements(num_els);
> json_object_object_add(jnode, "elements", jelements);
>
> jnetkeys = json_object_new_array();
> @@ -932,6 +1018,180 @@ bool mesh_db_del_node(uint16_t unicast)
> return save_config();
> }
>
> +static json_object *init_model(uint16_t mod_id)
> +{
> + json_object *jmod, *jarray;
> +
> + jmod = json_object_new_object();
> +
> + if (!write_uint16_hex(jmod, "modelId", mod_id)) {
> + json_object_put(jmod);
> + return NULL;
> + }
> +
> + jarray = json_object_new_array();
> + json_object_object_add(jmod, "bind", jarray);
> +
> + jarray = json_object_new_array();
> + json_object_object_add(jmod, "subscribe", jarray);
> +
> + return jmod;
> +}
> +
> +static json_object *init_vendor_model(uint32_t mod_id)
> +{
> + json_object *jmod, *jarray;
> +
> + jmod = json_object_new_object();
> +
> + if (!write_uint32_hex(jmod, "modelId", mod_id)) {
> + json_object_put(jmod);
> + return NULL;
> + }
> +
> + jarray = json_object_new_array();
> + json_object_object_add(jmod, "bind", jarray);
> +
> + jarray = json_object_new_array();
> + json_object_object_add(jmod, "subscribe", jarray);
> +
> + return jmod;
> +}
> +
> +bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len)
> +{
> + uint16_t features;
> + int sz, i = 0;
> + json_object *jnode, *jobj, *jelements;
> + uint16_t crpl;
> +
> + if (!cfg || !cfg->jcfg)
> + return false;
> +
> + jnode = get_node_by_unicast(unicast);
> + if (!jnode)
> + return false;
> +
> + /* skip page -- We only support Page Zero */
> + data++;
> + len--;
> +
> + /* If "crpl" property is present, composition is already recorded */
> + if (json_object_object_get_ex(jnode, "crpl", &jobj))
> + return true;
> +
> + if (!write_uint16_hex(jnode, "cid", l_get_le16(&data[0])))
> + return false;
> +
> + if (!write_uint16_hex(jnode, "pid", l_get_le16(&data[2])))
> + return false;
> +
> + if (!write_uint16_hex(jnode, "vid", l_get_le16(&data[4])))
> + return false;
> +
> + crpl = l_get_le16(&data[6]);
> +
> + features = l_get_le16(&data[8]);
> + data += 10;
> + len -= 10;
> +
> + jobj = json_object_object_get(jnode, "features");
> + if (!jobj) {
> + jobj = json_object_new_object();
> + json_object_object_add(jnode, "features", jobj);
> + }
> +
> + if (!(features & FEATURE_RELAY))
> + write_int(jobj, "relay", 2);
> +
> + if (!(features & FEATURE_FRIEND))
> + write_int(jobj, "friend", 2);
> +
> + if (!(features & FEATURE_PROXY))
> + write_int(jobj, "proxy", 2);
> +
> + if (!(features & FEATURE_LPN))
> + write_int(jobj, "lowPower", 2);
> +
> + jelements = json_object_object_get(jnode, "elements");
> + if (!jelements)
> + return false;
> +
> + sz = json_object_array_length(jelements);
> +
> + while (len) {
> + json_object *jentry, *jmods;
> + uint32_t mod_id;
> + uint8_t m, v;
> +
> + /* Mismatch in the element count */
> + if (i >= sz)
> + return false;
> +
> + jentry = json_object_array_get_idx(jelements, i);
> +
> + if (!write_uint16_hex(jentry, "location", l_get_le16(data)))
> + return false;
> +
> + data += 2;
> + len -= 2;
> +
> + m = *data++;
> + v = *data++;
> + len -= 2;
> +
> + jmods = json_object_object_get(jentry, "models");
> + if (!jmods || json_object_get_type(jmods) != json_type_array)
> + return false;
> +
> + while (len >= 2 && m--) {
> + mod_id = l_get_le16(data);
> +
> + jobj = init_model(mod_id);
> + if (!jobj)
> + goto fail;
> +
> + json_object_array_add(jmods, jobj);
> + data += 2;
> + len -= 2;
> + }
> +
> + while (len >= 4 && v--) {
> + jobj = json_object_new_object();
> + mod_id = l_get_le16(data + 2);
> + mod_id = l_get_le16(data) << 16 | mod_id;
> +
> + jobj = init_vendor_model(mod_id);
> + if (!jobj)
> + goto fail;
> +
> + json_object_array_add(jmods, jobj);
> +
> + data += 4;
> + len -= 4;
> + }
> +
> + i++;
> + }
> +
> + /* CRPL is written last. Will be used to check composition's presence */
> + if (!write_uint16_hex(jnode, "crpl", crpl))
> + goto fail;
> +
> + /* Initiate remote's composition from storage */
> + if (!load_composition(jnode, unicast))
> + goto fail;
> +
> + return save_config();
> +
> +fail:
> + /* Reset elements array */
> + json_object_object_del(jnode, "elements");
> + init_elements(sz);
> +
> + return false;
> +}
> +
> bool mesh_db_get_token(uint8_t token[8])
> {
> if (!cfg || !cfg->jcfg)
> diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
> index 1f9e4e3d3..89c644400 100644
> --- a/tools/mesh/mesh-db.h
> +++ b/tools/mesh/mesh-db.h
> @@ -38,11 +38,11 @@ bool mesh_db_get_addr_range(uint16_t *low, uint16_t *high);
> bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
> uint16_t net_idx);
> bool mesh_db_del_node(uint16_t unicast);
> -bool mesh_db_node_set_composition(uint16_t unicast, uint16_t cid, uint16_t pid,
> - uint16_t vid, uint16_t crpl,
> - struct mesh_config_modes modes,
> - struct l_queue *elements);
> -
> +bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data,
> + uint16_t len);
> +bool mesh_db_add_provisioner(const char *name, uint8_t uuid[16],
> + uint16_t unicast_low, uint16_t unicast_high,
> + uint16_t group_low, uint16_t group_high);
> bool mesh_db_node_set_net_transmit(uint16_t unicast, uint8_t cnt,
> uint16_t interval);
> bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx);
> diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c
> index 24bc59129..344de798b 100644
> --- a/tools/mesh/remote.c
> +++ b/tools/mesh/remote.c
> @@ -35,12 +35,14 @@ struct remote_node {
> uint16_t unicast;
> struct l_queue *net_keys;
> struct l_queue *app_keys;
> + struct l_queue **els;
> uint8_t uuid[16];
> uint8_t num_ele;
> };
>
> static struct l_queue *nodes;
>
> +
> static bool key_present(struct l_queue *keys, uint16_t app_idx)
> {
> const struct l_queue_entry *l;
> @@ -55,6 +57,26 @@ static bool key_present(struct l_queue *keys, uint16_t app_idx)
> return false;
> }
>
> +static int compare_mod_id(const void *a, const void *b, void *user_data)
> +{
> + uint32_t id1 = L_PTR_TO_UINT(a);
> + uint32_t id2 = L_PTR_TO_UINT(b);
> +
> + if (id1 >= VENDOR_ID_MASK)
> + id1 &= ~VENDOR_ID_MASK;
> +
> + if (id2 >= VENDOR_ID_MASK)
> + id2 &= ~VENDOR_ID_MASK;
> +
> + if (id1 < id2)
> + return -1;
> +
> + if (id1 > id2)
> + return 1;
> +
> + return 0;
> +}
> +
> static int compare_unicast(const void *a, const void *b, void *user_data)
> {
> const struct remote_node *a_rmt = a;
> @@ -92,7 +114,7 @@ static bool match_bound_key(const void *a, const void *b)
> uint8_t remote_del_node(uint16_t unicast)
> {
> struct remote_node *rmt;
> - uint8_t num_ele;
> + uint8_t num_ele, i;
>
> rmt = l_queue_remove_if(nodes, match_node_addr, L_UINT_TO_PTR(unicast));
> if (!rmt)
> @@ -100,8 +122,13 @@ uint8_t remote_del_node(uint16_t unicast)
>
> num_ele = rmt->num_ele;
>
> - l_queue_destroy(rmt->net_keys, NULL);
> - l_queue_destroy(rmt->app_keys, NULL);
> + for (i = 0; i < num_ele; ++i)
> + l_queue_destroy(rmt->els[i], NULL);
> +
> + l_free(rmt->els);
> +
> + l_queue_destroy(rmt->net_keys, l_free);
> + l_queue_destroy(rmt->app_keys, l_free);
> l_free(rmt);
>
> mesh_db_del_node(unicast);
> @@ -126,6 +153,8 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
>
> l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
>
> + rmt->els = l_new(struct l_queue *, ele_cnt);
> +
> if (!nodes)
> nodes = l_queue_new();
>
> @@ -133,6 +162,30 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
> return true;
> }
>
> +bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
> + bool vendor)
> +{
> + struct remote_node *rmt;
> +
> + rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(unicast));
> + if (!rmt)
> + return false;
> +
> + if (ele_idx >= rmt->num_ele)
> + return false;
> +
> + if (!rmt->els[ele_idx])
> + rmt->els[ele_idx] = l_queue_new();
> +
> + if (!vendor)
> + mod_id = VENDOR_ID_MASK | mod_id;
> +
> + l_queue_insert(rmt->els[ele_idx], L_UINT_TO_PTR(mod_id),
> + compare_mod_id, NULL);
> +
> + return true;
> +}
> +
> bool remote_add_net_key(uint16_t addr, uint16_t net_idx)
> {
> struct remote_node *rmt;
> @@ -224,9 +277,35 @@ static void print_key(void *key, void *user_data)
> bt_shell_printf("%u (0x%3.3x), ", idx, idx);
> }
>
> +static void print_model(void *model, void *user_data)
> +{
> + uint32_t mod_id = L_PTR_TO_UINT(model);
> +
> + if (mod_id >= VENDOR_ID_MASK) {
> + mod_id &= ~VENDOR_ID_MASK;
> + bt_shell_printf("\t\t\t" COLOR_GREEN "SIG model: %4.4x\n"
> + COLOR_OFF, mod_id);
> + return;
> + }
> +
> + bt_shell_printf("\t\t\t" COLOR_GREEN "Vendor model: %8.8x\n"
> + COLOR_OFF, mod_id);
> +
> +}
> +
> +static void print_element(struct l_queue *mods, int idx)
> +{
> + if (!mods)
> + return;
> +
> + bt_shell_printf("\t\t" COLOR_GREEN "element %u:\n" COLOR_OFF, idx);
> + l_queue_foreach(mods, print_model, NULL);
> +}
> +
> static void print_node(void *rmt, void *user_data)
> {
> struct remote_node *node = rmt;
> + int i;
> char *str;
>
> bt_shell_printf(COLOR_YELLOW "Mesh node:\n" COLOR_OFF);
> @@ -235,8 +314,6 @@ static void print_node(void *rmt, void *user_data)
> l_free(str);
> bt_shell_printf("\t" COLOR_GREEN "primary = %4.4x\n" COLOR_OFF,
> node->unicast);
> - bt_shell_printf("\t" COLOR_GREEN "elements = %u\n" COLOR_OFF,
> - node->num_ele);
> bt_shell_printf("\t" COLOR_GREEN "net_keys = ");
> l_queue_foreach(node->net_keys, print_key, NULL);
> bt_shell_printf("\n" COLOR_OFF);
> @@ -246,6 +323,12 @@ static void print_node(void *rmt, void *user_data)
> l_queue_foreach(node->app_keys, print_key, NULL);
> bt_shell_printf("\n" COLOR_OFF);
> }
> +
> + bt_shell_printf("\t" COLOR_GREEN "elements (%u):\n" COLOR_OFF,
> + node->num_ele);
> +
> + for (i = 0; i < node->num_ele; ++i)
> + print_element(node->els[i], i);
> }
>
> void remote_print_node(uint16_t addr)
> diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h
> index 63382ed90..33398c8bd 100644
> --- a/tools/mesh/remote.h
> +++ b/tools/mesh/remote.h
> @@ -20,6 +20,8 @@
> bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
> uint8_t ele_cnt, uint16_t net_idx);
> uint8_t remote_del_node(uint16_t unicast);
> +bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
> + bool vendor);
> uint16_t remote_get_next_unicast(uint16_t low, uint16_t high, uint8_t ele_cnt);
> bool remote_add_net_key(uint16_t addr, uint16_t net_idx);
> bool remote_del_net_key(uint16_t addr, uint16_t net_idx);