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