Mesh: Add support for Configuration DB & Node API
authorAnupam Roy <anupam.r@samsung.com>
Fri, 17 Jul 2020 10:30:54 +0000 (16:00 +0530)
committerAnupam Roy <anupam.r@samsung.com>
Fri, 17 Jul 2020 10:30:54 +0000 (16:00 +0530)
This patch handles following
- JSON DB for remembering configured network
- Structures & API for accessing provisioned nodes

Change-Id: I2abf92481863c18e8f3c970074f26151587c2c08
Signed-off-by: Anupam Roy <anupam.r@samsung.com>
bt-service/CMakeLists.txt
bt-service/services/include/bt-service-mesh-cdb.h [new file with mode: 0644]
bt-service/services/include/bt-service-mesh-nodes.h [new file with mode: 0644]
bt-service/services/mesh/bt-service-mesh-cdb.c [new file with mode: 0644]
bt-service/services/mesh/bt-service-mesh-nodes.c [new file with mode: 0644]

index a3cc685..cdc7843 100644 (file)
@@ -33,6 +33,8 @@ SET(SRCS
 ./services/audio/hf/bt-service-hf-client.c
 ./services/mesh/bt-service-mesh-util.c
 ./services/mesh/bt-service-mesh-keys.c
+./services/mesh/bt-service-mesh-cdb.c
+./services/mesh/bt-service-mesh-nodes.c
 )
 
 IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_FEATURE_BT_OBEX")
diff --git a/bt-service/services/include/bt-service-mesh-cdb.h b/bt-service/services/include/bt-service-mesh-cdb.h
new file mode 100644 (file)
index 0000000..0da6a59
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Anupam Roy <anupam.r@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *              http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef BT_SERVICE_MESH_CDB_H_
+#define BT_SERVICE_MESH_CDB_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include <json-c/json.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+       char *cfg_fname;
+       char *app_cred;
+       json_object *jcfg;
+       uint8_t token[8];
+       uint8_t uuid[16]; /* Network UUID */
+       struct timeval write_time;
+       GSList *groups;
+} _bt_mesh_cdb_t;
+
+/* Virtual Group */
+typedef struct {
+       uint8_t label_uuid[16];
+       uint16_t grp_addr;
+} _bt_mesh_group_t;
+
+
+void _bt_mesh_conf_free(_bt_mesh_cdb_t *cfg);
+
+bool _bt_mesh_conf_parse_data(void *cfg, int k);
+
+_bt_mesh_cdb_t * _bt_mesh_conf_database_create(const char *file_name,
+       const uint8_t uuid[16], const uint8_t token[8],
+               const char *network_name,
+                       const char *app_cred);
+
+bool _bt_mesh_conf_set_phase_network_key(_bt_mesh_cdb_t *cfg,
+       uint16_t net_idx, uint8_t phase);
+
+bool _bt_mesh_conf_delete_application_key(_bt_mesh_cdb_t *cfg,
+               uint16_t app_idx);
+
+bool _bt_mesh_conf_insert_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t idx, uint8_t key_refresh);
+
+bool _bt_mesh_conf_delete_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t net_idx);
+
+bool _bt_mesh_conf_set_unicast_address_range(_bt_mesh_cdb_t *cfg,
+               uint16_t low, uint16_t high);
+
+bool _bt_mesh_conf_insert_node_object(_bt_mesh_cdb_t *cfg,
+               uint8_t uuid[16], uint8_t num_els,
+                       uint16_t unicast, uint16_t net_idx);
+
+bool _bt_mesh_conf_get_element_count(_bt_mesh_cdb_t *cfg,
+               uint16_t *num_elems);
+
+uint16_t** _bt_mesh_conf_get_all_model_info(_bt_mesh_cdb_t *cfg,
+               int element_index, int *num_models);
+
+bool _bt_mesh_conf_get_token_info(uint8_t token[8]);
+
+bool _bt_mesh_conf_insert_application_key(_bt_mesh_cdb_t *cfg,
+               uint16_t net_idx, uint16_t app_idx);
+
+bool _bt_mesh_conf_get_unicast_address_range(uint16_t *low,
+       uint16_t *high);
+
+bool _bt_mesh_conf_node_set_network_transmission(uint16_t unicast,
+               uint8_t cnt, uint16_t interval);
+
+bool _bt_mesh_conf_node_insert_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t idx);
+
+bool _bt_mesh_conf_node_delete_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t idx);
+
+bool _bt_mesh_conf_node_insert_application_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t idx);
+
+bool _bt_mesh_conf_node_delete_application_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t idx);
+
+bool _bt_mesh_conf_node_set_timetolive_value(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint8_t ttl);
+
+bool _bt_mesh_conf_node_set_write_op_mode(uint16_t unicast,
+               const char *keyword, int value);
+
+bool _bt_mesh_conf_bind_model(uint16_t unicast,
+               uint8_t ele, bool vendor,
+                       uint32_t mod_id, uint16_t app_idx);
+
+bool _bt_mesh_conf_unbind_model(uint16_t unicast,
+               uint8_t ele, bool vendor,
+                       uint32_t mod_id, uint16_t app_idx);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* BT_SERVICE_MESH_CDB_H_ */
diff --git a/bt-service/services/include/bt-service-mesh-nodes.h b/bt-service/services/include/bt-service-mesh-nodes.h
new file mode 100644 (file)
index 0000000..32b2973
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Anupam Roy <anupam.r@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *              http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef BT_SERVICE_MESH_NODES_H_
+#define BT_SERVICE_MESH_NODES_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include "bt-service-mesh-cdb.h"
+#include <json-c/json.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _bt_mesh_node_load_net(uint8_t net_uuid[]);
+
+void _bt_mesh_node_unload_net(_bt_mesh_cdb_t *cfg);
+
+bool _bt_mesh_node_add_node(uint8_t net_uuid[],
+       const uint8_t uuid[16], uint16_t unicast,
+               uint8_t ele_cnt, uint16_t net_idx);
+
+uint8_t _bt_mesh_node_del_node(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast);
+
+bool _bt_mesh_node_set_model(uint8_t net_uuid[],
+               uint16_t unicast, uint8_t ele_idx,
+                       uint32_t mod_id, bool vendor);
+
+uint16_t _bt_mesh_node_get_next_unicast(uint8_t net_uuid[],
+               uint16_t low, uint16_t high,
+                       uint8_t ele_cnt);
+
+bool _bt_mesh_node_is_netkey_added(uint8_t net_uuid[],
+               uint16_t net_idx);
+
+bool _bt_mesh_node_is_appkey_added(uint8_t net_uuid[],
+       uint16_t app_idx);
+
+bool _bt_mesh_node_add_net_key(uint8_t net_uuid[],
+               uint16_t addr, uint16_t net_idx);
+
+bool _bt_mesh_node_del_net_key(_bt_mesh_cdb_t *cfg,
+               uint8_t net_uuid[], uint16_t addr,
+                       uint16_t net_idx);
+
+bool _bt_mesh_node_add_app_key(uint8_t net_uuid[],
+               uint16_t addr, uint16_t app_idx);
+
+bool _bt_mesh_node_del_app_key(uint8_t net_uuid[],
+               uint16_t addr, uint16_t app_idx);
+
+uint16_t _bt_mesh_node_get_subnet_idx(uint8_t net_uuid[],
+               uint16_t addr);
+
+void _bt_mesh_node_print_node(uint8_t net_uuid[],
+               uint16_t addr);
+
+void _bt_mesh_node_print_all(uint8_t net_uuid[]);
+
+bool _bt_mesh_node_get_all(uint8_t net_uuid[], GArray **out);
+
+bool _bt_mesh_node_get_models(uint8_t net_uuid[],
+               uint16_t unicast, uint8_t ele_idx,
+                       GArray **out);
+
+bool _bt_mesh_node_get_unicast_from_dev_uuid(uint8_t net_uuid[],
+               const uint8_t dev_uuid[16], uint16_t *unicast);
+
+bool _bt_mesh_node_get_element_count(uint8_t net_uuid[],
+               uint16_t unicast, uint8_t *count);
+
+bool _bt_mesh_node_get_all_netkeys(uint8_t net_uuid[],
+               uint16_t unicast, GArray **out);
+
+bool _bt_mesh_node_get_all_appkeys(uint8_t net_uuid[],
+               uint16_t unicast, GArray **out);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* BT_SERVICE_MESH_NODES_H_ */
diff --git a/bt-service/services/mesh/bt-service-mesh-cdb.c b/bt-service/services/mesh/bt-service-mesh-cdb.c
new file mode 100644 (file)
index 0000000..ded20c5
--- /dev/null
@@ -0,0 +1,845 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Anupam Roy <anupam.r@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *              http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <glib.h>
+#include <dlog.h>
+#include "bt-service-common.h"
+#include "bt-service-core-adapter.h"
+#include "bt-service-event-receiver.h"
+#include "bt-request-handler.h"
+#include "bluetooth-api.h"
+
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include "bt-internal-types.h"
+#include "bt-service-util.h"
+#include "bt-service-common.h"
+#include "bt-service-event.h"
+#include "bt-service-mesh-cdb.h"
+#include "bt-service-mesh-nodes.h"
+#include "bt-service-mesh-keys.h"
+#include "bt-service-mesh-util.h"
+
+#include "bt-internal-types.h"
+
+#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 <sys/time.h>
+#include <ell/ell.h>
+
+#include <oal-hardware.h>
+#include <oal-manager.h>
+#include <oal-event.h>
+#include <oal-adapter-mgr.h>
+#include <oal-device-mgr.h>
+#include <oal-gatt.h>
+
+static const char *bak_ext = ".bak";
+static const char *tmp_ext = ".tmp";
+
+static bool __bt_mesh_save_cdb(
+               _bt_mesh_cdb_t *cfg, const char *fname)
+{
+       FILE *outfile;
+       const char *str;
+       bool result = false;
+
+       outfile = fopen(fname, "w");
+       if (!outfile) {
+               BT_ERR("Failed to save configuration to %s",
+                               cfg->cfg_fname);
+               return false;
+       }
+
+       str = json_object_to_json_string_ext(cfg->jcfg,
+                       JSON_C_TO_STRING_PRETTY);
+
+       if (fwrite(str, sizeof(char), strlen(str), outfile) < strlen(str))
+               BT_ERR("Incomplete write of mesh configuration");
+       else
+               result = true;
+
+       fclose(outfile);
+
+       return result;
+}
+
+static bool __bt_mesh_save_configruation_file(_bt_mesh_cdb_t *cfg)
+{
+       char *fname_tmp, *fname_bak, *fname_cfg;
+       bool result = false;
+
+       fname_cfg = cfg->cfg_fname;
+       fname_tmp = g_strdup_printf("%s%s", fname_cfg, tmp_ext);
+       fname_bak = g_strdup_printf("%s%s", fname_cfg, bak_ext);
+       remove(fname_tmp);
+
+       result = __bt_mesh_save_cdb(cfg, fname_tmp);
+
+       if (result) {
+               remove(fname_bak);
+               rename(fname_cfg, fname_bak);
+               rename(fname_tmp, fname_cfg);
+       }
+
+       remove(fname_tmp);
+
+       g_free(fname_tmp);
+       g_free(fname_bak);
+
+       gettimeofday(&cfg->write_time, NULL);
+
+       return result;
+}
+
+static bool __mesh_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) {
+               BT_ERR("MESH:Error: %s should contain an integer value\n",
+                               keyword);
+               return false;
+       }
+
+       return true;
+}
+
+static bool __mesh_write_int(json_object *jobj,
+               const char *keyword, int val)
+{
+       json_object *jval;
+
+       json_object_object_del(jobj, keyword);
+
+       jval = json_object_new_int(val);
+       if (!jval)
+               return false;
+
+       json_object_object_add(jobj, keyword, jval);
+       return true;
+}
+
+static bool __mesh_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;
+}
+
+static bool __mesh_add_app_key(json_object *jobj,
+               uint16_t net_idx, uint16_t app_idx)
+{
+       json_object *jkey, *jarray;
+
+       json_object_object_get_ex(jobj, "appKeys", &jarray);
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       jkey = json_object_new_object();
+
+       if (!__mesh_write_int(jkey, "boundNetKey", (int)net_idx))
+               goto fail;
+
+       if (!__mesh_write_int(jkey, "index", (int)app_idx))
+               goto fail;
+
+       json_object_array_add(jarray, jkey);
+
+       return true;
+fail:
+       json_object_put(jkey);
+       return false;
+}
+
+static bool __mesh_add_node_key(_bt_mesh_cdb_t *cfg,
+               json_object *jobj, const char *desc, uint16_t idx)
+{
+       json_object *jkey, *jarray;
+
+       json_object_object_get_ex(jobj, desc, &jarray);
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       jkey = json_object_new_object();
+
+       if (!__mesh_write_int(jkey, "index", (int)idx)) {
+               json_object_put(jkey);
+               return false;
+       }
+
+       json_object_array_add(jarray, jkey);
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+static json_object *__mesh_get_node_by_unicast(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast)
+{
+       json_object *jarray;
+       int i, sz;
+
+       if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jarray))
+               return NULL;
+
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return NULL;
+
+       sz = json_object_array_length(jarray);
+
+       for (i = 0; i < sz; ++i) {
+               json_object *jentry, *jval;
+               uint16_t addr;
+               const char *str;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               if (!json_object_object_get_ex(jentry, "unicastAddress",
+                                       &jval))
+                       return NULL;
+
+               str = json_object_get_string(jval);
+               if (sscanf(str, "%04hx", &addr) != 1)
+                       continue;
+
+               if (addr == unicast)
+                       return jentry;
+       }
+
+       return NULL;
+}
+
+static json_object *__mesh_get_node_by_uuid(json_object *jcfg,
+               uint8_t uuid[16])
+{
+       json_object *jarray = NULL;
+       char buf[33];
+       int i, sz;
+
+       _bt_mesh_util_convert_hex_to_string(uuid, 16, buf, sizeof(buf));
+
+       json_object_object_get_ex(jcfg, "nodes", &jarray);
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return NULL;
+
+       sz = json_object_array_length(jarray);
+
+       for (i = 0; i < sz; ++i) {
+               json_object *jentry, *jval;
+               const char *str;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               if (!json_object_object_get_ex(jentry, "uuid", &jval))
+                       return NULL;
+
+               str = json_object_get_string(jval);
+               if (strlen(str) != 32)
+                       continue;
+
+               if (!g_strcmp0(buf, str))
+                       return jentry;
+       }
+
+       return NULL;
+}
+
+static json_object *__mesh_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;
+               int jidx;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               if (!__mesh_get_int(jentry, "index", &jidx))
+                       return NULL;
+
+               if (jidx == idx)
+                       return jentry;
+       }
+
+       return NULL;
+}
+
+static bool __mesh_add_string(json_object *jobj,
+               const char *desc, const char *str)
+{
+       json_object *jstring = json_object_new_string(str);
+
+       if (!jstring)
+               return false;
+
+       json_object_object_add(jobj, desc, jstring);
+       return true;
+}
+
+static bool __mesh_add_u8_8(json_object *jobj,
+               const char *desc, const uint8_t value[8])
+{
+       json_object *jstring;
+       char buf[17];
+
+       _bt_mesh_util_convert_hex_to_string((uint8_t *) value, 8, buf, 17);
+       jstring = json_object_new_string(buf);
+       if (!jstring)
+               return false;
+
+       json_object_object_add(jobj, desc, jstring);
+       return true;
+}
+
+static bool __mesh_add_u8_16(json_object *jobj,
+               const char *desc, const uint8_t value[16])
+{
+       json_object *jstring;
+       char buf[33];
+
+       _bt_mesh_util_convert_hex_to_string((uint8_t *) value, 16, buf, 33);
+       jstring = json_object_new_string(buf);
+       if (!jstring)
+               return false;
+
+       json_object_object_add(jobj, desc, jstring);
+       return true;
+}
+
+void _bt_mesh_conf_free(_bt_mesh_cdb_t *cfg)
+{
+       g_free(cfg->cfg_fname);
+       g_free(cfg->app_cred);
+       json_object_put(cfg->jcfg);
+       g_free(cfg);
+}
+
+bool _bt_mesh_conf_parse_data(void *cfg,  int k)
+{
+       _bt_mesh_cdb_t *conf = (_bt_mesh_cdb_t*) cfg;
+       if (!conf)
+               return false;
+       return true;
+}
+
+static void __mesh_jarray_key_del(json_object *jarray, int16_t idx)
+{
+       int i, sz = json_object_array_length(jarray);
+
+       for (i = 0; i < sz; ++i) {
+               json_object *jentry;
+               int val;
+
+               jentry = json_object_array_get_idx(jarray, i);
+
+               if (!__mesh_get_int(jentry, "index", &val))
+                       continue;
+
+               if (val == idx) {
+                       json_object_array_del_idx(jarray, i, 1);
+                       return;
+               }
+       }
+}
+
+static bool __mesh_delete_key(_bt_mesh_cdb_t *cfg,
+               json_object *jobj, const char *desc, uint16_t idx)
+{
+       json_object *jarray;
+
+       if (!json_object_object_get_ex(jobj, desc, &jarray))
+               return true;
+
+       __mesh_jarray_key_del(jarray, idx);
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+bool _bt_mesh_conf_set_phase_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t net_idx, uint8_t phase)
+{
+       json_object *jval, *jarray, *jkey;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       json_object_object_get_ex(cfg->jcfg, "netKeys", &jarray);
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       jkey = __mesh_get_key_object(jarray, net_idx);
+       if (!jkey)
+               return false;
+
+       jval = json_object_new_int(phase);
+       if (!jval)
+               return false;
+
+       json_object_object_add(jkey, "phase", jval);
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+bool _bt_mesh_conf_delete_application_key(_bt_mesh_cdb_t *cfg, uint16_t app_idx)
+{
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       return __mesh_delete_key(cfg, cfg->jcfg, "appKeys", app_idx);
+}
+
+bool _bt_mesh_conf_set_unicast_address_range(_bt_mesh_cdb_t *cfg,
+               uint16_t low, uint16_t high)
+{
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       if (!__mesh_write_uint16_hex(cfg->jcfg, "low", low))
+               return false;
+
+       if (!__mesh_write_uint16_hex(cfg->jcfg, "high", high))
+               return false;
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+bool _bt_mesh_conf_insert_node_object(_bt_mesh_cdb_t *cfg,
+               uint8_t uuid[16], uint8_t num_els,
+                       uint16_t unicast, uint16_t net_idx)
+{
+       json_object *jnode;
+       json_object *jelements, *jnodes, *jnetkeys, *jappkeys;
+       int i;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_uuid(cfg->jcfg, uuid);
+       if (jnode) {
+               BT_ERR("MESH:Node already exists");
+               return false;
+       }
+
+       jnode = json_object_new_object();
+       if (!jnode)
+               return false;
+
+       if (!__mesh_add_u8_16(jnode, "uuid", uuid))
+               goto fail;
+
+       jelements = json_object_new_array();
+       if (!jelements)
+               goto fail;
+
+       for (i = 0; i < num_els; ++i) {
+               json_object *jelement = json_object_new_object();
+
+               if (!jelement) {
+                       json_object_put(jelements);
+                       goto fail;
+               }
+
+               __mesh_write_int(jelement, "elementIndex", i);
+               json_object_array_add(jelements, jelement);
+       }
+
+       json_object_object_add(jnode, "elements", jelements);
+
+       jnetkeys = json_object_new_array();
+       if (!jnetkeys)
+               goto fail;
+
+       json_object_object_add(jnode, "netKeys", jnetkeys);
+
+       if (!__mesh_add_node_key(cfg, jnode, "netKeys", net_idx))
+               goto fail;
+
+       jappkeys = json_object_new_array();
+       if (!jappkeys)
+               goto fail;
+
+       json_object_object_add(jnode, "appKeys", jappkeys);
+
+       if (!__mesh_write_uint16_hex(jnode, "unicastAddress", unicast))
+               goto fail;
+
+       if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jnodes))
+               goto fail;
+
+       json_object_array_add(jnodes, jnode);
+
+       if (!__bt_mesh_save_configruation_file(cfg))
+               goto fail;
+
+       return true;
+
+fail:
+       json_object_put(jnode);
+       return false;
+}
+
+bool _bt_mesh_conf_insert_application_key(_bt_mesh_cdb_t *cfg,
+               uint16_t net_idx, uint16_t app_idx)
+{
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       if (!__mesh_add_app_key(cfg->jcfg, net_idx, app_idx))
+               return false;
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+bool _bt_mesh_conf_insert_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t net_idx, uint8_t key_refresh)
+{
+       json_object *jkey, *jarray;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       json_object_object_get_ex(cfg->jcfg, "netKeys", &jarray);
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       if (__mesh_get_key_object(jarray, net_idx))
+               return true;
+
+       jkey = json_object_new_object();
+
+       if (!__mesh_write_int(jkey, "index", net_idx))
+               goto fail;
+
+       if (!__mesh_write_int(jkey, "phase", key_refresh))
+               goto fail;
+
+       json_object_array_add(jarray, jkey);
+
+       return __bt_mesh_save_configruation_file(cfg);
+
+fail:
+       json_object_put(jkey);
+       return false;
+}
+
+bool _bt_mesh_conf_delete_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t net_idx)
+{
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       return __mesh_delete_key(cfg, cfg->jcfg, "netKeys", net_idx);
+}
+
+
+bool _bt_mesh_conf_node_set_timetolive_value(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint8_t ttl)
+{
+       json_object *jnode;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_unicast(cfg, unicast);
+       if (!jnode)
+               return false;
+
+       if (!__mesh_write_int(jnode, "defaultTTL", ttl))
+               return false;
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+bool _bt_mesh_conf_node_insert_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t net_idx)
+{
+       json_object *jnode;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_unicast(cfg, unicast);
+       if (!jnode)
+               return false;
+
+       return __mesh_add_node_key(cfg, jnode, "netKeys", net_idx);
+}
+
+bool _bt_mesh_conf_node_delete_network_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t net_idx)
+{
+       json_object *jnode;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_unicast(cfg, unicast);
+       if (!jnode)
+               return false;
+
+       return __mesh_delete_key(cfg, jnode, "netKeys", net_idx);
+}
+
+bool _bt_mesh_conf_node_insert_application_key(_bt_mesh_cdb_t *cfg,
+               uint16_t unicast, uint16_t idx)
+{
+       json_object *jnode;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_unicast(cfg, unicast);
+       if (!jnode)
+               return false;
+
+       return __mesh_add_node_key(cfg, jnode, "appKeys", idx);
+}
+
+bool _bt_mesh_conf_node_delete_application_key(_bt_mesh_cdb_t *cfg,
+       uint16_t unicast, uint16_t idx)
+{
+       json_object *jnode;
+
+       if (!cfg || !cfg->jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_unicast(cfg, unicast);
+       if (!jnode)
+               return false;
+
+       return __mesh_delete_key(cfg, jnode, "appKeys", idx);
+}
+
+_bt_mesh_cdb_t *_bt_mesh_conf_database_create(const char *file_name,
+               const uint8_t uuid[16],
+                       const uint8_t token[8], const char *network_name,
+                               const char *app_cred)
+{
+       _bt_mesh_cdb_t *cfg;
+       json_object *jcfg, *jarray;
+
+       if (!file_name)
+               return NULL;
+
+       if (!network_name)
+               return NULL;
+
+       if (!app_cred)
+               return NULL;
+
+       jcfg = json_object_new_object();
+       if (!jcfg)
+               return NULL;
+
+       cfg = g_malloc0(sizeof(_bt_mesh_cdb_t));
+       cfg->jcfg = jcfg;
+       cfg->cfg_fname = g_strdup(file_name);
+       cfg->app_cred = g_strdup(app_cred);
+       memcpy(&cfg->token, (void*)token, 8);
+       memcpy(&cfg->uuid, (void*)uuid, 16);
+
+       if (!__mesh_add_u8_8(jcfg, "Network_Token", token))
+               goto fail;
+
+       if (!__mesh_add_u8_16(jcfg, "Config_Node_UUID", uuid))
+               goto fail;
+
+       if (!__mesh_add_string(jcfg, "Network_Name", network_name))
+               goto fail;
+
+       if (!__mesh_add_string(jcfg, "Application_Credential", app_cred))
+               goto fail;
+
+       jarray = json_object_new_array();
+       if (!jarray)
+               goto fail;
+
+       json_object_object_add(jcfg, "nodes", jarray);
+
+       jarray = json_object_new_array();
+       if (!jarray)
+               goto fail;
+
+       json_object_object_add(jcfg, "netKeys", jarray);
+
+       jarray = json_object_new_array();
+       if (!jarray)
+               goto fail;
+
+       json_object_object_add(jcfg, "appKeys", jarray);
+
+       if (!__bt_mesh_save_configruation_file(cfg))
+               goto fail;
+
+       return cfg;
+
+fail:
+       _bt_mesh_conf_free(cfg);
+
+       return NULL;
+}
+
+bool _bt_mesh_conf_delete_node(_bt_mesh_cdb_t *cfg, uint16_t unicast)
+{
+       json_object *jarray;
+       int i, sz;
+
+       if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jarray))
+               return false;
+
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       sz = json_object_array_length(jarray);
+
+       for (i = 0; i < sz; ++i) {
+               json_object *jentry, *jval;
+               uint16_t addr;
+               const char *str;
+
+               jentry = json_object_array_get_idx(jarray, i);
+               if (!json_object_object_get_ex(jentry, "unicastAddress",
+                                       &jval))
+                       continue;
+
+               str = json_object_get_string(jval);
+               if (sscanf(str, "%04hx", &addr) != 1)
+                       continue;
+
+               if (addr == unicast)
+                       break;
+       }
+
+       if (i == sz)
+               return true;
+
+       json_object_array_del_idx(jarray, i, 1);
+
+       return __bt_mesh_save_configruation_file(cfg);
+}
+
+uint16_t** _bt_mesh_conf_get_all_model_info(_bt_mesh_cdb_t *cfg,
+               int element_index, int *num_models)
+{
+       int sz;
+       int i;
+       json_object *jcfg;
+       json_object *jnode;
+       json_object *jarray = NULL;
+       json_object *jelement = NULL;
+       json_object *jmodelarray = NULL;
+       const char *str;
+       uint16_t **models;
+
+       if (!cfg)
+               return NULL;
+
+       jcfg = cfg->jcfg;
+       if (!jcfg)
+               return NULL;
+
+       jnode = __mesh_get_node_by_uuid(jcfg, cfg->uuid);
+       if (jnode)
+               return NULL;
+
+       /* Get element array object */
+       json_object_object_get_ex(jnode, "elements", &jarray);
+
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return NULL;
+
+       /* Get specific element by index */
+       jelement = __mesh_get_key_object(jarray, element_index);
+       if (!jelement)
+               return NULL;
+
+
+       /* Get Model array object inside the selected element */
+       json_object_object_get_ex(jelement, "models", &jmodelarray);
+
+       if (!jmodelarray || json_object_get_type(jmodelarray) != json_type_array)
+               return NULL;
+
+       sz = json_object_array_length(jmodelarray);
+       models = (uint16_t**) g_malloc0(sz * sizeof(uint16_t*));
+
+       for (i = 0; i < sz; ++i) {
+               json_object *jentry;
+
+               jentry = json_object_array_get_idx(jmodelarray, i);
+               str = json_object_get_string(jentry);
+               /* Only standard models are handled now */
+               if (sscanf(str, "%04hx", models[i]) != 1)
+                       return NULL;
+       }
+       /* TODO: Need to handle vendor models */
+       *num_models = sz;
+       return models;
+}
+
+bool _bt_mesh_conf_get_element_count(_bt_mesh_cdb_t *cfg,
+               uint16_t *num_elems)
+{
+       int sz;
+       json_object *jcfg;
+       json_object *jnode;
+       json_object *jarray = NULL;
+
+       if (!cfg)
+               return false;
+
+       jcfg = cfg->jcfg;
+       if (!jcfg)
+               return false;
+
+       jnode = __mesh_get_node_by_uuid(jcfg, cfg->uuid);
+       if (jnode)
+               return false;
+
+       json_object_object_get_ex(jnode, "elements", &jarray);
+
+       if (!jarray || json_object_get_type(jarray) != json_type_array)
+               return false;
+
+       sz = json_object_array_length(jarray);
+       if (sz == 0)
+               return false;
+       *num_elems = sz;
+
+       return true;
+}
diff --git a/bt-service/services/mesh/bt-service-mesh-nodes.c b/bt-service/services/mesh/bt-service-mesh-nodes.c
new file mode 100644 (file)
index 0000000..acffb35
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Anupam Roy <anupam.r@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *              http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <glib.h>
+#include <dlog.h>
+#include "bt-service-common.h"
+#include "bt-service-core-adapter.h"
+#include "bt-service-event-receiver.h"
+#include "bt-request-handler.h"
+#include "bluetooth-api.h"
+
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include "bt-internal-types.h"
+#include "bt-service-util.h"
+#include "bt-service-common.h"
+#include "bt-service-event.h"
+
+#include "bt-service-mesh-cdb.h"
+#include "bt-service-mesh-keys.h"
+#include "bt-service-mesh-util.h"
+
+#include <ell/ell.h>
+
+#include "bt-internal-types.h"
+
+struct _bt_mesh_node_t {
+       uint16_t unicast;
+       struct l_queue *net_keys;
+       struct l_queue *app_keys;
+       struct l_queue **els;
+       uint8_t uuid[16];
+       uint8_t num_ele;
+};
+
+struct mesh_network_t {
+       uint8_t net_uuid[16];
+       struct l_queue *nodes;
+};
+
+static struct l_queue *networks;
+
+struct mesh_key_index {
+       uint8_t uuid[16];
+       uint16_t idx;
+};
+
+static bool __mesh_match_node_dev_uuid(const void *a, const void *b)
+{
+       const struct _bt_mesh_node_t *node = a;
+       uint8_t* dev_uuid = (uint8_t*)b;
+
+       if (memcmp(node->uuid, dev_uuid, 16) == 0) {
+               BT_INFO("Mesh: Found Node with given Dev UUID");
+               return true;
+       }
+
+       return false;
+}
+
+static bool __mesh_net_uuid_match(const void *a, const void *b)
+{
+       const struct mesh_network_t *net = a;
+       uint8_t* uuid = (uint8_t*)b;
+
+       if (memcmp(net->net_uuid, uuid, 16) == 0) {
+               BT_INFO("Mesh: Found network with given Net UUID");
+               return true;
+       }
+
+       return false;
+}
+
+static bool __mesh_key_present(struct l_queue *keys, uint16_t app_idx)
+{
+       const struct l_queue_entry *l;
+
+       for (l = l_queue_get_entries(keys); l; l = l->next) {
+               uint16_t idx = L_PTR_TO_UINT(l->data);
+
+               if (idx == app_idx)
+                       return true;
+       }
+
+       return false;
+}
+
+static int __mesh_compare_mod_id(const void *a, const void *b,
+               void *user_data)
+{
+       uint32_t id1 = L_PTR_TO_UINT(a);
+       uint32_t id2 = L_PTR_TO_UINT(b);
+
+       if (id1 >= MESH_VENDOR_ID_MASK)
+               id1 &= ~MESH_VENDOR_ID_MASK;
+
+       if (id2 >= MESH_VENDOR_ID_MASK)
+               id2 &= ~MESH_VENDOR_ID_MASK;
+
+       if (id1 < id2)
+               return -1;
+
+       if (id1 > id2)
+               return 1;
+
+       return 0;
+}
+
+static int __mesh_compare_unicast(const void *a, const void *b,
+               void *user_data)
+{
+       const struct _bt_mesh_node_t *a_rmt = a;
+       const struct _bt_mesh_node_t *b_rmt = b;
+
+       if (a_rmt->unicast < b_rmt->unicast)
+               return -1;
+
+       if (a_rmt->unicast > b_rmt->unicast)
+               return 1;
+
+       return 0;
+}
+
+static bool __mesh_match_node_addr(const void *a, const void *b)
+{
+       const struct _bt_mesh_node_t *rmt = a;
+       uint16_t addr = L_PTR_TO_UINT(b);
+
+       if (addr >= rmt->unicast &&
+                       addr <= (rmt->unicast + rmt->num_ele - 1))
+               return true;
+
+       return false;
+}
+
+void _bt_mesh_node_load_net(uint8_t net_uuid[])
+{
+       struct mesh_network_t *network;
+       BT_INFO("Mesh:Nodes: Create new network");
+
+       if (l_queue_find(networks, __mesh_net_uuid_match, net_uuid))
+               return;
+
+       if (!networks)
+               networks = l_queue_new();
+
+       network = l_new(struct mesh_network_t, 1);
+       memcpy(network->net_uuid, net_uuid, 16);
+       network->nodes =  l_queue_new();
+       l_queue_push_tail(networks, network);
+}
+
+bool _bt_mesh_node_get_unicast_from_dev_uuid(uint8_t net_uuid[],
+               const uint8_t dev_uuid[], uint16_t *unicast)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_dev_uuid, dev_uuid);
+       if (rmt)
+               return false;
+
+       *unicast = rmt->unicast;
+       return true;
+}
+
+bool _bt_mesh_node_get_element_count(uint8_t net_uuid[],
+               uint16_t unicast, uint8_t *count)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes, __mesh_match_node_addr,
+                       L_UINT_TO_PTR(unicast));
+       if (rmt)
+               return false;
+
+       *count = rmt->num_ele;
+
+       return true;
+}
+
+bool _bt_mesh_node_add_node(uint8_t net_uuid[],
+       const uint8_t node_uuid[16], uint16_t unicast,
+               uint8_t ele_cnt, uint16_t net_idx)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(unicast));
+       if (rmt)
+               return false;
+
+       rmt = l_new(struct _bt_mesh_node_t, 1);
+       memcpy(rmt->uuid, node_uuid, 16);
+       rmt->unicast = unicast;
+       rmt->num_ele = ele_cnt;
+       rmt->net_keys = l_queue_new();
+
+       l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
+
+       rmt->els = l_new(struct l_queue *, ele_cnt);
+
+       if (!network->nodes)
+               network->nodes = l_queue_new();
+
+       l_queue_insert(network->nodes, rmt, __mesh_compare_unicast, NULL);
+       return true;
+}
+
+bool _bt_mesh_node_get_models(uint8_t net_uuid[],
+               uint16_t unicast, uint8_t ele_idx,
+                       GArray **out)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+       const struct l_queue_entry *entry;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(unicast));
+       if (!rmt)
+               return false;
+
+       if (!rmt->els[ele_idx])
+               return false;
+
+       entry = l_queue_get_entries(rmt->els[ele_idx]);
+
+       for (; entry; entry = entry->next) {
+               uint32_t model = L_PTR_TO_UINT(entry->data);
+               g_array_append_vals(*out, &model, sizeof(uint32_t));
+       }
+       return true;
+}
+
+bool _bt_mesh_node_set_model(uint8_t net_uuid[],
+       uint16_t unicast, uint8_t ele_idx,
+               uint32_t mod_id, bool vendor)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(unicast));
+       if (!rmt)
+               return false;
+
+       if (ele_idx >= rmt->num_ele)
+               return false;
+
+       if (!rmt->els[ele_idx])
+               rmt->els[ele_idx] = l_queue_new();
+
+       if (!vendor)
+               mod_id = MESH_VENDOR_ID_MASK | mod_id;
+
+       l_queue_insert(rmt->els[ele_idx], L_UINT_TO_PTR(mod_id),
+                       __mesh_compare_mod_id, NULL);
+
+       return true;
+}
+
+bool _bt_mesh_node_get_all_appkeys(uint8_t net_uuid[],
+               uint16_t unicast, GArray **out)
+{
+       struct mesh_network_t *network;
+       const struct l_queue_entry *entry;
+       struct _bt_mesh_node_t *rmt;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+               __mesh_match_node_addr, L_UINT_TO_PTR(unicast));
+       if (!rmt)
+               return false;
+
+       entry = l_queue_get_entries(rmt->app_keys);
+
+       for (; entry; entry = entry->next) {
+
+               uint16_t app_idx = L_PTR_TO_UINT(entry->data);
+
+               g_array_append_vals(*out, &app_idx, sizeof(uint16_t));
+       }
+       return true;
+}
+
+bool _bt_mesh_node_get_all_netkeys(uint8_t net_uuid[],
+               uint16_t unicast, GArray **out)
+{
+       struct mesh_network_t *network;
+       const struct l_queue_entry *entry;
+       struct _bt_mesh_node_t *rmt;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(unicast));
+       if (!rmt)
+               return false;
+
+       entry = l_queue_get_entries(rmt->net_keys);
+
+       for (; entry; entry = entry->next) {
+
+               uint16_t net_idx = L_PTR_TO_UINT(entry->data);
+
+               g_array_append_vals(*out, &net_idx, sizeof(uint16_t));
+       }
+       return true;
+}
+
+bool _bt_mesh_node_get_all(uint8_t net_uuid[], GArray **out)
+{
+       struct mesh_network_t *network;
+       const struct l_queue_entry *entry;
+       bluetooth_mesh_node_info_t n;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       entry = l_queue_get_entries(network->nodes);
+
+       for (; entry; entry = entry->next) {
+
+               memset(&n, 0x00, sizeof(bluetooth_mesh_node_info_t));
+               struct _bt_mesh_node_t *node = entry->data;
+
+               n.primary_unicast = node->unicast;
+               n.num_elements = node->num_ele;
+
+               g_array_append_vals(*out, &n,
+                               sizeof(bluetooth_mesh_node_info_t));
+       }
+       return true;
+}
+
+bool _bt_mesh_node_is_netkey_added(uint8_t net_uuid[],
+               uint16_t net_idx)
+{
+       struct mesh_network_t *network;
+       const struct l_queue_entry *entry;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       entry = l_queue_get_entries(network->nodes);
+
+       for (; entry; entry = entry->next) {
+               struct _bt_mesh_node_t *node = entry->data;
+
+               if (__mesh_key_present(node->net_keys, net_idx))
+                       return true;
+       }
+       return false;
+}
+
+bool _bt_mesh_node_is_appkey_added(uint8_t net_uuid[],
+               uint16_t app_idx)
+{
+       struct mesh_network_t *network;
+       const struct l_queue_entry *entry;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       entry = l_queue_get_entries(network->nodes);
+
+       for (; entry; entry = entry->next) {
+               struct _bt_mesh_node_t *node = entry->data;
+
+               if (__mesh_key_present(node->app_keys, app_idx))
+                       return true;
+       }
+       return false;
+}
+
+bool _bt_mesh_node_add_net_key(uint8_t net_uuid[],
+               uint16_t addr, uint16_t net_idx)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks, __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(addr));
+       if (!rmt)
+               return false;
+
+       if (__mesh_key_present(rmt->net_keys, net_idx))
+               return false;
+
+       l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
+       return true;
+}
+
+bool _bt_mesh_node_add_app_key(uint8_t net_uuid[],
+               uint16_t addr, uint16_t app_idx)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks,
+                       __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(addr));
+       if (!rmt)
+               return false;
+
+       if (!rmt->app_keys)
+               rmt->app_keys = l_queue_new();
+
+       if (__mesh_key_present(rmt->app_keys, app_idx))
+               return false;
+
+       l_queue_push_tail(rmt->app_keys, L_UINT_TO_PTR(app_idx));
+       return true;
+}
+
+bool _bt_mesh_node_del_app_key(uint8_t net_uuid[],
+               uint16_t addr, uint16_t app_idx)
+{
+       struct _bt_mesh_node_t *rmt;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks,
+                       __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return false;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(addr));
+       if (!rmt)
+               return false;
+
+       return l_queue_remove(rmt->app_keys, L_UINT_TO_PTR(app_idx));
+}
+
+uint16_t _bt_mesh_node_get_subnet_idx(uint8_t net_uuid[],
+               uint16_t addr)
+{
+       struct _bt_mesh_node_t *rmt;
+       uint32_t net_idx;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks,
+                       __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return MESH_NET_IDX_INVALID;
+
+       rmt = l_queue_find(network->nodes,
+                       __mesh_match_node_addr, L_UINT_TO_PTR(addr));
+
+       if (!rmt || l_queue_isempty(rmt->net_keys))
+               return MESH_NET_IDX_INVALID;
+
+       net_idx = L_PTR_TO_UINT(l_queue_peek_head(rmt->net_keys));
+
+       return (uint16_t) net_idx;
+}
+
+uint16_t _bt_mesh_node_get_next_unicast(uint8_t net_uuid[],
+               uint16_t low, uint16_t high, uint8_t ele_cnt)
+{
+       struct _bt_mesh_node_t *rmt;
+       const struct l_queue_entry *l;
+       uint16_t addr;
+       struct mesh_network_t *network;
+
+       network = l_queue_find(networks,
+                       __mesh_net_uuid_match, net_uuid);
+       if (!network)
+               return 0;
+
+       /* Note: the address space includes both
+          low and high terminal values */
+       if (ele_cnt > (high - low + 1))
+               return 0;
+
+       if (!network->nodes || l_queue_isempty(network->nodes))
+               return low;
+
+       addr = low;
+       l = l_queue_get_entries(network->nodes);
+
+       /* Cycle through the sorted (by unicast) node list */
+       for (; l; l = l->next) {
+               rmt = l->data;
+
+               if (rmt->unicast >= (addr + ele_cnt))
+                       return addr;
+
+               if ((rmt->unicast + rmt->num_ele) > addr)
+                       addr = rmt->unicast + rmt->num_ele;
+       }
+
+       if ((addr + ele_cnt - 1) <= high)
+               return addr;
+
+       return 0;
+}