linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/2] Remote node reset implementation
@ 2020-03-13 18:08 Inga Stotland
  2020-03-13 18:08 ` [PATCH BlueZ 1/2] tools/mesh-cfgclient: Implement node-reset command Inga Stotland
  2020-03-13 18:08 ` [PATCH BlueZ 2/2] mesh: Fix processing of Config Node Reset message Inga Stotland
  0 siblings, 2 replies; 3+ messages in thread
From: Inga Stotland @ 2020-03-13 18:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This set of patches provides complete implementation of sending
and processing of Config Node Reset and Config Node Reset Status
messages

Inga Stotland (2):
  tools/mesh-cfgclient: Implement node-reset command
  mesh: Fix processing of Config Node Reset message

 mesh/cfgmod-server.c   | 14 ++++----
 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 +
 7 files changed, 154 insertions(+), 61 deletions(-)

-- 
2.21.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH BlueZ 1/2] tools/mesh-cfgclient: Implement node-reset command
  2020-03-13 18:08 [PATCH BlueZ 0/2] Remote node reset implementation Inga Stotland
@ 2020-03-13 18:08 ` Inga Stotland
  2020-03-13 18:08 ` [PATCH BlueZ 2/2] mesh: Fix processing of Config Node Reset message Inga Stotland
  1 sibling, 0 replies; 3+ messages in thread
From: Inga Stotland @ 2020-03-13 18:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

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..1641cee4c 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);
-- 
2.21.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH BlueZ 2/2] mesh: Fix processing of Config Node Reset message
  2020-03-13 18:08 [PATCH BlueZ 0/2] Remote node reset implementation Inga Stotland
  2020-03-13 18:08 ` [PATCH BlueZ 1/2] tools/mesh-cfgclient: Implement node-reset command Inga Stotland
@ 2020-03-13 18:08 ` Inga Stotland
  1 sibling, 0 replies; 3+ messages in thread
From: Inga Stotland @ 2020-03-13 18:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This fixes a condition when a node continues processing messages
after it has been reset by a remote configuration client.
Upon receiving Config Node Reset message, a node deregisters it's
message receive callbacks and a complete node removal happens after
a grace interval to allow sending of Config Node Reset Status reply.
---
 mesh/cfgmod-server.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index a1f682765..6499c3f2f 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -1223,20 +1223,20 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 
 	case OP_NODE_RESET:
 		n = mesh_model_opcode_set(OP_NODE_RESET_STATUS, msg);
-		/*
-		 * Delay node removal to give it a chance to send back the
-		 * status
-		 */
+
+		/* After reset, node is not processing any incoming messages */
+		mesh_net_detach(net);
+
+		/* Delay node removal to give it a chance to send the status */
 		l_timeout_create(1, node_reset, node, NULL);
 		break;
 	}
 
-	if (n) {
-		/* print_packet("App Tx", long_msg ? long_msg : msg, n); */
+	if (n)
 		mesh_model_send(node, dst, src,
 				APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
 				long_msg ? long_msg : msg, n);
-	}
+
 	l_free(long_msg);
 
 	return true;
-- 
2.21.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-03-13 18:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-13 18:08 [PATCH BlueZ 0/2] Remote node reset implementation Inga Stotland
2020-03-13 18:08 ` [PATCH BlueZ 1/2] tools/mesh-cfgclient: Implement node-reset command Inga Stotland
2020-03-13 18:08 ` [PATCH BlueZ 2/2] mesh: Fix processing of Config Node Reset message Inga Stotland

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).