All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.