Linux-Bluetooth Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH BlueZ 0/3] Code re-org and clean up
@ 2020-07-13 23:05 Inga Stotland
  2020-07-13 23:05 ` [PATCH BlueZ 1/3] mesh: Use static array to hold config server response Inga Stotland
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Inga Stotland @ 2020-07-13 23:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This patch set is part of the on-going  clean up effort that targets some
of more convoluted areas of meshd source code.
The patchset provides better functional separation, smaller function
granularity and better memory handling.

Inga Stotland (3):
  mesh: Use static array to hold config server response
  mesh: Add size checks for every opcode in config server
  mesh: move model functionality out of node.c to model.c

 mesh/cfgmod-server.c    |  99 ++++++-----
 mesh/cfgmod.h           |   4 +-
 mesh/mesh-config-json.c |   5 +-
 mesh/model.c            | 359 +++++++++++++++++++++++++++++++++-------
 mesh/model.h            |  32 ++--
 mesh/node.c             | 286 ++++----------------------------
 6 files changed, 403 insertions(+), 382 deletions(-)

-- 
2.26.2


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

* [PATCH BlueZ 1/3] mesh: Use static array to hold config server response
  2020-07-13 23:05 [PATCH BlueZ 0/3] Code re-org and clean up Inga Stotland
@ 2020-07-13 23:05 ` Inga Stotland
  2020-07-13 23:05 ` [PATCH BlueZ 2/3] mesh: Add size checks for every opcode in config server Inga Stotland
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Inga Stotland @ 2020-07-13 23:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This eliminates dynamic allocation for long responses and local
arrays for short responses. Instead, aclear text response from
config server is written into a static buffer and then encoded
into dynamically allocated messafe buffer to use in actual
transmission.
---
 mesh/cfgmod-server.c | 53 +++++++++++++-------------------------------
 1 file changed, 16 insertions(+), 37 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 14b4a980e..08a74d014 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -32,21 +32,20 @@
 #include "mesh/mesh-config.h"
 #include "mesh/cfgmod.h"
 
-#define CFG_MAX_MSG_LEN 380
-
 /* Supported composition pages, sorted high to low */
 /* Only page 0 is currently supported */
 static const uint8_t supported_pages[] = {
 	0
 };
 
+static uint8_t msg[MAX_MSG_LEN];
+
 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, 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];
 	size_t n;
 
 	n = mesh_model_opcode_set(OP_CONFIG_MODEL_PUB_STATUS, msg);
@@ -193,7 +192,6 @@ static void send_sub_status(struct mesh_node *node, uint16_t net_idx,
 					uint8_t status, uint16_t ele_addr,
 					uint16_t addr, uint32_t mod)
 {
-	uint8_t msg[12];
 	int n = mesh_model_opcode_set(OP_CONFIG_MODEL_SUB_STATUS, msg);
 
 	msg[n++] = status;
@@ -224,7 +222,6 @@ static bool config_sub_get(struct mesh_node *node, uint16_t net_idx,
 	int status;
 	uint8_t *msg_status;
 	uint16_t buf_size;
-	uint8_t msg[5 + sizeof(uint16_t) * MAX_GRP_PER_MOD];
 
 	/* Incoming message has already been size-checked */
 	ele_addr = l_get_le16(pkt);
@@ -430,7 +427,6 @@ static void send_model_app_status(struct mesh_node *node, uint16_t net_idx,
 					uint8_t status, uint16_t addr,
 					uint32_t id, uint16_t idx)
 {
-	uint8_t msg[12];
 	size_t n = mesh_model_opcode_set(OP_MODEL_APP_STATUS, msg);
 
 	msg[n++] = status;
@@ -455,21 +451,14 @@ static void model_app_list(struct mesh_node *node, uint16_t net_idx,
 {
 	uint16_t ele_addr;
 	uint32_t mod_id = 0xffff;
-	uint8_t *msg = NULL;
 	uint8_t *status;
-	uint16_t n, buf_size;
+	uint16_t n;
 	int result;
 
-	buf_size = MAX_BINDINGS * sizeof(uint16_t);
-	msg = l_malloc(7 + buf_size);
-	if (!msg)
-		return;
-
 	ele_addr = l_get_le16(pkt);
 
 	switch (size) {
 	default:
-		l_free(msg);
 		return;
 	case 4:
 		n = mesh_model_opcode_set(OP_MODEL_APP_LIST, msg);
@@ -495,7 +484,7 @@ static void model_app_list(struct mesh_node *node, uint16_t net_idx,
 
 
 	result = mesh_model_get_bindings(node, ele_addr, mod_id, msg + n,
-							buf_size, &size);
+						MAX_MSG_LEN - n, &size);
 	n += size;
 
 	if (result >= 0) {
@@ -503,8 +492,6 @@ static void model_app_list(struct mesh_node *node, uint16_t net_idx,
 		mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx,
 						DEFAULT_TTL, false, msg, n);
 	}
-
-	l_free(msg);
 }
 
 static bool model_app_bind(struct mesh_node *node, uint16_t net_idx,
@@ -736,8 +723,6 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 	struct timeval time_now;
 	uint32_t opcode, tmp32;
 	int b_res = MESH_STATUS_SUCCESS;
-	uint8_t msg[11];
-	uint8_t *long_msg = NULL;
 	struct mesh_net_heartbeat *hb;
 	uint16_t n_idx, a_idx;
 	uint8_t state, status;
@@ -771,9 +756,8 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		if (size != 1)
 			return false;
 
-		long_msg = l_malloc(CFG_MAX_MSG_LEN);
-		n = mesh_model_opcode_set(OP_DEV_COMP_STATUS, long_msg);
-		n += get_composition(node, pkt[0], long_msg + n);
+		n = mesh_model_opcode_set(OP_DEV_COMP_STATUS, msg);
+		n += get_composition(node, pkt[0], msg + n);
 
 		break;
 
@@ -1040,14 +1024,13 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 
 		n_idx = l_get_le16(pkt);
 
-		long_msg = l_malloc(CFG_MAX_MSG_LEN);
-		n = mesh_model_opcode_set(OP_APPKEY_LIST, long_msg);
+		n = mesh_model_opcode_set(OP_APPKEY_LIST, msg);
 
-		status = appkey_list(net, n_idx, long_msg + n + 3,
-						CFG_MAX_MSG_LEN - n - 3, &size);
+		status = appkey_list(net, n_idx, msg + n + 3,
+						MAX_MSG_LEN - n - 3, &size);
 
-		long_msg[n] = status;
-		l_put_le16(n_idx, long_msg + n + 1);
+		msg[n] = status;
+		l_put_le16(n_idx, msg + n + 1);
 		n += (size + 3);
 		break;
 
@@ -1088,11 +1071,10 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		break;
 
 	case OP_NETKEY_GET:
-		long_msg = l_malloc(CFG_MAX_MSG_LEN);
-		n = mesh_model_opcode_set(OP_NETKEY_LIST, long_msg);
-		size = CFG_MAX_MSG_LEN - n;
+		n = mesh_model_opcode_set(OP_NETKEY_LIST, msg);
+		size = MAX_MSG_LEN - n;
 
-		if (mesh_net_key_list_get(net, long_msg + n, &size))
+		if (mesh_net_key_list_get(net, msg + n, &size))
 			n += size;
 		else
 			n = 0;
@@ -1244,11 +1226,8 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 	}
 
 	if (n)
-		mesh_model_send(node, dst, src,
-				APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, false,
-				long_msg ? long_msg : msg, n);
-
-	l_free(long_msg);
+		mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx,
+						DEFAULT_TTL, false, msg, n);
 
 	return true;
 }
-- 
2.26.2


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

* [PATCH BlueZ 2/3] mesh: Add size checks for every opcode in config server
  2020-07-13 23:05 [PATCH BlueZ 0/3] Code re-org and clean up Inga Stotland
  2020-07-13 23:05 ` [PATCH BlueZ 1/3] mesh: Use static array to hold config server response Inga Stotland
@ 2020-07-13 23:05 ` Inga Stotland
  2020-07-13 23:05 ` [PATCH BlueZ 3/3] mesh: move model functionality out of node.c to model.c Inga Stotland
  2020-07-16 17:20 ` [PATCH BlueZ 0/3] Code re-org and clean up Gix, Brian
  3 siblings, 0 replies; 5+ messages in thread
From: Inga Stotland @ 2020-07-13 23:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This adds missing size checks for the incoming config server messages.
---
 mesh/cfgmod-server.c | 46 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 37 insertions(+), 9 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 08a74d014..9046a1ad9 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -754,7 +754,7 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 
 	case OP_DEV_COMP_GET:
 		if (size != 1)
-			return false;
+			return true;
 
 		n = mesh_model_opcode_set(OP_DEV_COMP_STATUS, msg);
 		n += get_composition(node, pkt[0], msg + n);
@@ -770,6 +770,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall Through */
 
 	case OP_CONFIG_DEFAULT_TTL_GET:
+		if (opcode == OP_CONFIG_DEFAULT_TTL_GET && size != 0)
+			return true;
+
 		l_debug("Get/Set Default TTL");
 
 		n = mesh_model_opcode_set(OP_CONFIG_DEFAULT_TTL_STATUS, msg);
@@ -792,6 +795,8 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		break;
 
 	case OP_CONFIG_MODEL_PUB_GET:
+		if (size != 4 && size != 6)
+			return true;
 		config_pub_get(node, net_idx, src, dst, pkt, size);
 		break;
 
@@ -832,6 +837,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall Through */
 
 	case OP_CONFIG_RELAY_GET:
+		if (opcode == OP_CONFIG_RELAY_GET && size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_CONFIG_RELAY_STATUS, msg);
 
 		msg[n++] = node_relay_mode_get(node, &count, &interval);
@@ -853,6 +861,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall Through */
 
 	case OP_CONFIG_NETWORK_TRANSMIT_GET:
+		if (opcode == OP_CONFIG_NETWORK_TRANSMIT_GET && size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_CONFIG_NETWORK_TRANSMIT_STATUS,
 									msg);
 		mesh_net_transmit_params_get(net, &count, &interval);
@@ -869,6 +880,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall Through */
 
 	case OP_CONFIG_PROXY_GET:
+		if (opcode == OP_CONFIG_PROXY_GET && size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_CONFIG_PROXY_STATUS, msg);
 
 		msg[n++] = node_proxy_mode_get(node);
@@ -883,9 +897,7 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		if (n_idx > 0xfff)
 			return true;
 
-		/*
-		 * Currently no support for proxy: node identity not supported
-		 */
+		/* Currently setting node identity not supported */
 
 		/* Fall Through */
 
@@ -918,6 +930,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall Through */
 
 	case OP_CONFIG_BEACON_GET:
+		if (opcode == OP_CONFIG_BEACON_GET && size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_CONFIG_BEACON_STATUS, msg);
 
 		msg[n++] = node_beacon_mode_get(node);
@@ -932,6 +947,8 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall Through */
 
 	case OP_CONFIG_FRIEND_GET:
+		if (opcode == OP_CONFIG_FRIEND_GET && size != 0)
+			return true;
 
 		n = mesh_model_opcode_set(OP_CONFIG_FRIEND_STATUS, msg);
 
@@ -1071,13 +1088,14 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		break;
 
 	case OP_NETKEY_GET:
+		if (size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_NETKEY_LIST, msg);
 		size = MAX_MSG_LEN - n;
 
 		if (mesh_net_key_list_get(net, msg + n, &size))
 			n += size;
-		else
-			n = 0;
 		break;
 
 	case OP_MODEL_APP_BIND:
@@ -1089,21 +1107,22 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 	case OP_VEND_MODEL_APP_GET:
 		if (size != 6)
 			return true;
+
 		model_app_list(node, net_idx, src, dst, pkt, size);
 		break;
 
 	case OP_MODEL_APP_GET:
 		if (size != 4)
 			return true;
+
 		model_app_list(node, net_idx, src, dst, pkt, size);
 		break;
 
 	case OP_CONFIG_HEARTBEAT_PUB_SET:
 		l_debug("OP_CONFIG_HEARTBEAT_PUB_SET");
-		if (size != 9) {
-			l_debug("bad size %d", size);
+		if (size != 9)
 			return true;
-		}
+
 		if (pkt[2] > 0x11 || pkt[3] > 0x10 || pkt[4] > 0x7f)
 			return true;
 		else if (IS_VIRTUAL(l_get_le16(pkt)))
@@ -1150,6 +1169,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		break;
 
 	case OP_CONFIG_HEARTBEAT_PUB_GET:
+		if (size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_CONFIG_HEARTBEAT_PUB_STATUS, msg);
 		msg[n++] = b_res;
 		l_put_le16(hb->pub_dst, msg + n);
@@ -1179,6 +1201,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		/* Fall through */
 
 	case OP_CONFIG_HEARTBEAT_SUB_GET:
+		if (opcode == OP_CONFIG_HEARTBEAT_SUB_GET && size != 0)
+			return true;
+
 		gettimeofday(&time_now, NULL);
 		time_now.tv_sec -= hb->sub_start;
 
@@ -1218,6 +1243,9 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
 		break;
 
 	case OP_NODE_RESET:
+		if (size != 0)
+			return true;
+
 		n = mesh_model_opcode_set(OP_NODE_RESET_STATUS, msg);
 
 		/* Delay node removal to give it a chance to send the status */
-- 
2.26.2


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

* [PATCH BlueZ 3/3] mesh: move model functionality out of node.c to model.c
  2020-07-13 23:05 [PATCH BlueZ 0/3] Code re-org and clean up Inga Stotland
  2020-07-13 23:05 ` [PATCH BlueZ 1/3] mesh: Use static array to hold config server response Inga Stotland
  2020-07-13 23:05 ` [PATCH BlueZ 2/3] mesh: Add size checks for every opcode in config server Inga Stotland
@ 2020-07-13 23:05 ` Inga Stotland
  2020-07-16 17:20 ` [PATCH BlueZ 0/3] Code re-org and clean up Gix, Brian
  3 siblings, 0 replies; 5+ messages in thread
From: Inga Stotland @ 2020-07-13 23:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: brian.gix, Inga Stotland

This moves the model related code out of node.c to model.c providing
for better functional separation of modules.
---
 mesh/cfgmod.h           |   4 +-
 mesh/mesh-config-json.c |   5 +-
 mesh/model.c            | 359 +++++++++++++++++++++++++++++++++-------
 mesh/model.h            |  32 ++--
 mesh/node.c             | 286 ++++----------------------------
 5 files changed, 350 insertions(+), 336 deletions(-)

diff --git a/mesh/cfgmod.h b/mesh/cfgmod.h
index 383fdbf6b..0bfa71680 100644
--- a/mesh/cfgmod.h
+++ b/mesh/cfgmod.h
@@ -17,8 +17,8 @@
  *
  */
 
-#define CONFIG_SRV_MODEL	(VENDOR_ID_MASK | 0x0000)
-#define CONFIG_CLI_MODEL	(VENDOR_ID_MASK | 0x0001)
+#define CONFIG_SRV_MODEL	0x0000
+#define CONFIG_CLI_MODEL	0x0001
 
 /* New List */
 #define OP_APPKEY_ADD				0x00
diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c
index 88f715fc1..deb0019f9 100644
--- a/mesh/mesh-config-json.c
+++ b/mesh/mesh-config-json.c
@@ -1126,18 +1126,15 @@ static bool parse_models(json_object *jmodels, struct mesh_config_element *ele)
 			if (sscanf(str, "%04x", &id) != 1)
 				goto fail;
 
-			id |= VENDOR_ID_MASK;
 		} else if (len == 8) {
 			if (sscanf(str, "%08x", &id) != 1)
 				goto fail;
+			mod->vendor = true;
 		} else
 			goto fail;
 
 		mod->id = id;
 
-		if (len == 8)
-			mod->vendor = true;
-
 		if (json_object_object_get_ex(jmodel, "bind", &jarray)) {
 			if (json_object_get_type(jarray) != json_type_array ||
 					!parse_bindings(jarray, mod))
diff --git a/mesh/model.c b/mesh/model.c
index afac6ec69..9aecd5b1d 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -137,6 +137,20 @@ static bool match_model_id(const void *a, const void *b)
 	return (mesh_model_get_model_id(model) == id);
 }
 
+static int compare_model_id(const void *a, const void *b, void *user_data)
+{
+	uint32_t a_id = mesh_model_get_model_id(a);
+	uint32_t b_id = mesh_model_get_model_id(b);
+
+	if (a_id < b_id)
+		return -1;
+
+	if (a_id > b_id)
+		return 1;
+
+	return 0;
+}
+
 static struct mesh_model *get_model(struct mesh_node *node, uint8_t ele_idx,
 						uint32_t id, int *status)
 {
@@ -1023,9 +1037,8 @@ done:
 	return result;
 }
 
-int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
-				uint16_t src, uint8_t ttl,
-				const void *msg, uint16_t msg_len)
+static int model_publish(struct mesh_node *node, uint32_t id, uint16_t src,
+				uint8_t ttl, const void *msg, uint16_t msg_len)
 {
 	struct mesh_net *net = node_get_net(node);
 	struct mesh_model *mod;
@@ -1041,14 +1054,14 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
 	if (src == 0)
 		src = mesh_net_get_address(net);
 
-	mod = find_model(node, src, mod_id, &status);
+	mod = find_model(node, src, id, &status);
 	if (!mod) {
-		l_debug("model %x not found", mod_id);
+		l_debug("model %x not found", id);
 		return MESH_ERROR_NOT_FOUND;
 	}
 
 	if (!mod->pub) {
-		l_debug("publication doesn't exist (model %x)", mod_id);
+		l_debug("publication doesn't exist (model %x)", id);
 		return MESH_ERROR_DOES_NOT_EXIST;
 	}
 
@@ -1069,6 +1082,24 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
 	return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED;
 }
 
+int mesh_model_publish(struct mesh_node *node, uint16_t mod_id,
+				uint16_t src, uint8_t ttl,
+				const void *msg, uint16_t msg_len)
+{
+	uint32_t id = mod_id | VENDOR_ID_MASK;
+
+	return model_publish(node, id, src, ttl, msg, msg_len);
+}
+
+int mesh_model_vendor_publish(struct mesh_node *node, uint16_t vendor_id,
+				uint16_t mod_id, uint16_t src, uint8_t ttl,
+				const void *msg, uint16_t msg_len)
+{
+	uint32_t id = mod_id | ((uint32_t)(vendor_id) << 16);
+
+	return model_publish(node, id, src, ttl, msg, msg_len);
+}
+
 bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
 					uint16_t app_idx, uint16_t net_idx,
 					uint8_t ttl, bool segmented,
@@ -1173,7 +1204,21 @@ void mesh_model_free(void *data)
 	l_free(mod);
 }
 
-struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t id)
+static void remove_subs(struct mesh_node *node, struct mesh_model *mod)
+{
+	const struct l_queue_entry *entry;
+	struct mesh_net *net = node_get_net(node);
+
+	entry = l_queue_get_entries(mod->subs);
+
+	for (; entry; entry = entry->next)
+		mesh_net_dst_unreg(net, (uint16_t) L_PTR_TO_UINT(entry->data));
+
+	l_queue_clear(mod->subs, NULL);
+	l_queue_clear(mod->virtuals, unref_virt);
+}
+
+static struct mesh_model *model_new(uint8_t ele_idx, uint32_t id)
 {
 	struct mesh_model *mod = l_new(struct mesh_model, 1);
 
@@ -1190,6 +1235,95 @@ struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t id)
 	return mod;
 }
 
+static void model_enable_pub(struct mesh_model *mod, bool enable)
+{
+	mod->pub_enabled = enable;
+
+	if (!mod->pub_enabled && mod->pub) {
+		if (mod->pub->virt)
+			unref_virt(mod->pub->virt);
+
+		l_free(mod->pub);
+		mod->pub = NULL;
+	}
+}
+
+static void model_enable_sub(struct mesh_node *node, struct mesh_model *mod,
+								bool enable)
+{
+	mod->sub_enabled = enable;
+
+	if (!mod->sub_enabled)
+		remove_subs(node, mod);
+}
+
+static bool get_model_options(struct mesh_node *node, struct mesh_model *mod,
+					struct l_dbus_message_iter *opts)
+{
+	const char *key;
+	struct l_dbus_message_iter var;
+	bool opt;
+
+	while (l_dbus_message_iter_next_entry(opts, &key, &var)) {
+
+		if (!strcmp(key, "Publish")) {
+			if (!l_dbus_message_iter_get_variant(&var, "b", &opt))
+				return false;
+
+			model_enable_pub(mod, opt);
+		} else if (!strcmp(key, "Subscribe")) {
+			if (!l_dbus_message_iter_get_variant(&var, "b", &opt))
+				return false;
+
+			model_enable_sub(node, mod, opt);
+		} else
+			return false;
+	}
+
+	return true;
+}
+
+static bool add_model(struct mesh_node *node, uint8_t ele_idx, uint32_t id,
+					struct l_dbus_message_iter *opts)
+{
+	struct l_queue *mods;
+	struct mesh_model *mod;
+
+	mods = node_get_element_models(node, ele_idx, NULL);
+
+	/* Disallow duplicates */
+	mod = l_queue_find(mods, match_model_id, L_UINT_TO_PTR(id));
+	if (mod)
+		return false;
+
+	mod = model_new(ele_idx, id);
+
+	if (opts && !get_model_options(node, mod, opts)) {
+		mesh_model_free(mod);
+		return false;
+	}
+
+	l_queue_insert(mods, mod, compare_model_id, NULL);
+	return true;
+}
+
+bool mesh_model_add(struct mesh_node *node, uint8_t ele_idx, uint16_t mod_id,
+					struct l_dbus_message_iter *opts)
+{
+	uint32_t id = mod_id | VENDOR_ID_MASK;
+
+	return add_model(node, ele_idx, id, opts);
+}
+
+bool mesh_model_vendor_add(struct mesh_node *node, uint8_t ele_idx,
+					uint16_t vendor_id, uint16_t mod_id,
+					struct l_dbus_message_iter *opts)
+{
+	uint32_t id = mod_id | ((uint32_t)(vendor_id) << 16);
+
+	return add_model(node, ele_idx, id, opts);
+}
+
 /* Internal models only */
 static void restore_model_state(struct mesh_model *mod)
 {
@@ -1220,17 +1354,18 @@ uint32_t mesh_model_get_model_id(const struct mesh_model *model)
 
 /* This registers an internal model, i.e. implemented within meshd */
 bool mesh_model_register(struct mesh_node *node, uint8_t ele_idx,
-					uint32_t mod_id,
+					uint16_t mod_id,
 					const struct mesh_model_ops *cbs,
 					void *user_data)
 {
 	struct mesh_model *mod;
+	uint32_t id;
 	int status;
 
 	/* Internal models are always SIG models */
-	mod_id = VENDOR_ID_MASK | mod_id;
+	id = VENDOR_ID_MASK | mod_id;
 
-	mod = get_model(node, ele_idx, mod_id, &status);
+	mod = get_model(node, ele_idx, id, &status);
 	if (!mod)
 		return false;
 
@@ -1487,20 +1622,6 @@ int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
 	return MESH_STATUS_SUCCESS;
 }
 
-static void remove_subs(struct mesh_node *node, struct mesh_model *mod)
-{
-	const struct l_queue_entry *entry;
-	struct mesh_net *net = node_get_net(node);
-
-	entry = l_queue_get_entries(mod->subs);
-
-	for (; entry; entry = entry->next)
-		mesh_net_dst_unreg(net, (uint16_t) L_PTR_TO_UINT(entry->data));
-
-	l_queue_clear(mod->subs, NULL);
-	l_queue_clear(mod->virtuals, unref_virt);
-}
-
 int mesh_model_sub_del_all(struct mesh_node *node, uint16_t addr, uint32_t id)
 {
 	int status;
@@ -1522,12 +1643,10 @@ int mesh_model_sub_del_all(struct mesh_node *node, uint16_t addr, uint32_t id)
 	return MESH_STATUS_SUCCESS;
 }
 
-struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
-								void *data)
+static struct mesh_model *model_setup(struct mesh_net *net, uint8_t ele_idx,
+					struct mesh_config_model *db_mod)
 {
-	struct mesh_config_model *db_mod = data;
 	struct mesh_model *mod;
-	struct mesh_net *net;
 	struct mesh_config_pub *pub = db_mod->pub;
 	uint32_t i;
 
@@ -1537,7 +1656,7 @@ struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
 		return NULL;
 	}
 
-	mod = mesh_model_new(ele_idx, db_mod->vendor ? db_mod->id :
+	mod = model_new(ele_idx, db_mod->vendor ? db_mod->id :
 						db_mod->id | VENDOR_ID_MASK);
 
 	/* Implicitly bind config server model to device key */
@@ -1557,17 +1676,18 @@ struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
 		return mod;
 	}
 
-	net = node_get_net(node);
-
 	/* Add application key bindings if present */
 	if (db_mod->bindings) {
 		mod->bindings = l_queue_new();
 		for (i = 0; i < db_mod->num_bindings; i++)
-			model_bind_idx(node, mod, db_mod->bindings[i]);
+			l_queue_push_tail(mod->bindings,
+					L_UINT_TO_PTR(db_mod->bindings[i]));
 	}
 
-	/* Add publication if present */
-	if (pub) {
+	mod->pub_enabled = db_mod->pub_enabled;
+
+	/* Add publication if enabled and present */
+	if (mod->pub_enabled && pub) {
 		uint8_t retransmit = pub->count +
 					((pub->interval / 50 - 1) << 3);
 		if (pub->virt)
@@ -1579,8 +1699,10 @@ struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
 				pub->ttl, pub->period, retransmit);
 	}
 
-	/* Add subscriptions if present */
-	if (!db_mod->subs)
+	mod->sub_enabled = db_mod->sub_enabled;
+
+	/* Add subscriptions if enabled and present */
+	if (!db_mod->subs || !mod->sub_enabled)
 		return mod;
 
 	for (i = 0; i < db_mod->num_subs; i++) {
@@ -1605,6 +1727,59 @@ struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
 	return mod;
 }
 
+bool mesh_model_add_from_storage(struct mesh_node *node, uint8_t ele_idx,
+				struct l_queue *mods, struct l_queue *db_mods)
+{
+	struct mesh_net *net = node_get_net(node);
+	const struct l_queue_entry *entry;
+
+	/* Allow empty elements */
+	if (!db_mods)
+		return true;
+
+	entry = l_queue_get_entries(db_mods);
+
+	for (; entry; entry = entry->next) {
+		struct mesh_model *mod;
+		struct mesh_config_model *db_mod;
+		uint32_t id;
+
+		db_mod = entry->data;
+
+		id = db_mod->vendor ? db_mod->id : db_mod->id | VENDOR_ID_MASK;
+
+		if (l_queue_find(mods, match_model_id, L_UINT_TO_PTR(id)))
+			return false;
+
+		mod = model_setup(net, ele_idx, db_mod);
+		if (!mod)
+			return false;
+
+		l_queue_insert(mods, mod, compare_model_id, NULL);
+	}
+
+	return true;
+}
+
+void mesh_model_convert_to_storage(struct l_queue *db_mods,
+							struct l_queue *mods)
+{
+
+	const struct l_queue_entry *entry = l_queue_get_entries(mods);
+
+	for (; entry; entry = entry->next) {
+		struct mesh_model *mod = entry->data;
+		struct mesh_config_model *db_mod;
+
+		db_mod = l_new(struct mesh_config_model, 1);
+		db_mod->id = mod->id;
+		db_mod->vendor = mod->id < VENDOR_ID_MASK;
+		db_mod->pub_enabled = mod->pub_enabled;
+		db_mod->sub_enabled = mod->sub_enabled;
+		l_queue_push_tail(db_mods, db_mod);
+	}
+}
+
 uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf)
 {
 	if (opcode <= 0x7e) {
@@ -1669,7 +1844,7 @@ bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size,
 	return true;
 }
 
-void model_build_config(void *model, void *msg_builder)
+void mesh_model_build_config(void *model, void *msg_builder)
 {
 	struct l_dbus_message_builder *builder = msg_builder;
 	struct mesh_model *mod = model;
@@ -1715,36 +1890,44 @@ void model_build_config(void *model, void *msg_builder)
 	l_dbus_message_builder_leave_struct(builder);
 }
 
-void mesh_model_enable_pub(struct mesh_model *mod, bool enable)
+void mesh_model_update_opts(struct mesh_node *node, uint8_t ele_idx,
+				struct l_queue *curr, struct l_queue *updated)
 {
-	mod->pub_enabled = enable;
+	uint16_t primary;
+	const struct l_queue_entry *entry;
 
-	if (!mod->pub_enabled && mod->pub) {
-		if (mod->pub->virt)
-			unref_virt(mod->pub->virt);
+	primary = node_get_primary(node);
+	entry = l_queue_get_entries(curr);
 
-		l_free(mod->pub);
-		mod->pub = NULL;
-	}
-}
+	for (; entry; entry = entry->next) {
+		struct mesh_model *mod, *updated_mod = entry->data;
+		uint32_t id = mesh_model_get_model_id(updated_mod);
+		bool updated_opt, vendor = id < VENDOR_ID_MASK;
 
-bool mesh_model_is_pub_enabled(struct mesh_model *mod)
-{
-	return mod->pub_enabled;
-}
+		mod = l_queue_find(curr, match_model_id, L_UINT_TO_PTR(id));
+		if (!mod)
+			continue;
 
-void mesh_model_enable_sub(struct mesh_node *node, struct mesh_model *mod,
-								bool enable)
-{
-	mod->sub_enabled = enable;
+		if (!vendor)
+			id &= ~VENDOR_ID_MASK;
 
-	if (!mod->sub_enabled)
-		remove_subs(node, mod);
-}
+		updated_opt = updated_mod->pub_enabled;
+		if (mod->pub_enabled != updated_opt) {
+			model_enable_pub(mod, updated_opt);
+			mesh_config_model_pub_enable(node_config_get(node),
+							primary + ele_idx, id,
+							vendor, updated_opt);
+		}
 
-bool mesh_model_is_sub_enabled(struct mesh_model *mod)
-{
-	return mod->sub_enabled;
+		updated_opt = updated_mod->sub_enabled;
+
+		if (mod->pub_enabled != updated_opt) {
+			model_enable_sub(node, mod, updated_opt);
+			mesh_config_model_sub_enable(node_config_get(node),
+							primary + ele_idx, id,
+							vendor, updated_opt);
+			}
+		}
 }
 
 void mesh_model_init(void)
@@ -1757,3 +1940,59 @@ void mesh_model_cleanup(void)
 	l_queue_destroy(mesh_virtuals, l_free);
 	mesh_virtuals = NULL;
 }
+
+/* Populate composition buffer with model IDs */
+uint16_t mesh_model_generate_composition(struct l_queue *mods, uint16_t buf_sz,
+								uint8_t *buf)
+{
+	const struct l_queue_entry *entry;
+	uint8_t num_s = 0, num_v = 0;
+	uint8_t *mod_buf;
+	uint16_t n;
+
+	/* Store models IDs, store num_s and num_v later */
+	mod_buf = buf;
+	n = 2;
+
+	entry = l_queue_get_entries(mods);
+
+	/* Get SIG models */
+	for (; entry; entry = entry->next) {
+		struct mesh_model *mod = entry->data;
+
+		if (n + 2 > buf_sz)
+			goto done;
+
+		if ((mod->id & VENDOR_ID_MASK) == VENDOR_ID_MASK) {
+			l_put_le16((uint16_t) (mod->id & 0xffff), buf + n);
+			n += 2;
+			num_s++;
+		}
+	}
+
+	/* Get vendor models */
+	entry = l_queue_get_entries(mods);
+
+	for (; entry; entry = entry->next) {
+		struct mesh_model *mod = entry->data;
+		uint16_t vendor;
+
+		if (n + 4 > buf_sz)
+			goto done;
+
+		if ((mod->id & VENDOR_ID_MASK) == VENDOR_ID_MASK)
+			continue;
+
+		vendor = (uint16_t) (mod->id >> 16);
+		l_put_le16(vendor, buf + n);
+		n += 2;
+		l_put_le16((uint16_t) (mod->id & 0xffff), buf + n);
+		n += 2;
+		num_v++;
+	}
+
+done:
+	mod_buf[0] = num_s;
+	mod_buf[1] = num_v;
+	return n;
+}
diff --git a/mesh/model.h b/mesh/model.h
index 0377d3fdd..09309c497 100644
--- a/mesh/model.h
+++ b/mesh/model.h
@@ -60,14 +60,20 @@ struct mesh_model_ops {
 	mesh_model_sub_cb sub;
 };
 
-struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t mod_id);
+bool mesh_model_add(struct mesh_node *node, uint8_t ele_idx, uint16_t mod_id,
+					struct l_dbus_message_iter *opts);
+bool mesh_model_vendor_add(struct mesh_node *node, uint8_t ele_idx,
+					uint16_t vendor_id, uint16_t mod_id,
+					struct l_dbus_message_iter *opts);
 void mesh_model_free(void *data);
 uint32_t mesh_model_get_model_id(const struct mesh_model *model);
 bool mesh_model_register(struct mesh_node *node, uint8_t ele_idx,
-			uint32_t mod_id, const struct mesh_model_ops *cbs,
+			uint16_t mod_id, const struct mesh_model_ops *cbs,
 							void *user_data);
-struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
-								void *data);
+bool mesh_model_add_from_storage(struct mesh_node *node, uint8_t ele_idx,
+				struct l_queue *mods, struct l_queue *db_mods);
+void mesh_model_convert_to_storage(struct l_queue *db_mods,
+							struct l_queue *mods);
 struct mesh_model_pub *mesh_model_pub_get(struct mesh_node *node,
 				uint16_t addr, uint32_t mod_id, int *status);
 int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
@@ -95,8 +101,11 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
 					uint16_t app_idx, uint16_t net_idx,
 					uint8_t ttl, bool segmented,
 					const void *msg, uint16_t msg_len);
-int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, uint16_t src,
+int mesh_model_publish(struct mesh_node *node, uint16_t mod_id, uint16_t src,
 				uint8_t ttl, const void *msg, uint16_t msg_len);
+int mesh_model_vendor_publish(struct mesh_node *node, uint16_t vendor_id,
+				uint16_t mod_id, uint16_t src, uint8_t ttl,
+				const void *msg, uint16_t msg_len);
 bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
 			uint32_t seq, uint32_t iv_index, uint16_t net_idx,
 			uint16_t src, uint16_t dst, uint8_t key_aid,
@@ -108,13 +117,10 @@ struct l_queue *mesh_model_get_appkeys(struct mesh_node *node);
 uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf);
 bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size, uint32_t *opcode,
 								uint16_t *n);
-void model_build_config(void *model, void *msg_builder);
-
-void mesh_model_enable_pub(struct mesh_model *mod, bool enable);
-bool mesh_model_is_pub_enabled(struct mesh_model *mod);
-void mesh_model_enable_sub(struct mesh_node *node, struct mesh_model *mod,
-								bool enable);
-bool mesh_model_is_sub_enabled(struct mesh_model *mod);
-
+void mesh_model_build_config(void *model, void *msg_builder);
+void mesh_model_update_opts(struct mesh_node *node, uint8_t ele_idx,
+				struct l_queue *curr, struct l_queue *updated);
+uint16_t mesh_model_generate_composition(struct l_queue *mods, uint16_t buf_sz,
+								uint8_t *buf);
 void mesh_model_init(void);
 void mesh_model_cleanup(void);
diff --git a/mesh/node.c b/mesh/node.c
index c61167bda..46cf15d53 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -186,28 +186,6 @@ static bool match_element_path(const void *a, const void *b)
 	return (!strcmp(element->path, path));
 }
 
-static bool match_model_id(const void *a, const void *b)
-{
-	const struct mesh_model *mod = a;
-	uint32_t mod_id = L_PTR_TO_UINT(b);
-
-	return mesh_model_get_model_id(mod) == mod_id;
-}
-
-static int compare_model_id(const void *a, const void *b, void *user_data)
-{
-	uint32_t a_id = mesh_model_get_model_id(a);
-	uint32_t b_id = mesh_model_get_model_id(b);
-
-	if (a_id < b_id)
-		return -1;
-
-	if (a_id > b_id)
-		return 1;
-
-	return 0;
-}
-
 struct mesh_node *node_find_by_uuid(uint8_t uuid[16])
 {
 	return l_queue_find(nodes, match_device_uuid, uuid);
@@ -225,25 +203,6 @@ uint8_t *node_uuid_get(struct mesh_node *node)
 	return node->uuid;
 }
 
-static void add_internal_model(struct mesh_node *node, uint32_t mod_id,
-								uint8_t ele_idx)
-{
-	struct node_element *ele;
-	struct mesh_model *mod;
-
-	ele = l_queue_find(node->elements, match_element_idx,
-							L_UINT_TO_PTR(ele_idx));
-	if (!ele)
-		return;
-
-	if (l_queue_find(ele->models, match_model_id, L_UINT_TO_PTR(mod_id)))
-		return;
-
-	mod = mesh_model_new(ele_idx, mod_id);
-
-	l_queue_insert(ele->models, mod, compare_model_id, NULL);
-}
-
 static void set_defaults(struct mesh_node *node)
 {
 	node->lpn = MESH_MODE_UNSUPPORTED;
@@ -359,46 +318,6 @@ void node_remove(struct mesh_node *node)
 	free_node_resources(node);
 }
 
-static bool add_models_from_storage(struct mesh_node *node,
-					struct node_element *ele,
-					struct mesh_config_element *db_ele)
-{
-	const struct l_queue_entry *entry;
-
-	if (!ele->models)
-		ele->models = l_queue_new();
-
-	entry = l_queue_get_entries(db_ele->models);
-
-	for (; entry; entry = entry->next) {
-		struct mesh_model *mod;
-		struct mesh_config_model *db_mod;
-		uint32_t id;
-
-		db_mod = entry->data;
-
-		id = db_mod->vendor ? db_mod->id : db_mod->id | VENDOR_ID_MASK;
-
-		if (l_queue_find(ele->models, match_model_id,
-							L_UINT_TO_PTR(id)))
-			return false;
-
-		mod = mesh_model_setup(node, ele->idx, db_mod);
-		if (!mod)
-			return false;
-
-		if (!db_mod->pub_enabled)
-			mesh_model_enable_pub(mod, false);
-
-		if (!db_mod->sub_enabled)
-			mesh_model_enable_sub(node, mod, false);
-
-		l_queue_insert(ele->models, mod, compare_model_id, NULL);
-	}
-
-	return true;
-}
-
 static bool add_element_from_storage(struct mesh_node *node,
 					struct mesh_config_element *db_ele)
 {
@@ -411,7 +330,12 @@ static bool add_element_from_storage(struct mesh_node *node,
 	ele->idx = db_ele->index;
 	ele->location = db_ele->location;
 
-	if (!db_ele->models || !add_models_from_storage(node, ele, db_ele))
+
+	if (!ele->models)
+		ele->models = l_queue_new();
+
+	if (!mesh_model_add_from_storage(node, ele->idx, ele->models,
+							db_ele->models))
 		return false;
 
 	l_queue_push_tail(node->elements, ele);
@@ -424,12 +348,13 @@ static bool add_elements_from_storage(struct mesh_node *node,
 	const struct l_queue_entry *entry;
 
 	entry = l_queue_get_entries(db_node->elements);
+
 	for (; entry; entry = entry->next)
 		if (!add_element_from_storage(node, entry->data))
 			return false;
 
 	/* Add configuration server model on the primary element */
-	add_internal_model(node, CONFIG_SRV_MODEL, PRIMARY_ELE_IDX);
+	mesh_model_add(node, PRIMARY_ELE_IDX, CONFIG_SRV_MODEL, NULL);
 
 	return true;
 }
@@ -888,9 +813,8 @@ uint8_t node_friend_mode_get(struct mesh_node *node)
 static uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf,
 								uint16_t sz)
 {
-	uint16_t n, features;
-	uint16_t num_ele = 0;
-	const struct l_queue_entry *ele_entry;
+	uint16_t n, features, num_ele = 0;
+	const struct l_queue_entry *entry;
 
 	if (!node || sz < MIN_COMP_SIZE)
 		return 0;
@@ -920,12 +844,10 @@ static uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf,
 	l_put_le16(features, buf + n);
 	n += 2;
 
-	ele_entry = l_queue_get_entries(node->elements);
-	for (; ele_entry; ele_entry = ele_entry->next) {
-		struct node_element *ele = ele_entry->data;
-		const struct l_queue_entry *mod_entry;
-		uint8_t num_s = 0, num_v = 0;
-		uint8_t *mod_buf;
+	entry = l_queue_get_entries(node->elements);
+
+	for (; entry; entry = entry->next) {
+		struct node_element *ele = entry->data;
 
 		if (ele->idx != num_ele)
 			return 0;
@@ -939,59 +861,8 @@ static uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf,
 		l_put_le16(ele->location, buf + n);
 		n += 2;
 
-		/* Store models IDs, store num_s and num_v later */
-		mod_buf = buf + n;
-		n += 2;
-
-		/* Get SIG models */
-		mod_entry = l_queue_get_entries(ele->models);
-		for (; mod_entry; mod_entry = mod_entry->next) {
-			struct mesh_model *mod = mod_entry->data;
-			uint32_t mod_id;
-
-			mod_id = mesh_model_get_model_id(
-					(const struct mesh_model *) mod);
-
-			if ((mod_id & VENDOR_ID_MASK) == VENDOR_ID_MASK) {
-				if (n + 2 > sz)
-					goto element_done;
-
-				l_put_le16((uint16_t) (mod_id & 0xffff),
+		n += mesh_model_generate_composition(ele->models, sz - n,
 								buf + n);
-				n += 2;
-				num_s++;
-			}
-		}
-
-		/* Get vendor models */
-		mod_entry = l_queue_get_entries(ele->models);
-		for (; mod_entry; mod_entry = mod_entry->next) {
-			struct mesh_model *mod = mod_entry->data;
-			uint32_t mod_id;
-			uint16_t vendor;
-
-			mod_id = mesh_model_get_model_id(
-					(const struct mesh_model *) mod);
-
-			vendor = (uint16_t) (mod_id >> 16);
-			if (vendor != 0xffff) {
-				if (n + 4 > sz)
-					goto element_done;
-
-				l_put_le16(vendor, buf + n);
-				n += 2;
-				l_put_le16((uint16_t) (mod_id & 0xffff),
-								buf + n);
-				n += 2;
-				num_v++;
-			}
-
-		}
-
-element_done:
-		mod_buf[0] = num_s;
-		mod_buf[1] = num_v;
-
 	}
 
 	if (!num_ele)
@@ -1128,52 +999,6 @@ static void app_disc_cb(struct l_dbus *bus, void *user_data)
 	free_node_dbus_resources(node);
 }
 
-static bool get_model_options(struct mesh_node *node, struct mesh_model *mod,
-					struct l_dbus_message_iter *opts)
-{
-	const char *key;
-	struct l_dbus_message_iter var;
-	bool opt;
-
-	while (l_dbus_message_iter_next_entry(opts, &key, &var)) {
-
-		if (!strcmp(key, "Publish")) {
-			if (!l_dbus_message_iter_get_variant(&var, "b", &opt))
-				return false;
-			mesh_model_enable_pub(mod, opt);
-		} else if (!strcmp(key, "Subscribe")) {
-			if (!l_dbus_message_iter_get_variant(&var, "b", &opt))
-				return false;
-			mesh_model_enable_sub(node, mod, opt);
-		} else
-			return false;
-	}
-
-	return true;
-}
-
-static bool generate_model(struct mesh_node *node, struct node_element *ele,
-				uint32_t id, struct l_dbus_message_iter *opts)
-{
-	struct mesh_model *mod;
-
-	/* Disallow duplicates */
-	if (l_queue_find(ele->models, match_model_id,
-			 L_UINT_TO_PTR(id)))
-		return false;
-
-	mod = mesh_model_new(ele->idx, id);
-
-	if (!get_model_options(node, mod, opts)) {
-		l_free(mod);
-		return false;
-	}
-
-	l_queue_insert(ele->models, mod, compare_model_id, NULL);
-
-	return true;
-}
-
 static bool get_sig_models_from_properties(struct mesh_node *node,
 					struct node_element *ele,
 					struct l_dbus_message_iter *property)
@@ -1189,13 +1014,12 @@ static bool get_sig_models_from_properties(struct mesh_node *node,
 
 	/* Bluetooth SIG defined models */
 	while (l_dbus_message_iter_next_entry(&mods, &m_id, &var)) {
-		uint32_t id = m_id | VENDOR_ID_MASK;
 
 		/* Allow Config Server Model only on the primary element */
-		if (ele->idx != PRIMARY_ELE_IDX && id == CONFIG_SRV_MODEL)
+		if (ele->idx != PRIMARY_ELE_IDX && m_id == CONFIG_SRV_MODEL)
 			return false;
 
-		if (!generate_model(node, ele, id, &var))
+		if (!mesh_model_add(node, ele->idx, m_id, &var))
 			return false;
 	}
 
@@ -1217,9 +1041,7 @@ static bool get_vendor_models_from_properties(struct mesh_node *node,
 
 	/* Vendor defined models */
 	while (l_dbus_message_iter_next_entry(&mods, &v_id, &m_id, &var)) {
-		uint32_t id = m_id | (v_id << 16);
-
-		if (!generate_model(node, ele, id, &var))
+		if (!mesh_model_vendor_add(node, ele->idx, v_id, m_id, &var))
 			return false;
 	}
 
@@ -1295,7 +1117,7 @@ static bool get_element_properties(struct mesh_node *node, const char *path,
 	 * the operation below will be a "no-op".
 	 */
 	if (ele->idx == PRIMARY_ELE_IDX)
-		add_internal_model(node, CONFIG_SRV_MODEL, PRIMARY_ELE_IDX);
+		mesh_model_add(node, PRIMARY_ELE_IDX, CONFIG_SRV_MODEL, NULL);
 
 	return true;
 fail:
@@ -1332,7 +1154,6 @@ static void convert_node_to_storage(struct mesh_node *node,
 	for (; entry; entry = entry->next) {
 		struct node_element *ele = entry->data;
 		struct mesh_config_element *db_ele;
-		const struct l_queue_entry *mod_entry;
 
 		db_ele = l_new(struct mesh_config_element, 1);
 
@@ -1340,21 +1161,8 @@ static void convert_node_to_storage(struct mesh_node *node,
 		db_ele->location = ele->location;
 		db_ele->models = l_queue_new();
 
-		mod_entry = l_queue_get_entries(ele->models);
-
-		for (; mod_entry; mod_entry = mod_entry->next) {
-			struct mesh_model *mod = mod_entry->data;
-			struct mesh_config_model *db_mod;
-			uint32_t mod_id = mesh_model_get_model_id(mod);
+		mesh_model_convert_to_storage(db_ele->models, ele->models);
 
-			db_mod = l_new(struct mesh_config_model, 1);
-			db_mod->id = mod_id;
-			db_mod->vendor = ((mod_id & VENDOR_ID_MASK)
-							!= VENDOR_ID_MASK);
-			db_mod->pub_enabled = mesh_model_is_pub_enabled(mod);
-			db_mod->sub_enabled = mesh_model_is_sub_enabled(mod);
-			l_queue_push_tail(db_ele->models, db_mod);
-		}
 		l_queue_push_tail(db_node->elements, db_ele);
 	}
 
@@ -1375,6 +1183,7 @@ static bool create_node_config(struct mesh_node *node, const uint8_t uuid[16])
 
 	/* Free temporarily allocated resources */
 	entry = l_queue_get_entries(db_node.elements);
+
 	for (; entry; entry = entry->next) {
 		struct mesh_config_element *db_ele = entry->data;
 
@@ -1517,7 +1326,6 @@ static void update_model_options(struct mesh_node *node,
 	len = l_queue_length(node->elements);
 
 	for (i = 0; i < len; i++) {
-		const struct l_queue_entry *entry;
 
 		ele = l_queue_find(node->elements, match_element_idx,
 							L_UINT_TO_PTR(i));
@@ -1526,42 +1334,8 @@ static void update_model_options(struct mesh_node *node,
 		if (!ele || !ele_attach)
 			continue;
 
-		entry = l_queue_get_entries(ele->models);
-
-		for (; entry; entry = entry->next) {
-			struct mesh_model *mod, *updated_mod = entry->data;
-			uint32_t id = mesh_model_get_model_id(updated_mod);
-			bool opt, updated_opt;
-			bool vendor = id < VENDOR_ID_MASK;
-
-			mod = l_queue_find(ele_attach->models, match_model_id,
-							L_UINT_TO_PTR(id));
-			if (!mod)
-				continue;
-
-			if (!vendor)
-				id &= ~VENDOR_ID_MASK;
-
-			opt = mesh_model_is_pub_enabled(mod);
-			updated_opt = mesh_model_is_pub_enabled(updated_mod);
-
-			if (updated_opt != opt) {
-				mesh_model_enable_pub(mod, updated_opt);
-				mesh_config_model_pub_enable(attach->cfg,
-							attach->primary + i, id,
-							vendor, updated_opt);
-			}
-
-			opt = mesh_model_is_sub_enabled(mod);
-			updated_opt = mesh_model_is_sub_enabled(updated_mod);
-
-			if (updated_opt != opt) {
-				mesh_model_enable_sub(node, mod, updated_opt);
-				mesh_config_model_sub_enable(attach->cfg,
-							attach->primary + i, id,
-							vendor, updated_opt);
-			}
-		}
+		mesh_model_update_opts(node, ele->idx, ele_attach->models,
+								ele->models);
 	}
 }
 
@@ -1964,7 +1738,7 @@ static void build_element_config(void *a, void *b)
 	l_dbus_message_builder_enter_array(builder, "(qa{sv})");
 
 	/* Iterate over models */
-	l_queue_foreach(ele->models, model_build_config, builder);
+	l_queue_foreach(ele->models, mesh_model_build_config, builder);
 
 	l_dbus_message_builder_leave_array(builder);
 
@@ -2243,7 +2017,7 @@ static struct l_dbus_message *publish_call(struct l_dbus *dbus,
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 							"Incorrect data");
 
-	result = mesh_model_publish(node, VENDOR_ID_MASK | mod_id, src,
+	result = mesh_model_publish(node, mod_id, src,
 				mesh_net_get_default_ttl(node->net), data, len);
 
 	if (result != MESH_ERROR_NONE)
@@ -2260,8 +2034,7 @@ static struct l_dbus_message *vendor_publish_call(struct l_dbus *dbus,
 	const char *sender, *ele_path;
 	struct l_dbus_message_iter iter_data;
 	uint16_t src;
-	uint16_t model_id, vendor;
-	uint32_t vendor_mod_id;
+	uint16_t mod_id, vendor_id;
 	struct node_element *ele;
 	uint8_t *data = NULL;
 	uint32_t len;
@@ -2274,8 +2047,8 @@ static struct l_dbus_message *vendor_publish_call(struct l_dbus *dbus,
 	if (strcmp(sender, node->owner))
 		return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
 
-	if (!l_dbus_message_get_arguments(msg, "oqqay", &ele_path, &vendor,
-							&model_id, &iter_data))
+	if (!l_dbus_message_get_arguments(msg, "oqqay", &ele_path, &vendor_id,
+							&mod_id, &iter_data))
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
 
 	ele = l_queue_find(node->elements, match_element_path, ele_path);
@@ -2290,8 +2063,7 @@ static struct l_dbus_message *vendor_publish_call(struct l_dbus *dbus,
 		return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
 							"Incorrect data");
 
-	vendor_mod_id = (vendor << 16) | model_id;
-	result = mesh_model_publish(node, vendor_mod_id, src,
+	result = mesh_model_vendor_publish(node, vendor_id, mod_id, src,
 				mesh_net_get_default_ttl(node->net), data, len);
 
 	if (result != MESH_ERROR_NONE)
-- 
2.26.2


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

* Re: [PATCH BlueZ 0/3] Code re-org and clean up
  2020-07-13 23:05 [PATCH BlueZ 0/3] Code re-org and clean up Inga Stotland
                   ` (2 preceding siblings ...)
  2020-07-13 23:05 ` [PATCH BlueZ 3/3] mesh: move model functionality out of node.c to model.c Inga Stotland
@ 2020-07-16 17:20 ` Gix, Brian
  3 siblings, 0 replies; 5+ messages in thread
From: Gix, Brian @ 2020-07-16 17:20 UTC (permalink / raw)
  To: linux-bluetooth, Stotland, Inga

Applied first two of patchset.

Holding off on the 3rd until I can more test more completely.

On Mon, 2020-07-13 at 16:05 -0700, Inga Stotland wrote:
> This patch set is part of the on-going  clean up effort that targets some
> of more convoluted areas of meshd source code.
> The patchset provides better functional separation, smaller function
> granularity and better memory handling.
> 
> Inga Stotland (3):
>   mesh: Use static array to hold config server response
>   mesh: Add size checks for every opcode in config server
>   mesh: move model functionality out of node.c to model.c
> 
>  mesh/cfgmod-server.c    |  99 ++++++-----
>  mesh/cfgmod.h           |   4 +-
>  mesh/mesh-config-json.c |   5 +-
>  mesh/model.c            | 359 +++++++++++++++++++++++++++++++++-------
>  mesh/model.h            |  32 ++--
>  mesh/node.c             | 286 ++++----------------------------
>  6 files changed, 403 insertions(+), 382 deletions(-)
> 

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

end of thread, back to index

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-13 23:05 [PATCH BlueZ 0/3] Code re-org and clean up Inga Stotland
2020-07-13 23:05 ` [PATCH BlueZ 1/3] mesh: Use static array to hold config server response Inga Stotland
2020-07-13 23:05 ` [PATCH BlueZ 2/3] mesh: Add size checks for every opcode in config server Inga Stotland
2020-07-13 23:05 ` [PATCH BlueZ 3/3] mesh: move model functionality out of node.c to model.c Inga Stotland
2020-07-16 17:20 ` [PATCH BlueZ 0/3] Code re-org and clean up Gix, Brian

Linux-Bluetooth Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-bluetooth/0 linux-bluetooth/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-bluetooth linux-bluetooth/ https://lore.kernel.org/linux-bluetooth \
		linux-bluetooth@vger.kernel.org
	public-inbox-index linux-bluetooth

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-bluetooth


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git