Patchset Applied On Tue, 2020-03-17 at 15:15 -0700, Inga Stotland wrote: > This implements one-pass removal oa a remote node from a mesh network > by issuing a node-reset command from config menu. The following actions > are performed: > - Config Node Reset message is sent to a remote node > - Upon either receiving Config Node Reset Status or response timeout, > node record is removed from configuration client's database and, > by calling DeleteRemoteNode() method on mesh.Management interface > > node-delete command from the main menu is removed. > --- > tools/mesh-cfgclient.c | 77 ++++++++++++++++-------------------------- > tools/mesh/cfgcli.c | 60 ++++++++++++++++++++++++++++---- > tools/mesh/cfgcli.h | 4 ++- > tools/mesh/mesh-db.c | 39 +++++++++++++++++++++ > tools/mesh/remote.c | 20 +++++++++++ > tools/mesh/remote.h | 1 + > 6 files changed, 147 insertions(+), 54 deletions(-) > > diff --git a/tools/mesh-cfgclient.c b/tools/mesh-cfgclient.c > index 4b7bd2200..e4523e5fc 100644 > --- a/tools/mesh-cfgclient.c > +++ b/tools/mesh-cfgclient.c > @@ -342,9 +342,38 @@ static bool send_key(void *user_data, uint16_t dst, uint16_t key_idx, > send_key_setup, NULL, req, l_free) != 0; > } > > +static void delete_node_setup(struct l_dbus_message *msg, void *user_data) > +{ > + struct generic_request *req = user_data; > + uint16_t primary; > + uint8_t ele_cnt; > + > + primary = (uint16_t) req->arg1; > + ele_cnt = (uint8_t) req->arg2; > + > + l_dbus_message_set_arguments(msg, "qy", primary, ele_cnt); > +} > + > +static void delete_node(uint16_t primary, uint8_t ele_cnt) > +{ > + struct generic_request *req; > + > + if (!local || !local->proxy || !local->mgmt_proxy) { > + bt_shell_printf("Node is not attached\n"); > + return; > + } > + > + req = l_new(struct generic_request, 1); > + req->arg1 = primary; > + req->arg2 = ele_cnt; > + > + l_dbus_proxy_method_call(local->mgmt_proxy, "DeleteRemoteNode", > + delete_node_setup, NULL, req, l_free); > +} > + > static void client_init(void) > { > - cfgcli = cfgcli_init(send_key, (void *) app.ele.path); > + cfgcli = cfgcli_init(send_key, delete_node, (void *) app.ele.path); > cfgcli->ops.set_send_func(send_msg, (void *) app.ele.path); > } > > @@ -801,50 +830,6 @@ static void free_generic_request(void *data) > l_free(req); > } > > -static void delete_node_setup(struct l_dbus_message *msg, void *user_data) > -{ > - struct generic_request *req = user_data; > - uint16_t primary; > - uint8_t ele_cnt; > - > - primary = (uint16_t) req->arg1; > - ele_cnt = (uint8_t) req->arg2; > - > - l_dbus_message_set_arguments(msg, "qy", primary, ele_cnt); > -} > - > -static void cmd_delete_node(int argc, char *argv[]) > -{ > - struct generic_request *req; > - > - if (!local || !local->proxy || !local->mgmt_proxy) { > - bt_shell_printf("Node is not attached\n"); > - return; > - } > - > - if (argc < 3) { > - bt_shell_printf("Unicast and element count are required\n"); > - return; > - } > - > - req = l_new(struct generic_request, 1); > - > - if (sscanf(argv[1], "%04x", &req->arg1) != 1) > - goto fail; > - > - if (sscanf(argv[2], "%u", &req->arg2) != 1) > - goto fail; > - > - l_dbus_proxy_method_call(local->mgmt_proxy, "DeleteRemoteNode", > - delete_node_setup, NULL, req, l_free); > - > - /* TODO:: Delete node from configuration */ > - return; > - > -fail: > - l_free(req); > -} > - > static void import_node_reply(struct l_dbus_proxy *proxy, > struct l_dbus_message *msg, void *user_data) > { > @@ -1359,8 +1344,6 @@ static const struct bt_shell_menu main_menu = { > { "node-import", "<uuid> <net_idx> <primary> <ele_count> <dev_key>", > cmd_import_node, > "Import an externally provisioned remote node"}, > - { "node-delete", "<primary> <ele_count>", cmd_delete_node, > - "Delete a remote node"}, > { "list-nodes", NULL, cmd_list_nodes, > "List remote mesh nodes"}, > { "keys", NULL, cmd_keys, > diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c > index 33e77d878..0c82d9f82 100644 > --- a/tools/mesh/cfgcli.c > +++ b/tools/mesh/cfgcli.c > @@ -65,6 +65,7 @@ static struct l_queue *groups; > > static void *send_data; > static model_send_msg_func_t send_msg; > +static delete_remote_func_t mgr_del_remote; > > static void *key_data; > static key_send_func_t send_key_msg; > @@ -191,6 +192,15 @@ static const char *opcode_str(uint32_t opcode) > return cmd->desc; > } > > +static void reset_remote_node(uint16_t addr) > +{ > + uint8_t ele_cnt = remote_del_node(addr); > + > + bt_shell_printf("Remote removed (primary %4.4x)\n", addr); > + if (ele_cnt && mgr_del_remote) > + mgr_del_remote(addr, ele_cnt); > +} > + > static void free_request(void *a) > { > struct pending_req *req = a; > @@ -222,6 +232,10 @@ static void wait_rsp_timeout(struct l_timeout *timeout, void *user_data) > bt_shell_printf("No response for \"%s\" from %4.4x\n", > req->cmd->desc, req->addr); > > + /* Node reset case: delete the remote even if there is no response */ > + if (req->cmd->opcode == OP_NODE_RESET) > + reset_remote_node(req->addr); > + > l_queue_remove(requests, req); > free_request(req); > } > @@ -713,11 +727,9 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data, > > /* Per Mesh Profile 4.3.2.54 */ > case OP_NODE_RESET_STATUS: > - if (len != 1) > - return true; > > - bt_shell_printf("Node %4.4x reset status %s\n", > - src, mesh_status_str(data[0])); > + bt_shell_printf("Node %4.4x is reset\n", src); > + reset_remote_node(src); > > break; > > @@ -1656,7 +1668,41 @@ static void cmd_friend_get(int argc, char *argv[]) > > static void cmd_node_reset(int argc, char *argv[]) > { > - cmd_default(OP_NODE_RESET); > + uint16_t n, i; > + uint8_t msg[8]; > + struct pending_req *req; > + > + if (IS_UNASSIGNED(target)) { > + bt_shell_printf("Destination not set\n"); > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > + } > + > + /* Cannot remet self */ > + if (target == 0x0001) { > + bt_shell_printf("Resetting self not allowed\n"); > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > + } > + > + n = mesh_opcode_set(OP_NODE_RESET, msg); > + > + req = l_new(struct pending_req, 1); > + req->addr = target; > + req->cmd = get_cmd(OP_NODE_RESET); > + > + /* > + * As a courtesy to the remote node, send the reset command > + * several times. Treat this as a single request with a longer > + * response timeout. > + */ > + req->timer = l_timeout_create(rsp_timeout * 2, > + wait_rsp_timeout, req, NULL); > + > + l_queue_push_tail(requests, req); > + > + for (i = 0; i < 5; i++) > + send_msg(send_data, target, APP_IDX_DEV_REMOTE, msg, n); > + > + return bt_shell_noninteractive_quit(EXIT_SUCCESS); > } > > static void cmd_netkey_get(int argc, char *argv[]) > @@ -1831,13 +1877,15 @@ static struct model_info cli_info = { > .vendor_id = VENDOR_ID_INVALID > }; > > -struct model_info *cfgcli_init(key_send_func_t key_send, void *user_data) > +struct model_info *cfgcli_init(key_send_func_t key_send, > + delete_remote_func_t del_node, void *user_data) > { > if (!key_send) > return NULL; > > send_key_msg = key_send; > key_data = user_data; > + mgr_del_remote = del_node; > requests = l_queue_new(); > groups = mesh_db_load_groups(); > bt_shell_add_submenu(&cfg_menu); > diff --git a/tools/mesh/cfgcli.h b/tools/mesh/cfgcli.h > index 9b283d9d5..89a67f5de 100644 > --- a/tools/mesh/cfgcli.h > +++ b/tools/mesh/cfgcli.h > @@ -25,6 +25,8 @@ struct mesh_group { > > typedef bool (*key_send_func_t) (void *user_data, uint16_t dst, > uint16_t idx, bool is_appkey, bool update); > +typedef void (*delete_remote_func_t) (uint16_t primary, uint8_t ele_cnt); > > -struct model_info *cfgcli_init(key_send_func_t key_func, void *user_data); > +struct model_info *cfgcli_init(key_send_func_t key_func, > + delete_remote_func_t del_node, void *user_data); > void cfgcli_cleanup(void); > diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c > index 4a26a667e..e938ee733 100644 > --- a/tools/mesh/mesh-db.c > +++ b/tools/mesh/mesh-db.c > @@ -845,6 +845,45 @@ fail: > return false; > } > > +bool mesh_db_del_node(uint16_t unicast) > +{ > + json_object *jarray; > + int i, sz; > + > + if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jarray)) > + return false; > + > + if (!jarray || json_object_get_type(jarray) != json_type_array) > + return false; > + > + sz = json_object_array_length(jarray); > + > + for (i = 0; i < sz; ++i) { > + json_object *jentry, *jval; > + uint16_t addr; > + const char *str; > + > + jentry = json_object_array_get_idx(jarray, i); > + if (!json_object_object_get_ex(jentry, "unicastAddress", > + &jval)) > + continue; > + > + str = json_object_get_string(jval); > + if (sscanf(str, "%04hx", &addr) != 1) > + continue; > + > + if (addr == unicast) > + break; > + } > + > + if (i == sz) > + return true; > + > + json_object_array_del_idx(jarray, i, 1); > + > + return mesh_config_save((struct mesh_config *) cfg, true, NULL, NULL); > +} > + > bool mesh_db_get_token(uint8_t token[8]) > { > if (!cfg || !cfg->jcfg) > diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c > index 533d59b28..b9bc6b5c0 100644 > --- a/tools/mesh/remote.c > +++ b/tools/mesh/remote.c > @@ -89,6 +89,26 @@ static bool match_bound_key(const void *a, const void *b) > return (net_idx == keys_get_bound_key(app_idx)); > } > > +uint8_t remote_del_node(uint16_t unicast) > +{ > + struct remote_node *rmt; > + uint8_t num_ele; > + > + rmt = l_queue_remove_if(nodes, match_node_addr, L_UINT_TO_PTR(unicast)); > + if (!rmt) > + return 0; > + > + num_ele = rmt->num_ele; > + > + l_queue_destroy(rmt->net_keys, NULL); > + l_queue_destroy(rmt->app_keys, NULL); > + l_free(rmt); > + > + mesh_db_del_node(unicast); > + > + return num_ele; > +} > + > bool remote_add_node(const uint8_t uuid[16], uint16_t unicast, > uint8_t ele_cnt, uint16_t net_idx) > { > diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h > index f2a6f48dd..63382ed90 100644 > --- a/tools/mesh/remote.h > +++ b/tools/mesh/remote.h > @@ -19,6 +19,7 @@ > > bool remote_add_node(const uint8_t uuid[16], uint16_t unicast, > uint8_t ele_cnt, uint16_t net_idx); > +uint8_t remote_del_node(uint16_t unicast); > uint16_t remote_get_next_unicast(uint16_t low, uint16_t high, uint8_t ele_cnt); > bool remote_add_net_key(uint16_t addr, uint16_t net_idx); > bool remote_del_net_key(uint16_t addr, uint16_t net_idx);