2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 00/20] Mesh Configuration Database

This patch set (I apologize for its size, but this cannot be helped)
implements support for the newly published Mesh Configuration Database
Profile.

The changes are mostly contained to tools/mesh-cfgclient.c and tools/mesh
subdirectory. The only exception is the introduction of a new D-Bus mesh
API method ExportKeys() on org.bluez.mesh.Management1 interface.

The new functionality allows to export a snapshot of mesh state
from the point of view of mesh provisioner/configuration manager in
a standard format that can be used for to transferring the "ownership"
of the mesh configuration to another provisioner/configuration manager.

The changes break backwards compatibility with for the previous
versions of config-db.json that were generated when using
mesh-cfgclient tool. This can be amended by manually correcting the
field names and property values.

Inga Stotland (20):
tools/mesh-cfgclient: Save provisioner info
tools/mesh-cfgclient: Add timestamp to config database
tools/mesh-cfgclient: Update stored NetKey and AppKey
tools/mesh-cfgclient: Keep track of updated keys
tools/mesh: Add new info to stored remote nodes
tools/mesh-cfgclient: Overwrite config values when adding new ones
tools/mesh-cfgclient: Store remote node's model bindings
tools/mesh-cfgclient: Store remote node's model subs
tools/mesh-cfgclient: Disallow model commands w/o composition
tools/mesh-cfgclient: Store remote's model publication info
tools/mesh-cfgclient: Check the result of config save
tools/mesh-cfgclient: Rename mesh-db APIs for consistency
tools/mesh-cfgclient: Save remote node feature setting
tools/mesh-cfgclient: Store remote's heartbeat sub/pub
tools/mesh-cfgclient: Add group parent address for DB compliance
doc/mesh-api: Add ExportKeys call
mesh: Implement ExportKeys() method
tools/mesh-cfgclient: Store UUIDs in standard format
tools/mesh-cfgclient: Excluded addresses property
tools/mesh-cfgclient: Export configuration database

doc/mesh-api.txt | 56 ++
mesh/keyring.c | 286 ++++++++-
mesh/keyring.h | 2 +
mesh/manager.c | 35 ++
tools/mesh-cfgclient.c | 212 ++++++-
tools/mesh/cfgcli.c | 284 ++++++---
tools/mesh/keys.c | 4 +-
tools/mesh/mesh-db.c | 1260 +++++++++++++++++++++++++++++++++++++---
tools/mesh/mesh-db.h | 66 ++-
tools/mesh/model.h | 13 +-
tools/mesh/remote.c | 205 +++++--
tools/mesh/remote.h | 11 +-
12 files changed, 2206 insertions(+), 228 deletions(-)

--
2.31.1


2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 03/20] tools/mesh-cfgclient: Update stored NetKey and AppKey

NetKeys:
- Record additional properties: "name", "minSecurity", "timestamp"

AppKeys:
- Record additional property: "name"
---
tools/mesh/mesh-db.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index d42587da8..5b3c4b2f7 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -517,6 +517,7 @@ static void load_remotes(json_object *jcfg)
static bool add_app_key(json_object *jobj, uint16_t net_idx, uint16_t app_idx)
{
json_object *jkey, *jarray;
+ char buf[12];

json_object_object_get_ex(jobj, "appKeys", &jarray);
if (!jarray || json_object_get_type(jarray) != json_type_array)
@@ -524,6 +525,11 @@ static bool add_app_key(json_object *jobj, uint16_t net_idx, uint16_t app_idx)

jkey = json_object_new_object();

+ snprintf(buf, 12, "AppKey %4.4x", app_idx);
+
+ if (!add_string(jkey, "name", buf))
+ goto fail;
+
if (!write_int(jkey, "boundNetKey", (int)net_idx))
goto fail;

@@ -721,6 +727,7 @@ static bool load_keys(json_object *jobj)
bool mesh_db_net_key_add(uint16_t net_idx)
{
json_object *jkey, *jarray;
+ char buf[12];

if (!cfg || !cfg->jcfg)
return false;
@@ -734,12 +741,20 @@ bool mesh_db_net_key_add(uint16_t net_idx)

jkey = json_object_new_object();

+ snprintf(buf, 12, "Subnet %4.4x", net_idx);
+
+ if (!add_string(jkey, "name", buf))
+ goto fail;
+
if (!write_int(jkey, "index", net_idx))
goto fail;

if (!write_int(jkey, "phase", KEY_REFRESH_PHASE_NONE))
goto fail;

+ if (!add_string(jkey, "minSecurity", "secure"))
+ goto fail;
+
if (!set_timestamp(jkey))
goto fail;

--
2.31.1

2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 01/20] tools/mesh-cfgclient: Save provisioner info

This adds "provisioners" property to the config database.
The property includes the provisioner's name, UUID of the provisioner
device (corresponds to the local node), allocated unicast, group and
scene ranges.
The current implementation limitations:
- only one provisioner in the mesh network is supported,
- the unicast range is assumed to be contiguous,
- the group range is assumed to be contiguous,
- no support for scenes (empty array).
---
tools/mesh-cfgclient.c | 5 +-
tools/mesh/mesh-db.c | 110 ++++++++++++++++++++++++++++++++++++-----
tools/mesh/mesh-db.h | 1 -
3 files changed, 103 insertions(+), 13 deletions(-)

diff --git a/tools/mesh-cfgclient.c b/tools/mesh-cfgclient.c
index 70553c95c..62dcecb2f 100644
--- a/tools/mesh-cfgclient.c
+++ b/tools/mesh-cfgclient.c
@@ -1823,13 +1823,16 @@ static struct l_dbus_message *join_complete(struct l_dbus *dbus,
return l_dbus_message_new_error(message, dbus_err_fail, NULL);
}

- mesh_db_set_addr_range(low_addr, high_addr);
keys_add_net_key(PRIMARY_NET_IDX);
mesh_db_net_key_add(PRIMARY_NET_IDX);

remote_add_node(app.uuid, 0x0001, 1, PRIMARY_NET_IDX);
mesh_db_add_node(app.uuid, 0x0001, 1, PRIMARY_NET_IDX);

+ mesh_db_add_provisioner("BlueZ mesh-cfgclient", app.uuid,
+ low_addr, high_addr,
+ GROUP_ADDRESS_LOW, GROUP_ADDRESS_HIGH);
+
l_idle_oneshot(attach_node, NULL, NULL);

return l_dbus_message_new_method_return(message);
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 034d7be2b..50fbc18cb 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -245,7 +245,7 @@ static json_object *get_node_by_uuid(json_object *jcfg, uint8_t uuid[16])
const char *str;

jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "uuid", &jval))
+ if (!json_object_object_get_ex(jentry, "UUID", &jval))
return NULL;

str = json_object_get_string(jval);
@@ -429,7 +429,7 @@ static void load_remotes(json_object *jcfg)
if (!jnode)
continue;

- if (!json_object_object_get_ex(jnode, "uuid", &jval))
+ if (!json_object_object_get_ex(jnode, "UUID", &jval))
continue;

str = json_object_get_string(jval);
@@ -931,7 +931,7 @@ bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
if (!jnode)
return false;

- if (!add_u8_16(jnode, "uuid", uuid))
+ if (!add_u8_16(jnode, "UUID", uuid))
goto fail;

jelements = init_elements(num_els);
@@ -1188,14 +1188,32 @@ bool mesh_db_get_token(uint8_t token[8])

bool mesh_db_get_addr_range(uint16_t *low, uint16_t *high)
{
- json_object *jlow, *jhigh;
+ json_object *jprov, *jarray, *jobj, *jlow, *jhigh;
const char *str;

if (!cfg || !cfg->jcfg)
return false;

- if (!json_object_object_get_ex(cfg->jcfg, "low", &jlow) ||
- !json_object_object_get_ex(cfg->jcfg, "high", &jhigh))
+ jarray = json_object_object_get(cfg->jcfg, "provisioniers");
+
+ if (!jarray || json_object_get_type(jarray) != json_type_array)
+ return false;
+
+ /* Assumption: only one provisioner in the system */
+ jprov = json_object_array_get_idx(jarray, 0);
+ if (!jprov)
+ return false;
+
+ if (!json_object_object_get_ex(jprov, "allocatedUnicastRange", &jarray))
+ return false;
+
+ /* Assumption: only one contiguous range is specified */
+ jobj = json_object_array_get_idx(jarray, 0);
+ if (!jobj)
+ return false;
+
+ if (!json_object_object_get_ex(jobj, "lowAddress", &jlow) ||
+ !json_object_object_get_ex(jobj, "highAddress", &jhigh))
return false;

str = json_object_get_string(jlow);
@@ -1209,18 +1227,82 @@ bool mesh_db_get_addr_range(uint16_t *low, uint16_t *high)
return true;
}

-bool mesh_db_set_addr_range(uint16_t low, uint16_t high)
+/*
+ * This is a simplistic implementation onf allocated range, where
+ * the range is one contiguous chunk of the address space.
+ */
+static bool add_range(json_object *jobj, const char *keyword, uint16_t low,
+ uint16_t high)
{
+ json_object *jarray, *jrange;
+
+ jrange = json_object_new_object();
+
+ if (!write_uint16_hex(jrange, "lowAddress", low))
+ goto fail;
+
+ if (!write_uint16_hex(jrange, "highAddress", high))
+ goto fail;
+
+ jarray = json_object_new_array();
+ if (!jarray)
+ goto fail;
+
+ json_object_array_add(jarray, jrange);
+ json_object_object_add(jobj, keyword, jarray);
+
+ return true;
+
+fail:
+ json_object_put(jrange);
+
+ return false;
+}
+
+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)
+{
+ json_object *jprovs, *jprov, *jscenes;
+
if (!cfg || !cfg->jcfg)
return false;

- if (!write_uint16_hex(cfg->jcfg, "low", low))
+ if (!json_object_object_get_ex(cfg->jcfg, "provisioners", &jprovs))
return false;

- if (!write_uint16_hex(cfg->jcfg, "high", high))
+ if (!jprovs || json_object_get_type(jprovs) != json_type_array)
return false;

+ jprov = json_object_new_object();
+
+ if (!add_string(jprov, "provisionerName", name))
+ goto fail;
+
+ if (!add_u8_16(jprov, "UUID", uuid))
+ goto fail;
+
+ if (!add_range(jprov, "allocatedUnicastRange", unicast_low,
+ unicast_high))
+ goto fail;
+
+ if (!add_range(jprov, "allocatedGroupRange", group_low, group_high))
+ goto fail;
+
+ /* Scenes are not supported. Just add an empty array */
+ jscenes = json_object_new_array();
+ if (!jscenes)
+ goto fail;
+
+ json_object_object_add(jprov, "allocatedSceneRange", jscenes);
+
+ json_object_array_add(jprovs, jprov);
+
return save_config();
+
+fail:
+ json_object_put(jprov);
+ return false;
}

uint32_t mesh_db_get_iv_index(void)
@@ -1408,10 +1490,10 @@ bool mesh_db_create(const char *fname, const uint8_t token[8],

l_uuid_v4(uuid);

- if (!add_u8_16(jcfg, "uuid", uuid))
+ if (!add_u8_16(jcfg, "meshUUID", uuid))
goto fail;

- if (mesh_name && !add_string(jcfg, "name", mesh_name))
+ if (mesh_name && !add_string(jcfg, "meshName", mesh_name))
goto fail;

jarray = json_object_new_array();
@@ -1420,6 +1502,12 @@ bool mesh_db_create(const char *fname, const uint8_t token[8],

json_object_object_add(jcfg, "nodes", jarray);

+ jarray = json_object_new_array();
+ if (!jarray)
+ goto fail;
+
+ json_object_object_add(jcfg, "provisioners", jarray);
+
jarray = json_object_new_array();
if (!jarray)
goto fail;
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index 22518c618..efd579553 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -24,7 +24,6 @@ bool mesh_db_net_key_del(uint16_t idx);
bool mesh_db_net_key_phase_set(uint16_t net_idx, uint8_t phase);
bool mesh_db_app_key_add(uint16_t net_idx, uint16_t app_idx);
bool mesh_db_app_key_del(uint16_t app_idx);
-bool mesh_db_set_addr_range(uint16_t low, uint16_t high);
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,
--
2.31.1

2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 09/20] tools/mesh-cfgclient: Disallow model commands w/o composition

If remote node's composition hasn't been acquired, disallow commands
that change model state (that is, bindings, subscriptions, publications).
Prompt to run "get-composition" command first.
---
tools/mesh/cfgcli.c | 26 ++++++++++++++++++++++++++
tools/mesh/mesh-db.c | 10 ++++++++--
tools/mesh/remote.c | 23 +++++++++++++++++++++++
tools/mesh/remote.h | 2 ++
4 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index 71bf2e706..19a42947e 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -434,6 +434,9 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

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

case OP_APPKEY_STATUS:
@@ -1233,6 +1236,12 @@ static void cmd_bind(uint32_t opcode, int argc, char *argv[])
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}

+ if (!remote_has_composition(target)) {
+ bt_shell_printf("Node composition is unknown\n");
+ bt_shell_printf("Call \"get-composition\" first\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
n = mesh_opcode_set(opcode, msg);

put_le16(parms[0], msg + n);
@@ -1429,6 +1438,12 @@ static void cmd_pub_set(int argc, char *argv[])
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}

+ if (!remote_has_composition(target)) {
+ bt_shell_printf("Node composition is unknown\n");
+ bt_shell_printf("Call \"get-composition\" first\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
pub_addr = parms[1];

grp = l_queue_find(groups, match_group_addr, L_UINT_TO_PTR(pub_addr));
@@ -1523,6 +1538,12 @@ static void subscription_cmd(int argc, char *argv[], uint32_t opcode)
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}

+ if (!remote_has_composition(target)) {
+ bt_shell_printf("Node composition is unknown\n");
+ bt_shell_printf("Call \"get-composition\" first\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
sub_addr = parms[1];

grp = l_queue_find(groups, match_group_addr, L_UINT_TO_PTR(sub_addr));
@@ -1722,6 +1743,11 @@ static void cmd_hb_sub_set(int argc, char *argv[])
uint8_t msg[32];
uint32_t parm_cnt;

+ if (IS_UNASSIGNED(target)) {
+ bt_shell_printf("Destination not set\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_SUB_SET, msg);

parm_cnt = read_input_parameters(argc, argv);
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 1b03e2d90..8445d33f4 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -574,11 +574,17 @@ static void load_remotes(json_object *jcfg)
remote_update_app_key(unicast, key_idx, updated, false);
}

- load_composition(jnode, unicast);
+ if (!load_composition(jnode, unicast))
+ continue;

- node_count++;
+ /* If "crpl" is present, composition's is available */
+ jval = NULL;
+ if (json_object_object_get_ex(jnode, "crpl", &jval) && jval)
+ remote_set_composition(unicast, true);

/* TODO: Add the rest of the configuration */
+
+ node_count++;
}

if (node_count != sz)
diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c
index 5f598cb8b..2f8493f8a 100644
--- a/tools/mesh/remote.c
+++ b/tools/mesh/remote.c
@@ -35,6 +35,7 @@ struct remote_node {
struct l_queue *net_keys;
struct l_queue *app_keys;
struct l_queue **els;
+ bool comp;
uint8_t uuid[16];
uint8_t num_ele;
};
@@ -192,6 +193,28 @@ bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
return true;
}

+void remote_set_composition(uint16_t addr, bool comp)
+{
+ struct remote_node *rmt;
+
+ rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+ if (!rmt)
+ return;
+
+ rmt->comp = comp;
+}
+
+bool remote_has_composition(uint16_t addr)
+{
+ struct remote_node *rmt;
+
+ rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+ if (!rmt)
+ return false;
+
+ return rmt->comp;
+}
+
bool remote_add_net_key(uint16_t addr, uint16_t net_idx, bool save)
{
struct remote_node *rmt;
diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h
index 74747689a..2fb0d83ce 100644
--- a/tools/mesh/remote.h
+++ b/tools/mesh/remote.h
@@ -25,6 +25,8 @@ bool remote_del_app_key(uint16_t addr, uint16_t app_idx);
bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
bool save);
void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx);
+void remote_set_composition(uint16_t addr, bool comp);
+bool remote_has_composition(uint16_t addr);
uint16_t remote_get_subnet_idx(uint16_t addr);
void remote_print_node(uint16_t addr);
void remote_print_all(void);
--
2.31.1

2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 08/20] tools/mesh-cfgclient: Store remote node's model subs

Update remote node's model subscriptions after a successful completion
of "sub-add", "sub-del", "sub-wrt" and "sub-del_all" commands.
---
tools/mesh/cfgcli.c | 68 +++++++++++++----
tools/mesh/mesh-db.c | 178 +++++++++++++++++++++++++++++++++++++++++++
tools/mesh/mesh-db.h | 17 +++++
3 files changed, 250 insertions(+), 13 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index c3241a9b7..71bf2e706 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -387,14 +387,21 @@ static void print_appkey_list(uint16_t len, uint8_t *data)
}
}

+static bool match_group_addr(const void *a, const void *b)
+{
+ const struct mesh_group *grp = a;
+ uint16_t addr = L_PTR_TO_UINT(b);
+
+ return grp->addr == addr;
+}
+
static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
uint16_t len)
{
- uint32_t opcode;
+ uint32_t opcode, mod_id;
const struct cfg_cmd *cmd;
- uint16_t app_idx, net_idx, addr;
- uint16_t ele_addr;
- uint32_t mod_id;
+ uint16_t app_idx, net_idx, addr, ele_addr;
+ struct mesh_group *grp;
struct model_pub pub;
int n;
struct pending_req *req;
@@ -664,10 +671,53 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
addr = get_le16(data + 3);
bt_shell_printf("Element Addr\t%4.4x\n", ele_addr);

- print_mod_id(data + 5, len == 9, "");
+ mod_id = print_mod_id(data + 5, len == 9, "");

bt_shell_printf("Subscr Addr\t%4.4x\n", addr);

+ grp = l_queue_find(groups, match_group_addr,
+ L_UINT_TO_PTR(addr));
+
+ if (data[0] != MESH_STATUS_SUCCESS || !cmd)
+ return true;
+
+ switch (cmd->opcode) {
+ default:
+ return true;
+ case OP_CONFIG_MODEL_SUB_ADD:
+ mesh_db_node_model_add_sub(src, ele_addr, len == 9,
+ mod_id, addr);
+ break;
+ case OP_CONFIG_MODEL_SUB_DELETE:
+ mesh_db_node_model_del_sub(src, ele_addr, len == 9,
+ mod_id, addr);
+ break;
+ case OP_CONFIG_MODEL_SUB_OVERWRITE:
+ mesh_db_node_model_overwrt_sub(src, ele_addr, len == 9,
+ mod_id, addr);
+ break;
+ case OP_CONFIG_MODEL_SUB_DELETE_ALL:
+ mesh_db_node_model_del_sub_all(src, ele_addr, len == 9,
+ mod_id);
+ break;
+ case OP_CONFIG_MODEL_SUB_VIRT_ADD:
+ if (grp)
+ mesh_db_node_model_add_sub_virt(src, ele_addr,
+ len == 9, mod_id, grp->label);
+ break;
+ case OP_CONFIG_MODEL_SUB_VIRT_DELETE:
+ if (grp)
+ mesh_db_node_model_del_sub_virt(src, ele_addr,
+ len == 9, mod_id, grp->label);
+ break;
+ case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE:
+ if (grp)
+ mesh_db_node_model_overwrt_sub_virt(src,
+ ele_addr, len == 9,
+ mod_id, grp->label);
+ break;
+ }
+
break;

/* Per Mesh Profile 4.3.2.27 */
@@ -820,14 +870,6 @@ static uint32_t read_input_parameters(int argc, char *argv[])
return i;
}

-static bool match_group_addr(const void *a, const void *b)
-{
- const struct mesh_group *grp = a;
- uint16_t addr = L_PTR_TO_UINT(b);
-
- return grp->addr == addr;
-}
-
static int compare_group_addr(const void *a, const void *b, void *user_data)
{
const struct mesh_group *grp0 = a;
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index da5817acf..1b03e2d90 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -814,6 +814,178 @@ bool mesh_db_node_model_unbind(uint16_t unicast, uint16_t ele_addr, bool vendor,
(int) app_idx, "bind", false);
}

+static void jarray_string_del(json_object *jarray, const char *str, size_t len)
+{
+ int i, sz = json_object_array_length(jarray);
+
+ for (i = 0; i < sz; ++i) {
+ json_object *jentry;
+ char *str_entry;
+
+ jentry = json_object_array_get_idx(jarray, i);
+ str_entry = (char *)json_object_get_string(jentry);
+
+ if (str_entry && (strlen(str_entry) == len) &&
+ !strncmp(str, str_entry, len)) {
+ json_object_array_del_idx(jarray, i, 1);
+ return;
+ }
+ }
+}
+
+static bool update_model_string_array(uint16_t unicast, uint16_t ele_addr,
+ bool vendor, uint32_t mod_id,
+ const char *str, uint32_t len,
+ const char *keyword, bool add)
+{
+ json_object *jarray, *jmod, *jstring;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jmod = get_model(unicast, ele_addr, mod_id, vendor);
+ if (!jmod)
+ return false;
+
+ if (!json_object_object_get_ex(jmod, keyword, &jarray))
+ return false;
+
+ if (!jarray || json_object_get_type(jarray) != json_type_array)
+ return false;
+
+ jarray_string_del(jarray, str, len);
+
+ if (!add)
+ return true;
+
+ jstring = json_object_new_string(str);
+ if (!jstring)
+ return false;
+
+ json_object_array_add(jarray, jstring);
+
+ return save_config();
+}
+
+bool mesh_db_node_model_add_sub(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, uint16_t addr)
+{
+ char buf[5];
+
+ snprintf(buf, 5, "%4.4x", addr);
+
+ return update_model_string_array(unicast, ele, vendor, mod_id, buf, 4,
+ "subscribe", true);
+}
+
+bool mesh_db_node_model_del_sub(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, uint16_t addr)
+{
+ char buf[5];
+
+ snprintf(buf, 5, "%4.4x", addr);
+
+ return update_model_string_array(unicast, ele, vendor, mod_id, buf, 4,
+ "subscribe", false);
+}
+
+bool mesh_db_node_model_add_sub_virt(uint16_t unicast, uint16_t ele,
+ bool vendor, uint32_t mod_id,
+ uint8_t *label)
+{
+ char buf[33];
+
+ hex2str(label, 16, buf, sizeof(buf));
+
+ return update_model_string_array(unicast, ele, vendor, mod_id, buf, 32,
+ "subscribe", true);
+
+}
+
+bool mesh_db_node_model_del_sub_virt(uint16_t unicast, uint16_t ele,
+ bool vendor, uint32_t mod_id,
+ uint8_t *label)
+{
+ char buf[33];
+
+ hex2str(label, 16, buf, sizeof(buf));
+
+ return update_model_string_array(unicast, ele, vendor, mod_id, buf, 32,
+ "subscribe", false);
+}
+
+static json_object *delete_subs(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id)
+{
+ json_object *jarray, *jmod;
+
+ if (!cfg || !cfg->jcfg)
+ return NULL;
+
+ jmod = get_model(unicast, ele, mod_id, vendor);
+ if (!jmod)
+ return NULL;
+
+ json_object_object_del(jmod, "subscribe");
+
+ jarray = json_object_new_array();
+ if (!jarray)
+ return NULL;
+
+ json_object_object_add(jmod, "subscribe", jarray);
+
+ return jarray;
+}
+
+bool mesh_db_node_model_del_sub_all(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id)
+{
+
+ if (!delete_subs(unicast, ele, vendor, mod_id))
+ return false;
+
+ return save_config();
+}
+
+static bool sub_overwrite(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, char *buf)
+{
+ json_object *jarray, *jstring;
+
+ jarray = delete_subs(unicast, ele, vendor, mod_id);
+ if (!jarray)
+ return false;
+
+ jstring = json_object_new_string(buf);
+ if (!jstring)
+ return false;
+
+ json_object_array_add(jarray, jstring);
+
+ return save_config();
+}
+
+bool mesh_db_node_model_overwrt_sub(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, uint16_t addr)
+{
+ char buf[5];
+
+ snprintf(buf, 5, "%4.4x", addr);
+
+ return sub_overwrite(unicast, ele, vendor, mod_id, buf);
+}
+
+bool mesh_db_node_model_overwrt_sub_virt(uint16_t unicast, uint16_t ele,
+ bool vendor, uint32_t mod_id,
+ uint8_t *label)
+{
+ char buf[33];
+
+ hex2str(label, 16, buf, sizeof(buf));
+
+ return sub_overwrite(unicast, ele, vendor, mod_id, buf);
+}
+
static void jarray_key_del(json_object *jarray, int16_t idx)
{
int i, sz = json_object_array_length(jarray);
@@ -1340,6 +1512,9 @@ static json_object *init_model(uint16_t mod_id)
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;
}

@@ -1357,6 +1532,9 @@ static json_object *init_vendor_model(uint32_t mod_id)
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;
}

diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index c3ee81457..384376cbd 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -48,6 +48,23 @@ bool mesh_db_node_model_bind(uint16_t unicast, uint16_t ele_addr, bool vendor,
uint32_t mod_id, uint16_t app_idx);
bool mesh_db_node_model_unbind(uint16_t unicast, uint16_t ele_addr, bool vendor,
uint32_t mod_id, uint16_t app_idx);
+bool mesh_db_node_model_add_sub(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, uint16_t addr);
+bool mesh_db_node_model_del_sub(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, uint16_t addr);
+bool mesh_db_node_model_overwrt_sub(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id, uint16_t addr);
+bool mesh_db_node_model_add_sub_virt(uint16_t unicast, uint16_t ele,
+ bool vendor, uint32_t mod_id,
+ uint8_t *label);
+bool mesh_db_node_model_del_sub_virt(uint16_t unicast, uint16_t ele,
+ bool vendor, uint32_t mod_id,
+ uint8_t *label);
+bool mesh_db_node_model_overwrt_sub_virt(uint16_t unicast, uint16_t ele,
+ bool vendor, uint32_t mod_id,
+ uint8_t *label);
+bool mesh_db_node_model_del_sub_all(uint16_t unicast, uint16_t ele, bool vendor,
+ uint32_t mod_id);
struct l_queue *mesh_db_load_groups(void);
bool mesh_db_add_group(struct mesh_group *grp);
bool mesh_db_add_rejected_addr(uint16_t unicast, uint32_t iv_index);
--
2.31.1

2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 11/20] tools/mesh-cfgclient: Check the result of config save

After successful completion of configuration commands that change
configuration state of network, the updates are expected to be
recorded in configuration file. If for the results are not saved,
print a warning message.
---
tools/mesh/cfgcli.c | 119 +++++++++++++++++++++++---------------------
tools/mesh/remote.c | 10 ++--
tools/mesh/remote.h | 2 +-
3 files changed, 70 insertions(+), 61 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index 2766d47ca..9399228c8 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -405,6 +405,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
struct model_pub pub;
int n;
struct pending_req *req;
+ bool saved = false;

if (mesh_opcode_get(data, len, &opcode, &n)) {
len -= n;
@@ -428,20 +429,19 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

case OP_DEV_COMP_STATUS:
if (len < MIN_COMPOSITION_LEN)
- break;
+ return true;

print_composition(data, len);

- if (!mesh_db_node_set_composition(src, data, len))
- bt_shell_printf("Failed to save node composition!\n");
- else
+ saved = mesh_db_node_set_composition(src, data, len);
+ if (saved)
remote_set_composition(src, true);

break;

case OP_APPKEY_STATUS:
if (len != 4)
- break;
+ return true;

bt_shell_printf("Node %4.4x AppKey status %s\n", src,
mesh_status_str(data[0]));
@@ -452,23 +452,22 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("AppKey\t%u (0x%3.3x)\n", app_idx, app_idx);

if (data[0] != MESH_STATUS_SUCCESS)
- break;
+ return true;

if (!cmd)
- break;
+ return true;

if (cmd->opcode == OP_APPKEY_ADD)
- remote_add_app_key(src, app_idx, true);
+ saved = remote_add_app_key(src, app_idx, true);
else if (cmd->opcode == OP_APPKEY_DELETE)
- remote_del_app_key(src, app_idx);
+ saved = remote_del_app_key(src, app_idx);
else if (cmd->opcode == OP_APPKEY_UPDATE)
- remote_update_app_key(src, app_idx, true, true);
-
+ saved = remote_update_app_key(src, app_idx, true, true);
break;

case OP_APPKEY_LIST:
if (len < 3)
- break;
+ return true;

bt_shell_printf("AppKey List (node %4.4x) Status %s\n",
src, mesh_status_str(data[0]));
@@ -478,16 +477,16 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
len -= 3;

if (data[0] != MESH_STATUS_SUCCESS)
- break;
+ return true;

data += 3;
print_appkey_list(len, data);

- break;
+ return true;

case OP_NETKEY_STATUS:
if (len != 3)
- break;
+ return true;

bt_shell_printf("Node %4.4x NetKey status %s\n", src,
mesh_status_str(data[0]));
@@ -496,23 +495,23 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("\tNetKey %u (0x%3.3x)\n", net_idx, net_idx);

if (data[0] != MESH_STATUS_SUCCESS)
- break;
+ return true;

if (!cmd)
- break;
+ return true;

if (cmd->opcode == OP_NETKEY_ADD)
- remote_add_net_key(src, net_idx, true);
+ saved = remote_add_net_key(src, net_idx, true);
else if (cmd->opcode == OP_NETKEY_DELETE)
- remote_del_net_key(src, net_idx);
+ saved = remote_del_net_key(src, net_idx);
else if (cmd->opcode == OP_NETKEY_UPDATE)
- remote_update_net_key(src, net_idx, true, true);
+ saved = remote_update_net_key(src, net_idx, true, true);

break;

case OP_NETKEY_LIST:
if (len < 2)
- break;
+ return true;

bt_shell_printf("NetKey List (node %4.4x):\n", src);

@@ -530,11 +529,11 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("\t %u (0x%3.3x)\n", net_idx, net_idx);
}

- break;
+ return true;

case OP_CONFIG_KEY_REFRESH_PHASE_STATUS:
if (len != 4)
- break;
+ return true;

bt_shell_printf("Node %4.4x Key Refresh Phase status %s\n", src,
mesh_status_str(data[0]));
@@ -546,14 +545,16 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
if (data[0] != MESH_STATUS_SUCCESS)
return true;

- if (data[3] == KEY_REFRESH_PHASE_NONE)
- remote_finish_key_refresh(src, net_idx);
+ if (data[3] != KEY_REFRESH_PHASE_NONE)
+ return true;
+
+ saved = remote_finish_key_refresh(src, net_idx);

break;

case OP_MODEL_APP_STATUS:
if (len != 7 && len != 9)
- break;
+ return true;

bt_shell_printf("Node %4.4x: Model App status %s\n", src,
mesh_status_str(data[0]));
@@ -567,14 +568,14 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("AppIdx\t\t%u (0x%3.3x)\n ", app_idx, app_idx);

if (data[0] != MESH_STATUS_SUCCESS || !cmd)
- break;
+ return true;

if (cmd->opcode == OP_MODEL_APP_BIND)
- mesh_db_node_model_bind(src, addr, len == 9, mod_id,
- app_idx);
+ saved = mesh_db_node_model_bind(src, addr, len == 9,
+ mod_id, app_idx);
else
- mesh_db_node_model_unbind(src, addr, len == 9, mod_id,
- app_idx);
+ saved = mesh_db_node_model_unbind(src, addr, len == 9,
+ mod_id, app_idx);

break;

@@ -585,7 +586,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("NetIdx %4.4x, NodeIdState 0x%02x, status %s\n",
get_le16(data + 1), data[3],
mesh_status_str(data[0]));
- break;
+ return true;

case OP_CONFIG_BEACON_STATUS:
if (len != 1)
@@ -616,7 +617,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
return true;

bt_shell_printf("Node %4.4x Default TTL %d\n", src, data[0]);
- mesh_db_node_ttl_set(src, data[0]);
+ saved = mesh_db_node_ttl_set(src, data[0]);

break;

@@ -670,15 +671,18 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
if (IS_VIRTUAL(pub.u.addr)) {
grp = l_queue_find(groups, match_group_addr,
L_UINT_TO_PTR(pub.u.addr));
- if (!grp)
+ if (!grp) {
+ bt_shell_printf("Unknown virtual group\n");
return true;
+ }

memcpy(pub.u.label, grp->label, sizeof(pub.u.label));

}

- mesh_db_node_model_set_pub(src, ele_addr, len == 14, mod_id,
- &pub, IS_VIRTUAL(pub.u.addr));
+ saved = mesh_db_node_model_set_pub(src, ele_addr, len == 14,
+ mod_id, &pub,
+ IS_VIRTUAL(pub.u.addr));

break;

@@ -708,34 +712,36 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
default:
return true;
case OP_CONFIG_MODEL_SUB_ADD:
- mesh_db_node_model_add_sub(src, ele_addr, len == 9,
- mod_id, addr);
+ saved = mesh_db_node_model_add_sub(src, ele_addr,
+ len == 9, mod_id, addr);
break;
case OP_CONFIG_MODEL_SUB_DELETE:
- mesh_db_node_model_del_sub(src, ele_addr, len == 9,
- mod_id, addr);
+ saved = mesh_db_node_model_del_sub(src, ele_addr,
+ len == 9, mod_id, addr);
break;
case OP_CONFIG_MODEL_SUB_OVERWRITE:
- mesh_db_node_model_overwrt_sub(src, ele_addr, len == 9,
- mod_id, addr);
+ saved = mesh_db_node_model_overwrt_sub(src, ele_addr,
+ len == 9, mod_id, addr);
break;
case OP_CONFIG_MODEL_SUB_DELETE_ALL:
- mesh_db_node_model_del_sub_all(src, ele_addr, len == 9,
- mod_id);
+ saved = mesh_db_node_model_del_sub_all(src, ele_addr,
+ len == 9, mod_id);
break;
case OP_CONFIG_MODEL_SUB_VIRT_ADD:
if (grp)
- mesh_db_node_model_add_sub_virt(src, ele_addr,
- len == 9, mod_id, grp->label);
+ saved = mesh_db_node_model_add_sub_virt(src,
+ ele_addr, len == 9,
+ mod_id, grp->label);
break;
case OP_CONFIG_MODEL_SUB_VIRT_DELETE:
if (grp)
- mesh_db_node_model_del_sub_virt(src, ele_addr,
- len == 9, mod_id, grp->label);
+ saved = mesh_db_node_model_del_sub_virt(src,
+ ele_addr, len == 9,
+ mod_id, grp->label);
break;
case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE:
if (grp)
- mesh_db_node_model_overwrt_sub_virt(src,
+ saved = mesh_db_node_model_overwrt_sub_virt(src,
ele_addr, len == 9,
mod_id, grp->label);
break;
@@ -749,14 +755,14 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
return true;

print_sub_list(src, false, data, len);
- break;
+ return true;

case OP_CONFIG_VEND_MODEL_SUB_LIST:
if (len < 7)
return true;

print_sub_list(src, true, data, len);
- break;
+ return true;

/* Per Mesh Profile 4.3.2.50 */
case OP_MODEL_APP_LIST:
@@ -772,8 +778,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
data += 5;
len -= 5;
print_appkey_list(len, data);
-
- break;
+ return true;

case OP_VEND_MODEL_APP_LIST:
if (len < 7)
@@ -791,8 +796,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
data += 7;
len -= 7;
print_appkey_list(len, data);
-
- break;
+ return true;

/* Per Mesh Profile 4.3.2.63 */
case OP_CONFIG_HEARTBEAT_PUB_STATUS:
@@ -842,7 +846,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("Node %4.4x is reset\n", src);
reset_remote_node(src);

- break;
+ return true;

/* Per Mesh Profile 4.3.2.57 */
case OP_CONFIG_FRIEND_STATUS:
@@ -854,6 +858,9 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
break;
}

+ if (!saved)
+ bt_shell_printf("Warning: Configuration not updated\n");
+
return true;
}

diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c
index 2f8493f8a..dd294fe4d 100644
--- a/tools/mesh/remote.c
+++ b/tools/mesh/remote.c
@@ -351,18 +351,19 @@ bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
return true;
}

-void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx)
+bool remote_finish_key_refresh(uint16_t addr, uint16_t net_idx)
{
struct remote_node *rmt;
struct remote_key *key;
const struct l_queue_entry *l;
+ bool res = true;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
if (!rmt)
- return;
+ return false;

if (!remote_update_net_key(addr, net_idx, false, true))
- return;
+ return false;

l = l_queue_get_entries(rmt->app_keys);

@@ -374,9 +375,10 @@ void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx)

key->updated = false;

- mesh_db_node_app_key_update(addr, key->idx, false);
+ res &= mesh_db_node_app_key_update(addr, key->idx, false);
}

+ return res;
}

uint16_t remote_get_subnet_idx(uint16_t addr)
diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h
index 2fb0d83ce..66457237e 100644
--- a/tools/mesh/remote.h
+++ b/tools/mesh/remote.h
@@ -24,7 +24,7 @@ bool remote_add_app_key(uint16_t addr, uint16_t app_idx, bool save);
bool remote_del_app_key(uint16_t addr, uint16_t app_idx);
bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
bool save);
-void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx);
+bool remote_finish_key_refresh(uint16_t addr, uint16_t net_idx);
void remote_set_composition(uint16_t addr, bool comp);
bool remote_has_composition(uint16_t addr);
uint16_t remote_get_subnet_idx(uint16_t addr);
--
2.31.1

2021-09-23 03:29:20

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 06/20] tools/mesh-cfgclient: Overwrite config values when adding new ones

This changes common utilities used in mesh-db.c to replace old values
by default whenever a new value is written.
---
tools/mesh/mesh-db.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index bf9344931..f0e0aeb71 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -54,6 +54,9 @@ static bool add_string(json_object *jobj, const char *desc, const char *str)
if (!jstring)
return false;

+ /* Overwrite old value if present */
+ json_object_object_del(jobj, desc);
+
json_object_object_add(jobj, desc, jstring);
return true;
}
@@ -69,8 +72,6 @@ static bool set_timestamp(json_object *jobj)

strftime(buf, 80, "%FT%TZ", tp);

- json_object_object_del(jobj, "timestamp");
-
return add_string(jobj, "timestamp", buf);
}

@@ -190,12 +191,13 @@ static bool write_int(json_object *jobj, const char *keyword, int val)
{
json_object *jval;

- json_object_object_del(jobj, keyword);
-
jval = json_object_new_int(val);
if (!jval)
return false;

+ /* Overwrite old value if present */
+ json_object_object_del(jobj, keyword);
+
json_object_object_add(jobj, keyword, jval);
return true;
}
@@ -222,12 +224,13 @@ static bool write_bool(json_object *jobj, const char *keyword, bool val)
{
json_object *jval;

- json_object_object_del(jobj, keyword);
-
jval = json_object_new_boolean(val);
if (!jval)
return false;

+ /* Overwrite old value if present */
+ json_object_object_del(jobj, keyword);
+
json_object_object_add(jobj, keyword, jval);
return true;
}
@@ -262,6 +265,9 @@ static bool write_uint16_hex(json_object *jobj, const char *desc,
if (!jstring)
return false;

+ /* Overwrite old value if present */
+ json_object_object_del(jobj, desc);
+
json_object_object_add(jobj, desc, jstring);
return true;
}
@@ -327,6 +333,9 @@ static bool add_u8_8(json_object *jobj, const char *desc,
if (!jstring)
return false;

+ /* Overwrite old value if present */
+ json_object_object_del(jobj, desc);
+
json_object_object_add(jobj, desc, jstring);
return true;
}
@@ -342,6 +351,9 @@ static bool add_u8_16(json_object *jobj, const char *desc,
if (!jstring)
return false;

+ /* Overwrite old value if present */
+ json_object_object_del(jobj, desc);
+
json_object_object_add(jobj, desc, jstring);
return true;
}
--
2.31.1

2021-09-23 03:29:33

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 13/20] tools/mesh-cfgclient: Save remote node feature setting

Save the information for remote node's relay, friend, proxy and
secure network beacon settings.
---
tools/mesh/cfgcli.c | 14 +++-
tools/mesh/mesh-db.c | 160 +++++++++++++++++++++++++++++++++++--------
tools/mesh/mesh-db.h | 5 ++
3 files changed, 151 insertions(+), 28 deletions(-)

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

bt_shell_printf("Node %4.4x: Config Beacon Status 0x%02x\n",
src, data[0]);
+
+ saved = mesh_db_node_set_beacon(src, data[0] != 0);
break;

case OP_CONFIG_RELAY_STATUS:
@@ -602,6 +604,10 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

bt_shell_printf("Node %4.4x: Relay 0x%02x, cnt %d, steps %d\n",
src, data[0], data[1] & 0x7, data[1] >> 3);
+
+ saved = mesh_db_node_set_relay(src, data[0], data[1] & 7,
+ ((data[1] >> 3) + 1) * 10);
+
break;

case OP_CONFIG_PROXY_STATUS:
@@ -610,6 +616,8 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

bt_shell_printf("Node %4.4x Proxy state 0x%02x\n",
src, data[0]);
+
+ saved = mesh_db_node_set_proxy(src, data[0]);
break;

case OP_CONFIG_DEFAULT_TTL_STATUS:
@@ -618,7 +626,6 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

bt_shell_printf("Node %4.4x Default TTL %d\n", src, data[0]);
saved = mesh_db_node_set_ttl(src, data[0]);
-
break;

case OP_CONFIG_MODEL_PUB_STATUS:
@@ -838,6 +845,9 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

bt_shell_printf("Node %4.4x: Net transmit cnt %d, steps %d\n",
src, data[0] & 7, data[0] >> 3);
+
+ saved = mesh_db_node_set_net_transmit(src, data[0] & 7,
+ ((data[0] >> 3) + 1) * 10);
break;

/* Per Mesh Profile 4.3.2.54 */
@@ -855,6 +865,8 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

bt_shell_printf("Node %4.4x Friend state 0x%02x\n",
src, data[0]);
+
+ saved = mesh_db_node_set_friend(src, data[0]);
break;
}

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 46efb81ea..3290c5b8e 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -137,12 +137,12 @@ static void release_config(void)
cfg = NULL;
}

-static json_object *get_node_by_unicast(uint16_t unicast)
+static json_object *get_node_by_unicast(json_object *jcfg, uint16_t unicast)
{
json_object *jarray;
int i, sz;

- if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jarray))
+ if (!json_object_object_get_ex(jcfg, "nodes", &jarray))
return NULL;

if (!jarray || json_object_get_type(jarray) != json_type_array)
@@ -655,7 +655,7 @@ bool mesh_db_node_set_ttl(uint16_t unicast, uint8_t ttl)
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -665,12 +665,135 @@ bool mesh_db_node_set_ttl(uint16_t unicast, uint8_t ttl)
return save_config();
}

+static bool add_transmit_info(json_object *jobj, int cnt, int interval,
+ const char *desc)
+{
+ json_object *jtxmt;
+
+ json_object_object_del(jobj, desc);
+ jtxmt = json_object_new_object();
+
+ if (!write_int(jtxmt, "count", cnt))
+ goto fail;
+
+ if (!write_int(jtxmt, "interval", interval))
+ goto fail;
+
+ json_object_object_add(jobj, desc, jtxmt);
+ return true;
+
+fail:
+ json_object_put(jtxmt);
+ return false;
+}
+
+bool mesh_db_node_set_net_transmit(uint16_t unicast, uint8_t cnt,
+ uint16_t interval)
+{
+ json_object *jnode;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ if (!add_transmit_info(jnode, cnt, interval, "networkTransmit"))
+ return false;
+
+ return save_config();
+}
+
+static bool set_feature(json_object *jnode, const char *desc, uint8_t feature)
+{
+ json_object *jobj;
+
+ if (feature > MESH_MODE_UNSUPPORTED)
+ return false;
+
+ jobj = json_object_object_get(jnode, "features");
+ if (!jobj) {
+ jobj = json_object_new_object();
+ json_object_object_add(jnode, "features", jobj);
+ }
+
+ if (!write_int(jobj, desc, feature))
+ return false;
+
+ return save_config();
+}
+
+bool mesh_db_node_set_relay(uint16_t unicast, uint8_t relay, uint8_t cnt,
+ uint16_t interval)
+{
+ json_object *jnode;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ if (relay < MESH_MODE_UNSUPPORTED &&
+ !add_transmit_info(jnode, cnt, interval, "relayRetransmit"))
+ return false;
+
+ return set_feature(jnode, "relay", relay);
+}
+
+bool mesh_db_node_set_proxy(uint16_t unicast, uint8_t proxy)
+{
+ json_object *jnode;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ return set_feature(jnode, "proxy", proxy);
+}
+
+bool mesh_db_node_set_friend(uint16_t unicast, uint8_t friend)
+{
+ json_object *jnode;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ return set_feature(jnode, "friend", friend);
+}
+
+bool mesh_db_node_set_beacon(uint16_t unicast, bool enabled)
+{
+ json_object *jnode;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ if (!write_bool(jnode, "secureNetworkBeacon", enabled))
+ return false;
+
+ return save_config();
+}
+
static json_object *get_element(uint16_t unicast, uint16_t ele_addr)
{
json_object *jnode, *jarray;
int i, ele_cnt;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -993,23 +1116,6 @@ bool mesh_db_node_model_overwrt_sub_virt(uint16_t unicast, uint16_t ele,
return sub_overwrite(unicast, ele, vendor, mod_id, buf);
}

-static bool add_transmit_info(json_object *jobj, int cnt, int interval,
- const char *desc)
-{
- json_object *jtxmt;
-
- jtxmt = json_object_new_object();
-
- if (!write_int(jtxmt, "count", cnt))
- return false;
-
- if (!write_int(jtxmt, "interval", interval))
- return false;
-
- json_object_object_add(jobj, desc, jtxmt);
- return true;
-}
-
bool mesh_db_node_model_set_pub(uint16_t unicast, uint16_t ele_addr,
bool vendor, uint32_t mod_id,
struct model_pub *pub, bool virt)
@@ -1113,7 +1219,7 @@ bool mesh_db_node_add_net_key(uint16_t unicast, uint16_t idx)
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -1127,7 +1233,7 @@ bool mesh_db_node_del_net_key(uint16_t unicast, uint16_t net_idx)
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -1143,7 +1249,7 @@ static bool key_update(uint16_t unicast, int16_t idx, bool updated,
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -1180,7 +1286,7 @@ bool mesh_db_node_add_app_key(uint16_t unicast, uint16_t idx)
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -1194,7 +1300,7 @@ bool mesh_db_node_del_app_key(uint16_t unicast, uint16_t idx)
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

@@ -1635,7 +1741,7 @@ bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len)
if (!cfg || !cfg->jcfg)
return false;

- jnode = get_node_by_unicast(unicast);
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
if (!jnode)
return false;

diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index 147fbf98c..b3b0bce79 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -37,6 +37,11 @@ bool mesh_db_add_provisioner(const char *name, uint8_t uuid[16],
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_set_relay(uint16_t unicast, uint8_t relay, uint8_t cnt,
+ uint16_t interval);
+bool mesh_db_node_set_proxy(uint16_t unicast, uint8_t proxy);
+bool mesh_db_node_set_friend(uint16_t unicast, uint8_t friend);
+bool mesh_db_node_set_beacon(uint16_t unicast, bool enabled);
bool mesh_db_node_add_net_key(uint16_t unicast, uint16_t idx);
bool mesh_db_node_del_net_key(uint16_t unicast, uint16_t idx);
bool mesh_db_node_update_net_key(uint16_t unicast, uint16_t idx, bool updated);
--
2.31.1

2021-09-23 03:29:53

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 14/20] tools/mesh-cfgclient: Store remote's heartbeat sub/pub

Store remote node's heartbeat publication or subscription info upon
receiving CONFIG_HEARTBEAT_PUB_STATUS or CONFIG_HEARTBEAT_SUB_STATUS
messages when the messages' status code is set to Success.
---
tools/mesh/cfgcli.c | 30 +++++++++---
tools/mesh/mesh-db.c | 113 +++++++++++++++++++++++++++++++++++++++++--
tools/mesh/mesh-db.h | 4 ++
3 files changed, 135 insertions(+), 12 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index b5f39df18..2bf1a1503 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -400,7 +400,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
{
uint32_t opcode, mod_id;
const struct cfg_cmd *cmd;
- uint16_t app_idx, net_idx, addr, ele_addr;
+ uint16_t app_idx, net_idx, addr, ele_addr, features;
struct mesh_group *grp;
struct model_pub pub;
int n;
@@ -813,13 +813,21 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("\nNode %4.4x Heartbeat publish status %s\n",
src, mesh_status_str(data[0]));

- bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 1));
- bt_shell_printf("Count\t\t%2.2x\n", data[3]);
- bt_shell_printf("Period\t\t%2.2x\n", data[4]);
+ if (data[0] != MESH_STATUS_SUCCESS)
+ return true;
+
+ addr = get_le16(data + 1);
+ bt_shell_printf("Destination\t%4.4x\n", addr);
+ bt_shell_printf("CountLog\t\t%2.2x\n", data[3]);
+ bt_shell_printf("PeriodLog\t\t%2.2x\n", data[4]);
bt_shell_printf("TTL\t\t%2.2x\n", data[5]);
- bt_shell_printf("Features\t%4.4x\n", get_le16(data + 6));
+ features = get_le16(data + 6);
+ bt_shell_printf("Features\t%4.4x\n", features);
net_idx = get_le16(data + 8);
bt_shell_printf("Net_Idx\t%u (0x%3.3x)\n", net_idx, net_idx);
+
+ saved = mesh_db_node_set_hb_pub(src, addr, net_idx, data[4],
+ data[5], features);
break;

/* Per Mesh Profile 4.3.2.66 */
@@ -830,12 +838,20 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
bt_shell_printf("\nNode %4.4x Heartbeat subscribe status %s\n",
src, mesh_status_str(data[0]));

- bt_shell_printf("Source\t\t%4.4x\n", get_le16(data + 1));
- bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 3));
+ if (data[0] != MESH_STATUS_SUCCESS)
+ return true;
+
+ ele_addr = get_le16(data + 1);
+ bt_shell_printf("Source\t\t%4.4x\n", ele_addr);
+ addr = get_le16(data + 3);
+ bt_shell_printf("Destination\t%4.4x\n", addr);
bt_shell_printf("Period\t\t%2.2x\n", data[5]);
bt_shell_printf("Count\t\t%2.2x\n", data[6]);
bt_shell_printf("Min Hops\t%2.2x\n", data[7]);
bt_shell_printf("Max Hops\t%2.2x\n", data[8]);
+
+ saved = mesh_db_node_set_hb_sub(src, ele_addr, addr);
+
break;

/* Per Mesh Profile 4.3.2.71 */
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 3290c5b8e..42ba831d4 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -963,12 +963,24 @@ static void jarray_string_del(json_object *jarray, const char *str, size_t len)
}
}

+static bool add_array_string(json_object *jarray, const char *str)
+{
+ json_object *jstring;
+
+ jstring = json_object_new_string(str);
+ if (!jstring)
+ return false;
+
+ json_object_array_add(jarray, jstring);
+ return true;
+}
+
static bool update_model_string_array(uint16_t unicast, uint16_t ele_addr,
bool vendor, uint32_t mod_id,
const char *str, uint32_t len,
const char *keyword, bool add)
{
- json_object *jarray, *jmod, *jstring;
+ json_object *jarray, *jmod;

if (!cfg || !cfg->jcfg)
return false;
@@ -988,12 +1000,9 @@ static bool update_model_string_array(uint16_t unicast, uint16_t ele_addr,
if (!add)
return true;

- jstring = json_object_new_string(str);
- if (!jstring)
+ if (!add_array_string(jarray, str))
return false;

- json_object_array_add(jarray, jstring);
-
return save_config();
}

@@ -1179,6 +1188,100 @@ fail:
return false;
}

+bool mesh_db_node_set_hb_pub(uint16_t unicast, uint16_t dst, uint16_t net_idx,
+ uint8_t period_log, uint8_t ttl,
+ uint16_t features)
+{
+ json_object *jnode, *jpub, *jarray = NULL;
+ uint32_t period;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ if (period_log > 0x12 || ttl > 0x7F)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ jpub = json_object_new_object();
+
+ if (!write_uint16_hex(jpub, "address", dst))
+ goto fail;
+
+ period = period_log ? 1 << (period_log - 1) : 0;
+
+ if (!write_int(jpub, "period", period))
+ goto fail;
+
+ if (!write_int(jpub, "ttl", ttl))
+ goto fail;
+
+ if (!write_int(jpub, "index", net_idx))
+ goto fail;
+
+ jarray = json_object_new_array();
+
+ if (features & FEATURE_PROXY)
+ if (!add_array_string(jarray, "proxy"))
+ goto fail;
+
+ if (features & FEATURE_RELAY)
+ if (!add_array_string(jarray, "relay"))
+ goto fail;
+
+ if (features & FEATURE_FRIEND)
+ if (!add_array_string(jarray, "friend"))
+ goto fail;
+
+ if (features & FEATURE_LPN)
+ if (!add_array_string(jarray, "lowPower"))
+ goto fail;
+
+ json_object_object_add(jpub, "features", jarray);
+ json_object_object_del(jnode, "heartbeatPub");
+ json_object_object_add(jnode, "heartbeatPub", jpub);
+
+ return save_config();
+
+fail:
+ if (jarray)
+ json_object_put(jarray);
+
+ json_object_put(jpub);
+ return false;
+}
+
+bool mesh_db_node_set_hb_sub(uint16_t unicast, uint16_t src, uint16_t dst)
+{
+ json_object *jnode, *jsub;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(cfg->jcfg, unicast);
+ if (!jnode)
+ return false;
+
+ jsub = json_object_new_object();
+
+ if (!write_uint16_hex(jsub, "source", src))
+ goto fail;
+
+ if (!write_uint16_hex(jsub, "destination", dst))
+ goto fail;
+
+ json_object_object_del(jnode, "heartbeatSub");
+ json_object_object_add(jnode, "heartbeatSub", jsub);
+
+ return save_config();
+
+fail:
+ json_object_put(jsub);
+ return false;
+}
+
static void jarray_key_del(json_object *jarray, int16_t idx)
{
int i, sz = json_object_array_length(jarray);
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index b3b0bce79..16c46c046 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -74,6 +74,10 @@ bool mesh_db_node_model_del_sub_all(uint16_t unicast, uint16_t ele, bool vendor,
bool mesh_db_node_model_set_pub(uint16_t unicast, uint16_t ele_addr,
bool vendor, uint32_t mod_id,
struct model_pub *pub, bool virt);
+bool mesh_db_node_set_hb_pub(uint16_t unicast, uint16_t dst, uint16_t net_idx,
+ uint8_t period_log, uint8_t ttl,
+ uint16_t features);
+bool mesh_db_node_set_hb_sub(uint16_t unicast, uint16_t src, uint16_t dst);
struct l_queue *mesh_db_load_groups(void);
bool mesh_db_add_group(struct mesh_group *grp);
bool mesh_db_add_rejected_addr(uint16_t unicast, uint32_t iv_index);
--
2.31.1

2021-09-23 03:30:07

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 18/20] tools/mesh-cfgclient: Store UUIDs in standard format

Use standard xxxx-xx-xx-xx-xxxxxxxx format for string
representation of mesh and node UUIDs in stored configuration.
---
tools/mesh/mesh-db.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 0dc811801..b45212fc9 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -293,10 +293,11 @@ static bool write_uint32_hex(json_object *jobj, const char *desc, uint32_t val)
static json_object *get_node_by_uuid(json_object *jcfg, uint8_t uuid[16])
{
json_object *jarray = NULL;
- char buf[33];
+ char buf[37];
int i, sz;

- hex2str(uuid, 16, buf, sizeof(buf));
+ if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
+ return NULL;

json_object_object_get_ex(jcfg, "nodes", &jarray);
if (!jarray || json_object_get_type(jarray) != json_type_array)
@@ -313,7 +314,7 @@ static json_object *get_node_by_uuid(json_object *jcfg, uint8_t uuid[16])
return NULL;

str = json_object_get_string(jval);
- if (strlen(str) != 32)
+ if (strlen(str) != 36)
continue;

if (!strcmp(buf, str))
@@ -506,10 +507,11 @@ static void load_remotes(json_object *jcfg)
continue;

str = json_object_get_string(jval);
- if (strlen(str) != 32)
+ if (strlen(str) != 36)
continue;

- str2hex(str, 32, uuid, 16);
+ if (!l_uuid_from_string(str, uuid))
+ continue;

if (!json_object_object_get_ex(jnode, "unicastAddress", &jval))
continue;
@@ -1698,6 +1700,7 @@ bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
{
json_object *jnode;
json_object *jelements, *jnodes, *jnetkeys, *jappkeys;
+ char buf[37];

if (!cfg || !cfg->jcfg)
return false;
@@ -1712,9 +1715,11 @@ bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
if (!jnode)
return false;

- if (!add_u8_16(jnode, "UUID", uuid))
+ if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
goto fail;

+ if (!add_string(jnode, "UUID", buf))
+ goto fail;

if (!add_string(jnode, "security", "secure"))
goto fail;
@@ -2065,6 +2070,7 @@ bool mesh_db_add_provisioner(const char *name, uint8_t uuid[16],
uint16_t group_low, uint16_t group_high)
{
json_object *jprovs, *jprov, *jscenes;
+ char buf[37];

if (!cfg || !cfg->jcfg)
return false;
@@ -2080,7 +2086,10 @@ bool mesh_db_add_provisioner(const char *name, uint8_t uuid[16],
if (!add_string(jprov, "provisionerName", name))
goto fail;

- if (!add_u8_16(jprov, "UUID", uuid))
+ if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
+ goto fail;
+
+ if (!add_string(jprov, "UUID", buf))
goto fail;

if (!add_range(jprov, "allocatedUnicastRange", unicast_low,
@@ -2270,6 +2279,7 @@ bool mesh_db_create(const char *fname, const uint8_t token[8],
{
json_object *jcfg, *jarray;
uint8_t uuid[16];
+ char buf[37];

if (cfg)
return false;
@@ -2291,7 +2301,10 @@ bool mesh_db_create(const char *fname, const uint8_t token[8],

l_uuid_v4(uuid);

- if (!add_u8_16(jcfg, "meshUUID", uuid))
+ if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
+ goto fail;
+
+ if (!add_string(jcfg, "meshUUID", buf))
goto fail;

if (mesh_name && !add_string(jcfg, "meshName", mesh_name))
--
2.31.1

2021-09-23 03:30:08

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 16/20] doc/mesh-api: Add ExportKeys call

Add description for a new method:
ExportKeys() on org.bluez.mesh.Management1 interface.

This method is used by the authorized application to export information
about network keys, application keys and device keys present in the local
key database.
---
doc/mesh-api.txt | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
index ce651c801..85de6705e 100644
--- a/doc/mesh-api.txt
+++ b/doc/mesh-api.txt
@@ -728,6 +728,62 @@ Methods:
PossibleErrors:
org.bluez.mesh.Error.InvalidArguments

+ dict ExportKeys(void)
+
+ This method is used by the application to export information
+ about network keys, application keys and device keys present
+ in the local key database.
+
+ dict
+ A dictionary that contains information for the keys
+ stored in the keyring with the following keys defined:
+
+ NetKeys:
+ array{struct} net_keys:
+
+ uint16 index
+ Subnet index
+
+ array{byte}[16] key
+
+ dict:
+ A dictionary that contains optional
+ key info with the following keys
+ defined:
+
+ uint8 Phase
+ Key Refresh phase of the subnet
+
+ array{byte}[16] OldKey
+
+ array{struct} AppKeys:
+
+ uint16 index
+
+ Application key index
+
+ array{byte}[16] key
+
+ dict:
+ A dictionary of optional
+ key info with the
+ following keys defined:
+
+ array{byte}[16] OldKey
+
+ DevKeys:
+ array{struct} dev_keys:
+
+ Device Key information for known remote
+ nodes in the configured Mesh network
+
+ uint16 unicast
+
+ Unicast address of the node's primary
+ element
+
+ array{byte}[16] key
+
Mesh Application Hierarchy
==========================
Service unique name
--
2.31.1

2021-09-23 03:30:08

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 20/20] tools/mesh-cfgclient: Export configuration database

This adds main menu command "export-db".
When the command is invoked, JSON configuration object is
cloned and trimmed of extraneous properties.
Information about netkeys, appkeys and device keys are obtained
from bluetooth-meshd by calling ExportKeys() method.
The obtained key values are recorded in the export JSON object.
---
tools/mesh-cfgclient.c | 195 +++++++++++++++++++++++++++++++++++++++++
tools/mesh/mesh-db.c | 191 ++++++++++++++++++++++++++++++++++++++++
tools/mesh/mesh-db.h | 7 ++
3 files changed, 393 insertions(+)

diff --git a/tools/mesh-cfgclient.c b/tools/mesh-cfgclient.c
index beeb115dc..237afbb5f 100644
--- a/tools/mesh-cfgclient.c
+++ b/tools/mesh-cfgclient.c
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <dbus/dbus.h>
#include <errno.h>
+#include <libgen.h>
#include <stdio.h>
#include <time.h>

@@ -51,6 +52,7 @@
#define MAX_CRPL_SIZE 0x7fff

#define DEFAULT_CFG_FILE "config_db.json"
+#define DEFAULT_EXPORT_FILE "export_db.json"

struct meshcfg_el {
const char *path;
@@ -835,6 +837,197 @@ static void cmd_scan_unprov(int argc, char *argv[])

}

+static uint8_t *parse_key(struct l_dbus_message_iter *iter, uint16_t id,
+ const char *name)
+{
+ uint8_t *val;
+ uint32_t len;
+
+ if (!l_dbus_message_iter_get_fixed_array(iter, &val, &len)
+ || len != 16) {
+ bt_shell_printf("Failed to parse %s %4.4x\n", name, id);
+ return NULL;
+ }
+
+ return val;
+}
+
+static bool parse_app_keys(struct l_dbus_message_iter *iter, uint16_t net_idx,
+ void *user_data)
+{
+ struct l_dbus_message_iter app_keys, app_key, opts;
+ uint16_t app_idx;
+
+ if (!l_dbus_message_iter_get_variant(iter, "a(qaya{sv})", &app_keys))
+ return false;
+
+ while (l_dbus_message_iter_next_entry(&app_keys, &app_idx, &app_key,
+ &opts)) {
+ struct l_dbus_message_iter var;
+ uint8_t *val, *old_val = NULL;
+ const char *key;
+
+ val = parse_key(&app_key, app_idx, "AppKey");
+ if (!val)
+ return false;
+
+ while (l_dbus_message_iter_next_entry(&opts, &key, &var)) {
+ if (!strcmp(key, "OldKey")) {
+ if (!l_dbus_message_iter_get_variant(&var, "ay",
+ &app_key))
+ return false;
+
+ old_val = parse_key(&app_key, app_idx,
+ "old NetKey");
+
+ if (!old_val)
+ return false;
+ }
+ }
+
+ mesh_db_set_app_key(user_data, net_idx, app_idx, val, old_val);
+ }
+
+ return true;
+}
+
+static bool parse_net_keys(struct l_dbus_message_iter *iter, void *user_data)
+{
+ struct l_dbus_message_iter net_keys, net_key, opts;
+ uint16_t idx;
+
+ if (!l_dbus_message_iter_get_variant(iter, "a(qaya{sv})", &net_keys))
+ return false;
+
+ while (l_dbus_message_iter_next_entry(&net_keys, &idx, &net_key,
+ &opts)) {
+ struct l_dbus_message_iter var;
+ uint8_t *val, *old_val = NULL;
+ uint8_t phase = KEY_REFRESH_PHASE_NONE;
+ const char *key;
+
+ val = parse_key(&net_key, idx, "NetKey");
+ if (!val)
+ return false;
+
+ while (l_dbus_message_iter_next_entry(&opts, &key, &var)) {
+ if (!strcmp(key, "AppKeys")) {
+ if (!parse_app_keys(&var, idx, user_data))
+ return false;
+ } else if (!strcmp(key, "Phase")) {
+ if (!l_dbus_message_iter_get_variant(&var, "y",
+ &phase))
+ return false;
+ } else if (!strcmp(key, "OldKey")) {
+ if (!l_dbus_message_iter_get_variant(&var, "ay",
+ &net_key))
+ return false;
+
+ old_val = parse_key(&net_key, idx,
+ "old NetKey");
+
+ if (!old_val)
+ return false;
+ }
+ }
+
+ mesh_db_set_net_key(user_data, idx, val, old_val, phase);
+ }
+
+ return true;
+}
+
+static bool parse_dev_keys(struct l_dbus_message_iter *iter, void *user_data)
+{
+ struct l_dbus_message_iter keys, dev_key;
+ uint16_t unicast;
+
+ if (!l_dbus_message_iter_get_variant(iter, "a(qay)", &keys))
+ return false;
+
+ while (l_dbus_message_iter_next_entry(&keys, &unicast, &dev_key)) {
+ uint8_t *data;
+
+ data = parse_key(&dev_key, unicast, "Device Key");
+ if (!data)
+ return false;
+
+ mesh_db_set_device_key(user_data, unicast, data);
+ }
+
+ return true;
+}
+
+static void export_keys_reply(struct l_dbus_proxy *proxy,
+ struct l_dbus_message *msg, void *user_data)
+{
+ struct l_dbus_message_iter iter, var;
+ char *cfg_dir = NULL, *fname = NULL;
+ const char *key;
+ bool is_error = true;
+
+ if (l_dbus_message_is_error(msg)) {
+ const char *name;
+
+ l_dbus_message_get_error(msg, &name, NULL);
+ bt_shell_printf("Failed to export keys: %s", name);
+ goto done;
+
+ }
+
+ if (!l_dbus_message_get_arguments(msg, "a{sv}", &iter)) {
+ bt_shell_printf("Malformed ExportKeys reply");
+ goto done;
+ }
+
+ while (l_dbus_message_iter_next_entry(&iter, &key, &var)) {
+ if (!strcmp(key, "NetKeys")) {
+ if (!parse_net_keys(&var, user_data))
+ goto done;
+ } else if (!strcmp(key, "DevKeys")) {
+ if (!parse_dev_keys(&var, user_data))
+ goto done;
+ }
+ }
+
+ is_error = false;
+
+ cfg_dir = l_strdup(cfg_fname);
+ cfg_dir = dirname(cfg_dir);
+
+ fname = l_strdup_printf("%s/%s", cfg_dir, DEFAULT_EXPORT_FILE);
+
+done:
+ if (mesh_db_finish_export(is_error, user_data, fname)) {
+ if (!is_error)
+ bt_shell_printf("Config DB is exported to %s\n", fname);
+ }
+
+ l_free(cfg_dir);
+ l_free(fname);
+}
+
+static void cmd_export_db(int argc, char *argv[])
+{
+ void *cfg_export;
+
+ if (!local || !local->proxy || !local->mgmt_proxy) {
+ bt_shell_printf("Node is not attached\n");
+ return;
+ }
+
+ /* Generate a properly formatted DB from the local config */
+ cfg_export = mesh_db_prepare_export();
+ if (!cfg_export) {
+ bt_shell_printf("Failed to prepare config db\n");
+ return;
+ }
+
+ /* Export the keys from the daemon */
+ l_dbus_proxy_method_call(local->mgmt_proxy, "ExportKeys", NULL,
+ export_keys_reply, cfg_export, NULL);
+}
+
static void cmd_list_unprov(int argc, char *argv[])
{
bt_shell_printf(COLOR_YELLOW "Unprovisioned devices:\n" COLOR_OFF);
@@ -1395,6 +1588,8 @@ static const struct bt_shell_menu main_menu = {
"List remote mesh nodes"},
{ "keys", NULL, cmd_keys,
"List available keys"},
+ { "export-db", NULL, cmd_export_db,
+ "Export mesh configuration database"},
{ } },
};

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 262a274c7..12055c1a9 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -48,6 +48,13 @@ static struct mesh_db *cfg;
static const char *bak_ext = ".bak";
static const char *tmp_ext = ".tmp";

+static const char *js_schema = "http://json-schema.org/draft-04/schema#";
+static const char *schema_id = "http://www.bluetooth.com/specifications/"
+ "assigned-numbers/mesh-profile/"
+ "cdb-schema.json#";
+const char *schema_version = "1.0.0";
+
+
static bool add_string(json_object *jobj, const char *desc, const char *str)
{
json_object *jstring = json_object_new_string(str);
@@ -2412,3 +2419,187 @@ fail:

return false;
}
+
+bool mesh_db_set_device_key(void *expt_cfg, uint16_t unicast, uint8_t key[16])
+{
+ json_object *jnode;
+
+ if (!expt_cfg)
+ return false;
+
+ jnode = get_node_by_unicast(expt_cfg, unicast);
+ if (!jnode)
+ return false;
+
+ return add_u8_16(jnode, "deviceKey", key);
+}
+
+bool mesh_db_set_net_key(void *expt_cfg, uint16_t idx, uint8_t key[16],
+ uint8_t *old_key, uint8_t phase)
+{
+ json_object *jarray, *jkey;
+
+ if (!expt_cfg)
+ return false;
+
+ json_object_object_get_ex(expt_cfg, "netKeys", &jarray);
+ if (!jarray || json_object_get_type(jarray) != json_type_array)
+ return false;
+
+ jkey = get_key_object(jarray, idx);
+ if (!jkey)
+ return false;
+
+ if (!write_int(jkey, "phase", phase))
+ return false;
+
+ if (!add_u8_16(jkey, "key", key))
+ return false;
+
+ if (old_key && !(!add_u8_16(jkey, "oldKey", old_key)))
+ return false;
+
+ return true;
+}
+
+
+bool mesh_db_set_app_key(void *expt_cfg, uint16_t net_idx, uint16_t app_idx,
+ uint8_t key[16], uint8_t *old_key)
+{
+ json_object *jarray, *jkey;
+
+ if (!expt_cfg)
+ return false;
+
+ json_object_object_get_ex(expt_cfg, "appKeys", &jarray);
+ if (!jarray || json_object_get_type(jarray) != json_type_array)
+ return false;
+
+ jkey = get_key_object(jarray, app_idx);
+ if (!jkey)
+ return false;
+
+ if (!add_u8_16(jkey, "key", key))
+ return false;
+
+ if (old_key && !(!add_u8_16(jkey, "oldKey", old_key)))
+ return false;
+
+ return true;
+}
+
+void *mesh_db_prepare_export(void)
+{
+ json_object *export = NULL, *jarray;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ if (json_object_deep_copy(cfg->jcfg, &export, NULL) != 0)
+ return NULL;
+
+ /* Delete token */
+ json_object_object_del(export, "token");
+
+ /* Delete IV index */
+ json_object_object_del(export, "ivIndex");
+
+ /* Scenes are not supported. Just add an empty array */
+ jarray = json_object_new_array();
+ json_object_object_add(export, "scenes", jarray);
+
+ write_bool(export, "partial", false);
+
+ return export;
+}
+
+bool mesh_db_finish_export(bool is_error, void *expt_cfg, const char *fname)
+{
+ FILE *outfile = NULL;
+ const char *str, *hdr;
+ json_object *jhdr = NULL;
+ bool result = false;
+ char *pos;
+
+ uint32_t sz;
+
+ if (!expt_cfg)
+ return false;
+
+ if (is_error) {
+ json_object_put(expt_cfg);
+ return true;
+ }
+
+ if (!fname)
+ goto done;
+
+ outfile = fopen(fname, "w");
+ if (!outfile) {
+ l_error("Failed to save configuration to %s", fname);
+ goto done;
+ }
+
+ jhdr = json_object_new_object();
+ if (!add_string(jhdr, "$schema", js_schema))
+ goto done;
+
+ if (!add_string(jhdr, "id", schema_id))
+ goto done;
+
+ if (!add_string(jhdr, "version", schema_version))
+ goto done;
+
+ hdr = json_object_to_json_string_ext(jhdr, JSON_C_TO_STRING_PRETTY |
+ JSON_C_TO_STRING_NOSLASHESCAPE);
+
+ str = json_object_to_json_string_ext(expt_cfg, JSON_C_TO_STRING_PRETTY |
+ JSON_C_TO_STRING_NOSLASHESCAPE);
+
+ if (!hdr || !str)
+ goto done;
+
+ /*
+ * Write two strings to the output while stripping closing "}" from the
+ * header string and opening "{" from the config object.
+ */
+
+ pos = strrchr(hdr, '}');
+ if (!pos)
+ goto done;
+
+ *pos = '\0';
+
+ pos = strrchr(hdr, '"');
+ if (!pos)
+ goto done;
+
+ pos[1] = ',';
+
+ if (fwrite(hdr, sizeof(char), strlen(hdr), outfile) < strlen(hdr))
+ goto done;
+
+ pos = strchr(str, '{');
+ if (!pos || pos[1] == '\0')
+ goto done;
+
+ pos++;
+
+ sz = strlen(pos);
+
+ if (fwrite(pos, sizeof(char), sz, outfile) < sz)
+ goto done;
+
+ result = true;
+
+done:
+ if (outfile)
+ fclose(outfile);
+
+ json_object_put(expt_cfg);
+
+ if (jhdr)
+ json_object_put(jhdr);
+
+ return result;
+}
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index 16c46c046..4b6b2adb3 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -82,3 +82,10 @@ struct l_queue *mesh_db_load_groups(void);
bool mesh_db_add_group(struct mesh_group *grp);
bool mesh_db_add_rejected_addr(uint16_t unicast, uint32_t iv_index);
bool mesh_db_clear_rejected(uint32_t iv_index);
+bool mesh_db_set_device_key(void *expt_cfg, uint16_t unicast, uint8_t key[16]);
+bool mesh_db_set_net_key(void *expt_cfg, uint16_t idx, uint8_t key[16],
+ uint8_t *old_key, uint8_t phase);
+bool mesh_db_set_app_key(void *expt_cfg, uint16_t net_idx, uint16_t app_idx,
+ uint8_t key[16], uint8_t *old_key);
+void *mesh_db_prepare_export(void);
+bool mesh_db_finish_export(bool is_error, void *expt_cfg, const char *fname);
--
2.31.1

2021-09-23 03:30:10

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 19/20] tools/mesh-cfgclient: Excluded addresses property

The correct name for a property that contains a list of addresses
not allowed in circulation is "networkExclusions"
The "excluded" property in "nodes" array entry is used to indicated that
this node has been removed from a mesh network and it's address should not
be re-used.
---
tools/mesh/mesh-db.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index b45212fc9..262a274c7 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -1724,7 +1724,7 @@ bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
if (!add_string(jnode, "security", "secure"))
goto fail;

- if (!write_bool(jnode, "blacklisted", false))
+ if (!write_bool(jnode, "excluded", false))
goto fail;

if (!write_bool(jnode, "configComplete", false))
@@ -2165,7 +2165,7 @@ static bool load_rejected_addresses(json_object *jobj)
json_object *jarray;
int i, cnt;

- json_object_object_get_ex(jobj, "blacklistedAddresses", &jarray);
+ json_object_object_get_ex(jobj, "networkExclusions", &jarray);
if (!jarray || json_object_get_type(jarray) != json_type_array)
return true;

@@ -2212,11 +2212,10 @@ bool mesh_db_add_rejected_addr(uint16_t unicast, uint32_t iv_index)
if (!cfg || !cfg->jcfg)
return false;

- json_object_object_get_ex(cfg->jcfg, "blacklistedAddresses", &jarray);
+ json_object_object_get_ex(cfg->jcfg, "networkExclusions", &jarray);
if (!jarray) {
jarray = json_object_new_array();
- json_object_object_add(cfg->jcfg, "blacklistedAddresses",
- jarray);
+ json_object_object_add(cfg->jcfg, "networkExclusions", jarray);
}

idx = get_rejected_by_iv_index(jarray, iv_index);
@@ -2261,7 +2260,7 @@ bool mesh_db_clear_rejected(uint32_t iv_index)
if (!cfg || !cfg->jcfg)
return false;

- json_object_object_get_ex(cfg->jcfg, "blacklistedAddresses", &jarray);
+ json_object_object_get_ex(cfg->jcfg, "networkExclusions", &jarray);
if (!jarray || json_object_get_type(jarray) != json_type_array)
return false;

@@ -2338,7 +2337,7 @@ bool mesh_db_create(const char *fname, const uint8_t token[8],
if (!jarray)
goto fail;

- json_object_object_add(jcfg, "blacklistedAddresses", jarray);
+ json_object_object_add(jcfg, "networkExclusions", jarray);

write_int(jcfg, "ivIndex", 0);

--
2.31.1

2021-09-23 03:31:17

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 10/20] tools/mesh-cfgclient: Store remote's model publication info

Update remote node's model publication after a successful completion
of "pub-set" or "pub-get" commands.
---
tools/mesh/cfgcli.c | 42 +++++++++++++++++------
tools/mesh/mesh-db.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
tools/mesh/mesh-db.h | 4 +++
tools/mesh/model.h | 13 ++++---
4 files changed, 124 insertions(+), 16 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index 19a42947e..2766d47ca 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -334,7 +334,7 @@ static void print_pub(uint16_t ele_addr, uint32_t mod_id,
struct model_pub *pub)
{
bt_shell_printf("\tElement: %4.4x\n", ele_addr);
- bt_shell_printf("\tPub Addr: %4.4x\n", pub->u.addr16);
+ bt_shell_printf("\tPub Addr: %4.4x\n", pub->u.addr);

if (mod_id < VENDOR_ID_MASK)
bt_shell_printf("\tModel: %8.8x\n", mod_id);
@@ -634,31 +634,51 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

mod_id = print_mod_id(data + 10, len == 14, "");

- pub.u.addr16 = get_le16(data + 3);
+ pub.u.addr = get_le16(data + 3);
+
pub.app_idx = get_le16(data + 5);
+ pub.cred = ((pub.app_idx & 0x1000) != 0);
+ pub.app_idx &= 0x3ff;
+
pub.ttl = data[7];
- pub.period = data[8];
- n = (data[8] & 0x3f);
+ pub.prd_steps = (data[8] & 0x3f);

print_pub(ele_addr, mod_id, &pub);

switch (data[8] >> 6) {
case 0:
- bt_shell_printf("Period\t\t%d ms\n", n * 100);
+ pub.prd_res = 100;
break;
case 2:
- n *= 10;
- /* fall through */
+ pub.prd_res = 10;
+ break;
case 1:
- bt_shell_printf("Period\t\t%d sec\n", n);
+ pub.prd_res = 10000;
break;
case 3:
- bt_shell_printf("Period\t\t%d min\n", n * 10);
+ pub.prd_res = 600000;
break;
}

- bt_shell_printf("Rexmit count\t%d\n", data[9] & 0x7);
- bt_shell_printf("Rexmit steps\t%d\n", data[9] >> 3);
+ bt_shell_printf("Period\t\t%d ms\n", pub.period);
+
+ pub.rtx_cnt = data[9] & 0x7;
+ pub.rtx_interval = ((data[9] >> 3) + 1) * 50;
+ bt_shell_printf("Rexmit count\t%d\n", pub.rtx_cnt);
+ bt_shell_printf("Rexmit steps\t%d\n", pub.rtx_interval);
+
+ if (IS_VIRTUAL(pub.u.addr)) {
+ grp = l_queue_find(groups, match_group_addr,
+ L_UINT_TO_PTR(pub.u.addr));
+ if (!grp)
+ return true;
+
+ memcpy(pub.u.label, grp->label, sizeof(pub.u.label));
+
+ }
+
+ mesh_db_node_model_set_pub(src, ele_addr, len == 14, mod_id,
+ &pub, IS_VIRTUAL(pub.u.addr));

break;

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 8445d33f4..f63edd5ae 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -32,6 +32,7 @@
#include "tools/mesh/keys.h"
#include "tools/mesh/remote.h"
#include "tools/mesh/cfgcli.h"
+#include "tools/mesh/model.h"
#include "tools/mesh/mesh-db.h"

#define KEY_IDX_INVALID NET_IDX_INVALID
@@ -992,6 +993,86 @@ bool mesh_db_node_model_overwrt_sub_virt(uint16_t unicast, uint16_t ele,
return sub_overwrite(unicast, ele, vendor, mod_id, buf);
}

+static bool add_transmit_info(json_object *jobj, int cnt, int interval,
+ const char *desc)
+{
+ json_object *jtxmt;
+
+ jtxmt = json_object_new_object();
+
+ if (!write_int(jtxmt, "count", cnt))
+ return false;
+
+ if (!write_int(jtxmt, "interval", interval))
+ return false;
+
+ json_object_object_add(jobj, desc, jtxmt);
+ return true;
+}
+
+bool mesh_db_node_model_set_pub(uint16_t unicast, uint16_t ele_addr,
+ bool vendor, uint32_t mod_id,
+ struct model_pub *pub, bool virt)
+{
+ json_object *jmod, *jpub, *jobj = NULL;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jmod = get_model(unicast, ele_addr, mod_id, vendor);
+ if (!jmod)
+ return false;
+
+ jpub = json_object_new_object();
+
+ if (!virt && !write_uint16_hex(jpub, "address", pub->u.addr))
+ goto fail;
+
+ if (virt) {
+ char buf[33];
+
+ hex2str(pub->u.label, 16, buf, sizeof(buf));
+
+ if (!add_string(jpub, "address", buf))
+ goto fail;
+ }
+
+ if (!write_int(jpub, "index", pub->app_idx))
+ goto fail;
+
+ if (!write_int(jpub, "ttl", pub->ttl))
+ goto fail;
+
+ if (!write_int(jpub, "credentials", pub->cred ? 1 : 0))
+ goto fail;
+
+ if (!add_transmit_info(jpub, pub->rtx_cnt, pub->rtx_interval,
+ "retransmit"))
+ goto fail;
+
+ jobj = json_object_new_object();
+
+ if (!write_int(jobj, "numberOfSteps", pub->prd_steps))
+ goto fail;
+
+ if (!write_int(jobj, "resolution", pub->prd_res))
+ goto fail;
+
+ json_object_object_add(jpub, "period", jobj);
+
+ json_object_object_del(jmod, "publish");
+ json_object_object_add(jmod, "publish", jpub);
+
+ return save_config();
+
+fail:
+ if (jobj)
+ json_object_put(jobj);
+
+ json_object_put(jpub);
+ return false;
+}
+
static void jarray_key_del(json_object *jarray, int16_t idx)
{
int i, sz = json_object_array_length(jarray);
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index 384376cbd..885dabe90 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -11,6 +11,7 @@
#include "mesh/mesh-config.h"

struct mesh_group;
+struct model_pub;

bool mesh_db_create(const char *fname, const uint8_t token[8],
const char *name);
@@ -65,6 +66,9 @@ bool mesh_db_node_model_overwrt_sub_virt(uint16_t unicast, uint16_t ele,
uint8_t *label);
bool mesh_db_node_model_del_sub_all(uint16_t unicast, uint16_t ele, bool vendor,
uint32_t mod_id);
+bool mesh_db_node_model_set_pub(uint16_t unicast, uint16_t ele_addr,
+ bool vendor, uint32_t mod_id,
+ struct model_pub *pub, bool virt);
struct l_queue *mesh_db_load_groups(void);
bool mesh_db_add_group(struct mesh_group *grp);
bool mesh_db_add_rejected_addr(uint16_t unicast, uint32_t iv_index);
diff --git a/tools/mesh/model.h b/tools/mesh/model.h
index 7359ea7df..5e20719b2 100644
--- a/tools/mesh/model.h
+++ b/tools/mesh/model.h
@@ -25,14 +25,17 @@ typedef int (*model_bind_func_t)(uint16_t app_idx, int action);

struct model_pub {
uint16_t app_idx;
+ uint16_t period;
union {
- uint16_t addr16;
- uint8_t va_128[16];
+ uint16_t addr;
+ uint8_t label[16];
} u;
+ bool cred;
+ uint32_t prd_res;
+ uint16_t rtx_interval;
+ uint8_t prd_steps;
+ uint8_t rtx_cnt;
uint8_t ttl;
- uint8_t credential;
- uint8_t period;
- uint8_t retransmit;
};

typedef int (*model_pub_func_t)(struct model_pub *pub);
--
2.31.1

2021-09-23 03:31:43

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 15/20] tools/mesh-cfgclient: Add group parent address for DB compliance

---
tools/mesh/mesh-db.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 42ba831d4..0dc811801 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -1590,6 +1590,10 @@ bool mesh_db_add_group(struct mesh_group *grp)
goto fail;
}

+ /* Initialize parent group to unassigned address for now*/
+ if (!write_uint16_hex(jgroup, "parentAddress", UNASSIGNED_ADDRESS))
+ goto fail;
+
json_object_array_add(jgroups, jgroup);

return save_config();
--
2.31.1

2021-09-23 03:31:43

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 04/20] tools/mesh-cfgclient: Keep track of updated keys

---
tools/mesh/cfgcli.c | 33 ++++----
tools/mesh/mesh-db.c | 151 ++++++++++++++++++++++++++++++-----
tools/mesh/mesh-db.h | 2 +
tools/mesh/remote.c | 182 +++++++++++++++++++++++++++++++++----------
tools/mesh/remote.h | 9 ++-
5 files changed, 299 insertions(+), 78 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index d8eee4edc..485d13b5a 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -447,13 +447,12 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
if (!cmd)
break;

- if (cmd->opcode == OP_APPKEY_ADD) {
- if (remote_add_app_key(src, app_idx))
- mesh_db_node_app_key_add(src, app_idx);
- } else if (cmd->opcode == OP_APPKEY_DELETE) {
- if (remote_del_app_key(src, app_idx))
- mesh_db_node_app_key_del(src, app_idx);
- }
+ if (cmd->opcode == OP_APPKEY_ADD)
+ remote_add_app_key(src, app_idx, true);
+ else if (cmd->opcode == OP_APPKEY_DELETE)
+ remote_del_app_key(src, app_idx);
+ else if (cmd->opcode == OP_APPKEY_UPDATE)
+ remote_update_app_key(src, app_idx, true, true);

break;

@@ -492,13 +491,12 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
if (!cmd)
break;

- if (cmd->opcode == OP_NETKEY_ADD) {
- if (remote_add_net_key(src, net_idx))
- mesh_db_node_net_key_add(src, net_idx);
- } else if (cmd->opcode == OP_NETKEY_DELETE) {
- if (remote_del_net_key(src, net_idx))
- mesh_db_node_net_key_del(src, net_idx);
- }
+ if (cmd->opcode == OP_NETKEY_ADD)
+ remote_add_net_key(src, net_idx, true);
+ else if (cmd->opcode == OP_NETKEY_DELETE)
+ remote_del_net_key(src, net_idx);
+ else if (cmd->opcode == OP_NETKEY_UPDATE)
+ remote_update_net_key(src, net_idx, true, true);

break;

@@ -534,6 +532,13 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,

bt_shell_printf("\tNetKey %u (0x%3.3x)\n", net_idx, net_idx);
bt_shell_printf("\tKR Phase %2.2x\n", data[3]);
+
+ if (data[0] != MESH_STATUS_SUCCESS)
+ return true;
+
+ if (data[3] == KEY_REFRESH_PHASE_NONE)
+ remote_finish_key_refresh(src, net_idx);
+
break;

case OP_MODEL_APP_STATUS:
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 5b3c4b2f7..a57a5d547 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -200,6 +200,38 @@ static bool write_int(json_object *jobj, const char *keyword, int val)
return true;
}

+static bool get_bool(json_object *jobj, const char *keyword, bool *value)
+{
+ json_object *jvalue;
+
+ if (!json_object_object_get_ex(jobj, keyword, &jvalue))
+ return false;
+
+ if (json_object_get_type(jvalue) != json_type_boolean) {
+ l_error("Error: %s should contain a boolean value\n",
+ keyword);
+ return false;
+ }
+
+ *value = json_object_get_boolean(jvalue);
+
+ return true;
+}
+
+static bool write_bool(json_object *jobj, const char *keyword, bool val)
+{
+ json_object *jval;
+
+ json_object_object_del(jobj, keyword);
+
+ jval = json_object_new_boolean(val);
+ if (!jval)
+ return false;
+
+ json_object_object_add(jobj, keyword, jval);
+ return true;
+}
+
static json_object *get_key_object(json_object *jarray, uint16_t idx)
{
int i, sz = json_object_array_length(jarray);
@@ -347,6 +379,20 @@ static uint16_t node_parse_key(json_object *jarray, int i)
return (uint16_t)idx;
}

+static bool node_check_key_updated(json_object *jarray, int i, bool *updated)
+{
+ json_object *jkey;
+
+ jkey = json_object_array_get_idx(jarray, i);
+ if (!jkey)
+ return false;
+
+ if (!get_bool(jkey, "updated", updated))
+ return false;
+
+ return true;
+}
+
static int compare_group_addr(const void *a, const void *b, void *user_data)
{
const struct mesh_group *grp0 = a;
@@ -483,10 +529,17 @@ static void load_remotes(json_object *jcfg)
remote_add_node((const uint8_t *)uuid, unicast, ele_cnt,
key_idx);
for (j = 1; j < key_cnt; j++) {
+ bool updated = false;
+
key_idx = node_parse_key(jarray, j);

- if (key_idx != KEY_IDX_INVALID)
- remote_add_net_key(unicast, key_idx);
+ if (key_idx == KEY_IDX_INVALID)
+ continue;
+
+ remote_add_net_key(unicast, key_idx, false);
+
+ node_check_key_updated(jarray, j, &updated);
+ remote_update_net_key(unicast, key_idx, updated, false);
}

json_object_object_get_ex(jnode, "appKeys", &jarray);
@@ -496,10 +549,17 @@ static void load_remotes(json_object *jcfg)
key_cnt = json_object_array_length(jarray);

for (j = 0; j < key_cnt; j++) {
+ bool updated = false;
+
key_idx = node_parse_key(jarray, j);

- if (key_idx != KEY_IDX_INVALID)
- remote_add_app_key(unicast, key_idx);
+ if (key_idx == KEY_IDX_INVALID)
+ continue;
+
+ remote_add_app_key(unicast, key_idx, false);
+
+ node_check_key_updated(jarray, j, &updated);
+ remote_update_app_key(unicast, key_idx, updated, false);
}

load_composition(jnode, unicast);
@@ -554,28 +614,19 @@ static bool add_node_key(json_object *jobj, const char *desc, uint16_t idx)

jkey = json_object_new_object();

- if (!write_int(jkey, "index", (int)idx)) {
- json_object_put(jkey);
- return false;
- }
+ if (!write_int(jkey, "index", (int)idx))
+ goto fail;
+
+ if (!write_bool(jkey, "updated", false))
+ goto fail;

json_object_array_add(jarray, jkey);

return save_config();
-}
-
-bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx)
-{
- json_object *jnode;
-
- if (!cfg || !cfg->jcfg)
- return false;

- jnode = get_node_by_unicast(unicast);
- if (!jnode)
- return false;
-
- return add_node_key(jnode, "netKeys", idx);
+fail:
+ json_object_put(jkey);
+ return false;
}

bool mesh_db_node_ttl_set(uint16_t unicast, uint8_t ttl)
@@ -628,6 +679,20 @@ static bool delete_key(json_object *jobj, const char *desc, uint16_t idx)
return save_config();
}

+bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx)
+{
+ json_object *jnode;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(unicast);
+ if (!jnode)
+ return false;
+
+ return add_node_key(jnode, "netKeys", idx);
+}
+
bool mesh_db_node_net_key_del(uint16_t unicast, uint16_t net_idx)
{
json_object *jnode;
@@ -642,6 +707,45 @@ bool mesh_db_node_net_key_del(uint16_t unicast, uint16_t net_idx)
return delete_key(jnode, "netKeys", net_idx);
}

+static bool key_update(uint16_t unicast, int16_t idx, bool updated,
+ const char *desc)
+{
+ json_object *jnode, *jarray;
+ int i, sz;
+
+ if (!cfg || !cfg->jcfg)
+ return false;
+
+ jnode = get_node_by_unicast(unicast);
+ if (!jnode)
+ return false;
+
+ if (!json_object_object_get_ex(jnode, desc, &jarray))
+ return false;
+
+ sz = json_object_array_length(jarray);
+
+ for (i = 0; i < sz; ++i) {
+ json_object *jentry;
+ int val;
+
+ jentry = json_object_array_get_idx(jarray, i);
+
+ if (!get_int(jentry, "index", &val))
+ continue;
+
+ if ((val == idx) && write_bool(jentry, "updated", updated))
+ return save_config();
+ }
+
+ return false;
+}
+
+bool mesh_db_node_net_key_update(uint16_t unicast, uint16_t idx, bool updated)
+{
+ return key_update(unicast, idx, updated, "netKeys");
+}
+
bool mesh_db_node_app_key_add(uint16_t unicast, uint16_t idx)
{
json_object *jnode;
@@ -670,6 +774,11 @@ bool mesh_db_node_app_key_del(uint16_t unicast, uint16_t idx)
return delete_key(jnode, "appKeys", idx);
}

+bool mesh_db_node_app_key_update(uint16_t unicast, uint16_t idx, bool updated)
+{
+ return key_update(unicast, idx, updated, "appKeys");
+}
+
static bool load_keys(json_object *jobj)
{
json_object *jarray, *jentry;
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index efd579553..c1bcb3ae6 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -38,8 +38,10 @@ 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);
bool mesh_db_node_net_key_del(uint16_t unicast, uint16_t idx);
+bool mesh_db_node_net_key_update(uint16_t unicast, uint16_t idx, bool updated);
bool mesh_db_node_app_key_add(uint16_t unicast, uint16_t idx);
bool mesh_db_node_app_key_del(uint16_t unicast, uint16_t idx);
+bool mesh_db_node_app_key_update(uint16_t unicast, uint16_t idx, bool updated);
bool mesh_db_node_ttl_set(uint16_t unicast, uint8_t ttl);
bool mesh_db_node_write_mode(uint16_t unicast, const char *keyword, int value);
bool mesh_db_node_model_binding_add(uint16_t unicast, uint8_t ele, bool vendor,
diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c
index e60a3681d..5f598cb8b 100644
--- a/tools/mesh/remote.c
+++ b/tools/mesh/remote.c
@@ -25,6 +25,11 @@

#define abs_diff(a, b) ((a) > (b) ? (a) - (b) : (b) - (a))

+struct remote_key {
+ uint16_t idx;
+ bool updated;
+};
+
struct remote_node {
uint16_t unicast;
struct l_queue *net_keys;
@@ -42,20 +47,6 @@ struct rejected_addr {
static struct l_queue *nodes;
static struct l_queue *reject_list;

-static bool key_present(struct l_queue *keys, uint16_t app_idx)
-{
- const struct l_queue_entry *l;
-
- for (l = l_queue_get_entries(keys); l; l = l->next) {
- uint16_t idx = L_PTR_TO_UINT(l->data);
-
- if (idx == app_idx)
- return true;
- }
-
- return false;
-}
-
static int compare_mod_id(const void *a, const void *b, void *user_data)
{
uint32_t id1 = L_PTR_TO_UINT(a);
@@ -102,12 +93,20 @@ static bool match_node_addr(const void *a, const void *b)
return false;
}

+static bool match_key(const void *a, const void *b)
+{
+ const struct remote_key *key = a;
+ uint16_t idx = L_PTR_TO_UINT(b);
+
+ return (key->idx == idx);
+}
+
static bool match_bound_key(const void *a, const void *b)
{
- uint16_t app_idx = L_PTR_TO_UINT(a);
+ const struct remote_key *app_key = a;
uint16_t net_idx = L_PTR_TO_UINT(b);

- return (net_idx == keys_get_bound_key(app_idx));
+ return (net_idx == keys_get_bound_key(app_key->idx));
}

uint8_t remote_del_node(uint16_t unicast)
@@ -142,6 +141,7 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
uint8_t ele_cnt, uint16_t net_idx)
{
struct remote_node *rmt;
+ struct remote_key *key;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(unicast));
if (rmt)
@@ -153,7 +153,10 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
rmt->num_ele = ele_cnt;
rmt->net_keys = l_queue_new();

- l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
+ key = l_new(struct remote_key, 1);
+ key->idx = net_idx;
+
+ l_queue_push_tail(rmt->net_keys, key);

rmt->els = l_new(struct l_queue *, ele_cnt);

@@ -161,6 +164,7 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
nodes = l_queue_new();

l_queue_insert(nodes, rmt, compare_unicast, NULL);
+
return true;
}

@@ -188,49 +192,84 @@ bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
return true;
}

-bool remote_add_net_key(uint16_t addr, uint16_t net_idx)
+bool remote_add_net_key(uint16_t addr, uint16_t net_idx, bool save)
{
struct remote_node *rmt;
+ struct remote_key *key;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
if (!rmt)
return false;

- if (key_present(rmt->net_keys, net_idx))
- return false;
+ if (l_queue_find(rmt->net_keys, match_key, L_UINT_TO_PTR(net_idx)))
+ return true;

- l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
- return true;
+ key = l_new(struct remote_key, 1);
+ key->idx = net_idx;
+
+ l_queue_push_tail(rmt->net_keys, key);
+
+ if (save)
+ return mesh_db_node_net_key_add(addr, net_idx);
+ else
+ return true;
}

bool remote_del_net_key(uint16_t addr, uint16_t net_idx)
{
struct remote_node *rmt;
- void *data;
+ struct remote_key *key;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
if (!rmt)
return false;

- if (!l_queue_remove(rmt->net_keys, L_UINT_TO_PTR(net_idx)))
+ key = l_queue_remove_if(rmt->net_keys, match_key,
+ L_UINT_TO_PTR(net_idx));
+ if (!key)
return false;

- data = l_queue_remove_if(rmt->app_keys, match_bound_key,
+ mesh_db_node_net_key_del(addr, net_idx);
+
+ l_free(key);
+ key = l_queue_remove_if(rmt->app_keys, match_bound_key,
L_UINT_TO_PTR(net_idx));
- while (data) {
- uint16_t app_idx = (uint16_t) L_PTR_TO_UINT(data);

- mesh_db_node_app_key_del(rmt->unicast, app_idx);
- data = l_queue_remove_if(rmt->app_keys, match_bound_key,
+ while (key) {
+ mesh_db_node_app_key_del(rmt->unicast, key->idx);
+ l_free(key);
+
+ key = l_queue_remove_if(rmt->app_keys, match_bound_key,
L_UINT_TO_PTR(net_idx));
}

return true;
}

-bool remote_add_app_key(uint16_t addr, uint16_t app_idx)
+bool remote_update_net_key(uint16_t addr, uint16_t net_idx, bool update,
+ bool save)
+{
+ struct remote_node *rmt;
+ struct remote_key *key;
+
+ rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+ if (!rmt)
+ return false;
+
+ key = l_queue_find(rmt->net_keys, match_key,
+ L_UINT_TO_PTR(net_idx));
+ key->updated = update;
+
+ if (save)
+ return mesh_db_node_net_key_update(addr, net_idx, update);
+ else
+ return true;
+}
+
+bool remote_add_app_key(uint16_t addr, uint16_t app_idx, bool save)
{
struct remote_node *rmt;
+ struct remote_key *key;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
if (!rmt)
@@ -239,44 +278,105 @@ bool remote_add_app_key(uint16_t addr, uint16_t app_idx)
if (!rmt->app_keys)
rmt->app_keys = l_queue_new();

- if (key_present(rmt->app_keys, app_idx))
- return false;
+ if (l_queue_find(rmt->app_keys, match_key, L_UINT_TO_PTR(app_idx)))
+ return true;

- l_queue_push_tail(rmt->app_keys, L_UINT_TO_PTR(app_idx));
- return true;
+ key = l_new(struct remote_key, 1);
+ key->idx = app_idx;
+
+ l_queue_push_tail(rmt->app_keys, key);
+
+ if (save)
+ return mesh_db_node_app_key_add(addr, app_idx);
+ else
+ return true;
}

bool remote_del_app_key(uint16_t addr, uint16_t app_idx)
{
struct remote_node *rmt;
+ struct remote_key *key;
+
+ rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+ if (!rmt)
+ return false;
+
+ key = l_queue_remove_if(rmt->app_keys, match_key,
+ L_UINT_TO_PTR(app_idx));
+ l_free(key);
+
+ return mesh_db_node_app_key_del(addr, app_idx);
+}
+
+bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
+ bool save)
+{
+ struct remote_node *rmt;
+ struct remote_key *key;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
if (!rmt)
return false;

- return l_queue_remove(rmt->app_keys, L_UINT_TO_PTR(app_idx));
+ key = l_queue_find(rmt->app_keys, match_key,
+ L_UINT_TO_PTR(app_idx));
+ key->updated = update;
+
+ if (save)
+ return mesh_db_node_app_key_update(addr, app_idx, update);
+ else
+ return true;
+}
+
+void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx)
+{
+ struct remote_node *rmt;
+ struct remote_key *key;
+ const struct l_queue_entry *l;
+
+ rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+ if (!rmt)
+ return;
+
+ if (!remote_update_net_key(addr, net_idx, false, true))
+ return;
+
+ l = l_queue_get_entries(rmt->app_keys);
+
+ for (; l; l = l->next) {
+ key = l->data;
+
+ if (net_idx != keys_get_bound_key(key->idx))
+ continue;
+
+ key->updated = false;
+
+ mesh_db_node_app_key_update(addr, key->idx, false);
+ }
+
}

uint16_t remote_get_subnet_idx(uint16_t addr)
{
struct remote_node *rmt;
- uint32_t net_idx;
+ struct remote_key *key;

rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));

if (!rmt || l_queue_isempty(rmt->net_keys))
return NET_IDX_INVALID;

- net_idx = L_PTR_TO_UINT(l_queue_peek_head(rmt->net_keys));
+ key = l_queue_peek_head(rmt->net_keys);

- return (uint16_t) net_idx;
+ return key->idx;
}

-static void print_key(void *key, void *user_data)
+static void print_key(void *data, void *user_data)
{
- uint16_t idx = L_PTR_TO_UINT(key);
+ struct remote_key *key = data;

- bt_shell_printf("%u (0x%3.3x), ", idx, idx);
+ bt_shell_printf("%u (0x%3.3x) %s, ", key->idx, key->idx,
+ key->updated ? ", updated":"");
}

static void print_model(void *model, void *user_data)
diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h
index 8ecb097ae..74747689a 100644
--- a/tools/mesh/remote.h
+++ b/tools/mesh/remote.h
@@ -16,10 +16,15 @@ bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
void remote_add_rejected_address(uint16_t addr, uint32_t iv_index, bool save);
void remote_clear_rejected_addresses(uint32_t iv_index);
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_add_net_key(uint16_t addr, uint16_t net_idx, bool save);
bool remote_del_net_key(uint16_t addr, uint16_t net_idx);
-bool remote_add_app_key(uint16_t addr, uint16_t app_idx);
+bool remote_update_net_key(uint16_t addr, uint16_t net_idx, bool update,
+ bool save);
+bool remote_add_app_key(uint16_t addr, uint16_t app_idx, bool save);
bool remote_del_app_key(uint16_t addr, uint16_t app_idx);
+bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
+ bool save);
+void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx);
uint16_t remote_get_subnet_idx(uint16_t addr);
void remote_print_node(uint16_t addr);
void remote_print_all(void);
--
2.31.1

2021-09-23 03:31:43

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 17/20] mesh: Implement ExportKeys() method

Add implementation for new method ExportKeys() on
org.bluez.mesh.Management1 interface.
This method is used by the authorized application to export information
about network keys, application keys and device keys present in the
local key database.
---
mesh/keyring.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++++-
mesh/keyring.h | 2 +
mesh/manager.c | 35 ++++++
3 files changed, 322 insertions(+), 1 deletion(-)

diff --git a/mesh/keyring.c b/mesh/keyring.c
index f27fe4291..4b901643c 100644
--- a/mesh/keyring.c
+++ b/mesh/keyring.c
@@ -26,6 +26,7 @@

#include "mesh/mesh-defs.h"

+#include "mesh/dbus.h"
#include "mesh/node.h"
#include "mesh/keyring.h"

@@ -276,7 +277,6 @@ bool keyring_get_remote_dev_key(struct mesh_node *node, uint16_t unicast,

snprintf(key_file, PATH_MAX, "%s%s/%4.4x", node_path, dev_key_dir,
unicast);
-
fd = open(key_file, O_RDONLY);
if (fd >= 0) {
if (read(fd, dev_key, 16) == 16)
@@ -349,3 +349,287 @@ bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast,

return true;
}
+
+static DIR *open_key_dir(const char *node_path, const char *key_dir_name)
+{
+ char dir_path[PATH_MAX];
+ DIR *key_dir;
+
+ if (strlen(node_path) + strlen(key_dir_name) + 1 >= PATH_MAX)
+ return NULL;
+
+ snprintf(dir_path, PATH_MAX, "%s%s", node_path, key_dir_name);
+
+ key_dir = opendir(dir_path);
+ if (!key_dir) {
+ l_error("Failed to open keyring storage directory: %s",
+ dir_path);
+ return NULL;
+ }
+
+ return key_dir;
+}
+
+static int open_key_dir_entry(int dir_fd, struct dirent *entry,
+ uint8_t fname_len)
+{
+ if (entry->d_type != DT_REG)
+ return -1;
+
+ /* Check the file name length */
+ if (strlen(entry->d_name) != fname_len)
+ return -1;
+
+ return openat(dir_fd, entry->d_name, O_RDONLY);
+}
+
+static void append_old_key(struct l_dbus_message_builder *builder,
+ const uint8_t key[16])
+{
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', "OldKey");
+ l_dbus_message_builder_enter_variant(builder, "ay");
+ dbus_append_byte_array(builder, key, 16);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+}
+
+static void build_app_keys_reply(const char *node_path,
+ struct l_dbus_message_builder *builder,
+ uint16_t net_idx, uint8_t phase)
+{
+ DIR *key_dir;
+ int key_dir_fd;
+ struct dirent *entry;
+
+ key_dir = open_key_dir(node_path, app_key_dir);
+ if (!key_dir)
+ return;
+
+ key_dir_fd = dirfd(key_dir);
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', "AppKeys");
+ l_dbus_message_builder_enter_variant(builder, "a(qaya{sv})");
+ l_dbus_message_builder_enter_array(builder, "(qaya{sv})");
+
+ while ((entry = readdir(key_dir)) != NULL) {
+ struct keyring_app_key key;
+ int fd = open_key_dir_entry(key_dir_fd, entry, 3);
+
+ if (fd < 0)
+ continue;
+
+ if (read(fd, &key, sizeof(key)) != sizeof(key) ||
+ key.net_idx != net_idx) {
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+
+ l_dbus_message_builder_enter_struct(builder, "qaya{sv}");
+
+ l_dbus_message_builder_append_basic(builder, 'q', &key.app_idx);
+ dbus_append_byte_array(builder, key.new_key, 16);
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ if (phase != KEY_REFRESH_PHASE_NONE)
+ append_old_key(builder, key.old_key);
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_struct(builder);
+ }
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+
+ closedir(key_dir);
+}
+
+static bool build_net_keys_reply(const char *node_path,
+ struct l_dbus_message_builder *builder)
+{
+ DIR *key_dir;
+ int key_dir_fd;
+ struct dirent *entry;
+ bool result = false;
+
+ key_dir = open_key_dir(node_path, net_key_dir);
+ if (!key_dir)
+ return false;
+
+ key_dir_fd = dirfd(key_dir);
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', "NetKeys");
+ l_dbus_message_builder_enter_variant(builder, "a(qaya{sv})");
+ l_dbus_message_builder_enter_array(builder, "(qaya{sv})");
+
+ while ((entry = readdir(key_dir)) != NULL) {
+ struct keyring_net_key key;
+ int fd = open_key_dir_entry(key_dir_fd, entry, 3);
+
+ if (fd < 0)
+ continue;
+
+ if (read(fd, &key, sizeof(key)) != sizeof(key)) {
+ close(fd);
+ goto done;
+ }
+
+ close(fd);
+
+ /*
+ * If network key is stuck in phase 3, keyring
+ * write failed and this key info is unreliable.
+ */
+ if (key.phase == KEY_REFRESH_PHASE_THREE)
+ continue;
+
+ l_dbus_message_builder_enter_struct(builder, "qaya{sv}");
+
+ l_dbus_message_builder_append_basic(builder, 'q', &key.net_idx);
+ dbus_append_byte_array(builder, key.new_key, 16);
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ if (key.phase != KEY_REFRESH_PHASE_NONE) {
+ dbus_append_dict_entry_basic(builder, "Phase", "y",
+ &key.phase);
+ append_old_key(builder, key.old_key);
+ }
+
+ build_app_keys_reply(node_path, builder, key.net_idx,
+ key.phase);
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_struct(builder);
+ }
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+
+ result = true;
+done:
+ closedir(key_dir);
+
+ return result;
+
+}
+
+struct dev_key_entry {
+ uint16_t unicast;
+ uint8_t value[16];
+};
+
+static bool match_key_value(const void *a, const void *b)
+{
+ const struct dev_key_entry *key = a;
+ const uint8_t *value = b;
+
+ return (memcmp(key->value, value, 16) == 0);
+}
+
+static void build_dev_key_entry(void *a, void *b)
+{
+ struct dev_key_entry *key = a;
+ struct l_dbus_message_builder *builder = b;
+
+ l_dbus_message_builder_enter_struct(builder, "qay");
+ l_dbus_message_builder_append_basic(builder, 'q', &key->unicast);
+ dbus_append_byte_array(builder, key->value, 16);
+ l_dbus_message_builder_leave_struct(builder);
+}
+
+static bool build_dev_keys_reply(const char *node_path,
+ struct l_dbus_message_builder *builder)
+{
+ DIR *key_dir;
+ int key_dir_fd;
+ struct dirent *entry;
+ struct l_queue *keys;
+ bool result = false;
+
+ key_dir = open_key_dir(node_path, dev_key_dir);
+ /*
+ * There is always at least one device key present for a local node.
+ * Therefore, return false, if the directory does not exist.
+ */
+ if (!key_dir)
+ return false;
+
+ key_dir_fd = dirfd(key_dir);
+
+ keys = l_queue_new();
+
+ while ((entry = readdir(key_dir)) != NULL) {
+ uint8_t buf[16];
+ uint16_t unicast;
+ struct dev_key_entry *key;
+ int fd = open_key_dir_entry(key_dir_fd, entry, 4);
+
+ if (fd < 0)
+ continue;
+
+ if (read(fd, buf, 16) != 16) {
+ close(fd);
+ goto done;
+ }
+
+ close(fd);
+
+ if (sscanf(entry->d_name, "%04hx", &unicast) != 1)
+ goto done;
+
+ key = l_queue_find(keys, match_key_value, buf);
+
+ if (key) {
+ if (key->unicast > unicast)
+ key->unicast = unicast;
+ continue;
+ }
+
+ key = l_new(struct dev_key_entry, 1);
+ key->unicast = unicast;
+ memcpy(key->value, buf, 16);
+ l_queue_push_tail(keys, key);
+ }
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', "DevKeys");
+ l_dbus_message_builder_enter_variant(builder, "a(qay)");
+ l_dbus_message_builder_enter_array(builder, "(qay)");
+
+ l_queue_foreach(keys, build_dev_key_entry, builder);
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+
+ result = true;
+done:
+ l_queue_destroy(keys, l_free);
+ closedir(key_dir);
+
+ return result;
+}
+
+bool keyring_build_export_keys_reply(struct mesh_node *node,
+ struct l_dbus_message_builder *builder)
+{
+ const char *node_path;
+
+ if (!node)
+ return false;
+
+ node_path = node_get_storage_dir(node);
+
+ if (!build_net_keys_reply(node_path, builder))
+ return false;
+
+ return build_dev_keys_reply(node_path, builder);
+}
diff --git a/mesh/keyring.h b/mesh/keyring.h
index c2d38e9ff..ecf62cbc1 100644
--- a/mesh/keyring.h
+++ b/mesh/keyring.h
@@ -39,3 +39,5 @@ bool keyring_put_remote_dev_key(struct mesh_node *node, uint16_t unicast,
uint8_t count, uint8_t dev_key[16]);
bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast,
uint8_t count);
+bool keyring_build_export_keys_reply(struct mesh_node *node,
+ struct l_dbus_message_builder *builder);
diff --git a/mesh/manager.c b/mesh/manager.c
index d70993e3b..e66b1a45b 100644
--- a/mesh/manager.c
+++ b/mesh/manager.c
@@ -776,6 +776,38 @@ static struct l_dbus_message *set_key_phase_call(struct l_dbus *dbus,
return l_dbus_message_new_method_return(msg);
}

+static struct l_dbus_message *export_keys_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ const char *sender = l_dbus_message_get_sender(msg);
+ struct l_dbus_message_builder *builder;
+ struct l_dbus_message *reply;
+ struct mesh_node *node = user_data;
+
+ l_debug("Export Keys");
+
+ if (strcmp(sender, node_get_owner(node)))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ builder = l_dbus_message_builder_new(reply);
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ if (!keyring_build_export_keys_reply(node, builder)) {
+ l_dbus_message_builder_destroy(builder);
+ l_dbus_message_unref(reply);
+ return dbus_error(msg, MESH_ERROR_FAILED, NULL);
+ }
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ return reply;
+}
+
static void setup_management_interface(struct l_dbus_interface *iface)
{
l_dbus_interface_method(iface, "AddNode", 0, add_node_call, "",
@@ -807,6 +839,9 @@ static void setup_management_interface(struct l_dbus_interface *iface)
"app_index", "app_key");
l_dbus_interface_method(iface, "SetKeyPhase", 0, set_key_phase_call, "",
"qy", "net_index", "phase");
+ l_dbus_interface_method(iface, "ExportKeys", 0, export_keys_call,
+ "a(qaya{sv})a(qay)", "",
+ "net_keys", "dev_keys");
}

bool manager_dbus_init(struct l_dbus *bus)
--
2.31.1

2021-09-27 20:28:49

by Gix, Brian

[permalink] [raw]
Subject: Re: [PATCH BlueZ 00/20] Mesh Configuration Database

With very minor tweeks (to avoid introducing, then removing obsolete naming) Patchset has been applied.

On Wed, 2021-09-22 at 20:25 -0700, Inga Stotland wrote:
> This patch set (I apologize for its size, but this cannot be helped)
> implements support for the newly published Mesh Configuration Database
> Profile.
>
> The changes are mostly contained to tools/mesh-cfgclient.c and tools/mesh
> subdirectory. The only exception is the introduction of a new D-Bus mesh
> API method ExportKeys() on org.bluez.mesh.Management1 interface.
>
> The new functionality allows to export a snapshot of mesh state
> from the point of view of mesh provisioner/configuration manager in
> a standard format that can be used for to transferring the "ownership"
> of the mesh configuration to another provisioner/configuration manager.
>
> The changes break backwards compatibility with for the previous
> versions of config-db.json that were generated when using
> mesh-cfgclient tool. This can be amended by manually correcting the
> field names and property values.
>
> Inga Stotland (20):
>   tools/mesh-cfgclient: Save provisioner info
>   tools/mesh-cfgclient: Add timestamp to config database
>   tools/mesh-cfgclient: Update stored NetKey and AppKey
>   tools/mesh-cfgclient: Keep track of updated keys
>   tools/mesh: Add new info to stored remote nodes
>   tools/mesh-cfgclient: Overwrite config values when adding new ones
>   tools/mesh-cfgclient: Store remote node's model bindings
>   tools/mesh-cfgclient: Store remote node's model subs
>   tools/mesh-cfgclient: Disallow model commands w/o composition
>   tools/mesh-cfgclient: Store remote's model publication info
>   tools/mesh-cfgclient: Check the result of config save
>   tools/mesh-cfgclient: Rename mesh-db APIs for consistency
>   tools/mesh-cfgclient: Save remote node feature setting
>   tools/mesh-cfgclient: Store remote's heartbeat sub/pub
>   tools/mesh-cfgclient: Add group parent address for DB compliance
>   doc/mesh-api: Add ExportKeys call
>   mesh: Implement ExportKeys() method
>   tools/mesh-cfgclient: Store UUIDs in standard format
>   tools/mesh-cfgclient: Excluded addresses property
>   tools/mesh-cfgclient: Export configuration database
>
>  doc/mesh-api.txt       |   56 ++
>  mesh/keyring.c         |  286 ++++++++-
>  mesh/keyring.h         |    2 +
>  mesh/manager.c         |   35 ++
>  tools/mesh-cfgclient.c |  212 ++++++-
>  tools/mesh/cfgcli.c    |  284 ++++++---
>  tools/mesh/keys.c      |    4 +-
>  tools/mesh/mesh-db.c   | 1260 +++++++++++++++++++++++++++++++++++++---
>  tools/mesh/mesh-db.h   |   66 ++-
>  tools/mesh/model.h     |   13 +-
>  tools/mesh/remote.c    |  205 +++++--
>  tools/mesh/remote.h    |   11 +-
>  12 files changed, 2206 insertions(+), 228 deletions(-)
>