[PATCH BlueZ v6 12/14] mesh: Read and write mesh configuration in JSON format

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Inga Stotland <inga.stotland@xxxxxxxxx>

This adds implementation for parsing and writing Mesh configuration
into JSON format. Also, parse stored unprovisioned device composiotion.
---
 mesh/mesh-db.c | 1360 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mesh/mesh-db.h |  144 ++++++
 2 files changed, 1504 insertions(+)
 create mode 100644 mesh/mesh-db.c
 create mode 100644 mesh/mesh-db.h

diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
new file mode 100644
index 000000000..7bddab010
--- /dev/null
+++ b/mesh/mesh-db.c
@@ -0,0 +1,1360 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2018  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+#include "mesh/util.h"
+
+#include "mesh/mesh-db.h"
+
+#define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
+
+static bool get_int(json_object *jobj, const char *keyword, int *value)
+{
+	json_object *jvalue;
+
+	if (!json_object_object_get_ex(jobj, keyword, &jvalue))
+		return false;
+
+	*value = json_object_get_int(jvalue);
+	if (errno == EINVAL)
+		return false;
+
+	return true;
+}
+
+static bool add_key(json_object *jobject, const char *desc,
+					const uint8_t key[16])
+{
+	json_object *jstring;
+	char hexstr[33];
+
+	hex2str((uint8_t *) key, 16, hexstr, 33);
+	jstring = json_object_new_string(hexstr);
+	if (!jstring)
+		return false;
+
+	json_object_object_add(jobject, desc, jstring);
+	return true;
+}
+
+static json_object *get_element_model(json_object *jnode, int ele_idx,
+						uint32_t mod_id, bool vendor)
+{
+	json_object *jelements, *jelement, *jmodels;
+	int i, num_mods;
+	size_t len;
+	char buf[9];
+
+	if (!vendor)
+		snprintf(buf, 5, "%4.4x", (uint16_t)mod_id);
+	else
+		snprintf(buf, 9, "%8.8x", mod_id);
+
+	json_object_object_get_ex(jnode, "elements", &jelements);
+	if (!jelements)
+		return NULL;
+
+	jelement = json_object_array_get_idx(jelements, ele_idx);
+	if (!jelement)
+		return NULL;
+
+	json_object_object_get_ex(jelement, "models", &jmodels);
+	if (!jmodels)
+		return NULL;
+
+	num_mods = json_object_array_length(jmodels);
+	if (!num_mods)
+		return NULL;
+
+	if (!vendor) {
+		snprintf(buf, 5, "%4.4x", mod_id);
+		len = 4;
+	} else {
+		snprintf(buf, 9, "%8.8x", mod_id);
+		len = 8;
+	}
+
+	for (i = 0; i < num_mods; ++i) {
+		json_object *jmodel, *jvalue;
+		char *str;
+
+		jmodel = json_object_array_get_idx(jmodels, i);
+		json_object_object_get_ex(jmodel, "modelId", &jvalue);
+		if (!jvalue)
+			return NULL;
+
+		str = (char *)json_object_get_string(jvalue);
+		if (!str)
+			return NULL;
+
+		if (!strncmp(str, buf, len))
+			return jmodel;
+	}
+
+	return NULL;
+}
+
+static bool jarray_has_string(json_object *jarray, char *str, size_t len)
+{
+	int i, sz = json_object_array_length(jarray);
+
+	for (i = 0; i < sz; ++i) {
+		json_object *jentry;
+		char *str_entry;
+
+		jentry = json_object_array_get_idx(jarray, i);
+		str_entry = (char *)json_object_get_string(jentry);
+		if (!str_entry)
+			continue;
+
+		if (!strncmp(str, str_entry, len))
+			return true;
+	}
+
+	return false;
+}
+
+static json_object *jarray_string_del(json_object *jarray, char *str,
+								size_t len)
+{
+	int i, sz = json_object_array_length(jarray);
+	json_object *jarray_new;
+
+	jarray_new = json_object_new_array();
+	if (!jarray_new)
+		return NULL;
+
+	for (i = 0; i < sz; ++i) {
+		json_object *jentry;
+		char *str_entry;
+
+		jentry = json_object_array_get_idx(jarray, i);
+		str_entry = (char *)json_object_get_string(jentry);
+		if (str_entry && !strncmp(str, str_entry, len))
+			continue;
+
+		json_object_array_add(jarray_new, jentry);
+	}
+
+	return jarray_new;
+}
+
+static json_object *get_key_object(json_object *jarray, uint16_t idx)
+{
+	int i, sz = json_object_array_length(jarray);
+
+	for (i = 0; i < sz; ++i) {
+		json_object *jentry, *jvalue;
+		uint32_t jidx;
+
+		jentry = json_object_array_get_idx(jarray, i);
+		if (!json_object_object_get_ex(jentry, "index", &jvalue))
+			return NULL;
+
+		jidx = json_object_get_int(jvalue);
+
+		if (jidx == idx)
+			return jentry;
+	}
+
+	return NULL;
+}
+
+static json_object *jarray_key_del(json_object *jarray, int16_t idx)
+{
+	json_object *jarray_new;
+	int i, sz = json_object_array_length(jarray);
+	char idx_str[5];
+
+	snprintf(idx_str, 5, "%4.4x", idx);
+
+	jarray_new = json_object_new_array();
+	if (!jarray_new)
+		return NULL;
+
+	for (i = 0; i < sz; ++i) {
+		json_object *jentry, *jvalue;
+		char *str;
+
+		jentry = json_object_array_get_idx(jarray, i);
+
+		if (json_object_object_get_ex(jentry, "index", &jvalue)) {
+			str = (char *)json_object_get_string(jvalue);
+			if (str && !strncmp(str, idx_str, 4))
+				continue;
+		}
+
+		json_object_array_add(jarray_new, jentry);
+	}
+
+	return jarray_new;
+}
+
+bool mesh_db_read_iv_index(json_object *jobj, uint32_t *idx, bool *update)
+{
+	int tmp;
+
+	/* IV index */
+	if (!get_int(jobj, "IVindex", &tmp))
+		return false;
+
+	*idx = (uint32_t) tmp;
+
+	if (!get_int(jobj, "IVupdate", &tmp))
+		return false;
+
+	*update = tmp ? true : false;
+
+	return true;
+}
+
+bool mesh_db_read_device_key(json_object *jobj, uint8_t key_buf[16])
+{
+	json_object *jvalue;
+	char *str;
+
+	if (!key_buf)
+		return false;
+
+	if (!json_object_object_get_ex(jobj, "deviceKey", &jvalue) ||
+								!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (!str2hex(str, strlen(str), key_buf, 16))
+		return false;
+
+	return true;
+}
+
+bool mesh_db_read_app_keys(json_object *jobj, mesh_db_app_key_cb cb,
+							void *user_data)
+{
+	json_object *jarray;
+	int len;
+	int i;
+
+	if (!cb)
+		return true;
+
+	json_object_object_get_ex(jobj, "appKeys", &jarray);
+	if (!jarray || (json_object_get_type(jarray) != json_type_array))
+		return false;
+
+	len = json_object_array_length(jarray);
+
+	for (i = 0; i < len; ++i) {
+		json_object *jtemp, *jvalue;
+		int app_idx, net_idx;
+		bool key_refresh = false;
+		char *str;
+		uint8_t key[16];
+		uint8_t new_key[16];
+
+		jtemp = json_object_array_get_idx(jarray, i);
+
+		if (!get_int(jtemp, "index", &app_idx))
+			return false;
+
+		if (!CHECK_KEY_IDX_RANGE(app_idx))
+			return false;
+
+		if (!get_int(jtemp, "boundNetKey", &net_idx))
+			return false;
+
+		if (!CHECK_KEY_IDX_RANGE(net_idx))
+			return false;
+
+		json_object_object_get_ex(jtemp, "oldKey", &jvalue);
+		if (jvalue) {
+			str = (char *)json_object_get_string(jvalue);
+			if (!str2hex(str, strlen(str), key, 16))
+				return false;
+			key_refresh = true;
+		}
+
+		json_object_object_get_ex(jtemp, "key", &jvalue);
+		if (!jvalue)
+			return false;
+
+		str = (char *)json_object_get_string(jvalue);
+		if (!str2hex(str, strlen(str), key_refresh ? new_key : key, 16))
+			return false;
+
+		if (!cb((uint16_t)net_idx, (uint16_t) app_idx, key,
+				key_refresh ? new_key : NULL, user_data))
+			return false;
+	}
+
+	return true;
+}
+
+bool mesh_db_read_net_keys(json_object *jobj, mesh_db_net_key_cb cb,
+								void *user_data)
+{
+	json_object *jarray;
+	int len;
+	int i;
+
+	if (!cb)
+		return true;
+
+	json_object_object_get_ex(jobj, "netKeys", &jarray);
+	if (!jarray || (json_object_get_type(jarray) != json_type_array))
+		return false;
+
+	len = json_object_array_length(jarray);
+
+	for (i = 0; i < len; ++i) {
+		json_object *jtemp, *jvalue;
+		int idx;
+		char *str;
+		bool key_refresh = false;
+		int phase;
+		uint8_t key[16];
+		uint8_t new_key[16];
+
+		jtemp = json_object_array_get_idx(jarray, i);
+
+		if (!get_int(jtemp, "index", &idx))
+			return false;
+
+		if (!CHECK_KEY_IDX_RANGE(idx))
+			return false;
+
+		json_object_object_get_ex(jtemp, "oldKey", &jvalue);
+		if (jvalue) {
+			str = (char *)json_object_get_string(jvalue);
+			if (!str2hex(str, strlen(str), key, 16))
+				return false;
+			key_refresh = true;
+		}
+
+		json_object_object_get_ex(jtemp, "key", &jvalue);
+		if (!jvalue)
+			return false;
+
+		str = (char *)json_object_get_string(jvalue);
+		if (!str2hex(str, strlen(str), key_refresh ? new_key : key, 16))
+			return false;
+
+		json_object_object_get_ex(jtemp, "keyRefresh", &jvalue);
+		if (!jvalue)
+			phase = KEY_REFRESH_PHASE_NONE;
+		else
+			phase = json_object_get_int(jvalue);
+
+
+		if (!cb((uint16_t)idx, key, key_refresh ? new_key : NULL, phase,
+								user_data))
+			return false;
+	}
+
+	return true;
+}
+
+bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
+					const uint8_t key[16], int phase)
+{
+	json_object *jarray, *jentry = NULL, *jstring;
+	char buf[5];
+
+	json_object_object_get_ex(jobj, "netKeys", &jarray);
+	if (!jarray && (phase != KEY_REFRESH_PHASE_NONE))
+		return false;
+
+	if (jarray)
+		jentry = get_key_object(jarray, idx);
+
+	/*
+	 * The key entry should exist if the key is updated
+	 * (i.e., Key Refresh is underway)
+	 */
+	if (!jentry && (phase != KEY_REFRESH_PHASE_NONE))
+		return false;
+
+	if (jentry) {
+		uint8_t buf[16];
+		json_object *jvalue;
+		char *str;
+
+		json_object_object_get_ex(jentry, "key", &jvalue);
+		if (!jvalue)
+			return false;
+
+		str = (char *)json_object_get_string(jvalue);
+		if (!str2hex(str, strlen(str), buf, sizeof(buf)))
+			return false;
+
+		/* If the same key, return success */
+		if (memcmp(key, buf, 16) == 0)
+			return true;
+
+		return false;
+	}
+
+	if (phase == KEY_REFRESH_PHASE_NONE) {
+		jentry = json_object_new_object();
+		if (!jentry)
+			goto fail;
+
+		snprintf(buf, 5, "%4.4x", idx);
+		jstring = json_object_new_string(buf);
+		if (!jstring)
+			goto fail;
+
+		json_object_object_add(jentry, "index", jstring);
+
+		snprintf(buf, 5, "%4.4x", idx);
+		jstring = json_object_new_string(buf);
+		if (!jstring)
+			goto fail;
+
+		if (!add_key(jentry, "key", key))
+			goto fail;
+
+		if (!jarray) {
+			jarray = json_object_new_array();
+			if (!jarray)
+				goto fail;
+			json_object_object_add(jobj, "netKeys", jarray);
+		}
+
+		json_object_array_add(jarray, jentry);
+
+	} else {
+
+		if (!json_object_object_get_ex(jentry, "key", &jstring))
+			return false;
+
+		json_object_object_add(jentry, "oldKey", jstring);
+		json_object_object_del(jentry, "key");
+
+		if (!add_key(jentry, "key", key))
+			return false;
+	}
+
+
+	json_object_object_add(jentry, "keyRefresh",
+					json_object_new_int(phase));
+
+	return true;
+fail:
+
+	if (jentry)
+		json_object_put(jentry);
+
+	return false;
+}
+
+bool mesh_db_net_key_del(json_object *jobj, uint16_t idx)
+{
+	json_object *jarray, *jarray_new;
+
+	json_object_object_get_ex(jobj, "netKeys", &jarray);
+	if (!jarray)
+		return true;
+
+	/* Check if matching entry exists */
+	if (!get_key_object(jarray, idx))
+		return true;
+
+	if (json_object_array_length(jarray) == 1) {
+		json_object_object_del(jobj, "netKeys");
+		return true;
+	}
+
+	/*
+	 * There is no easy way to delete a value from json array.
+	 * Create a new copy without specified element and
+	 * then remove old array.
+	 */
+	jarray_new = jarray_key_del(jarray, idx);
+	if (!jarray_new)
+		return false;
+
+	json_object_object_del(jobj, "netKeys");
+	json_object_object_add(jobj, "netKeys", jarray_new);
+
+	return true;
+}
+
+bool mesh_db_write_device_key(json_object *jnode, uint8_t *key)
+{
+	return add_key(jnode, "deviceKey", key);
+}
+
+bool mesh_db_app_key_add(json_object *jobj, uint16_t net_idx, uint16_t app_idx,
+			 const uint8_t key[16], bool update)
+{
+	json_object *jarray, *jentry = NULL, *jstring = NULL;
+	char buf[5];
+
+	json_object_object_get_ex(jobj, "appKeys", &jarray);
+	if (!jarray && update)
+		return false;
+
+	if (jarray)
+		jentry = get_key_object(jarray, app_idx);
+
+	/* The key entry should exist if the key is updated */
+	if (!jentry  && update)
+		return false;
+
+	if (jentry) {
+		uint8_t buf[16];
+		json_object *jvalue;
+		char *str;
+
+		json_object_object_get_ex(jentry, "key", &jvalue);
+		if (!jvalue)
+			return false;
+
+		str = (char *)json_object_get_string(jvalue);
+		if (!str2hex(str, strlen(str), buf, sizeof(buf)))
+			return false;
+
+		/* If the same key, return success */
+		if (memcmp(key, buf, 16) == 0)
+			return true;
+
+		return false;
+	}
+
+	if (!update) {
+		jentry = json_object_new_object();
+		if (!jentry)
+			goto fail;
+
+		snprintf(buf, 5, "%4.4x", app_idx);
+		jstring = json_object_new_string(buf);
+		if (!jstring)
+			goto fail;
+
+		json_object_object_add(jentry, "index", jstring);
+
+		snprintf(buf, 5, "%4.4x", net_idx);
+		jstring = json_object_new_string(buf);
+		if (!jstring)
+			goto fail;
+
+		json_object_object_add(jentry, "boundNetKey", jstring);
+
+		if (!add_key(jentry, "key", key))
+			goto fail;
+
+		if (!jarray) {
+			jarray = json_object_new_array();
+			if (!jarray)
+				goto fail;
+			json_object_object_add(jobj, "appKeys", jarray);
+		}
+
+		json_object_array_add(jarray, jentry);
+
+	} else {
+
+		if (!json_object_object_get_ex(jentry, "key", &jstring))
+			return false;
+
+		json_object_object_add(jentry, "oldKey", jstring);
+		json_object_object_del(jentry, "key");
+
+		if (!add_key(jentry, "key", key))
+			return false;
+	}
+
+	return true;
+fail:
+
+	if (jentry)
+		json_object_put(jentry);
+
+	return false;
+}
+
+bool mesh_db_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx)
+{
+	json_object *jarray, *jarray_new;
+
+	json_object_object_get_ex(jobj, "appKeys", &jarray);
+	if (!jarray)
+		return true;
+
+	/* Check if matching entry exists */
+	if (!get_key_object(jarray, idx))
+		return true;
+
+	if (json_object_array_length(jarray) == 1) {
+		json_object_object_del(jobj, "appKeys");
+		return true;
+	}
+
+	/*
+	 * There is no easy way to delete a value from json array.
+	 * Create a new copy without specified element and
+	 * then remove old array.
+	 */
+	jarray_new = jarray_key_del(jarray, idx);
+	if (!jarray_new)
+		return false;
+
+	json_object_object_del(jobj, "appKeys");
+	json_object_object_add(jobj, "appKeys", jarray_new);
+
+	return true;
+}
+
+bool mesh_db_model_binding_add(json_object *jnode, uint8_t ele_idx, bool vendor,
+				uint32_t mod_id, uint16_t app_idx)
+{
+	json_object *jmodel, *jstring, *jarray;
+	char buf[5];
+
+	jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
+	if (!jmodel)
+		return false;
+
+	json_object_object_get_ex(jmodel, "bind", &jarray);
+
+	snprintf(buf, 5, "%4.4x", app_idx);
+
+	if (jarray && jarray_has_string(jarray, buf, 4))
+		return true;
+
+	jstring = json_object_new_string(buf);
+	if (!jstring)
+		return false;
+
+	if (!jarray) {
+		jarray = json_object_new_array();
+		if (!jarray) {
+			json_object_put(jstring);
+			return false;
+		}
+		json_object_object_add(jmodel, "bind", jarray);
+	}
+
+	json_object_array_add(jarray, jstring);
+
+	return true;
+}
+
+bool mesh_db_model_binding_del(json_object *jnode, uint8_t ele_idx, bool vendor,
+				uint32_t mod_id, uint16_t app_idx)
+{
+	json_object *jmodel, *jarray, *jarray_new;
+	char buf[5];
+
+	jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
+	if (!jmodel)
+		return false;
+
+	json_object_object_get_ex(jmodel, "bind", &jarray);
+
+	snprintf(buf, 5, "%4.4x", app_idx);
+
+	if (!jarray || !jarray_has_string(jarray, buf, 4))
+		return true;
+
+	if (json_object_array_length(jarray) == 1) {
+		json_object_object_del(jmodel, "bind");
+		return true;
+	}
+
+	/*
+	 * There is no easy way to delete a value from json array.
+	 * Create a new copy without specified element and
+	 * then remove old array.
+	 */
+	jarray_new = jarray_string_del(jarray, buf, 4);
+	if (!jarray_new)
+		return false;
+
+	json_object_object_del(jmodel, "bind");
+	json_object_object_add(jmodel, "bind", jarray_new);
+
+	return true;
+}
+
+static void free_model(void *data)
+{
+	struct mesh_db_model *mod = data;
+
+	l_free(mod->bindings);
+	l_free(mod->subs);
+	l_free(mod->pub);
+	l_free(mod);
+}
+
+static void free_element(void *data)
+{
+	struct mesh_db_element *ele = data;
+
+	l_queue_destroy(ele->models, free_model);
+	l_free(ele);
+}
+
+static bool parse_bindings(json_object *jbindings, struct mesh_db_model *mod)
+{
+	int cnt;
+	int i;
+
+	cnt = json_object_array_length(jbindings);
+	if (cnt > 0xffff)
+		return false;
+
+	mod->num_subs = cnt;
+
+	/* Allow empty bindings list */
+	if (!cnt)
+		return true;
+
+	mod->bindings = l_new(uint16_t, cnt);
+	if (!mod->bindings)
+		return false;
+
+	for (i = 0; i < cnt; ++i) {
+		int idx;
+		json_object *jvalue;
+
+		jvalue = json_object_array_get_idx(jbindings, i);
+		if (!jvalue)
+			return false;
+
+		idx = json_object_get_int(jvalue);
+		if (!CHECK_KEY_IDX_RANGE(idx))
+			return false;
+
+		mod->bindings[i] = (uint16_t) idx;
+	}
+
+	return true;
+}
+
+static bool parse_models(json_object *jmodels, struct mesh_db_element *ele)
+{
+	int i, num_models;
+
+	num_models = json_object_array_length(jmodels);
+	if (!num_models)
+		return true;
+
+	for (i = 0; i < num_models; ++i) {
+		json_object *jmodel, *jarray, *jvalue;
+		struct mesh_db_model *mod;
+		uint32_t id;
+		int len;
+		char *str;
+
+		jmodel = json_object_array_get_idx(jmodels, i);
+		if (!jmodel)
+			goto fail;
+
+		mod = l_new(struct mesh_db_model, 1);
+		if (!ele)
+			goto fail;
+
+		json_object_object_get_ex(jmodel, "modelId", &jvalue);
+		str = (char *)json_object_get_string(jvalue);
+
+		len = strlen(str);
+
+		if (len != 4 && len != 8)
+			goto fail;
+
+		if (len == 4) {
+			if (sscanf(str, "%04x", &id) != 1)
+				goto fail;
+
+			id |= VENDOR_ID_MASK;
+		} else if (len == 8) {
+			if (sscanf(str, "%08x", &id) != 1)
+				goto fail;
+		} else
+			goto fail;
+
+		mod->id = id;
+
+		if (len == 8)
+			mod->vendor = true;
+
+		json_object_object_get_ex(jmodel, "bind", &jarray);
+
+		if (jarray && (json_object_get_type(jmodels) != json_type_array
+					|| !parse_bindings(jarray, mod)))
+			goto fail;
+
+		/* TODO add pub/sub */
+		l_queue_push_tail(ele->models, mod);
+	}
+
+	return true;
+
+fail:
+	l_queue_destroy(ele->models, free_model);
+	return false;
+}
+
+static bool parse_elements(json_object *jelements, struct mesh_db_node *node)
+{
+	int i, num_ele;
+
+	num_ele = json_object_array_length(jelements);
+	if (!num_ele)
+		/* Allow "empty" nodes */
+		return true;
+
+	node->elements = l_queue_new();
+	if (!node->elements)
+		return false;
+
+	for (i = 0; i < num_ele; ++i) {
+		json_object *jelement;
+		json_object *jmodels;
+		json_object *jvalue;
+		struct mesh_db_element *ele;
+		int index;
+		char *str;
+
+		jelement = json_object_array_get_idx(jelements, i);
+		if (!jelement)
+			goto fail;
+
+		if (!get_int(jelement, "elementIndex", &index) ||
+								index > num_ele)
+			goto fail;
+
+		ele = l_new(struct mesh_db_element, 1);
+		if (!ele)
+			goto fail;
+
+		ele->index = index;
+		ele->models = l_queue_new();
+		if (!ele->models)
+			goto fail;
+
+		json_object_object_get_ex(jelement, "location", &jvalue);
+		str = (char *)json_object_get_string(jvalue);
+		if (sscanf(str, "%04hx", &(ele->location)) != 1)
+			goto fail;
+
+		json_object_object_get_ex(jelement, "models", &jmodels);
+
+		if (jmodels && (json_object_get_type(jmodels) != json_type_array
+				|| !parse_models(jmodels, ele)))
+			goto fail;
+
+		l_queue_push_tail(node->elements, ele);
+	}
+
+	return true;
+
+fail:
+	l_queue_destroy(node->elements, free_element);
+	node->elements = NULL;
+
+	return false;
+}
+
+static int get_mode(json_object *jvalue)
+{
+	const char *str;
+
+	str = json_object_get_string(jvalue);
+	if (!str)
+		return 0xffffffff;
+
+	if (!strncasecmp(str, "disabled", strlen("disabled")))
+		return MESH_MODE_DISABLED;
+
+	if (!strncasecmp(str, "enabled", strlen("enabled")))
+		return MESH_MODE_ENABLED;
+
+	if (!strncasecmp(str, "unsupported", strlen("unsupported")))
+		return MESH_MODE_UNSUPPORTED;
+
+	return 0xffffffff;
+}
+
+static void parse_features(json_object *jconfig, struct mesh_db_node *node)
+{
+	json_object *jvalue, *jrelay;
+	int mode, count;
+	uint16_t interval;
+
+	json_object_object_get_ex(jconfig, "proxy", &jvalue);
+	if (jvalue) {
+		mode = get_mode(jvalue);
+		if (mode <= MESH_MODE_UNSUPPORTED)
+			node->modes.proxy = mode;
+	}
+
+	json_object_object_get_ex(jconfig, "friend", &jvalue);
+	if (jvalue) {
+		mode = get_mode(jvalue);
+		if (mode <= MESH_MODE_UNSUPPORTED)
+			node->modes.friend = mode;
+	}
+
+	json_object_object_get_ex(jconfig, "lowPower", &jvalue);
+	if (jvalue) {
+		mode = get_mode(jvalue);
+		if (mode <= MESH_MODE_UNSUPPORTED)
+			node->modes.friend = mode;
+	}
+
+	json_object_object_get_ex(jconfig, "beacon", &jvalue);
+	if (jvalue) {
+		mode = get_mode(jvalue);
+		if (mode <= MESH_MODE_ENABLED)
+			node->modes.beacon = mode;
+	}
+
+	json_object_object_get_ex(jconfig, "relay", &jrelay);
+	if (!jrelay)
+		return;
+
+	json_object_object_get_ex(jrelay, "mode", &jvalue);
+	if (jvalue) {
+		mode = get_mode(jvalue);
+		if (mode <= MESH_MODE_UNSUPPORTED)
+			node->modes.relay.state = mode;
+		else
+			return;
+	} else
+		return;
+
+	json_object_object_get_ex(jrelay, "count", &jvalue);
+	if (!jvalue)
+		return;
+
+	/* TODO: check range */
+	count = json_object_get_int(jvalue);
+	node->modes.relay.cnt = count;
+
+	json_object_object_get_ex(jrelay, "interval", &jvalue);
+	if (!jvalue)
+		return;
+
+	/* TODO: check range */
+	interval = json_object_get_int(jvalue);
+	node->modes.relay.interval = interval;
+}
+
+static bool parse_composition(json_object *jcomp, struct mesh_db_node *node)
+{
+	json_object *jvalue;
+	char *str;
+
+	/* All the fields in node composition are mandatory */
+	json_object_object_get_ex(jcomp, "cid", &jvalue);
+	if (!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (sscanf(str, "%04hx", &node->cid) != 1)
+		return false;
+
+	json_object_object_get_ex(jcomp, "pid", &jvalue);
+	if (!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (sscanf(str, "%04hx", &node->pid) != 1)
+		return false;
+
+	json_object_object_get_ex(jcomp, "vid", &jvalue);
+	if (!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (sscanf(str, "%04hx", &node->vid) != 1)
+		return false;
+
+	json_object_object_get_ex(jcomp, "crpl", &jvalue);
+	if (!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (sscanf(str, "%04hx", &node->crpl) != 1)
+		return false;
+
+	return true;
+}
+
+static uint16_t get_prov_flags(json_object *jarray, uint16_t max_value)
+{
+	int i, cnt;
+	uint16_t result = 0;
+
+	cnt = json_object_array_length(jarray);
+	if (!cnt)
+		return 0;
+
+	for (i = 0; i < cnt; ++i) {
+		json_object *jvalue;
+		int value;
+
+		jvalue = json_object_array_get_idx(jarray, i);
+		value = json_object_get_int(jvalue);
+		if (value > 16)
+			continue;
+
+		if ((1 << value) > max_value)
+			continue;
+
+		result |= (1 << value);
+	}
+
+	return result;
+}
+
+bool mesh_db_read_node(json_object *jnode, mesh_db_node_cb cb, void *user_data)
+{
+	struct mesh_db_node node;
+	json_object *jvalue;
+	char *str;
+
+	if (!cb) {
+		l_info("Node read callback is required");
+		return false;
+	}
+
+	memset(&node, 0, sizeof(node));
+
+	if (!parse_composition(jnode, &node)) {
+		l_info("Failed to parse local node composition");
+		return false;
+	}
+
+	parse_features(jnode, &node);
+
+	json_object_object_get_ex(jnode, "unicastAddress", &jvalue);
+	if (!jvalue) {
+		l_info("Bad config: Unicast address must be present");
+		return false;
+	}
+
+	str = (char *)json_object_get_string(jvalue);
+	if (sscanf(str, "%04hx", &node.unicast) != 1)
+		return false;
+
+	json_object_object_get_ex(jnode, "defaultTTL", &jvalue);
+	if (jvalue) {
+		int ttl = json_object_get_int(jvalue);
+
+		if (ttl < 0 || ttl == 1 || ttl > DEFAULT_TTL)
+			return false;
+		node.ttl = (uint8_t) ttl;
+	}
+
+	json_object_object_get_ex(jnode, "sequenceNumber", &jvalue);
+	if (jvalue)
+		node.seq_number = json_object_get_int(jvalue);
+
+	json_object_object_get_ex(jnode, "elements", &jvalue);
+	if (jvalue && json_object_get_type(jvalue) == json_type_array) {
+		if (!parse_elements(jvalue, &node))
+			return false;
+	}
+
+	return cb(&node, user_data);
+}
+
+bool mesh_db_read_unprovisioned_device(json_object *jnode, mesh_db_node_cb cb,
+								void *user_data)
+{
+	struct mesh_db_node node;
+	json_object *jvalue;
+	char *str;
+
+	if (!cb) {
+		l_info("Device read callback is required");
+		return false;
+	}
+
+	memset(&node, 0, sizeof(node));
+
+	if (!parse_composition(jnode, &node)) {
+		l_info("Failed to parse local device composition");
+		return false;
+	}
+
+	parse_features(jnode, &node);
+
+	json_object_object_get_ex(jnode, "elements", &jvalue);
+	if (jvalue && json_object_get_type(jvalue) == json_type_array) {
+		if (!parse_elements(jvalue, &node))
+			return false;
+	}
+
+	json_object_object_get_ex(jnode, "UUID", &jvalue);
+	if (!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (!str2hex(str, strlen(str), node.uuid, 16))
+		return false;
+
+	return cb(&node, user_data);
+}
+
+bool mesh_db_read_prov_info(json_object *jnode, struct mesh_db_prov *prov)
+{
+	json_object *jprov, *jarray, *jvalue, *jobj;
+	int value;
+	char *str;
+
+	if (!prov)
+		return false;
+
+	json_object_object_get_ex(jnode, "provision", &jprov);
+	if (!jprov)
+		return false;
+
+	json_object_object_get_ex(jprov, "algorithms", &jarray);
+	if (!jarray || json_object_get_type(jarray) != json_type_array)
+		return false;
+
+	prov->algorithm = get_prov_flags(jarray, ALG_FIPS_256_ECC);
+	if (!prov->algorithm) {
+		l_info("At least one algorithm must be indicated");
+		return false;
+	}
+
+	json_object_object_get_ex(jprov, "outputOOB", &jobj);
+	json_object_object_get_ex(jobj, "size", &jvalue);
+	value = json_object_get_int(jvalue);
+	if (value > 8)
+		return false;
+
+	prov->output_oob.size = (uint8_t) value;
+	json_object_object_get_ex(jobj, "actions", &jarray);
+	if (!jarray || json_object_get_type(jarray) != json_type_array)
+		return false;
+
+	prov->output_oob.actions = get_prov_flags(jarray, OOB_OUT_ALPHA);
+
+	json_object_object_get_ex(jprov, "inputOOB", &jobj);
+	json_object_object_get_ex(jobj, "size", &jvalue);
+	value = json_object_get_int(jvalue);
+	if (value > 8)
+		return false;
+
+	prov->input_oob.size = (uint8_t) value;
+	json_object_object_get_ex(jobj, "actions", &jarray);
+	if (!jarray || json_object_get_type(jarray) != json_type_array)
+		return false;
+
+	prov->input_oob.actions = get_prov_flags(jarray, OOB_IN_ALPHA);
+
+	json_object_object_get_ex(jprov, "publicType", &jvalue);
+	prov->pub_type = (json_object_get_boolean(jvalue)) ? 1 : 0;
+
+	json_object_object_get_ex(jprov, "staticType", &jvalue);
+	prov->static_type = (json_object_get_boolean(jvalue)) ? 1 : 0;
+
+	json_object_object_get_ex(jprov, "privateKey", &jvalue);
+	if (!jvalue)
+		return false;
+
+	str = (char *)json_object_get_string(jvalue);
+	if (!str2hex(str, strlen(str), prov->priv_key, 32))
+		return false;
+
+	return true;
+}
+
+bool mesh_db_write_uint16_hex(json_object *jobj, const char *desc,
+								uint16_t value)
+{
+	json_object *jstring;
+	char buf[5];
+
+	snprintf(buf, 5, "%4.4x", value);
+	jstring = json_object_new_string(buf);
+	if (!jstring)
+		return false;
+
+	json_object_object_add(jobj, desc, jstring);
+	return true;
+}
+
+bool mesh_db_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);
+	if (!jvalue)
+		return false;
+
+	json_object_object_add(jobj, keyword, jvalue);
+	return true;
+}
+
+bool mesh_db_write_bool(json_object *jobj, const char *keyword, bool value)
+{
+	json_object *jvalue;
+
+	json_object_object_del(jobj, keyword);
+
+	jvalue = json_object_new_boolean(value);
+	if (!jvalue)
+		return false;
+
+	json_object_object_add(jobj, keyword, jvalue);
+	return true;
+}
+
+bool mesh_db_write_mode(json_object *jobj, const char *keyword, int value)
+{
+	json_object *jstring;
+
+	switch (value) {
+	case MESH_MODE_DISABLED:
+		jstring = json_object_new_string("disabled");
+		break;
+	case MESH_MODE_ENABLED:
+		jstring = json_object_new_string("enabled");
+		break;
+	case MESH_MODE_UNSUPPORTED:
+		jstring = json_object_new_string("unsupported");
+		break;
+	default:
+		return false;
+	};
+
+	if (!jstring)
+		return false;
+
+	json_object_object_add(jobj, keyword, jstring);
+
+	return true;
+}
+
+bool mesh_db_write_relay_mode(json_object *jnode, uint8_t mode, uint8_t count,
+							uint16_t interval)
+{
+	json_object *jrelay;
+
+	json_object_object_del(jnode, "relay");
+
+	jrelay = json_object_new_object();
+	if (jrelay)
+		return false;
+
+	if (!mesh_db_write_mode(jrelay, "mode", mode))
+		goto fail;
+
+	if (!mesh_db_write_int(jrelay, "count", count))
+		goto fail;
+
+	if (!mesh_db_write_int(jrelay, "interval", interval))
+		goto fail;
+
+	json_object_object_add(jnode, "relay", jrelay);
+
+	return true;
+fail:
+	json_object_put(jrelay);
+	return false;
+}
+
+bool mesh_db_read_net_transmit(json_object *jobj, uint8_t *cnt,
+							uint16_t *interval)
+{
+	json_object *jretransmit, *jvalue;
+
+	json_object_object_get_ex(jobj, "retransmit", &jretransmit);
+	if (!jretransmit)
+		return false;
+
+	json_object_object_get_ex(jretransmit, "count", &jvalue);
+	if (!jvalue)
+		return false;
+
+	*cnt = (uint8_t) json_object_get_int(jvalue);
+
+	json_object_object_get_ex(jretransmit, "interval", &jvalue);
+	if (!jvalue)
+		return false;
+
+	*interval = (uint16_t) json_object_get_int(jvalue);
+
+	return true;
+}
+
+bool mesh_db_write_net_transmit(json_object *jobj, uint8_t cnt,
+							uint16_t interval)
+{
+	json_object *jretransmit;
+
+	json_object_object_del(jobj, "retransmit");
+
+	jretransmit = json_object_new_object();
+	if (jretransmit)
+		return false;
+
+	if (!mesh_db_write_int(jretransmit, "count", cnt))
+		goto fail;
+
+	if (!mesh_db_write_int(jretransmit, "interval", interval))
+		goto fail;
+
+	json_object_object_add(jobj, "retransmit", jretransmit);
+
+	return true;
+fail:
+	json_object_put(jretransmit);
+	return false;
+
+}
+
+bool mesh_db_write_iv_index(json_object *jobj, uint32_t idx, bool update)
+{
+	int tmp = update ? 1 : 0;
+
+	if (!mesh_db_write_int(jobj, "IVindex", idx))
+		return false;
+
+	if (!mesh_db_write_int(jobj, "IVupdate", tmp))
+		return false;
+
+	return true;
+}
+
+void mesh_db_remove_property(json_object *jobj, const char *desc)
+{
+	json_object_object_del(jobj, desc);
+}
diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
new file mode 100644
index 000000000..336302f28
--- /dev/null
+++ b/mesh/mesh-db.h
@@ -0,0 +1,144 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2018  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *
+ */
+
+#include <json-c/json.h>
+
+struct mesh_db_sub {
+	bool virt;
+	union {
+		uint16_t addr;
+		uint8_t	virt_addr[16];
+	} src;
+};
+
+struct mesh_db_pub {
+	bool virt;
+	uint16_t addr;
+	uint16_t idx;
+	uint8_t ttl;
+	uint8_t credential;
+	uint8_t period;
+	uint8_t retransmit;
+	uint8_t virt_addr[16];
+};
+
+struct mesh_db_model {
+	struct mesh_db_sub *subs;
+	struct mesh_db_pub *pub;
+	uint16_t *bindings;
+	uint32_t id;
+	bool vendor;
+	uint32_t num_bindings;
+	uint32_t num_subs;
+};
+
+struct mesh_db_element {
+	struct l_queue *models;
+	uint16_t location;
+	uint8_t index;
+};
+
+struct mesh_db_modes {
+	struct {
+		uint16_t interval;
+		uint8_t cnt;
+		uint8_t state;
+	} relay;
+	uint8_t lpn;
+	uint8_t friend;
+	uint8_t proxy;
+	uint8_t beacon;
+};
+
+struct mesh_db_node {
+	bool provisioner;
+	uint32_t seq_number;
+	struct mesh_db_modes modes;
+	uint16_t cid;
+	uint16_t pid;
+	uint16_t vid;
+	uint16_t crpl;
+	uint16_t unicast;
+	uint8_t ttl;
+	struct l_queue *elements;
+	uint8_t uuid[16];
+};
+
+struct mesh_db_prov {
+	uint16_t algorithm;
+	struct {
+		uint16_t actions;
+		uint8_t size;
+	} input_oob;
+	uint8_t pub_type;
+	struct {
+		uint16_t actions;
+		uint8_t size;
+	} output_oob;
+	uint8_t static_type;
+	uint8_t priv_key[32];
+};
+
+typedef bool (*mesh_db_net_key_cb)(uint16_t idx, uint8_t key[16],
+			uint8_t new_key[16], int phase, void *user_data);
+typedef bool (*mesh_db_app_key_cb)(uint16_t idx, uint16_t net_idx,
+			uint8_t key[16], uint8_t new_key[16], void *user_data);
+typedef bool (*mesh_db_node_cb)(struct mesh_db_node *node, void *user_data);
+
+bool mesh_db_read_node(json_object *jobj, mesh_db_node_cb cb, void *user_data);
+bool mesh_db_read_unprovisioned_device(json_object *jnode, mesh_db_node_cb cb,
+							void *user_data);
+bool mesh_db_read_prov_info(json_object *jnode, struct mesh_db_prov *prov);
+bool mesh_db_read_iv_index(json_object *jobj, uint32_t *idx, bool *update);
+bool mesh_db_read_device_key(json_object *jobj, uint8_t key_buf[16]);
+bool mesh_db_read_net_transmit(json_object *jobj, uint8_t *cnt,
+							uint16_t *interval);
+bool mesh_db_write_net_transmit(json_object *jobj, uint8_t cnt,
+							uint16_t interval);
+bool mesh_db_read_net_keys(json_object *jobj, mesh_db_net_key_cb cb,
+							void *user_data);
+bool mesh_db_read_app_keys(json_object *jobj, mesh_db_app_key_cb cb,
+							void *user_data);
+bool mesh_db_write_device_key(json_object *jobj, uint8_t *key);
+bool mesh_db_write_network_key(json_object *jobj, uint16_t idx, uint8_t *key,
+						uint8_t *new_key, int phase);
+bool mesh_db_write_app_key(json_object *jobj, uint16_t net_idx,
+			uint16_t app_idx, uint8_t *key, uint8_t *new_key);
+bool mesh_db_write_int(json_object *jobj, const char *keyword, int value);
+bool mesh_db_write_uint16_hex(json_object *jobj, const char *desc,
+								uint16_t value);
+bool mesh_db_write_bool(json_object *jobj, const char *keyword, bool value);
+bool mesh_db_write_relay_mode(json_object *jnode, uint8_t mode, uint8_t count,
+							uint16_t interval);
+bool mesh_db_write_mode(json_object *jobj, const char *keyword, int value);
+bool mesh_db_model_binding_add(json_object *jnode, uint8_t ele_idx, bool vendor,
+					uint32_t mod_id, uint16_t app_idx);
+bool mesh_db_model_binding_del(json_object *jnode, uint8_t ele_idx, bool vendor,
+					uint32_t mod_id, uint16_t app_idx);
+bool mesh_db_app_key_add(json_object *jnode, uint16_t net_idx, uint16_t app_idx,
+					const uint8_t key[16], bool update);
+bool mesh_db_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx);
+bool mesh_db_net_key_add(json_object *jobj, uint16_t net_idx,
+					const uint8_t key[16], int phase);
+bool mesh_db_net_key_del(json_object *jobj, uint16_t net_idx);
+bool mesh_db_write_kr_phase(json_object *jobj, uint16_t net_idx, int phase);
+bool mesh_db_write_address(json_object *jobj, uint16_t address);
+bool mesh_db_write_iv_index(json_object *jobj, uint32_t idx, bool update);
+void mesh_db_remove_property(json_object *jobj, const char *desc);
-- 
2.14.4

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux