All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ v3 0/6] Support for virtual labels
@ 2020-02-25 18:44 Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 1/6] tools/mesh-cfgclient: Add support " Inga Stotland
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

v3: Fixed subscription list generation to include virtual
    subscription addresses

*****************************
v2: Fixed a  backwards compatibility issue reported by Brian;
    Fixed Python test to correctly display updated configuration


*****************************
This patch set adds a capability to mesh-cfgclient to generate
and store virtual labels and use them in configuring remote
node's publications and subscriptions.
Regular group addresses are preeserved as well. This is done
dynamically: as a new group address is detected in either
subscription or publication configuration commands.

This new capability of mesh-cfgclient allowed for improved
testing of virtual pub/sub implementation in bluetooth-meshd
daemon. As a result, some deficiencies and legacy entaglements
were exposed, and consequently resolved and cleaned up.


Inga Stotland (6):
  tools/mesh-cfgclient: Add support for virtual labels
  tools/mesh-cfgclient: Clean up subscription list output
  tools/mesh-cfgclient: Save and restore group addresses
  mesh: Simplify model virtual pub/sub logic
  mesh: Clean up handling config model publication message
  test/test-mesh: Fix output og UpdateModelConfig method

 Makefile.tools       |   3 +-
 mesh/cfgmod-server.c | 131 +++++++--------------
 mesh/model.c         | 271 ++++++++++++++++++-------------------------
 mesh/model.h         |   9 +-
 test/test-mesh       |  11 +-
 tools/mesh/cfgcli.c  | 242 ++++++++++++++++++++++++++++++++------
 tools/mesh/cfgcli.h  |   5 +
 tools/mesh/mesh-db.c | 128 ++++++++++++++++++++
 tools/mesh/mesh-db.h |   4 +
 9 files changed, 514 insertions(+), 290 deletions(-)

-- 
2.21.1


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

* [PATCH BlueZ v3 1/6] tools/mesh-cfgclient: Add support for virtual labels
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
@ 2020-02-25 18:44 ` Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 2/6] tools/mesh-cfgclient: Clean up subscription list output Inga Stotland
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This adds commands to generate and use virtual addresses for
configuring remote node's publication and subscription.

New commands:
virt-add - generate a new label and calculate virtual address
group-list - displays group addresses that are in use and available
             virtual labels with corresponding virtual addresses
---
 Makefile.tools      |   3 +-
 tools/mesh/cfgcli.c | 203 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 188 insertions(+), 18 deletions(-)

diff --git a/Makefile.tools b/Makefile.tools
index 006554cf7..f43764adc 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -336,7 +336,8 @@ tools_mesh_cfgclient_SOURCES = tools/mesh-cfgclient.c \
 				tools/mesh/agent.h tools/mesh/agent.c \
 				tools/mesh/mesh-db.h tools/mesh/mesh-db.c \
 				mesh/util.h mesh/util.c \
-				mesh/mesh-config.h mesh/mesh-config-json.c
+				mesh/mesh-config.h mesh/mesh-config-json.c \
+				mesh/crypto.h mesh/crypto.c
 
 tools_mesh_cfgclient_LDADD = lib/libbluetooth-internal.la src/libshared-ell.la \
 						$(ell_ldadd) -ljson-c -lreadline
diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index cfa573de3..cd8fd425b 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -31,6 +31,8 @@
 #include "src/shared/util.h"
 
 #include "mesh/mesh-defs.h"
+#include "mesh/util.h"
+#include "mesh/crypto.h"
 
 #include "tools/mesh/util.h"
 #include "tools/mesh/model.h"
@@ -58,7 +60,13 @@ struct pending_req {
 	uint16_t addr;
 };
 
+struct mesh_group {
+	uint16_t addr;
+	uint8_t label[16];
+};
+
 static struct l_queue *requests;
+static struct l_queue *groups;
 
 static void *send_data;
 static model_send_msg_func_t send_msg;
@@ -764,6 +772,53 @@ 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;
+	const struct mesh_group *grp1 = b;
+
+	if (grp0->addr < grp1->addr)
+		return -1;
+
+	if (grp0->addr > grp1->addr)
+		return 1;
+
+	return 0;
+}
+
+static void print_virtual_not_found(uint16_t addr)
+{
+	bt_shell_printf("Virtual group with hash %4.4x not found\n", addr);
+	bt_shell_printf("To see available, use \"group-list\"\n");
+	bt_shell_printf("To create new, use \"virt-add\"\n");
+}
+
+static struct mesh_group *add_group(uint16_t addr)
+{
+	struct mesh_group *grp;
+
+	if (!IS_GROUP(addr))
+		return NULL;
+
+	grp = l_queue_find(groups, match_group_addr, L_UINT_TO_PTR(addr));
+	if (grp)
+		return grp;
+
+	grp = l_new(struct mesh_group, 1);
+	grp->addr = addr;
+	l_queue_insert(groups, grp, compare_group_addr, NULL);
+
+	return grp;
+}
+
 static void cmd_timeout_set(int argc, char *argv[])
 {
 	if (read_input_parameters(argc, argv) != 1)
@@ -1196,22 +1251,47 @@ static void cmd_ttl_set(int argc, char *argv[])
 static void cmd_pub_set(int argc, char *argv[])
 {
 	uint16_t n;
-	uint8_t msg[32];
+	uint8_t msg[48];
 	int parm_cnt;
-
-	n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg);
+	struct mesh_group *grp;
+	uint32_t opcode;
+	uint16_t pub_addr;
 
 	parm_cnt = read_input_parameters(argc, argv);
+
 	if (parm_cnt != 6 && parm_cnt != 7) {
 		bt_shell_printf("Bad arguments\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));
+	if (!grp)
+		grp = add_group(pub_addr);
+
+	if (!grp && IS_VIRTUAL(pub_addr)) {
+		print_virtual_not_found(pub_addr);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	opcode = (!IS_VIRTUAL(pub_addr)) ? OP_CONFIG_MODEL_PUB_SET :
+						OP_CONFIG_MODEL_PUB_VIRT_SET;
+
+	n = mesh_opcode_set(opcode, msg);
+
 	put_le16(parms[0], msg + n);
 	n += 2;
+
 	/* Publish address */
-	put_le16(parms[1], msg + n);
-	n += 2;
+	if (!IS_VIRTUAL(pub_addr)) {
+		put_le16(pub_addr, msg + n);
+		n += 2;
+	} else {
+		memcpy(msg + n, grp->label, 16);
+		n += 16;
+	}
+
 	/* AppKey index + credential (set to 0) */
 	put_le16(parms[2], msg + n);
 	n += 2;
@@ -1225,10 +1305,10 @@ static void cmd_pub_set(int argc, char *argv[])
 	/* Model Id */
 	n += put_model_id(msg + n, &parms[5], parm_cnt == 7);
 
-	if (!config_send(msg, n, OP_CONFIG_MODEL_PUB_SET))
+	if (!config_send(msg, n, opcode))
 		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
-	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+	bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_pub_get(int argc, char *argv[])
@@ -1263,8 +1343,8 @@ static void subscription_cmd(int argc, char *argv[], uint32_t opcode)
 	uint16_t n;
 	uint8_t msg[32];
 	int parm_cnt;
-
-	n = mesh_opcode_set(opcode, msg);
+	struct mesh_group *grp;
+	uint16_t sub_addr;
 
 	parm_cnt = read_input_parameters(argc, argv);
 	if (parm_cnt != 3 && parm_cnt != 4) {
@@ -1272,12 +1352,42 @@ static void subscription_cmd(int argc, char *argv[], uint32_t opcode)
 		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));
+
+	if (!grp && opcode != OP_CONFIG_MODEL_SUB_DELETE) {
+		grp = add_group(sub_addr);
+
+		if (!grp && IS_VIRTUAL(sub_addr)) {
+			print_virtual_not_found(sub_addr);
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
+		}
+	}
+
+	if (IS_VIRTUAL(sub_addr)) {
+		if (opcode == OP_CONFIG_MODEL_SUB_ADD)
+			opcode = OP_CONFIG_MODEL_SUB_VIRT_ADD;
+		else if (opcode == OP_CONFIG_MODEL_SUB_DELETE)
+			opcode = OP_CONFIG_MODEL_SUB_VIRT_DELETE;
+		else if (opcode == OP_CONFIG_MODEL_SUB_OVERWRITE)
+			opcode = OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE;
+	}
+
+	n = mesh_opcode_set(opcode, msg);
+
 	/* Element Address */
 	put_le16(parms[0], msg + n);
 	n += 2;
+
 	/* Subscription Address */
-	put_le16(parms[1], msg + n);
-	n += 2;
+	if (!IS_VIRTUAL(sub_addr)) {
+		put_le16(sub_addr, msg + n);
+		n += 2;
+	} else {
+		memcpy(msg + n, grp->label, 16);
+		n += 16;
+	}
 
 	/* Model ID */
 	n += put_model_id(msg + n, &parms[2], parm_cnt == 4);
@@ -1399,6 +1509,9 @@ static void cmd_hb_pub_set(int argc, char *argv[])
 
 	n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_PUB_SET, msg);
 
+	if (!l_queue_find(groups, match_group_addr, L_UINT_TO_PTR(parms[1])))
+		add_group(parms[1]);
+
 	parm_cnt = read_input_parameters(argc, argv);
 	if (parm_cnt != 6) {
 		bt_shell_printf("Bad arguments: %s\n", argv[1]);
@@ -1447,6 +1560,9 @@ static void cmd_hb_sub_set(int argc, char *argv[])
 		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
+	if (!l_queue_find(groups, match_group_addr, L_UINT_TO_PTR(parms[1])))
+		add_group(parms[1]);
+
 	/* Per Mesh Profile 4.3.2.65 */
 	/* Source address */
 	put_le16(parms[0], msg + n);
@@ -1537,6 +1653,54 @@ static void cmd_netkey_get(int argc, char *argv[])
 	cmd_default(OP_NETKEY_GET);
 }
 
+static void print_group(void *a, void *b)
+{
+	struct mesh_group *grp = a;
+	char buf[33];
+
+	if (!IS_VIRTUAL(grp->addr)) {
+		bt_shell_printf("\tGroup addr: %4.4x\n", grp->addr);
+		return;
+	}
+
+	hex2str(grp->label, 16, buf, sizeof(buf));
+	bt_shell_printf("\tVirtual addr: %4.4x, label: %s\n", grp->addr, buf);
+}
+
+static void cmd_add_virt(int argc, char *argv[])
+{
+	struct mesh_group *grp, *tmp;
+	uint8_t max_tries = 3;
+
+	grp = l_new(struct mesh_group, 1);
+
+retry:
+	l_getrandom(grp->label, 16);
+	mesh_crypto_virtual_addr(grp->label, &grp->addr);
+
+	/* For simplicity sake, avoid labels that map to the same hash */
+	tmp = l_queue_find(groups, match_group_addr, L_UINT_TO_PTR(grp->addr));
+	if (!tmp) {
+		l_queue_insert(groups, grp, compare_group_addr, NULL);
+		print_group(grp, NULL);
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+	}
+
+	max_tries--;
+	if (max_tries)
+		goto retry;
+
+	l_free(grp);
+	bt_shell_printf("Failed to generate unique label. Try again.");
+	bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
+static void cmd_list_groups(int argc, char *argv[])
+{
+	l_queue_foreach(groups, print_group, NULL);
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
 static bool tx_setup(model_send_msg_func_t send_func, void *user_data)
 {
 	if (!send_func)
@@ -1625,12 +1789,15 @@ static const struct bt_shell_menu cfg_menu = {
 				"Set heartbeat subscribe"},
 	{"hb-sub-get", NULL, cmd_hb_sub_get,
 				"Get heartbeat subscribe"},
-	{"sub-add", "<ele_addr> <sub_addr> <model_id> [vendor]", cmd_sub_add,
-				"Add subscription"},
-	{"sub-del", "<ele_addr> <sub_addr> <model_id> [vendor]", cmd_sub_del,
-				"Delete subscription"},
-	{"sub-wrt", "<ele_addr> <sub_addr> <model_id> [vendor]", cmd_sub_ovwrt,
-				"Overwrite subscription"},
+	{"virt-add", NULL, cmd_add_virt, "Generate and add a virtual label"},
+	{"group-list", NULL, cmd_list_groups,
+			"Display existing group addresses and virtual labels"},
+	{"sub-add", "<ele_addr> <sub_addr> <model_id> [vendor]",
+				cmd_sub_add, "Add subscription"},
+	{"sub-del", "<ele_addr> <sub_addr> <model_id> [vendor]",
+				cmd_sub_del, "Delete subscription"},
+	{"sub-wrt", "<ele_addr> <sub_addr> <model_id> [vendor]",
+				cmd_sub_ovwrt, "Overwrite subscription"},
 	{"sub-del-all", "<ele_addr> <model_id> [vendor]", cmd_sub_del_all,
 				"Delete subscription"},
 	{"sub-get", "<ele_addr> <model_id> [vendor]", cmd_sub_get,
@@ -1660,6 +1827,7 @@ struct model_info *cfgcli_init(key_send_func_t key_send, void *user_data)
 	send_key_msg = key_send;
 	key_data = user_data;
 	requests = l_queue_new();
+	groups = l_queue_new();
 
 	bt_shell_add_submenu(&cfg_menu);
 
@@ -1669,4 +1837,5 @@ struct model_info *cfgcli_init(key_send_func_t key_send, void *user_data)
 void cfgcli_cleanup(void)
 {
 	l_queue_destroy(requests, free_request);
+	l_queue_destroy(groups, l_free);
 }
-- 
2.21.1


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

* [PATCH BlueZ v3 2/6] tools/mesh-cfgclient: Clean up subscription list output
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 1/6] tools/mesh-cfgclient: Add support " Inga Stotland
@ 2020-02-25 18:44 ` Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 3/6] tools/mesh-cfgclient: Save and restore group addresses Inga Stotland
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This tightens up the subscritpiton list status print out:
use the same function for vendor and SIG models.
---
 tools/mesh/cfgcli.c | 40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index cd8fd425b..0c9f69e36 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -346,6 +346,25 @@ static void print_pub(uint16_t ele_addr, uint32_t mod_id,
 	bt_shell_printf("\tTTL: %2.2x\n", pub->ttl);
 }
 
+static void print_sub_list(uint16_t addr, bool is_vendor, uint8_t *data,
+								uint16_t len)
+{
+	uint16_t i;
+
+	bt_shell_printf("\nNode %4.4x Subscription List status %s\n",
+						addr, mesh_status_str(data[0]));
+
+	bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1));
+	print_mod_id(data + 3, is_vendor, "");
+
+	i = (is_vendor ? 7 : 5);
+
+	bt_shell_printf("Subscriptions:\n");
+
+	for (; i < len; i += 2)
+		bt_shell_printf("\t\t%4.4x\n ", get_le16(data + i));
+}
+
 static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
 							uint16_t len)
 {
@@ -611,33 +630,16 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
 		if (len < 5)
 			return true;
 
-		bt_shell_printf("\nNode %4.4x Subscription List status %s\n",
-				src, mesh_status_str(data[0]));
-
-		bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1));
-		print_mod_id(data + 3, false, "");
-
-		for (i = 5; i < len; i += 2)
-			bt_shell_printf("Subscr Addr\t%4.4x\n",
-							get_le16(data + i));
+		print_sub_list(src, false, data, len);
 		break;
 
 	case OP_CONFIG_VEND_MODEL_SUB_LIST:
 		if (len < 7)
 			return true;
 
-		bt_shell_printf("\nNode %4.4x Subscription List status %s\n",
-				src, mesh_status_str(data[0]));
-
-		bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1));
-		print_mod_id(data + 3, true, "");
-
-		for (i = 7; i < len; i += 2)
-			bt_shell_printf("Subscr Addr\t%4.4x\n",
-							get_le16(data + i));
+		print_sub_list(src, true, data, len);
 		break;
 
-
 	/* Per Mesh Profile 4.3.2.50 */
 	case OP_MODEL_APP_LIST:
 		if (len < 5)
-- 
2.21.1


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

* [PATCH BlueZ v3 3/6] tools/mesh-cfgclient: Save and restore group addresses
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 1/6] tools/mesh-cfgclient: Add support " Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 2/6] tools/mesh-cfgclient: Clean up subscription list output Inga Stotland
@ 2020-02-25 18:44 ` Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 4/6] mesh: Simplify model virtual pub/sub logic Inga Stotland
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This allows to save created virtual labels and group addresses
in configuration file. The stored values can be restored upon
the tool start up.
---
 tools/mesh/cfgcli.c  |  11 ++--
 tools/mesh/cfgcli.h  |   5 ++
 tools/mesh/mesh-db.c | 128 +++++++++++++++++++++++++++++++++++++++++++
 tools/mesh/mesh-db.h |   4 ++
 4 files changed, 141 insertions(+), 7 deletions(-)

diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index 0c9f69e36..5c990d2e8 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -60,11 +60,6 @@ struct pending_req {
 	uint16_t addr;
 };
 
-struct mesh_group {
-	uint16_t addr;
-	uint8_t label[16];
-};
-
 static struct l_queue *requests;
 static struct l_queue *groups;
 
@@ -818,6 +813,8 @@ static struct mesh_group *add_group(uint16_t addr)
 	grp->addr = addr;
 	l_queue_insert(groups, grp, compare_group_addr, NULL);
 
+	mesh_db_add_group(grp);
+
 	return grp;
 }
 
@@ -1685,6 +1682,7 @@ retry:
 	if (!tmp) {
 		l_queue_insert(groups, grp, compare_group_addr, NULL);
 		print_group(grp, NULL);
+		mesh_db_add_group(grp);
 		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
@@ -1829,8 +1827,7 @@ struct model_info *cfgcli_init(key_send_func_t key_send, void *user_data)
 	send_key_msg = key_send;
 	key_data = user_data;
 	requests = l_queue_new();
-	groups = l_queue_new();
-
+	groups = mesh_db_load_groups();
 	bt_shell_add_submenu(&cfg_menu);
 
 	return &cli_info;
diff --git a/tools/mesh/cfgcli.h b/tools/mesh/cfgcli.h
index 16d2e0a61..9b283d9d5 100644
--- a/tools/mesh/cfgcli.h
+++ b/tools/mesh/cfgcli.h
@@ -18,6 +18,11 @@
  *
  */
 
+struct mesh_group {
+	uint16_t addr;
+	uint8_t label[16];
+};
+
 typedef bool (*key_send_func_t) (void *user_data, uint16_t dst,
 				 uint16_t idx, bool is_appkey, bool update);
 
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 5dbb91440..41114f40f 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -41,6 +41,7 @@
 
 #include "tools/mesh/keys.h"
 #include "tools/mesh/remote.h"
+#include "tools/mesh/cfgcli.h"
 #include "tools/mesh/mesh-db.h"
 
 #define KEY_IDX_INVALID NET_IDX_INVALID
@@ -254,6 +255,20 @@ static uint16_t node_parse_key(json_object *jarray, int i)
 	return idx;
 }
 
+static int compare_group_addr(const void *a, const void *b, void *user_data)
+{
+	const struct mesh_group *grp0 = a;
+	const struct mesh_group *grp1 = b;
+
+	if (grp0->addr < grp1->addr)
+		return -1;
+
+	if (grp0->addr > grp1->addr)
+		return 1;
+
+	return 0;
+}
+
 static void load_remotes(json_object *jcfg)
 {
 	json_object *jnodes;
@@ -632,6 +647,112 @@ bool mesh_db_app_key_del(uint16_t app_idx)
 	return delete_key(cfg->jcfg, "appKeys", app_idx);
 }
 
+bool mesh_db_add_group(struct mesh_group *grp)
+{
+	json_object *jgroup, *jgroups, *jval;
+	char buf[16];
+
+	if (!cfg || !cfg->jcfg)
+		return false;
+
+	if (!json_object_object_get_ex(cfg->jcfg, "groups", &jgroups))
+		return false;
+
+	jgroup = json_object_new_object();
+	if (!jgroup)
+		return false;
+
+	snprintf(buf, 11, "Group_%4.4x", grp->addr);
+	jval = json_object_new_string(buf);
+	json_object_object_add(jgroup, "name", jval);
+
+	if (IS_VIRTUAL(grp->addr)) {
+		if (!add_u8_16(jgroup, grp->label, "address"))
+			goto fail;
+	} else {
+		snprintf(buf, 5, "%4.4x", grp->addr);
+		jval = json_object_new_string(buf);
+		if (!jval)
+			goto fail;
+		json_object_object_add(jgroup, "address", jval);
+	}
+
+	json_object_array_add(jgroups, jgroup);
+
+	return mesh_config_save((struct mesh_config *) cfg, true, NULL, NULL);
+
+fail:
+	json_object_put(jgroup);
+	return false;
+}
+
+struct l_queue *mesh_db_load_groups(void)
+{
+	json_object *jgroups;
+	struct l_queue *groups;
+	int i, sz;
+
+	if (!cfg || !cfg->jcfg)
+		return NULL;
+
+	if (!json_object_object_get_ex(cfg->jcfg, "groups", &jgroups)) {
+		jgroups = json_object_new_array();
+		if (!jgroups)
+			return NULL;
+
+		json_object_object_add(cfg->jcfg, "groups", jgroups);
+	}
+
+	groups = l_queue_new();
+
+	sz = json_object_array_length(jgroups);
+
+	for (i = 0; i < sz; ++i) {
+		json_object *jgroup, *jval;
+		struct mesh_group *grp;
+		uint16_t addr, addr_len;
+		const char *str;
+
+		jgroup = json_object_array_get_idx(jgroups, i);
+		if (!jgroup)
+			continue;
+
+		if (!json_object_object_get_ex(jgroup, "name", &jval))
+			continue;
+
+		str = json_object_get_string(jval);
+		if (strlen(str) != 10)
+			continue;
+
+		if (sscanf(str + 6, "%04hx", &addr) != 1)
+			continue;
+
+		if (!json_object_object_get_ex(jgroup, "address", &jval))
+			continue;
+
+		str = json_object_get_string(jval);
+		addr_len = strlen(str);
+		if (addr_len != 4 && addr_len != 32)
+			continue;
+
+		if (addr_len == 32 && !IS_VIRTUAL(addr))
+			continue;
+
+		grp = l_new(struct mesh_group, 1);
+
+		if (addr_len == 4)
+			sscanf(str, "%04hx", &grp->addr);
+		else {
+			str2hex(str, 32, grp->label, 16);
+			grp->addr = addr;
+		}
+
+		l_queue_insert(groups, grp, compare_group_addr, NULL);
+	}
+
+	return groups;
+}
+
 bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
 							uint16_t net_idx)
 {
@@ -802,6 +923,13 @@ bool mesh_db_create(const char *fname, const uint8_t token[8],
 		goto fail;
 
 	json_object_object_add(jcfg, "appKeys", jarray);
+#if 0
+	jarray = json_object_new_array();
+	if (!jarray)
+		goto fail;
+
+	json_object_object_add(jcfg, "groups", jarray);
+#endif
 
 	if (!mesh_config_save((struct mesh_config *) cfg, true, NULL, NULL))
 		goto fail;
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index 4a7b16ab4..80dc4ed53 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -19,6 +19,8 @@
 
 #include "mesh/mesh-config.h"
 
+struct mesh_group;
+
 bool mesh_db_create(const char *fname, const uint8_t token[8],
 							const char *name);
 bool mesh_db_load(const char *fname);
@@ -52,3 +54,5 @@ bool mesh_db_node_model_binding_add(uint16_t unicast, uint8_t ele, bool vendor,
 					uint32_t mod_id, uint16_t app_idx);
 bool mesh_db_node_model_binding_del(uint16_t unicast, uint8_t ele, bool vendor,
 					uint32_t mod_id, uint16_t app_idx);
+struct l_queue *mesh_db_load_groups(void);
+bool mesh_db_add_group(struct mesh_group *grp);
-- 
2.21.1


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

* [PATCH BlueZ v3 4/6] mesh: Simplify model virtual pub/sub logic
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
                   ` (2 preceding siblings ...)
  2020-02-25 18:44 ` [PATCH BlueZ v3 3/6] tools/mesh-cfgclient: Save and restore group addresses Inga Stotland
@ 2020-02-25 18:44 ` Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 5/6] mesh: Clean up handling config model publication message Inga Stotland
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This reorganizes the part of the code that handles model publishing
and subscribitng to virtual labels.
---
 mesh/model.c | 271 +++++++++++++++++++++------------------------------
 mesh/model.h |   9 +-
 2 files changed, 118 insertions(+), 162 deletions(-)

diff --git a/mesh/model.c b/mesh/model.c
index 4e5856292..e02658363 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -42,6 +42,8 @@
 /* Divide and round to ceiling (up) to calculate segment count */
 #define CEILDIV(val, div) (((val) + (div) - 1) / (div))
 
+#define VIRTUAL_BASE			0x10000
+
 struct mesh_model {
 	const struct mesh_model_ops *cbs;
 	void *user_data;
@@ -54,7 +56,6 @@ struct mesh_model {
 };
 
 struct mesh_virtual {
-	uint32_t id; /* Internal ID of a stored virtual addr, min val 0x10000 */
 	uint16_t ref_cnt;
 	uint16_t addr; /* 16-bit virtual address, used in messages */
 	uint8_t label[16]; /* 128 bit label UUID */
@@ -79,7 +80,6 @@ struct mod_forward {
 
 static struct l_queue *mesh_virtuals;
 
-static uint32_t virt_id_next = VIRTUAL_BASE;
 static struct timeval tx_start;
 
 static bool is_internal(uint32_t id)
@@ -120,14 +120,6 @@ static bool has_binding(struct l_queue *bindings, uint16_t idx)
 	return false;
 }
 
-static bool find_virt_by_id(const void *a, const void *b)
-{
-	const struct mesh_virtual *virt = a;
-	uint32_t id = L_PTR_TO_UINT(b);
-
-	return virt->id == id;
-}
-
 static bool find_virt_by_label(const void *a, const void *b)
 {
 	const struct mesh_virtual *virt = a;
@@ -307,7 +299,7 @@ static void append_dict_subs_array(struct l_dbus_message_builder *builder,
 	l_dbus_message_builder_enter_variant(builder, "av");
 	l_dbus_message_builder_enter_array(builder, "v");
 
-	if (!subs)
+	if (l_queue_isempty(subs))
 		goto virts;
 
 	for (entry = l_queue_get_entries(subs); entry; entry = entry->next) {
@@ -319,7 +311,7 @@ static void append_dict_subs_array(struct l_dbus_message_builder *builder,
 	}
 
 virts:
-	if (!virts)
+	if (l_queue_isempty(virts))
 		goto done;
 
 	for (entry = l_queue_get_entries(virts); entry; entry = entry->next) {
@@ -364,7 +356,7 @@ static void forward_model(void *a, void *b)
 	struct mesh_model *mod = a;
 	struct mod_forward *fwd = b;
 	struct mesh_virtual *virt;
-	uint32_t dst;
+	uint16_t dst;
 	bool result;
 
 	l_debug("model %8.8x with idx %3.3x", mod->id, fwd->app_idx);
@@ -379,20 +371,9 @@ static void forward_model(void *a, void *b)
 		fwd->has_dst = true;
 	else if (fwd->virt) {
 		virt = l_queue_find(mod->virtuals, simple_match, fwd->virt);
-
-		/* Check that this is not own publication */
-		if (mod->pub && (virt && virt->id == mod->pub->addr))
-			return;
-
 		if (virt) {
-			/*
-			 * Map Virtual addresses to a usable namespace that
-			 * prevents us for forwarding a false positive
-			 * (multiple Virtual Addresses that map to the same
-			 * 16-bit virtual address identifier)
-			 */
 			fwd->has_dst = true;
-			dst = virt->id;
+			dst = virt->addr;
 		}
 	} else {
 		if (l_queue_find(mod->subs, simple_match, L_UINT_TO_PTR(dst)))
@@ -627,8 +608,13 @@ done:
 
 static void remove_pub(struct mesh_node *node, struct mesh_model *mod)
 {
-	l_free(mod->pub);
-	mod->pub = NULL;
+	if (mod->pub) {
+		if (mod->pub->virt)
+			unref_virt(mod->pub->virt);
+
+		l_free(mod->pub);
+		mod->pub = NULL;
+	}
 
 	if (!mod->cbs)
 		/* External models */
@@ -650,11 +636,9 @@ static void model_unbind_idx(struct mesh_node *node, struct mesh_model *mod,
 		/* Internal model */
 		mod->cbs->bind(idx, ACTION_DELETE);
 
-	if (mod->pub && idx != mod->pub->idx)
-		return;
-
 	/* Remove model publication if the publication key is unbound */
-	remove_pub(node, mod);
+	if (mod->pub && idx == mod->pub->idx)
+		remove_pub(node, mod);
 }
 
 static void model_bind_idx(struct mesh_node *node, struct mesh_model *mod,
@@ -746,65 +730,64 @@ static struct mesh_virtual *add_virtual(const uint8_t *v)
 
 	memcpy(virt->label, v, 16);
 	virt->ref_cnt = 1;
-	virt->id = virt_id_next++;
 	l_queue_push_head(mesh_virtuals, virt);
 
 	return virt;
 }
 
-static int set_pub(struct mesh_model *mod, const uint8_t *pub_addr,
+static int set_pub(struct mesh_model *mod, uint16_t pub_addr,
 			uint16_t idx, bool cred_flag, uint8_t ttl,
-			uint8_t period, uint8_t retransmit, bool b_virt,
-			uint16_t *dst)
+			uint8_t period, uint8_t retransmit)
 {
-	struct mesh_virtual *virt = NULL;
-	uint16_t grp;
+	if (!mod->pub)
+		mod->pub = l_new(struct mesh_model_pub, 1);
 
-	if (dst) {
-		if (b_virt)
-			*dst = 0;
-		else
-			*dst = l_get_le16(pub_addr);
-	}
+	mod->pub->addr = pub_addr;
+	mod->pub->credential = cred_flag;
+	mod->pub->idx = idx;
+	mod->pub->ttl = ttl;
+	mod->pub->period = period;
+	mod->pub->retransmit = retransmit;
 
-	if (b_virt) {
-		virt = add_virtual(pub_addr);
-		if (!virt)
-			return MESH_STATUS_STORAGE_FAIL;
+	return MESH_STATUS_SUCCESS;
+}
 
-	}
+static int set_virt_pub(struct mesh_model *mod, const uint8_t *label,
+			uint16_t idx, bool cred_flag, uint8_t ttl,
+			uint8_t period, uint8_t retransmit)
+{
+	struct mesh_virtual *virt = NULL;
 
-	/* If the old publication address is virtual, remove it from lists */
-	if (mod->pub && mod->pub->addr >= VIRTUAL_BASE) {
-		struct mesh_virtual *old_virt;
+	virt = add_virtual(label);
+	if (!virt)
+		return MESH_STATUS_STORAGE_FAIL;
 
-		old_virt = l_queue_find(mod->virtuals, find_virt_by_id,
-						L_UINT_TO_PTR(mod->pub->addr));
-		if (old_virt) {
-			l_queue_remove(mod->virtuals, old_virt);
-			unref_virt(old_virt);
-		}
-	}
+	if (!mod->pub)
+		mod->pub = l_new(struct mesh_model_pub, 1);
+
+	mod->pub->virt = virt;
+	return set_pub(mod, virt->addr, idx, cred_flag, ttl, period,
+								retransmit);
+}
+
+static int add_virt_sub(struct mesh_net *net, struct mesh_model *mod,
+			     const uint8_t *label, uint16_t *dst)
+{
+	struct mesh_virtual *virt = l_queue_find(mod->virtuals,
+						find_virt_by_label, label);
 
-	mod->pub = l_new(struct mesh_model_pub, 1);
+	if (!virt) {
+		virt = add_virtual(label);
+		if (!virt)
+			return MESH_STATUS_STORAGE_FAIL;
 
-	if (b_virt) {
 		l_queue_push_head(mod->virtuals, virt);
-		grp = virt->addr;
-		mod->pub->addr = virt->id;
-	} else {
-		grp = l_get_le16(pub_addr);
-		mod->pub->addr = grp;
+		mesh_net_dst_reg(net, virt->addr);
+		l_debug("Added virtual sub addr %4.4x", virt->addr);
 	}
 
 	if (dst)
-		*dst = grp;
-
-	mod->pub->credential = cred_flag;
-	mod->pub->idx = idx;
-	mod->pub->ttl = ttl;
-	mod->pub->period = period;
-	mod->pub->retransmit = retransmit;
+		*dst = virt->addr;
 
 	return MESH_STATUS_SUCCESS;
 }
@@ -812,42 +795,25 @@ static int set_pub(struct mesh_model *mod, const uint8_t *pub_addr,
 static int add_sub(struct mesh_net *net, struct mesh_model *mod,
 			const uint8_t *group, bool b_virt, uint16_t *dst)
 {
-	struct mesh_virtual *virt = NULL;
 	uint16_t grp;
 
-	if (b_virt) {
-		virt = add_virtual(group);
-		if (!virt)
-			return MESH_STATUS_STORAGE_FAIL;
-
-		grp = virt->addr;
-	} else {
-		grp = l_get_le16(group);
-	}
+	if (b_virt)
+		return add_virt_sub(net, mod, group, dst);
 
+	grp = l_get_le16(group);
 	if (dst)
 		*dst = grp;
 
-	if (!mod->subs)
-		mod->subs = l_queue_new();
+	if (!l_queue_find(mod->subs, simple_match, L_UINT_TO_PTR(grp))) {
 
-	/* Check if this group already exists */
-	if (l_queue_find(mod->subs, simple_match, L_UINT_TO_PTR(grp))) {
-		if (b_virt)
-			unref_virt(virt);
+		if (!mod->subs)
+			mod->subs = l_queue_new();
 
-		return MESH_STATUS_SUCCESS;
+		l_queue_push_tail(mod->subs, L_UINT_TO_PTR(grp));
+		mesh_net_dst_reg(net, grp);
+		l_debug("Added group subscription %4.4x", grp);
 	}
 
-	if (b_virt)
-		l_queue_push_head(mod->virtuals, virt);
-
-	l_queue_push_tail(mod->subs, L_UINT_TO_PTR(grp));
-
-	l_debug("Added %4.4x", grp);
-
-	mesh_net_dst_reg(net, grp);
-
 	return MESH_STATUS_SUCCESS;
 }
 
@@ -1096,9 +1062,7 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
 {
 	struct mesh_net *net = node_get_net(node);
 	struct mesh_model *mod;
-	uint32_t target;
 	uint8_t *label = NULL;
-	uint16_t dst;
 	uint16_t net_idx;
 	bool result;
 	int status;
@@ -1125,35 +1089,21 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
 
 	gettimeofday(&tx_start, NULL);
 
-	target = mod->pub->addr;
-
-	if (IS_UNASSIGNED(target))
+	if (IS_UNASSIGNED(mod->pub->addr))
 		return MESH_ERROR_DOES_NOT_EXIST;
 
-	if (target >= VIRTUAL_BASE) {
-		struct mesh_virtual *virt;
+	if (mod->pub->virt)
+		label = mod->pub->virt->label;
 
-		virt = l_queue_find(mesh_virtuals, find_virt_by_id,
-						L_UINT_TO_PTR(target));
-		if (!virt)
-			return MESH_ERROR_NOT_FOUND;
-
-		label = virt->label;
-		dst = virt->addr;
-	} else {
-		dst = target;
-	}
-
-	l_debug("publish dst=%x", dst);
+	l_debug("publish dst=%x", mod->pub->addr);
 
 	net_idx = appkey_net_idx(net, mod->pub->idx);
 
 	result = msg_send(node, mod->pub->credential != 0, src,
-				dst, mod->pub->idx, net_idx, label, ttl,
-				msg, msg_len);
+				mod->pub->addr, mod->pub->idx, net_idx,
+				label, ttl, msg, msg_len);
 
 	return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED;
-
 }
 
 bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
@@ -1179,7 +1129,7 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
 int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *pub_addr, uint16_t idx, bool cred_flag,
 			uint8_t ttl, uint8_t period, uint8_t retransmit,
-			bool b_virt, uint16_t *dst)
+			bool is_virt, uint16_t *dst)
 {
 	struct mesh_model *mod;
 	int status;
@@ -1198,13 +1148,25 @@ int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
 	 * If the publication address is set to unassigned address value,
 	 * remove the publication
 	 */
-	if (!b_virt && IS_UNASSIGNED(l_get_le16(pub_addr))) {
+	if (!is_virt && IS_UNASSIGNED(l_get_le16(pub_addr))) {
 		remove_pub(node, mod);
 		return MESH_STATUS_SUCCESS;
 	}
 
-	status = set_pub(mod, pub_addr, idx, cred_flag, ttl, period, retransmit,
-								b_virt, dst);
+	/* Check if the old publication destination is a virtual label */
+	if (mod->pub && mod->pub->virt) {
+		unref_virt(mod->pub->virt);
+		mod->pub->virt = NULL;
+	}
+
+	if (!is_virt) {
+		status = set_pub(mod, l_get_le16(pub_addr), idx, cred_flag,
+						ttl, period, retransmit);
+	} else
+		status = set_virt_pub(mod, pub_addr, idx, cred_flag, ttl,
+						period, retransmit);
+
+	*dst = mod->pub->addr;
 
 	if (status != MESH_STATUS_SUCCESS)
 		return status;
@@ -1412,12 +1374,25 @@ int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
 		n += 2;
 	}
 
+	entry = l_queue_get_entries(mod->virtuals);
+
+	for (; entry; entry = entry->next) {
+		struct mesh_virtual *virt = entry->data;
+
+		if ((n + 2) > buf_size)
+			return MESH_STATUS_UNSPECIFIED_ERROR;
+
+		l_put_le16((uint16_t) L_PTR_TO_UINT(virt->addr), buf);
+		buf += 2;
+		n += 2;
+	}
+
 	*size = n;
 	return MESH_STATUS_SUCCESS;
 }
 
 int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
-			const uint8_t *group, bool b_virt, uint16_t *dst)
+			const uint8_t *group, bool is_virt, uint16_t *dst)
 {
 	int status;
 	struct mesh_model *mod;
@@ -1426,7 +1401,7 @@ int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 	if (!mod)
 		return status;
 
-	status = add_sub(node_get_net(node), mod, group, b_virt, dst);
+	status = add_sub(node_get_net(node), mod, group, is_virt, dst);
 
 	if (status != MESH_STATUS_SUCCESS)
 		return status;
@@ -1439,11 +1414,10 @@ int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 }
 
 int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
-			const uint8_t *group, bool b_virt, uint16_t *dst)
+			const uint8_t *group, bool is_virt, uint16_t *dst)
 {
 	int status;
 	struct l_queue *virtuals, *subs;
-	struct mesh_virtual *virt;
 	struct mesh_model *mod;
 
 	mod = find_model(node, addr, id, &status);
@@ -1458,20 +1432,7 @@ int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
 	if (!mod->subs || !mod->virtuals)
 		return MESH_STATUS_INSUFF_RESOURCES;
 
-	/*
-	 * When overwriting the Subscription List,
-	 * make sure any virtual Publication address is preserved
-	 */
-	if (mod->pub && mod->pub->addr >= VIRTUAL_BASE) {
-		virt = l_queue_find(virtuals, find_virt_by_id,
-				L_UINT_TO_PTR(mod->pub->addr));
-		if (virt) {
-			virt->ref_cnt++;
-			l_queue_push_head(mod->virtuals, virt);
-		}
-	}
-
-	status = add_sub(node_get_net(node), mod, group, b_virt, dst);
+	status = add_sub(node_get_net(node), mod, group, is_virt, dst);
 
 	if (status != MESH_STATUS_SUCCESS) {
 		/* Adding new group failed, so revert to old lists */
@@ -1502,7 +1463,7 @@ int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
 }
 
 int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
-			const uint8_t *group, bool b_virt, uint16_t *dst)
+			const uint8_t *group, bool is_virt, uint16_t *dst)
 {
 	int status;
 	uint16_t grp;
@@ -1512,7 +1473,7 @@ int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
 	if (!mod)
 		return status;
 
-	if (b_virt) {
+	if (is_virt) {
 		struct mesh_virtual *virt;
 
 		virt = l_queue_find(mod->virtuals, find_virt_by_label, group);
@@ -1611,22 +1572,16 @@ struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
 	}
 
 	/* Add publication if present */
-	if (pub && (pub->virt || !(IS_UNASSIGNED(pub->addr)))) {
-		uint8_t mod_addr[2];
-		uint8_t *pub_addr;
+	if (pub) {
 		uint8_t retransmit = pub->count +
 					((pub->interval / 50 - 1) << 3);
-
-		/* Add publication */
-		l_put_le16(pub->addr, &mod_addr);
-		pub_addr = pub->virt ? pub->virt_addr : mod_addr;
-
-		if (set_pub(mod, pub_addr, pub->idx, pub->credential, pub->ttl,
-			pub->period, retransmit, pub->virt, NULL) !=
-							MESH_STATUS_SUCCESS) {
-			mesh_model_free(mod);
-			return NULL;
-		}
+		if (pub->virt)
+			set_virt_pub(mod, pub->virt_addr, pub->idx,
+						pub->credential, pub->ttl,
+						pub->period, retransmit);
+		else if (!IS_UNASSIGNED(pub->addr))
+			set_pub(mod, pub->addr, pub->idx, pub->credential,
+				pub->ttl, pub->period, retransmit);
 	}
 
 	/* Add subscriptions if present */
diff --git a/mesh/model.h b/mesh/model.h
index 9c7ce9334..0613c9cca 100644
--- a/mesh/model.h
+++ b/mesh/model.h
@@ -24,8 +24,6 @@ struct mesh_model;
 #define MAX_BINDINGS	10
 #define MAX_GRP_PER_MOD	10
 
-#define VIRTUAL_BASE			0x10000
-
 #define OP_MODEL_TEST			0x8000fffe
 #define OP_MODEL_INVALID		0x8000ffff
 
@@ -35,8 +33,11 @@ struct mesh_model;
 #define ACTION_UPDATE		2
 #define ACTION_DELETE		3
 
+struct mesh_virtual;
+
 struct mesh_model_pub {
-	uint32_t addr;
+	struct mesh_virtual *virt;
+	uint16_t addr;
 	uint16_t idx;
 	uint8_t ttl;
 	uint8_t credential;
@@ -75,7 +76,7 @@ struct mesh_model_pub *mesh_model_pub_get(struct mesh_node *node,
 int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
 			const uint8_t *pub_addr, uint16_t idx, bool cred_flag,
 			uint8_t ttl, uint8_t period, uint8_t retransmit,
-			bool b_virt, uint16_t *dst);
+			bool is_virt, uint16_t *dst);
 
 int mesh_model_binding_add(struct mesh_node *node, uint16_t addr, uint32_t id,
 								uint16_t idx);
-- 
2.21.1


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

* [PATCH BlueZ v3 5/6] mesh: Clean up handling config model publication message
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
                   ` (3 preceding siblings ...)
  2020-02-25 18:44 ` [PATCH BlueZ v3 4/6] mesh: Simplify model virtual pub/sub logic Inga Stotland
@ 2020-02-25 18:44 ` Inga Stotland
  2020-02-25 18:44 ` [PATCH BlueZ v3 6/6] test/test-mesh: Fix output og UpdateModelConfig method Inga Stotland
  2020-02-26 19:23 ` [PATCH BlueZ v3 0/6] Support for virtual labels Gix, Brian
  6 siblings, 0 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This tightens up the Config Server code that handles the processing of
Config Model Publication Set and Config Model Publication Get messages.
---
 mesh/cfgmod-server.c | 131 +++++++++++++++----------------------------
 1 file changed, 44 insertions(+), 87 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 7111411c7..3eb7316fc 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -36,8 +36,8 @@
 
 static void send_pub_status(struct mesh_node *node, uint16_t net_idx,
 			uint16_t src, uint16_t dst,
-			uint8_t status, uint16_t ele_addr, uint16_t pub_addr,
-			uint32_t mod_id, uint16_t idx, bool cred_flag,
+			uint8_t status, uint16_t ele_addr, uint32_t mod_id,
+			uint16_t pub_addr, uint16_t idx, bool cred_flag,
 			uint8_t ttl, uint8_t period, uint8_t retransmit)
 {
 	uint8_t msg[16];
@@ -56,7 +56,7 @@ static void send_pub_status(struct mesh_node *node, uint16_t net_idx,
 	msg[n++] = period;
 	msg[n++] = retransmit;
 
-	if (mod_id < 0x10000 || mod_id > VENDOR_ID_MASK) {
+	if (mod_id >= VENDOR_ID_MASK) {
 		l_put_le16(mod_id, msg + n);
 		n += 2;
 	} else {
@@ -76,8 +76,7 @@ static bool config_pub_get(struct mesh_node *node, uint16_t net_idx,
 {
 	uint32_t mod_id;
 	uint16_t ele_addr;
-	int ele_idx;
-	struct mesh_model_pub *pub = NULL;
+	struct mesh_model_pub *pub;
 	int status;
 
 	if (size == 4) {
@@ -90,27 +89,22 @@ static bool config_pub_get(struct mesh_node *node, uint16_t net_idx,
 		return false;
 
 	ele_addr = l_get_le16(pkt);
-	ele_idx = node_get_element_idx(node, ele_addr);
-
-	if (ele_idx >= 0)
-		pub = mesh_model_pub_get(node, ele_addr, mod_id, &status);
-	else
-		status = MESH_STATUS_INVALID_ADDRESS;
+	pub = mesh_model_pub_get(node, ele_addr, mod_id, &status);
 
 	if (pub && status == MESH_STATUS_SUCCESS)
 		send_pub_status(node, net_idx, src, dst, status, ele_addr,
-				pub->addr, mod_id, pub->idx, pub->credential,
+				mod_id, pub->addr, pub->idx, pub->credential,
 				pub->ttl, pub->period, pub->retransmit);
 	else
-		send_pub_status(node, net_idx, src, dst, status, ele_addr, 0,
-							mod_id, 0, 0, 0, 0, 0);
+		send_pub_status(node, net_idx, src, dst, status, ele_addr,
+				mod_id, 0, 0, 0, 0, 0, 0);
 	return true;
 }
 
-static bool config_pub_set(struct mesh_node *node, uint16_t net_idx,
+static void config_pub_set(struct mesh_node *node, uint16_t net_idx,
 					uint16_t src, uint16_t dst,
-					const uint8_t *pkt, uint16_t size,
-					bool unreliable)
+					const uint8_t *pkt, uint8_t virt_offset,
+					bool vendor, bool unreliable)
 {
 	uint32_t mod_id;
 	uint16_t ele_addr, idx, ota = 0;
@@ -119,93 +113,58 @@ static bool config_pub_set(struct mesh_node *node, uint16_t net_idx,
 	uint8_t ttl, period;
 	uint8_t retransmit;
 	int status;
-	bool cred_flag, b_virt = false;
-	bool vendor = false;
-
-	switch (size) {
-	default:
-		return false;
-
-	case 11:
-		idx = l_get_le16(pkt + 4);
-		ttl = pkt[6];
-		period = pkt[7];
-		retransmit = pkt[8];
-		mod_id = l_get_le16(pkt + 9);
-		mod_id |= VENDOR_ID_MASK;
-		break;
+	bool cred_flag;
 
-	case 13:
-		idx = l_get_le16(pkt + 4);
-		ttl = pkt[6];
-		period = pkt[7];
-		retransmit = pkt[8];
-		mod_id = l_get_le16(pkt + 9) << 16;
-		mod_id |= l_get_le16(pkt + 11);
-		vendor = true;
-		break;
+	idx = l_get_le16(pkt + 4 + virt_offset);
+	ttl = pkt[6 + virt_offset];
+	period = pkt[7 + virt_offset];
+	retransmit = pkt[8 + virt_offset];
+	mod_id = l_get_le16(pkt + 9 + virt_offset);
 
-	case 25:
-		b_virt = true;
-		idx = l_get_le16(pkt + 18);
-		ttl = pkt[20];
-		period = pkt[21];
-		retransmit = pkt[22];
-		mod_id = l_get_le16(pkt + 23);
+	if (!vendor)
 		mod_id |= VENDOR_ID_MASK;
-		break;
-
-	case 27:
-		b_virt = true;
-		idx = l_get_le16(pkt + 18);
-		ttl = pkt[20];
-		period = pkt[21];
-		retransmit = pkt[22];
-		mod_id = l_get_le16(pkt + 23) << 16;
-		mod_id |= l_get_le16(pkt + 25);
-		vendor = true;
-		break;
-	}
+	else
+		mod_id |= l_get_le16(pkt + 11 + virt_offset);
 
 	ele_addr = l_get_le16(pkt);
 	pub_addr = pkt + 2;
 
-	/* Doesn't accept out-of-range TTLs */
-	if (ttl > TTL_MASK && ttl != DEFAULT_TTL)
-		return false;
+	/* Doesn't accept virtual seeming addresses */
+	test_addr = l_get_le16(pub_addr);
+	if (!virt_offset && IS_VIRTUAL(test_addr))
+		return;
 
 	/* Get cred_flag */
 	cred_flag = !!(CREDFLAG_MASK & idx);
 
-	/* Ignore non-IDX bits */
+	/* Get AppKey index */
 	idx &= APP_IDX_MASK;
 
-	/* Doesn't accept virtual seeming addresses */
-	test_addr = l_get_le16(pub_addr);
-	if (!b_virt && test_addr > 0x7fff && test_addr < 0xc000)
-		return false;
-
 	status = mesh_model_pub_set(node, ele_addr, mod_id, pub_addr, idx,
 					cred_flag, ttl, period, retransmit,
-					b_virt, &ota);
+					virt_offset != 0, &ota);
 
 	l_debug("pub_set: status %d, ea %4.4x, ota: %4.4x, mod: %x, idx: %3.3x",
 					status, ele_addr, ota, mod_id, idx);
 
-	if (IS_UNASSIGNED(ota) && !b_virt) {
-		ttl = period = idx = 0;
+	if (status != MESH_STATUS_SUCCESS) {
+		if (!unreliable)
+			send_pub_status(node, net_idx, src, dst, status,
+					ele_addr, mod_id, 0, 0, 0, 0, 0, 0);
 
-		/* Remove model publication from config file */
-		if (status == MESH_STATUS_SUCCESS)
-			mesh_config_model_pub_del(node_config_get(node),
-				ele_addr, vendor ? mod_id : mod_id & 0x0000ffff,
-									vendor);
-		goto done;
+		return;
 	}
 
-	if (status == MESH_STATUS_SUCCESS) {
+	if (IS_UNASSIGNED(ota) && !virt_offset) {
+		ttl = period = idx = 0;
+
+		/* Remove model publication from config file */
+		mesh_config_model_pub_del(node_config_get(node), ele_addr,
+				vendor ? mod_id : mod_id & ~VENDOR_ID_MASK,
+								vendor);
+	} else {
 		struct mesh_config_pub db_pub = {
-			.virt = b_virt,
+			.virt = (virt_offset != 0),
 			.addr = ota,
 			.idx = idx,
 			.ttl = ttl,
@@ -215,21 +174,19 @@ static bool config_pub_set(struct mesh_node *node, uint16_t net_idx,
 			.interval = ((retransmit >> 3) + 1) * 50
 		};
 
-		if (b_virt)
+		if (virt_offset)
 			memcpy(db_pub.virt_addr, pub_addr, 16);
 
 		/* Save model publication to config file */
 		if (!mesh_config_model_pub_add(node_config_get(node), ele_addr,
-					vendor ? mod_id : mod_id & 0x0000ffff,
+				vendor ? mod_id : mod_id & ~VENDOR_ID_MASK,
 					vendor, &db_pub))
 			status = MESH_STATUS_STORAGE_FAIL;
 	}
 
-done:
 	if (!unreliable)
 		send_pub_status(node, net_idx, src, dst, status, ele_addr, ota,
 			mod_id, idx, cred_flag, ttl, period, retransmit);
-	return true;
 }
 
 static void send_sub_status(struct mesh_node *node, uint16_t net_idx,
@@ -825,7 +782,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, uint16_t unicast,
 		if (size != 25 && size != 27)
 			return true;
 
-		config_pub_set(node, net_idx, src, unicast, pkt, size,
+		config_pub_set(node, net_idx, src, unicast, pkt, 14, size == 27,
 				!!(opcode & OP_UNRELIABLE));
 		break;
 
@@ -833,7 +790,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst, uint16_t unicast,
 		if (size != 11 && size != 13)
 			return true;
 
-		config_pub_set(node, net_idx, src, unicast, pkt, size,
+		config_pub_set(node, net_idx, src, unicast, pkt, 0, size == 13,
 				!!(opcode & OP_UNRELIABLE));
 		break;
 
-- 
2.21.1


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

* [PATCH BlueZ v3 6/6] test/test-mesh: Fix output og UpdateModelConfig method
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
                   ` (4 preceding siblings ...)
  2020-02-25 18:44 ` [PATCH BlueZ v3 5/6] mesh: Clean up handling config model publication message Inga Stotland
@ 2020-02-25 18:44 ` Inga Stotland
  2020-02-26 19:23 ` [PATCH BlueZ v3 0/6] Support for virtual labels Gix, Brian
  6 siblings, 0 replies; 8+ messages in thread
From: Inga Stotland @ 2020-02-25 18:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This correctly unpacks configuration dictionary received
in the UpdateModelConfig() method
---
 test/test-mesh | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/test/test-mesh b/test/test-mesh
index 929e28fd3..6a5ddbd17 100755
--- a/test/test-mesh
+++ b/test/test-mesh
@@ -554,7 +554,7 @@ class Element(dbus.service.Object):
 	def set_model_config(self, configs):
 		for config in configs:
 			mod_id = config[0]
-			self.UpdateModelConfiguration(mod_id, config[1])
+			self.update_model_config(mod_id, config[1])
 
 	@dbus.service.method(MESH_ELEMENT_IFACE,
 					in_signature="qqvay", out_signature="")
@@ -575,6 +575,11 @@ class Element(dbus.service.Object):
 					in_signature="qa{sv}", out_signature="")
 
 	def UpdateModelConfiguration(self, model_id, config):
+		cfg = unwrap(config)
+		print(cfg)
+		self.update_model_config(model_id, cfg)
+
+	def update_model_config(self, model_id, config):
 		print(('Update Model Config '), end='')
 		print(format(model_id, '04x'))
 		for model in self.models:
@@ -644,11 +649,11 @@ class Model():
 	def print_subscriptions(self, subscriptions):
 		for sub in subscriptions:
 			if isinstance(sub, int):
-				print('%04x' % sub, end=' ')
+				print('%04x,' % sub, end=' ')
 
 			if isinstance(sub, list):
 				label = uuid.UUID(bytes=b''.join(sub))
-				print(label, end=' ')
+				print(label, ',', end=' ')
 
 ########################
 # On Off Server Model
-- 
2.21.1


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

* Re: [PATCH BlueZ v3 0/6] Support for virtual labels
  2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
                   ` (5 preceding siblings ...)
  2020-02-25 18:44 ` [PATCH BlueZ v3 6/6] test/test-mesh: Fix output og UpdateModelConfig method Inga Stotland
@ 2020-02-26 19:23 ` Gix, Brian
  6 siblings, 0 replies; 8+ messages in thread
From: Gix, Brian @ 2020-02-26 19:23 UTC (permalink / raw)
  To: linux-bluetooth, Stotland, Inga

Patch set applied
On Tue, 2020-02-25 at 10:44 -0800, Inga Stotland wrote:
> v3: Fixed subscription list generation to include virtual
>     subscription addresses
> 
> *****************************
> v2: Fixed a  backwards compatibility issue reported by Brian;
>     Fixed Python test to correctly display updated configuration
> 
> 
> *****************************
> This patch set adds a capability to mesh-cfgclient to generate
> and store virtual labels and use them in configuring remote
> node's publications and subscriptions.
> Regular group addresses are preeserved as well. This is done
> dynamically: as a new group address is detected in either
> subscription or publication configuration commands.
> 
> This new capability of mesh-cfgclient allowed for improved
> testing of virtual pub/sub implementation in bluetooth-meshd
> daemon. As a result, some deficiencies and legacy entaglements
> were exposed, and consequently resolved and cleaned up.
> 
> 
> Inga Stotland (6):
>   tools/mesh-cfgclient: Add support for virtual labels
>   tools/mesh-cfgclient: Clean up subscription list output
>   tools/mesh-cfgclient: Save and restore group addresses
>   mesh: Simplify model virtual pub/sub logic
>   mesh: Clean up handling config model publication message
>   test/test-mesh: Fix output og UpdateModelConfig method
> 
>  Makefile.tools       |   3 +-
>  mesh/cfgmod-server.c | 131 +++++++--------------
>  mesh/model.c         | 271 ++++++++++++++++++-------------------------
>  mesh/model.h         |   9 +-
>  test/test-mesh       |  11 +-
>  tools/mesh/cfgcli.c  | 242 ++++++++++++++++++++++++++++++++------
>  tools/mesh/cfgcli.h  |   5 +
>  tools/mesh/mesh-db.c | 128 ++++++++++++++++++++
>  tools/mesh/mesh-db.h |   4 +
>  9 files changed, 514 insertions(+), 290 deletions(-)
> 

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

end of thread, other threads:[~2020-02-26 19:23 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-25 18:44 [PATCH BlueZ v3 0/6] Support for virtual labels Inga Stotland
2020-02-25 18:44 ` [PATCH BlueZ v3 1/6] tools/mesh-cfgclient: Add support " Inga Stotland
2020-02-25 18:44 ` [PATCH BlueZ v3 2/6] tools/mesh-cfgclient: Clean up subscription list output Inga Stotland
2020-02-25 18:44 ` [PATCH BlueZ v3 3/6] tools/mesh-cfgclient: Save and restore group addresses Inga Stotland
2020-02-25 18:44 ` [PATCH BlueZ v3 4/6] mesh: Simplify model virtual pub/sub logic Inga Stotland
2020-02-25 18:44 ` [PATCH BlueZ v3 5/6] mesh: Clean up handling config model publication message Inga Stotland
2020-02-25 18:44 ` [PATCH BlueZ v3 6/6] test/test-mesh: Fix output og UpdateModelConfig method Inga Stotland
2020-02-26 19:23 ` [PATCH BlueZ v3 0/6] Support for virtual labels Gix, Brian

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.