Linux-Bluetooth Archive on lore.kernel.org
 help / color / Atom feed
From: Inga Stotland <inga.stotland@intel.com>
To: linux-bluetooth@vger.kernel.org
Cc: brian.gix@intel.com, michal.lowas-rzechonek@silvair.com,
	jakub.witowski@silvair.com,
	Inga Stotland <inga.stotland@intel.com>
Subject: [PATCH BlueZ 05/10 v2] mesh: Confine dependency on json-c to mesh-config-json.c
Date: Sat, 13 Jul 2019 23:28:07 -0700
Message-ID: <20190714062812.31041-6-inga.stotland@intel.com> (raw)
In-Reply-To: <20190714062812.31041-1-inga.stotland@intel.com>

This removes dependency on json-s/json.h header from everywhere
in the code except for mesh-config-json.c. The details about
node configuration storage format are obfuscated: a pointer
to an opaque mesh_config structure is stored with mesh_node and is
passed around to mae all the storage related operations.
---
 mesh/cfgmod-server.c    |  17 +-
 mesh/mesh-config-json.c | 558 +++++++++++++++++++++++++++-------------
 mesh/mesh-config.h      |  77 +++---
 mesh/model.c            |   1 -
 mesh/node.c             |  37 ++-
 mesh/node.h             |   9 +-
 mesh/storage.c          | 205 +++++----------
 mesh/storage.h          |   4 +-
 8 files changed, 524 insertions(+), 384 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 0479a9185..c73e63b4e 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -24,8 +24,6 @@
 #include <sys/time.h>
 #include <ell/ell.h>
 
-#include "json-c/json.h"
-
 #include "mesh/mesh-defs.h"
 #include "mesh/node.h"
 #include "mesh/net.h"
@@ -197,7 +195,7 @@ static bool config_pub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
 
 		/* Remove model publication from config file */
 		if (status == MESH_STATUS_SUCCESS)
-			mesh_config_model_pub_del(node_jconfig_get(node),
+			mesh_config_model_pub_del(node_config_get(node),
 				ele_addr, vendor ? mod_id : mod_id & 0x0000ffff,
 									vendor);
 		goto done;
@@ -219,7 +217,7 @@ static bool config_pub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
 			memcpy(db_pub.virt_addr, pub_addr, 16);
 
 		/* Save model publication to config file */
-		if (!mesh_config_model_pub_add(node_jconfig_get(node), ele_addr,
+		if (!mesh_config_model_pub_add(node_config_get(node), ele_addr,
 					vendor ? mod_id : mod_id & 0x0000ffff,
 					vendor, &db_pub))
 			status = MESH_STATUS_STORAGE_FAIL;
@@ -331,18 +329,18 @@ static bool save_config_sub(struct mesh_node *node, uint16_t ele_addr,
 
 	if (opcode == OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE ||
 					opcode == OP_CONFIG_MODEL_SUB_OVERWRITE)
-		mesh_config_model_sub_del_all(node_jconfig_get(node),
+		mesh_config_model_sub_del_all(node_config_get(node),
 				ele_addr, vendor ? mod_id : mod_id & 0x0000ffff,
 									vendor);
 
 	if (opcode != OP_CONFIG_MODEL_SUB_VIRT_DELETE &&
 			opcode != OP_CONFIG_MODEL_SUB_DELETE)
-		return mesh_config_model_sub_add(node_jconfig_get(node),
+		return mesh_config_model_sub_add(node_config_get(node),
 					ele_addr,
 					vendor ? mod_id : mod_id & 0x0000ffff,
 					vendor, &db_sub);
 	else
-		return mesh_config_model_sub_del(node_jconfig_get(node),
+		return mesh_config_model_sub_del(node_config_get(node),
 					ele_addr,
 					vendor ? mod_id : mod_id & 0x0000ffff,
 					vendor, &db_sub);
@@ -419,7 +417,7 @@ static void config_sub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
 		status = mesh_model_sub_del_all(node, ele_addr, mod_id);
 
 		if (status == MESH_STATUS_SUCCESS)
-			mesh_config_model_sub_del_all(node_jconfig_get(node),
+			mesh_config_model_sub_del_all(node_config_get(node),
 				ele_addr, vendor ? mod_id : mod_id & 0x0000ffff,
 									vendor);
 		break;
@@ -878,8 +876,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
 
 		count = (pkt[0] >> 5) + 1;
 		interval = ((pkt[0] & 0x1f) + 1) * 10;
-		if (storage_set_transmit_params(node_jconfig_get(node), count,
-								interval))
+		if (storage_set_transmit_params(node, count, interval))
 			mesh_net_transmit_params_set(net, count, interval);
 		/* Fall Through */
 
diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c
index a0c3e27c0..096b93249 100644
--- a/mesh/mesh-config-json.c
+++ b/mesh/mesh-config-json.c
@@ -22,9 +22,14 @@
 #endif
 
 #define _GNU_SOURCE
+//#include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <ell/ell.h>
 #include <json-c/json.h>
@@ -35,6 +40,12 @@
 
 #define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
 
+struct mesh_config {
+	json_object *jnode;
+	char *node_path;
+	uint8_t uuid[16];
+};
+
 static bool get_int(json_object *jobj, const char *keyword, int *value)
 {
 	json_object *jvalue;
@@ -446,13 +457,18 @@ fail:
 	return false;
 }
 
-bool mesh_config_net_key_add(json_object *jobj, uint16_t idx,
+bool mesh_config_net_key_add(struct mesh_config *cfg, uint16_t idx,
 							const uint8_t key[16])
 {
-	json_object *jarray = NULL, *jentry = NULL, *jstring;
+	json_object *jnode, *jarray = NULL, *jentry = NULL, *jstring;
 	char buf[5];
 
-	json_object_object_get_ex(jobj, "netKeys", &jarray);
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
+	json_object_object_get_ex(jnode, "netKeys", &jarray);
 	if (jarray)
 		jentry = get_key_object(jarray, idx);
 
@@ -481,7 +497,7 @@ bool mesh_config_net_key_add(json_object *jobj, uint16_t idx,
 		jarray = json_object_new_array();
 		if (!jarray)
 			goto fail;
-		json_object_object_add(jobj, "netKeys", jarray);
+		json_object_object_add(jnode, "netKeys", jarray);
 	}
 
 	json_object_array_add(jarray, jentry);
@@ -494,13 +510,18 @@ fail:
 	return false;
 }
 
-bool mesh_config_net_key_update(json_object *jobj, uint16_t idx,
+bool mesh_config_net_key_update(struct mesh_config *cfg, uint16_t idx,
 							const uint8_t key[16])
 {
-	json_object *jarray, *jentry, *jstring;
+	json_object *jnode, *jarray, *jentry, *jstring;
 	const char *str;
 
-	if (!json_object_object_get_ex(jobj, "netKeys", &jarray))
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
+	if (!json_object_object_get_ex(jnode, "netKeys", &jarray))
 		return false;
 
 	jentry = get_key_object(jarray, idx);
@@ -525,11 +546,16 @@ bool mesh_config_net_key_update(json_object *jobj, uint16_t idx,
 	return true;
 }
 
-bool mesh_config_net_key_del(json_object *jobj, uint16_t idx)
+bool mesh_config_net_key_del(struct mesh_config *cfg, uint16_t idx)
 {
-	json_object *jarray, *jarray_new;
+	json_object *jnode, *jarray, *jarray_new;
 
-	if (!json_object_object_get_ex(jobj, "netKeys", &jarray))
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
+	if (!json_object_object_get_ex(jnode, "netKeys", &jarray))
 		return true;
 
 	/* Check if matching entry exists */
@@ -537,7 +563,7 @@ bool mesh_config_net_key_del(json_object *jobj, uint16_t idx)
 		return true;
 
 	if (json_object_array_length(jarray) == 1) {
-		json_object_object_del(jobj, "netKeys");
+		json_object_object_del(jnode, "netKeys");
 		return true;
 	}
 
@@ -550,29 +576,40 @@ bool mesh_config_net_key_del(json_object *jobj, uint16_t idx)
 	if (!jarray_new)
 		return false;
 
-	json_object_object_del(jobj, "netKeys");
-	json_object_object_add(jobj, "netKeys", jarray_new);
+	json_object_object_del(jnode, "netKeys");
+	json_object_object_add(jnode, "netKeys", jarray_new);
 
 	return true;
 }
 
-bool mesh_config_write_device_key(json_object *jnode, uint8_t *key)
+bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t *key)
 {
-	return add_key_value(jnode, "deviceKey", key);
+	if (!cfg)
+		return false;
+
+	return add_key_value(cfg->jnode, "deviceKey", key);
 }
 
-bool mesh_config_write_token(json_object *jnode, uint8_t *token)
+bool mesh_config_write_token(struct mesh_config *cfg, uint8_t *token)
 {
-	return add_u64_value(jnode, "token", token);
+	if (!cfg)
+		return false;
+
+	return add_u64_value(cfg->jnode, "token", token);
 }
 
-bool mesh_config_app_key_add(json_object *jobj, uint16_t net_idx,
+bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx,
 					uint16_t app_idx, const uint8_t key[16])
 {
-	json_object *jarray = NULL, *jentry = NULL, *jstring = NULL;
+	json_object *jnode, *jarray = NULL, *jentry = NULL, *jstring = NULL;
 	char buf[5];
 
-	json_object_object_get_ex(jobj, "appKeys", &jarray);
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
+	json_object_object_get_ex(jnode, "appKeys", &jarray);
 	if (jarray)
 		jentry = get_key_object(jarray, app_idx);
 
@@ -605,7 +642,7 @@ bool mesh_config_app_key_add(json_object *jobj, uint16_t net_idx,
 		jarray = json_object_new_array();
 		if (!jarray)
 			goto fail;
-		json_object_object_add(jobj, "appKeys", jarray);
+		json_object_object_add(jnode, "appKeys", jarray);
 	}
 
 	json_object_array_add(jarray, jentry);
@@ -619,13 +656,18 @@ fail:
 	return false;
 }
 
-bool mesh_config_app_key_update(json_object *jobj, uint16_t app_idx,
+bool mesh_config_app_key_update(struct mesh_config *cfg, uint16_t app_idx,
 							const uint8_t key[16])
 {
-	json_object *jarray, *jentry = NULL, *jstring = NULL;
+	json_object *jnode, *jarray, *jentry = NULL, *jstring = NULL;
 	const char *str;
 
-	if (!json_object_object_get_ex(jobj, "appKeys", &jarray))
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
+	if (!json_object_object_get_ex(jnode, "appKeys", &jarray))
 		return false;
 
 	/* The key entry should exist if the key is updated */
@@ -644,11 +686,17 @@ bool mesh_config_app_key_update(json_object *jobj, uint16_t app_idx,
 	return add_key_value(jentry, "key", key);
 }
 
-bool mesh_config_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx)
+bool mesh_config_app_key_del(struct mesh_config *cfg, uint16_t net_idx,
+								uint16_t idx)
 {
-	json_object *jarray, *jarray_new;
+	json_object *jnode, *jarray, *jarray_new;
 
-	if (!json_object_object_get_ex(jobj, "appKeys", &jarray))
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
+	if (!json_object_object_get_ex(jnode, "appKeys", &jarray))
 		return true;
 
 	/* Check if matching entry exists */
@@ -656,7 +704,7 @@ bool mesh_config_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx)
 		return true;
 
 	if (json_object_array_length(jarray) == 1) {
-		json_object_object_del(jobj, "appKeys");
+		json_object_object_del(jnode, "appKeys");
 		return true;
 	}
 
@@ -669,19 +717,24 @@ bool mesh_config_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx)
 	if (!jarray_new)
 		return false;
 
-	json_object_object_del(jobj, "appKeys");
-	json_object_object_add(jobj, "appKeys", jarray_new);
+	json_object_object_del(jnode, "appKeys");
+	json_object_object_add(jnode, "appKeys", jarray_new);
 
 	return true;
 }
 
-bool mesh_config_model_binding_add(json_object *jnode, uint8_t ele_idx,
+bool mesh_config_model_binding_add(struct mesh_config *cfg, uint8_t ele_idx,
 					bool vendor, uint32_t mod_id,
 							uint16_t app_idx)
 {
-	json_object *jmodel, *jstring, *jarray = NULL;
+	json_object *jnode, *jmodel, *jstring, *jarray = NULL;
 	char buf[5];
 
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
 	jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
 	if (!jmodel)
 		return false;
@@ -710,13 +763,18 @@ bool mesh_config_model_binding_add(json_object *jnode, uint8_t ele_idx,
 	return true;
 }
 
-bool mesh_config_model_binding_del(json_object *jnode, uint8_t ele_idx,
+bool mesh_config_model_binding_del(struct mesh_config *cfg, uint8_t ele_idx,
 					bool vendor, uint32_t mod_id,
 							uint16_t app_idx)
 {
-	json_object *jmodel, *jarray, *jarray_new;
+	json_object *jnode, *jmodel, *jarray, *jarray_new;
 	char buf[5];
 
+	if (!cfg)
+		return false;
+
+	jnode = cfg->jnode;
+
 	jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
 	if (!jmodel)
 		return false;
@@ -1189,45 +1247,32 @@ static bool read_net_transmit(json_object *jobj, struct mesh_config_node *node)
 	return true;
 }
 
-bool mesh_config_read_node(json_object *jnode, mesh_config_node_cb cb,
-							void *user_data)
+static bool read_node(json_object *jnode, struct mesh_config_node *node)
 {
-	struct mesh_config_node node;
 	json_object *jvalue;
 	char *str;
-	bool result = false;
-
-	if (!jnode)
-		return false;
-
-	if (!cb) {
-		l_info("Node read callback is required");
-		return false;
-	}
 
-	memset(&node, 0, sizeof(node));
-
-	if (!read_iv_index(jnode, &node.iv_index, &node.iv_update)) {
+	if (!read_iv_index(jnode, &node->iv_index, &node->iv_update)) {
 		l_info("Failed to read IV index");
 		return false;
 	}
 
-	if (!read_token(jnode, node.token)) {
+	if (!read_token(jnode, node->token)) {
 		l_info("Failed to read node token");
 		return false;
 	}
 
-	if (!read_device_key(jnode, node.dev_key)) {
+	if (!read_device_key(jnode, node->dev_key)) {
 		l_info("Failed to read node device key");
 		return false;
 	}
 
-	if (!parse_composition(jnode, &node)) {
+	if (!parse_composition(jnode, node)) {
 		l_info("Failed to parse local node composition");
 		return false;
 	}
 
-	parse_features(jnode, &node);
+	parse_features(jnode, node);
 
 	if (!json_object_object_get_ex(jnode, "unicastAddress", &jvalue)) {
 		l_info("Bad config: Unicast address must be present");
@@ -1235,7 +1280,7 @@ bool mesh_config_read_node(json_object *jnode, mesh_config_node_cb cb,
 	}
 
 	str = (char *)json_object_get_string(jvalue);
-	if (sscanf(str, "%04hx", &node.unicast) != 1)
+	if (sscanf(str, "%04hx", &node->unicast) != 1)
 		return false;
 
 	if (json_object_object_get_ex(jnode, "defaultTTL", &jvalue)) {
@@ -1243,55 +1288,45 @@ bool mesh_config_read_node(json_object *jnode, mesh_config_node_cb cb,
 
 		if (ttl < 0 || ttl == 1 || ttl > DEFAULT_TTL)
 			return false;
-		node.ttl = (uint8_t) ttl;
+		node->ttl = (uint8_t) ttl;
 	}
 
 	if (json_object_object_get_ex(jnode, "sequenceNumber", &jvalue))
-		node.seq_number = json_object_get_int(jvalue);
+		node->seq_number = json_object_get_int(jvalue);
 
 	/* Check for required "elements" property */
 	if (!json_object_object_get_ex(jnode, "elements", &jvalue))
 		return false;
 
-	if (!read_net_transmit(jnode, &node)) {
+	if (!read_net_transmit(jnode, node)) {
 		l_info("Failed to read node net transmit parameters");
 		return false;
 	}
 
-	if (!read_net_keys(jnode, &node)) {
+	if (!read_net_keys(jnode, node)) {
 		l_info("Failed to read net keys");
-		goto done;
+		return false;
 	}
 
-	if (!read_app_keys(jnode, &node)) {
+	if (!read_app_keys(jnode, node)) {
 		l_info("Failed to read app keys");
-		goto done;
+		return false;
 	}
 
-	if (!parse_elements(jvalue, &node)) {
+	if (!parse_elements(jvalue, node)) {
 		l_info("Failed to parse elements");
-		goto done;
+		return false;
 	}
 
-	result = cb(&node, user_data);
-
-done:
-	l_free(node.net_transmit);
-	l_queue_destroy(node.netkeys, l_free);
-	l_queue_destroy(node.netkeys, l_free);
-
-	return result;
+	return true;
 }
 
-bool mesh_config_write_uint16_hex(json_object *jobj, const char *desc,
+static bool write_uint16_hex(json_object *jobj, const char *desc,
 								uint16_t value)
 {
 	json_object *jstring;
 	char buf[5];
 
-	if (!jobj)
-		return false;
-
 	snprintf(buf, 5, "%4.4x", value);
 	jstring = json_object_new_string(buf);
 	if (!jstring)
@@ -1301,15 +1336,21 @@ bool mesh_config_write_uint16_hex(json_object *jobj, const char *desc,
 	return true;
 }
 
-bool mesh_config_write_uint32_hex(json_object *jobj, const char *desc,
+bool mesh_config_write_uint16_hex(struct mesh_config *cfg, const char *desc,
+								uint16_t value)
+{
+	if (!cfg)
+		return false;
+
+	return write_uint16_hex(cfg->jnode, desc, value);
+}
+
+static bool write_uint32_hex(json_object *jobj, const char *desc,
 								uint32_t value)
 {
 	json_object *jstring;
 	char buf[9];
 
-	if (!jobj)
-		return false;
-
 	snprintf(buf, 9, "%8.8x", value);
 	jstring = json_object_new_string(buf);
 	if (!jstring)
@@ -1319,13 +1360,19 @@ bool mesh_config_write_uint32_hex(json_object *jobj, const char *desc,
 	return true;
 }
 
-bool mesh_config_write_int(json_object *jobj, const char *keyword, int value)
+bool mesh_config_write_uint32_hex(struct mesh_config *cfg, const char *desc,
+								uint32_t value)
 {
-	json_object *jvalue;
-
-	if (!jobj)
+	if (!cfg)
 		return false;
 
+	return write_uint32_hex(cfg->jnode, desc, value);
+}
+
+static bool write_int(json_object *jobj, const char *keyword, int value)
+{
+	json_object *jvalue;
+
 	json_object_object_del(jobj, keyword);
 
 	jvalue = json_object_new_int(value);
@@ -1336,20 +1383,32 @@ bool mesh_config_write_int(json_object *jobj, const char *keyword, int value)
 	return true;
 }
 
-bool mesh_config_write_bool(json_object *jobj, const char *keyword, bool value)
+bool mesh_config_write_int(struct mesh_config *cfg, const char *keyword,
+								int value)
 {
-	json_object *jvalue;
+	if (!cfg)
+		return false;
+
+	return write_int(cfg->jnode, keyword, value);
+}
 
-	if (!jobj)
+bool mesh_config_write_bool(struct mesh_config *cfg, const char *keyword,
+								bool value)
+{
+	json_object *jnode, *jvalue;
+
+	if (!cfg)
 		return false;
 
-	json_object_object_del(jobj, keyword);
+	jnode = cfg->jnode;
+
+	json_object_object_del(jnode, keyword);
 
 	jvalue = json_object_new_boolean(value);
 	if (!jvalue)
 		return false;
 
-	json_object_object_add(jobj, keyword, jvalue);
+	json_object_object_add(jnode, keyword, jvalue);
 	return true;
 }
 
@@ -1365,13 +1424,10 @@ static const char *mode_to_string(int mode)
 	}
 }
 
-bool mesh_config_write_mode(json_object *jobj, const char *keyword, int value)
+static bool write_mode(json_object *jobj, const char *keyword, int value)
 {
 	json_object *jstring;
 
-	if (!jobj)
-		return false;
-
 	jstring = json_object_new_string(mode_to_string(value));
 
 	if (!jstring)
@@ -1382,30 +1438,36 @@ bool mesh_config_write_mode(json_object *jobj, const char *keyword, int value)
 	return true;
 }
 
-bool mesh_config_write_relay_mode(json_object *jnode, uint8_t mode,
+bool mesh_config_write_mode(struct mesh_config *cfg, const char *keyword,
+								int value)
+{
+	if (!cfg)
+		return false;
+
+	return write_mode(cfg->jnode, keyword, value);
+}
+
+static bool write_relay_mode(json_object *jobj, uint8_t mode,
 					uint8_t count, uint16_t interval)
 {
 	json_object *jrelay;
 
-	if (!jnode)
-		return false;
-
-	json_object_object_del(jnode, "relay");
+	json_object_object_del(jobj, "relay");
 
 	jrelay = json_object_new_object();
 	if (!jrelay)
 		return false;
 
-	if (!mesh_config_write_mode(jrelay, "mode", mode))
+	if (!write_mode(jrelay, "mode", mode))
 		goto fail;
 
-	if (!mesh_config_write_int(jrelay, "count", count))
+	if (!write_int(jrelay, "count", count))
 		goto fail;
 
-	if (!mesh_config_write_int(jrelay, "interval", interval))
+	if (!write_int(jrelay, "interval", interval))
 		goto fail;
 
-	json_object_object_add(jnode, "relay", jrelay);
+	json_object_object_add(jobj, "relay", jrelay);
 
 	return true;
 fail:
@@ -1413,27 +1475,38 @@ fail:
 	return false;
 }
 
-bool mesh_config_write_net_transmit(json_object *jobj, uint8_t cnt,
+bool mesh_config_write_relay_mode(struct mesh_config *cfg, uint8_t mode,
+					uint8_t count, uint16_t interval)
+{
+
+	if (!cfg)
+		return false;
+
+	return write_relay_mode(cfg->jnode, mode, count, interval);
+}
+
+bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt,
 							uint16_t interval)
 {
-	json_object *jretransmit;
+	json_object *jnode, *jretransmit;
 
-	if (!jobj)
+	if (!cfg)
 		return false;
+	jnode = cfg->jnode;
 
-	json_object_object_del(jobj, "retransmit");
+	json_object_object_del(jnode, "retransmit");
 
 	jretransmit = json_object_new_object();
 	if (jretransmit)
 		return false;
 
-	if (!mesh_config_write_int(jretransmit, "count", cnt))
+	if (!write_int(jretransmit, "count", cnt))
 		goto fail;
 
-	if (!mesh_config_write_int(jretransmit, "interval", interval))
+	if (!write_int(jretransmit, "interval", interval))
 		goto fail;
 
-	json_object_object_add(jobj, "retransmit", jretransmit);
+	json_object_object_add(jnode, "retransmit", jretransmit);
 
 	return true;
 fail:
@@ -1442,28 +1515,26 @@ fail:
 
 }
 
-bool mesh_config_write_iv_index(json_object *jobj, uint32_t idx, bool update)
+bool mesh_config_write_iv_index(struct mesh_config *cfg, uint32_t idx,
+								bool update)
 {
+	json_object *jnode;
 	int tmp = update ? 1 : 0;
 
-	if (!jobj)
+	if (!cfg)
 		return false;
 
-	if (!mesh_config_write_int(jobj, "IVindex", idx))
+	jnode = cfg->jnode;
+
+	if (!write_int(jnode, "IVindex", idx))
 		return false;
 
-	if (!mesh_config_write_int(jobj, "IVupdate", tmp))
+	if (!write_int(jnode, "IVupdate", tmp))
 		return false;
 
 	return true;
 }
 
-void mesh_config_remove_property(json_object *jobj, const char *desc)
-{
-	if (jobj)
-		json_object_object_del(jobj, desc);
-}
-
 static void add_model(void *a, void *b)
 {
 	struct mesh_config_model *mod = a;
@@ -1474,55 +1545,59 @@ static void add_model(void *a, void *b)
 		return;
 
 	if (!mod->vendor)
-		mesh_config_write_uint16_hex(jmodel, "modelId",
+		write_uint16_hex(jmodel, "modelId",
 						(uint16_t) mod->id);
 	else
-		mesh_config_write_uint32_hex(jmodel, "modelId", mod->id);
+		write_uint32_hex(jmodel, "modelId", mod->id);
 
 	json_object_array_add(jmodels, jmodel);
 }
 
 /* Add unprovisioned node (local) */
-bool mesh_config_add_node(json_object *jnode, struct mesh_config_node *node)
+struct mesh_config *mesh_config_create(const char *cfg_path,
+						const uint8_t uuid[16],
+						struct mesh_config_node *node)
 {
 	struct mesh_config_modes *modes = &node->modes;
 	const struct l_queue_entry *entry;
-	json_object *jelems;
+	json_object *jnode, *jelems;
+	struct mesh_config *cfg;
 
-	if (!jnode)
-		return false;
+	if (!cfg_path || !node)
+		return NULL;
+
+	jnode = json_object_new_object();
 
 	/* CID, PID, VID, crpl */
-	if (!mesh_config_write_uint16_hex(jnode, "cid", node->cid))
-		return false;
+	if (!write_uint16_hex(jnode, "cid", node->cid))
+		return NULL;
 
-	if (!mesh_config_write_uint16_hex(jnode, "pid", node->pid))
-		return false;
+	if (!write_uint16_hex(jnode, "pid", node->pid))
+		return NULL;
 
-	if (!mesh_config_write_uint16_hex(jnode, "vid", node->vid))
-		return false;
+	if (!write_uint16_hex(jnode, "vid", node->vid))
+		return NULL;
 
-	if (!mesh_config_write_uint16_hex(jnode, "crpl", node->crpl))
-		return false;
+	if (!write_uint16_hex(jnode, "crpl", node->crpl))
+		return NULL;
 
 	/* Features: relay, LPN, friend, proxy*/
-	if (!mesh_config_write_relay_mode(jnode, modes->relay.state,
-						modes->relay.cnt,
-						modes->relay.interval))
-		return false;
+	if (!write_relay_mode(jnode, modes->relay.state,
+				modes->relay.cnt, modes->relay.interval))
+		return NULL;
 
-	if (!mesh_config_write_mode(jnode, "lowPower", modes->lpn))
-		return false;
+	if (!write_mode(jnode, "lowPower", modes->lpn))
+		return NULL;
 
-	if (!mesh_config_write_mode(jnode, "friend", modes->friend))
-		return false;
+	if (!write_mode(jnode, "friend", modes->friend))
+		return NULL;
 
-	if (!mesh_config_write_mode(jnode, "proxy", modes->proxy))
-		return false;
+	if (!write_mode(jnode, "proxy", modes->proxy))
+		return NULL;
 
 	/* Beaconing state */
-	if (!mesh_config_write_mode(jnode, "beacon", modes->beacon))
-		return false;
+	if (!write_mode(jnode, "beacon", modes->beacon))
+		return NULL;
 
 	/* Sequence number */
 	json_object_object_add(jnode, "sequenceNumber",
@@ -1535,7 +1610,7 @@ bool mesh_config_add_node(json_object *jnode, struct mesh_config_node *node)
 	/* Elements */
 	jelems = json_object_new_array();
 	if (!jelems)
-		return false;
+		return NULL;
 
 	entry = l_queue_get_entries(node->elements);
 
@@ -1547,12 +1622,11 @@ bool mesh_config_add_node(json_object *jnode, struct mesh_config_node *node)
 
 		if (!jelement) {
 			json_object_put(jelems);
-			return false;
+			return NULL;
 		}
 
-		mesh_config_write_int(jelement, "elementIndex", ele->index);
-		mesh_config_write_uint16_hex(jelement, "location",
-								ele->location);
+		write_int(jelement, "elementIndex", ele->index);
+		write_uint16_hex(jelement, "location", ele->location);
 		json_object_array_add(jelems, jelement);
 
 		/* Models */
@@ -1562,7 +1636,7 @@ bool mesh_config_add_node(json_object *jnode, struct mesh_config_node *node)
 		jmodels = json_object_new_array();
 		if (!jmodels) {
 			json_object_put(jelems);
-			return false;
+			return NULL;
 		}
 
 		json_object_object_add(jelement, "models", jmodels);
@@ -1571,7 +1645,13 @@ bool mesh_config_add_node(json_object *jnode, struct mesh_config_node *node)
 
 	json_object_object_add(jnode, "elements", jelems);
 
-	return true;
+	cfg = l_new(struct mesh_config, 1);
+
+	cfg->jnode = jnode;
+	memcpy(cfg->uuid, uuid, 16);
+	cfg->node_path = l_strdup(cfg_path);
+
+	return cfg;
 }
 
 static void finish_key_refresh(json_object *jobj, uint16_t net_idx)
@@ -1605,15 +1685,17 @@ static void finish_key_refresh(json_object *jobj, uint16_t net_idx)
 
 }
 
-bool mesh_config_net_key_set_phase(json_object *jobj, uint16_t idx,
+bool mesh_config_net_key_set_phase(struct mesh_config *cfg, uint16_t idx,
 								uint8_t phase)
 {
-	json_object *jarray, *jentry = NULL;
+	json_object *jnode, *jarray, *jentry = NULL;
 
-	if (!jobj)
+	if (!cfg)
 		return false;
 
-	if (json_object_object_get_ex(jobj, "netKeys", &jarray))
+	jnode = cfg->jnode;
+
+	if (json_object_object_get_ex(jnode, "netKeys", &jarray))
 		jentry = get_key_object(jarray, idx);
 
 	if (!jentry)
@@ -1625,23 +1707,25 @@ bool mesh_config_net_key_set_phase(json_object *jobj, uint16_t idx,
 
 	if (phase == KEY_REFRESH_PHASE_NONE) {
 		json_object_object_del(jentry, "oldKey");
-		finish_key_refresh(jobj, idx);
+		finish_key_refresh(jnode, idx);
 	}
 
 	return true;
 }
 
-bool mesh_config_model_pub_add(json_object *jnode, uint16_t addr,
+bool mesh_config_model_pub_add(struct mesh_config *cfg, uint16_t addr,
 					uint32_t mod_id, bool vendor,
 					struct mesh_config_pub *pub)
 {
-	json_object *jmodel, *jpub, *jretransmit;
+	json_object *jnode, *jmodel, *jpub, *jretransmit;
 	bool res;
 	int ele_idx;
 
-	if (!jnode)
+	if (!cfg)
 		return false;
 
+	jnode = cfg->jnode;
+
 	ele_idx = get_element_index(jnode, addr);
 	if (ele_idx < 0)
 		return false;
@@ -1659,21 +1743,21 @@ bool mesh_config_model_pub_add(json_object *jnode, uint16_t addr,
 	if (pub->virt)
 		res = add_key_value(jpub, "address", pub->virt_addr);
 	else
-		res = mesh_config_write_uint16_hex(jpub, "address", pub->addr);
+		res = write_uint16_hex(jpub, "address", pub->addr);
 
 	if (!res)
 		goto fail;
 
-	if (!mesh_config_write_uint16_hex(jpub, "index", pub->idx))
+	if (!write_uint16_hex(jpub, "index", pub->idx))
 		goto fail;
 
-	if (!mesh_config_write_int(jpub, "ttl", pub->ttl))
+	if (!write_int(jpub, "ttl", pub->ttl))
 		goto fail;
 
-	if (!mesh_config_write_int(jpub, "period", pub->period))
+	if (!write_int(jpub, "period", pub->period))
 		goto fail;
 
-	if (!mesh_config_write_int(jpub, "credentials",
+	if (!write_int(jpub, "credentials",
 						pub->credential ? 1 : 0))
 		goto fail;
 
@@ -1681,10 +1765,10 @@ bool mesh_config_model_pub_add(json_object *jnode, uint16_t addr,
 	if (!jretransmit)
 		goto fail;
 
-	if (!mesh_config_write_int(jretransmit, "count", pub->count))
+	if (!write_int(jretransmit, "count", pub->count))
 		goto fail;
 
-	if (!mesh_config_write_int(jretransmit, "interval", pub->interval))
+	if (!write_int(jretransmit, "interval", pub->interval))
 		goto fail;
 
 	json_object_object_add(jpub, "retransmit", jretransmit);
@@ -1715,26 +1799,29 @@ static bool delete_model_property(json_object *jnode, uint16_t addr,
 	return true;
 }
 
-bool mesh_config_model_pub_del(json_object *jnode, uint16_t addr,
+bool mesh_config_model_pub_del(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor)
 {
-	if (!jnode)
+	if (!cfg)
 		return false;
 
-	return delete_model_property(jnode, addr, mod_id, vendor, "publish");
+	return delete_model_property(cfg->jnode, addr, mod_id, vendor,
+								"publish");
 }
 
-bool mesh_config_model_sub_add(json_object *jnode, uint16_t addr,
+bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor,
 						struct mesh_config_sub *sub)
 {
-	json_object *jmodel, *jstring, *jarray = NULL;
+	json_object *jnode, *jmodel, *jstring, *jarray = NULL;
 	int ele_idx, len;
 	char buf[33];
 
-	if (!jnode)
+	if (!cfg)
 		return false;
 
+	jnode = cfg->jnode;
+
 	ele_idx = get_element_index(jnode, addr);
 	if (ele_idx < 0)
 		return false;
@@ -1773,17 +1860,19 @@ bool mesh_config_model_sub_add(json_object *jnode, uint16_t addr,
 	return true;
 }
 
-bool mesh_config_model_sub_del(json_object *jnode, uint16_t addr,
+bool mesh_config_model_sub_del(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor,
 						struct mesh_config_sub *sub)
 {
-	json_object *jmodel, *jarray, *jarray_new;
+	json_object *jnode, *jmodel, *jarray, *jarray_new;
 	char buf[33];
 	int len, ele_idx;
 
-	if (!jnode)
+	if (!cfg)
 		return false;
 
+	jnode = cfg->jnode;
+
 	ele_idx = get_element_index(jnode, addr);
 	if (ele_idx < 0)
 		return false;
@@ -1826,11 +1915,126 @@ bool mesh_config_model_sub_del(json_object *jnode, uint16_t addr,
 	return true;
 }
 
-bool mesh_config_model_sub_del_all(json_object *jnode, uint16_t addr,
+bool mesh_config_model_sub_del_all(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor)
 {
+	if (!cfg)
+		return false;
+
+	return delete_model_property(cfg->jnode, addr, mod_id, vendor,
+								"subscribe");
+}
+
+bool mesh_config_load_node(const char *cfg_path, const uint8_t uuid[16],
+					mesh_config_node_cb cb, void *user_data)
+{
+	int fd;
+	char *str;
+	struct stat st;
+	ssize_t sz;
+	bool result = false;
+	json_object *jnode;
+	struct mesh_config_node node;
+
+	if (!cb) {
+		l_info("Node read callback is required");
+		return false;
+	}
+
+	l_info("Loading configuration from %s", cfg_path);
+
+	fd = open(cfg_path, O_RDONLY);
+	if (fd < 0)
+		return false;
+
+	if (fstat(fd, &st) == -1) {
+		close(fd);
+		return false;
+	}
+
+	str = (char *) l_new(char, st.st_size + 1);
+	if (!str) {
+		close(fd);
+		return false;
+	}
+
+	sz = read(fd, str, st.st_size);
+	if (sz != st.st_size) {
+		l_error("Failed to read configuration file %s", cfg_path);
+		goto done;
+	}
+
+	jnode = json_tokener_parse(str);
 	if (!jnode)
+		goto done;
+
+	memset(&node, 0, sizeof(node));
+	result = read_node(jnode, &node);
+
+	if (result) {
+		struct mesh_config *cfg = l_new(struct mesh_config, 1);
+
+		cfg->jnode = jnode;
+		memcpy(cfg->uuid, uuid, 16);
+		cfg->node_path = l_strdup(cfg_path);
+		result = cb(&node, uuid, cfg, user_data);
+
+		if (!result) {
+			l_free(cfg->node_path);
+			l_free(cfg);
+		}
+	}
+
+	/* Done with the node: free resources */
+	l_free(node.net_transmit);
+	l_queue_destroy(node.netkeys, l_free);
+	l_queue_destroy(node.appkeys, l_free);
+
+	if (!result)
+		json_object_put(jnode);
+
+done:
+	close(fd);
+	if (str)
+		l_free(str);
+
+	return result;
+}
+
+void mesh_config_release(struct mesh_config *cfg)
+{
+	if (!cfg)
+		return;
+
+	l_free(cfg->node_path);
+	json_object_put(cfg->jnode);
+	l_free(cfg);
+}
+
+bool mesh_config_save_config(struct mesh_config *cfg, const char *fname)
+{
+	FILE *outfile;
+	const char *str;
+	bool result = false;
+
+	if (!cfg)
+		return false;
+
+	outfile = fopen(fname, "w");
+	if (!outfile) {
+		l_error("Failed to save configuration to %s", fname);
 		return false;
+	}
+
+	str = json_object_to_json_string_ext(cfg->jnode,
+						JSON_C_TO_STRING_PRETTY);
+
+	if (fwrite(str, sizeof(char), strlen(str), outfile) < strlen(str))
+		l_warn("Incomplete write of mesh configuration");
+	else
+		result = true;
+
+	fclose(outfile);
 
-	return delete_model_property(jnode, addr, mod_id, vendor, "subscribe");
+	return result;
 }
diff --git a/mesh/mesh-config.h b/mesh/mesh-config.h
index 4ba02babb..8d01e760c 100644
--- a/mesh/mesh-config.h
+++ b/mesh/mesh-config.h
@@ -17,10 +17,12 @@
  *
  */
 
+struct mesh_config;
+
 struct mesh_config_sub {
 	bool virt;
 	union {
-		uint16_t addr;
+		uint16_t	addr;
 		uint8_t	virt_addr[16];
 	} src;
 };
@@ -104,59 +106,70 @@ struct mesh_config_node {
 };
 
 typedef bool (*mesh_config_node_cb)(struct mesh_config_node *node,
+							const uint8_t uuid[16],
+							struct mesh_config *cfg,
 							void *user_data);
 
-bool mesh_config_read_node(json_object *jobj, mesh_config_node_cb cb,
-							void *user_data);
-bool mesh_config_add_node(json_object *jnode, struct mesh_config_node *node);
-bool mesh_config_write_net_transmit(json_object *jobj, uint8_t cnt,
+bool mesh_config_load_node(const char *cfg_path, const uint8_t uuid[16],
+				mesh_config_node_cb cb, void *user_data);
+void mesh_config_release(struct mesh_config *cfg);
+bool mesh_config_save_config(struct mesh_config *cfg, const char *fname);
+struct mesh_config *mesh_config_create(const char *cfg_path,
+						const uint8_t uuid[16],
+						struct mesh_config_node *node);
+
+bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt,
 							uint16_t interval);
-bool mesh_config_write_device_key(json_object *jobj, uint8_t *key);
-bool mesh_config_write_token(json_object *jobj, uint8_t *token);
-bool mesh_config_write_network_key(json_object *jobj, uint16_t idx,
+bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t *key);
+bool mesh_config_write_token(struct mesh_config *cfg, uint8_t *token);
+bool mesh_config_write_network_key(struct mesh_config *cfg, uint16_t idx,
 				uint8_t *key, uint8_t *new_key, int phase);
-bool mesh_config_write_app_key(json_object *jobj, uint16_t net_idx,
+bool mesh_config_write_app_key(struct mesh_config *cfg, uint16_t net_idx,
 			uint16_t app_idx, uint8_t *key, uint8_t *new_key);
-bool mesh_config_write_int(json_object *jobj, const char *keyword, int value);
-bool mesh_config_write_uint16_hex(json_object *jobj, const char *desc,
+bool mesh_config_write_int(struct mesh_config *cfg,
+						const char *keyword, int value);
+bool mesh_config_write_uint16_hex(struct mesh_config *cfg, const char *desc,
 								uint16_t value);
-bool mesh_config_write_uint32_hex(json_object *jobj, const char *desc,
+bool mesh_config_write_uint32_hex(struct mesh_config *cfg, const char *desc,
 								uint32_t value);
-bool mesh_config_write_bool(json_object *jobj, const char *keyword, bool value);
-bool mesh_config_write_relay_mode(json_object *jnode, uint8_t mode,
+bool mesh_config_write_bool(struct mesh_config *cfg, const char *keyword,
+								bool value);
+bool mesh_config_write_relay_mode(struct mesh_config *cfg, uint8_t mode,
 					uint8_t count, uint16_t interval);
-bool mesh_config_write_mode(json_object *jobj, const char *keyword, int value);
-bool mesh_config_model_binding_add(json_object *jnode, uint8_t ele_idx,
+bool mesh_config_write_mode(struct mesh_config *cfg, const char *keyword,
+								int value);
+bool mesh_config_model_binding_add(struct mesh_config *cfg, uint8_t ele_idx,
 						bool vendor, uint32_t mod_id,
 							uint16_t app_idx);
-bool mesh_config_model_binding_del(json_object *jnode, uint8_t ele_idx,
+bool mesh_config_model_binding_del(struct mesh_config *cfg, uint8_t ele_idx,
 						bool vendor, uint32_t mod_id,
 							uint16_t app_idx);
-bool mesh_config_model_pub_add(json_object *jnode, uint16_t ele_addr,
+bool mesh_config_model_pub_add(struct mesh_config *cfg, uint16_t ele_addr,
 						uint32_t mod_id, bool vendor,
 						struct mesh_config_pub *pub);
-bool mesh_config_model_pub_del(json_object *jnode, uint16_t ele_addr,
+bool mesh_config_model_pub_del(struct mesh_config *cfg, uint16_t ele_addr,
 						uint32_t mod_id, bool vendor);
-bool mesh_config_model_sub_add(json_object *jnode, uint16_t addr,
+bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor,
 						struct mesh_config_sub *sub);
-bool mesh_config_model_sub_del(json_object *jnode, uint16_t addr,
+bool mesh_config_model_sub_del(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor,
 						struct mesh_config_sub *sub);
-bool mesh_config_model_sub_del_all(json_object *jnode, uint16_t addr,
+bool mesh_config_model_sub_del_all(struct mesh_config *cfg, uint16_t addr,
 						uint32_t mod_id, bool vendor);
-bool mesh_config_app_key_add(json_object *jnode, uint16_t net_idx,
+bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx,
 				uint16_t app_idx, const uint8_t key[16]);
-bool mesh_config_app_key_update(json_object *jobj, uint16_t app_idx,
+bool mesh_config_app_key_update(struct mesh_config *cfg, uint16_t app_idx,
 							const uint8_t key[16]);
-bool mesh_config_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx);
-bool mesh_config_net_key_add(json_object *jobj, uint16_t net_idx,
+bool mesh_config_app_key_del(struct mesh_config *cfg, uint16_t net_idx,
+								uint16_t idx);
+bool mesh_config_net_key_add(struct mesh_config *cfg, uint16_t net_idx,
 							const uint8_t key[16]);
-bool mesh_config_net_key_update(json_object *jobj, uint16_t idx,
+bool mesh_config_net_key_update(struct mesh_config *cfg, uint16_t idx,
 							const uint8_t key[16]);
-bool mesh_config_net_key_del(json_object *jobj, uint16_t net_idx);
-bool mesh_config_net_key_set_phase(json_object *jobj, uint16_t idx,
+bool mesh_config_net_key_del(struct mesh_config *cfg, uint16_t net_idx);
+bool mesh_config_net_key_set_phase(struct mesh_config *cfg, uint16_t idx,
 								uint8_t phase);
-bool mesh_config_write_address(json_object *jobj, uint16_t address);
-bool mesh_config_write_iv_index(json_object *jobj, uint32_t idx, bool update);
-void mesh_config_remove_property(json_object *jobj, const char *desc);
+bool mesh_config_write_address(struct mesh_config *cfg, uint16_t address);
+bool mesh_config_write_iv_index(struct mesh_config *cfg, uint32_t idx,
+								bool update);
diff --git a/mesh/model.c b/mesh/model.c
index 9331e1044..0f10727b4 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -23,7 +23,6 @@
 
 #include <sys/time.h>
 #include <ell/ell.h>
-#include <json-c/json.h>
 
 #include "mesh/mesh-defs.h"
 
diff --git a/mesh/node.c b/mesh/node.c
index 2b49f86d9..7fd0aa21d 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -26,7 +26,6 @@
 #include <sys/time.h>
 
 #include <ell/ell.h>
-#include <json-c/json.h>
 
 #include "mesh/mesh-defs.h"
 #include "mesh/mesh.h"
@@ -82,7 +81,7 @@ struct mesh_node {
 	char *app_path;
 	char *owner;
 	char *path;
-	void *jconfig;
+	struct mesh_config *cfg;
 	char *node_path;
 	uint32_t disc_watch;
 	time_t upd_sec;
@@ -392,9 +391,9 @@ static void set_app_key(void *a, void *b)
 						appkey->key, appkey->new_key);
 }
 
-bool node_init_from_storage(struct mesh_node *node, void *data)
+bool node_init_from_storage(struct mesh_node *node, const uint8_t uuid[16],
+					struct mesh_config_node *db_node)
 {
-	struct mesh_config_node *db_node = data;
 	unsigned int num_ele;
 	uint8_t mode;
 
@@ -753,7 +752,7 @@ bool node_proxy_mode_set(struct mesh_node *node, bool enable)
 		return false;
 
 	proxy = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
-	res = storage_set_mode(node->jconfig, proxy, "proxy");
+	res = storage_set_mode(node, proxy, "proxy");
 
 	if (res) {
 		node->proxy = proxy;
@@ -780,7 +779,7 @@ bool node_beacon_mode_set(struct mesh_node *node, bool enable)
 		return false;
 
 	beacon = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
-	res = storage_set_mode(node->jconfig, beacon, "beacon");
+	res = storage_set_mode(node, beacon, "beacon");
 
 	if (res) {
 		node->beacon = beacon;
@@ -807,7 +806,7 @@ bool node_friend_mode_set(struct mesh_node *node, bool enable)
 		return false;
 
 	friend = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
-	res = storage_set_mode(node->jconfig, friend, "friend");
+	res = storage_set_mode(node, friend, "friend");
 
 	if (res) {
 		node->friend = friend;
@@ -1350,14 +1349,14 @@ static void convert_node_to_storage(struct mesh_node *node,
 
 }
 
-static bool create_node_config(struct mesh_node *node)
+static bool create_node_config(struct mesh_node *node, const uint8_t uuid[16])
 {
 	struct mesh_config_node db_node;
 	const struct l_queue_entry *entry;
 	bool res;
 
 	convert_node_to_storage(node, &db_node);
-	res = storage_create_node_config(node, &db_node);
+	res = storage_create_node_config(node, uuid, &db_node);
 
 	/* Free temporarily allocated resources */
 	entry = l_queue_get_entries(db_node.elements);
@@ -1465,16 +1464,16 @@ static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr,
 
 	mesh_net_set_iv_index(node->net, iv_idx, ivu);
 
-	if (!mesh_config_write_uint16_hex(node->jconfig, "unicastAddress",
+	if (!mesh_config_write_uint16_hex(node->cfg, "unicastAddress",
 								unicast))
 		return false;
 
 	l_getrandom(node->token, sizeof(node->token));
-	if (!mesh_config_write_token(node->jconfig, node->token))
+	if (!mesh_config_write_token(node->cfg, node->token))
 		return false;
 
 	memcpy(node->dev_key, dev_key, 16);
-	if (!mesh_config_write_device_key(node->jconfig, dev_key))
+	if (!mesh_config_write_device_key(node->cfg, dev_key))
 		return false;
 
 	node->primary = unicast;
@@ -1490,7 +1489,7 @@ static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr,
 							MESH_STATUS_SUCCESS)
 			return false;
 
-		if (!mesh_config_net_key_set_phase(node->jconfig, net_key_idx,
+		if (!mesh_config_net_key_set_phase(node->cfg, net_key_idx,
 							KEY_REFRESH_PHASE_TWO))
 			return false;
 	}
@@ -1625,7 +1624,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 		set_defaults(node);
 		memcpy(node->uuid, req->data, 16);
 
-		if (!create_node_config(node))
+		if (!create_node_config(node, node->uuid))
 			goto fail;
 
 		cb(node, agent);
@@ -1640,7 +1639,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
 		set_defaults(node);
 		memcpy(node->uuid, req->data, 16);
 
-		if (!create_node_config(node))
+		if (!create_node_config(node, node->uuid))
 			goto fail;
 
 		/* Generate device and primary network keys */
@@ -2050,14 +2049,14 @@ bool node_add_pending_local(struct mesh_node *node, void *prov_node_info)
 			info->device_key, info->net_index, info->net_key);
 }
 
-void node_jconfig_set(struct mesh_node *node, void *jconfig)
+void node_config_set(struct mesh_node *node, struct mesh_config *cfg)
 {
-	node->jconfig = jconfig;
+	node->cfg = cfg;
 }
 
-void *node_jconfig_get(struct mesh_node *node)
+struct mesh_config *node_config_get(struct mesh_node *node)
 {
-	return node->jconfig;
+	return node->cfg;
 }
 
 void node_path_set(struct mesh_node *node, char *path)
diff --git a/mesh/node.h b/mesh/node.h
index 142527b30..b7e4bc761 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -21,6 +21,8 @@ struct mesh_net;
 struct mesh_node;
 struct mesh_io;
 struct mesh_agent;
+struct mesh_config;
+struct mesh_config_node;
 
 /* To prevent local node JSON cache thrashing, minimum update times */
 #define MIN_SEQ_TRIGGER	32
@@ -66,7 +68,8 @@ int node_get_element_idx(struct mesh_node *node, uint16_t ele_addr);
 struct l_queue *node_get_element_models(struct mesh_node *node, uint8_t ele_idx,
 								int *status);
 uint16_t node_get_crpl(struct mesh_node *node);
-bool node_init_from_storage(struct mesh_node *node, void *data);
+bool node_init_from_storage(struct mesh_node *node, const uint8_t uuid[16],
+					struct mesh_config_node *db_node);
 uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz);
 uint8_t node_lpn_mode_get(struct mesh_node *node);
 bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
@@ -95,7 +98,7 @@ void node_id_set(struct mesh_node *node, uint16_t node_id);
 uint16_t node_id_get(struct mesh_node *node);
 bool node_dbus_init(struct l_dbus *bus);
 void node_cleanup_all(void);
-void node_jconfig_set(struct mesh_node *node, void *jconfig);
-void *node_jconfig_get(struct mesh_node *node);
+void node_config_set(struct mesh_node *node, struct mesh_config *cfg);
+struct mesh_config *node_config_get(struct mesh_node *node);
 void node_path_set(struct mesh_node *node, char *path);
 char *node_path_get(struct mesh_node *node);
diff --git a/mesh/storage.c b/mesh/storage.c
index 645d84c97..869c6d70e 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -29,7 +29,6 @@
 #include <libgen.h>
 #include <ftw.h>
 
-#include <json-c/json.h>
 #include <ell/ell.h>
 
 #include "mesh/mesh-defs.h"
@@ -41,7 +40,7 @@
 #include "mesh/storage.h"
 
 struct write_info {
-	json_object *jnode;
+	struct mesh_config *cfg;
 	const char *node_path;
 	void *user_data;
 	mesh_status_func_t cb;
@@ -52,80 +51,41 @@ static const char *bak_ext = ".bak";
 static const char *tmp_ext = ".tmp";
 static const char *storage_dir;
 
-static bool read_node_cb(struct mesh_config_node *db_node, void *user_data)
+static bool read_node_cb(struct mesh_config_node *db_node,
+			const uint8_t uuid[16], struct mesh_config *cfg,
+			void *user_data)
 {
 	struct mesh_node *node = user_data;
 
-	if (!node_init_from_storage(node, db_node)) {
+	if (!node_init_from_storage(node, uuid, db_node)) {
 		node_remove(node);
 		return false;
 	}
 
+	node_config_set(node, cfg);
 	return true;
 }
 
 static bool parse_config(char *in_file, char *out_dir, const uint8_t uuid[16])
 {
-	int fd;
-	char *str;
-	struct stat st;
-	ssize_t sz;
-	json_object *jnode = NULL;
 	bool result = false;
 	struct mesh_node *node;
 
-	l_info("Loading configuration from %s", in_file);
-
-	fd = open(in_file, O_RDONLY);
-	if (fd < 0)
-		return false;
-
-	if (fstat(fd, &st) == -1) {
-		close(fd);
-		return false;
-	}
-
-	str = (char *) l_new(char, st.st_size + 1);
-	if (!str) {
-		close(fd);
-		return false;
-	}
-
-	sz = read(fd, str, st.st_size);
-	if (sz != st.st_size) {
-		l_error("Failed to read configuration file %s", in_file);
-		goto done;
-	}
-
-	jnode = json_tokener_parse(str);
-	if (!jnode)
-		goto done;
-
 	node = node_new(uuid);
 
-	result = mesh_config_read_node(jnode, read_node_cb, node);
+	result = mesh_config_load_node(in_file, uuid, read_node_cb, node);
 
-	if (!result) {
-		json_object_put(jnode);
+	if (!result)
 		node_remove(node);
-	}
-
-	node_jconfig_set(node, jnode);
-	node_path_set(node, out_dir);
-
-done:
-	close(fd);
-	if (str)
-		l_free(str);
+	else
+		node_path_set(node, out_dir);
 
 	return result;
 }
 
 bool storage_set_ttl(struct mesh_node *node, uint8_t ttl)
 {
-	json_object *jnode = node_jconfig_get(node);
-
-	if (!mesh_config_write_int(jnode, "defaultTTL", ttl))
+	if (!mesh_config_write_int(node_config_get(node), "defaultTTL", ttl))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -135,9 +95,8 @@ bool storage_set_ttl(struct mesh_node *node, uint8_t ttl)
 bool storage_set_relay(struct mesh_node *node, bool enable,
 				uint8_t count, uint8_t interval)
 {
-	json_object *jnode = node_jconfig_get(node);
-
-	if (!mesh_config_write_relay_mode(jnode, enable, count, interval))
+	if (!mesh_config_write_relay_mode(node_config_get(node), enable, count,
+								interval))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -147,9 +106,8 @@ bool storage_set_relay(struct mesh_node *node, bool enable,
 bool storage_set_transmit_params(struct mesh_node *node, uint8_t count,
 							uint8_t interval)
 {
-	json_object *jnode = node_jconfig_get(node);
-
-	if (!mesh_config_write_net_transmit(jnode, count, interval))
+	if (!mesh_config_write_net_transmit(node_config_get(node), count,
+								interval))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -159,9 +117,7 @@ bool storage_set_transmit_params(struct mesh_node *node, uint8_t count,
 bool storage_set_mode(struct mesh_node *node, uint8_t mode,
 						const char *mode_name)
 {
-	json_object *jnode = node_jconfig_get(node);
-
-	if (!mesh_config_write_mode(jnode, mode_name, mode))
+	if (!mesh_config_write_mode(node_config_get(node), mode_name, mode))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -171,7 +127,7 @@ bool storage_set_mode(struct mesh_node *node, uint8_t mode,
 bool storage_model_bind(struct mesh_node *node, uint16_t addr, uint32_t mod_id,
 				uint16_t app_idx, bool unbind)
 {
-	json_object *jnode;
+	struct mesh_config *cfg;
 	int ele_idx;
 	bool stored, is_vendor = (mod_id > 0xffff);
 
@@ -179,14 +135,14 @@ bool storage_model_bind(struct mesh_node *node, uint16_t addr, uint32_t mod_id,
 	if (ele_idx < 0)
 		return false;
 
-	jnode = node_jconfig_get(node);
+	cfg = node_config_get(node);
 
 	if (unbind)
-		stored = mesh_config_model_binding_del(jnode, ele_idx,
-						is_vendor, mod_id, app_idx);
+		stored = mesh_config_model_binding_del(cfg, ele_idx, is_vendor,
+							mod_id, app_idx);
 	else
-		stored = mesh_config_model_binding_add(jnode, ele_idx,
-						is_vendor, mod_id, app_idx);
+		stored = mesh_config_model_binding_add(cfg, ele_idx, is_vendor,
+							mod_id, app_idx);
 
 	if (stored)
 		storage_save_config(node, true, NULL, NULL);
@@ -197,18 +153,16 @@ bool storage_model_bind(struct mesh_node *node, uint16_t addr, uint32_t mod_id,
 bool storage_app_key_add(struct mesh_net *net, uint16_t net_idx,
 			uint16_t app_idx, const uint8_t key[16], bool update)
 {
-	json_object *jnode;
+	struct mesh_config *cfg;
 	struct mesh_node *node = mesh_net_node_get(net);
 	bool stored;
 
-	jnode = node_jconfig_get(node);
-	if (!jnode)
-		return false;
+	cfg = node_config_get(node);
 
 	if (update)
-		stored = mesh_config_app_key_update(jnode, app_idx, key);
+		stored = mesh_config_app_key_update(cfg, app_idx, key);
 	else
-		stored = mesh_config_app_key_add(jnode, net_idx, app_idx, key);
+		stored = mesh_config_app_key_add(cfg, net_idx, app_idx, key);
 
 	if (stored)
 		storage_save_config(node, true, NULL, NULL);
@@ -219,14 +173,12 @@ bool storage_app_key_add(struct mesh_net *net, uint16_t net_idx,
 bool storage_app_key_del(struct mesh_net *net, uint16_t net_idx,
 					uint16_t app_idx)
 {
-	json_object *jnode;
+	struct mesh_config *cfg;
 	struct mesh_node *node = mesh_net_node_get(net);
 
-	jnode = node_jconfig_get(node);
-	if (!jnode)
-		return false;
+	cfg = node_config_get(node);
 
-	if (!mesh_config_app_key_del(jnode, net_idx, app_idx))
+	if (!mesh_config_app_key_del(cfg, net_idx, app_idx))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -237,13 +189,13 @@ bool storage_net_key_add(struct mesh_net *net, uint16_t net_idx,
 					const uint8_t key[16], bool update)
 {
 	struct mesh_node *node = mesh_net_node_get(net);
-	json_object *jnode = node_jconfig_get(node);
+	struct mesh_config *cfg = node_config_get(node);
 	bool stored;
 
 	if (!update)
-		stored = mesh_config_net_key_add(jnode, net_idx, key);
+		stored = mesh_config_net_key_add(cfg, net_idx, key);
 	else
-		stored = mesh_config_net_key_update(jnode, net_idx, key);
+		stored = mesh_config_net_key_update(cfg, net_idx, key);
 
 	if (stored)
 		storage_save_config(node, true, NULL, NULL);
@@ -254,9 +206,9 @@ bool storage_net_key_add(struct mesh_net *net, uint16_t net_idx,
 bool storage_net_key_del(struct mesh_net *net, uint16_t net_idx)
 {
 	struct mesh_node *node = mesh_net_node_get(net);
-	json_object *jnode = node_jconfig_get(node);
+	struct mesh_config *cfg = node_config_get(node);
 
-	if (!mesh_config_net_key_del(jnode, net_idx))
+	if (!mesh_config_net_key_del(cfg, net_idx))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -267,9 +219,9 @@ bool storage_set_iv_index(struct mesh_net *net, uint32_t iv_index,
 								bool update)
 {
 	struct mesh_node *node = mesh_net_node_get(net);
-	json_object *jnode = node_jconfig_get(node);
+	struct mesh_config *cfg = node_config_get(node);
 
-	if (!mesh_config_write_iv_index(jnode, iv_index, update))
+	if (!mesh_config_write_iv_index(cfg, iv_index, update))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -280,9 +232,9 @@ bool storage_set_key_refresh_phase(struct mesh_net *net, uint16_t net_idx,
 								uint8_t phase)
 {
 	struct mesh_node *node = mesh_net_node_get(net);
-	json_object *jnode = node_jconfig_get(node);
+	struct mesh_config *cfg = node_config_get(node);
 
-	if (!mesh_config_net_key_set_phase(jnode, net_idx, phase))
+	if (!mesh_config_net_key_set_phase(cfg, net_idx, phase))
 		return false;
 
 	storage_save_config(node, true, NULL, NULL);
@@ -292,39 +244,15 @@ bool storage_set_key_refresh_phase(struct mesh_net *net, uint16_t net_idx,
 bool storage_write_sequence_number(struct mesh_net *net, uint32_t seq)
 {
 	struct mesh_node *node = mesh_net_node_get(net);
-	json_object *jnode = node_jconfig_get(node);
+	struct mesh_config *cfg = node_config_get(node);
 
-	if (!mesh_config_write_int(jnode, "sequenceNumber", seq))
+	if (!mesh_config_write_int(cfg, "sequenceNumber", seq))
 		return false;
 
 	storage_save_config(node, false, NULL, NULL);
 	return true;
 }
 
-static bool save_config(json_object *jnode, const char *config_name)
-{
-	FILE *outfile;
-	const char *str;
-	bool result = false;
-
-	outfile = fopen(config_name, "w");
-	if (!outfile) {
-		l_error("Failed to save configuration to %s", config_name);
-		return false;
-	}
-
-	str = json_object_to_json_string_ext(jnode, JSON_C_TO_STRING_PRETTY);
-
-	if (fwrite(str, sizeof(char), strlen(str), outfile) < strlen(str))
-		l_warn("Incomplete write of mesh configuration");
-	else
-		result = true;
-
-	fclose(outfile);
-
-	return result;
-}
-
 static void idle_save_config(void *user_data)
 {
 	struct write_info *info = user_data;
@@ -337,7 +265,7 @@ static void idle_save_config(void *user_data)
 	remove(tmp);
 
 	l_debug("Storage-Wrote");
-	result = save_config(info->jnode, tmp);
+	result = mesh_config_save_config(info->cfg, tmp);
 
 	if (result) {
 		remove(bak);
@@ -362,7 +290,7 @@ void storage_save_config(struct mesh_node *node, bool no_wait,
 	struct write_info *info;
 
 	info = l_new(struct write_info, 1);
-	info->jnode = node_jconfig_get(node);
+	info->cfg = node_config_get(node);
 	info->node_path = node_path_get(node);
 	info->cb = cb;
 	info->user_data = user_data;
@@ -462,48 +390,47 @@ bool storage_load_nodes(const char *dir_name)
 	return true;
 }
 
-bool storage_create_node_config(struct mesh_node *node, void *data)
+bool storage_create_node_config(struct mesh_node *node, const uint8_t uuid[16],
+					struct mesh_config_node *db_node)
 {
-	struct mesh_config_node *db_node = data;
-	char uuid[33];
+	char uuid_buf[33];
 	char name_buf[PATH_MAX];
-	json_object *jnode;
+	struct mesh_config *cfg;
 	size_t max_len = strlen(cfg_name) + strlen(bak_ext);
 
 	if (!storage_dir)
 		return false;
 
-	jnode = json_object_new_object();
-
-	if (!mesh_config_add_node(jnode, db_node))
+	if (!hex2str((uint8_t *) uuid, 16, uuid_buf, sizeof(uuid_buf)))
 		return false;
 
-	if (!hex2str(node_uuid_get(node), 16, uuid, sizeof(uuid)))
-		goto fail;
-
-	snprintf(name_buf, PATH_MAX, "%s/%s", storage_dir, uuid);
+	snprintf(name_buf, PATH_MAX, "%s/%s", storage_dir, uuid_buf);
 
 	if (strlen(name_buf) + max_len >= PATH_MAX)
-		goto fail;
+		return false;
 
 	/* Create a new directory and node.json file */
 	if (mkdir(name_buf, 0755) != 0)
-		goto fail;
+		return false;
 
 	node_path_set(node, name_buf);
 
-	snprintf(name_buf, PATH_MAX, "%s/%s%s", storage_dir, uuid, cfg_name);
+	snprintf(name_buf, PATH_MAX, "%s/%s%s", storage_dir, uuid_buf,
+								cfg_name);
 	l_debug("New node config %s", name_buf);
 
-	if (!save_config(jnode, name_buf))
-		goto fail;
+	cfg = mesh_config_create(name_buf, uuid, db_node);
+	if (!cfg)
+		return false;
 
-	node_jconfig_set(node, jnode);
+	if (!mesh_config_save_config(cfg, name_buf)) {
+		mesh_config_release(cfg);
+		return false;
+	}
+
+	node_config_set(node, cfg);
 
 	return true;
-fail:
-	json_object_put(jnode);
-	return false;
 }
 
 static int del_fobject(const char *fpath, const struct stat *sb, int typeflag,
@@ -529,17 +456,13 @@ void storage_remove_node_config(struct mesh_node *node)
 {
 	char *node_path, *node_name;
 	char uuid[33];
-	struct json_object *jnode;
 
 	if (!node)
 		return;
 
-	/* Free the node config json object */
-	jnode = node_jconfig_get(node);
-	if (jnode)
-		json_object_put(jnode);
-
-	node_jconfig_set(node, NULL);
+	/* Release node config object */
+	mesh_config_release(node_config_get(node));
+	node_config_set(node, NULL);
 
 	node_path = node_path_get(node);
 	l_debug("Delete node config %s", node_path);
diff --git a/mesh/storage.h b/mesh/storage.h
index a537ddb25..1fa48ad7a 100644
--- a/mesh/storage.h
+++ b/mesh/storage.h
@@ -19,9 +19,11 @@
 
 struct mesh_net;
 struct mesh_node;
+struct mesh_config_node;
 
 bool storage_load_nodes(const char *dir);
-bool storage_create_node_config(struct mesh_node *node, void *db_node);
+bool storage_create_node_config(struct mesh_node *node, const uint8_t uuid[16],
+					struct mesh_config_node *db_node);
 void storage_remove_node_config(struct mesh_node *node);
 void storage_save_config(struct mesh_node *node, bool no_wait,
 					mesh_status_func_t cb, void *user_data);
-- 
2.21.0


  parent reply index

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-14  6:28 [PATCH BlueZ 00/10 v2] mesh: Configuration storage re-org Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 01/10 v2] mesh: Move network config setup from storage.c to node.c Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 02/10 v2] mesh: Rename mesh-db.c to mesh-config-json.c Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 03/10 v2] mesh: Change mesh_db prefix to mesh_config Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 04/10 v2] mesh: Move load from storage functionality into node.c Inga Stotland
2019-07-14  6:28 ` Inga Stotland [this message]
2019-07-14  6:28 ` [PATCH BlueZ 06/10 v2] mesh: Replace storage_save_config with mesh_config_save_config Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 07/10 v2] mesh: Use mesh_config APIs to store node configuration Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 08/10 v2] mesh: Manage node config directory in mesh-config Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 09/10 v2] mesh: Create or re-use a node storage directory for keyring Inga Stotland
2019-07-14  6:28 ` [PATCH BlueZ 10/10 v2] mesh: Rename mesh_config_srv_init() to cfgmod_server_init() Inga Stotland

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190714062812.31041-6-inga.stotland@intel.com \
    --to=inga.stotland@intel.com \
    --cc=brian.gix@intel.com \
    --cc=jakub.witowski@silvair.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=michal.lowas-rzechonek@silvair.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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 linux-bluetooth@archiver.kernel.org
	public-inbox-index linux-bluetooth


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