Message ID | 20200507191702.13563-1-inga.stotland@intel.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [BlueZ] tools/mesh-cfgclient: Save node's composition in config | expand |
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);
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);