Mesh: Implement Configuration Client
authorAnupam Roy <anupam.r@samsung.com>
Fri, 17 Jul 2020 14:10:42 +0000 (19:40 +0530)
committerAnupam Roy <anupam.r@samsung.com>
Fri, 17 Jul 2020 14:25:36 +0000 (19:55 +0530)
This patchset primarily handles following
- Add Mesh Configuration Client
- Adds Node Operations
 a/ Save & retrieve Node composition & features
 b/ Save/Remove Keys added to node(s)
 c/ Save/Remove node(s) entry in CDB
- Mesh Group management

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

index d8268a1..82a5f39 100644 (file)
@@ -37,6 +37,7 @@ SET(SRCS
 ./services/mesh/bt-service-mesh-nodes.c
 ./services/mesh/bt-service-mesh-network.c
 ./services/mesh/bt-service-mesh-main.c
+./services/mesh/bt-service-mesh-config-client.c
 )
 
 IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_FEATURE_BT_OBEX")
diff --git a/bt-service/services/include/bt-service-mesh-config-client.h b/bt-service/services/include/bt-service-mesh-config-client.h
new file mode 100644 (file)
index 0000000..0e8f21f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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_CONFIG_CLIENT_H_
+#define BT_SERVICE_MESH_CONFIG_CLIENT_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include <json-c/json.h>
+#include "oal-mesh.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _bt_mesh_node_discover_vendor_features(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_node_features_t *req);
+
+int _bt_mesh_browse_remote_node(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_node_discover_t *req);
+
+bool _bt_mesh_check_pending_request(uint32_t opcode,
+               uint16_t dest, uint8_t net_uuid[]);
+
+void _bt_mesh_config_client_devkey_msg_handler(
+               event_mesh_devkey_message_t *event);
+
+int _bt_mesh_node_configure_key(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_key_configure_t *req);
+
+int _bt_mesh_ttl_execute_remote_node(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_node_ttl_info_t *req);
+
+int _bt_mesh_node_model_appkey_execute(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+int _bt_mesh_node_model_get_appkey_list(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+int _bt_mesh_node_model_get_subscription_list(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+int _bt_mesh_model_configure_group_subscription(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+int _bt_mesh_model_configure_virtual_group_subscription(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+int _bt_mesh_model_set_publication(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+int _bt_mesh_model_get_publication(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_configure_t *req);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* BT_SERVICE_MESH_CONFIG_CLIENT_H_ */
index 32add7b..66f101c 100644 (file)
@@ -40,6 +40,9 @@ int _bt_mesh_network_create_cdb(int result,
                        uint8_t uuid[16], uint8_t token[8],
                                const char *network);
 
+int _bt_mesh_network_load(const char *app_cred,
+               const char *sender, const char *token);
+
 int _bt_mesh_network_request_provisioning_data_request(
                uint8_t net_uuid[], uint8_t count);
 
@@ -101,6 +104,57 @@ int _bt_mesh_network_get_appkeys(const char *app_cred, const char *sender,
                bluetooth_mesh_network_t *network,  uint16_t net_idx,
                        GArray **out_param);
 
+int _bt_mesh_network_get_nodes(const char *app_cred, const char *sender,
+               bluetooth_mesh_network_t *network,  GArray **out_param);
+
+int _bt_mesh_element_get_models(const char *app_cred, const char *sender,
+               bluetooth_mesh_network_t *network,  uint16_t unicast,
+                       int elem_idx, GArray **out_param);
+
+int _bt_mesh_network_add_remote_node(uint8_t net_uuid[], uint8_t dev_uuid[],
+               uint16_t unicast, uint8_t count);
+
+bool _bt_mesh_network_save_remote_node_composition(uint8_t net_uuid[],
+               uint16_t remote_unicast,
+                       uint8_t *data, uint16_t data_len);
+
+bool _bt_mesh_network_save_remote_node_netkey(uint8_t net_uuid[],
+               uint16_t remote_unicast, uint16_t netkey_idx);
+
+bool _bt_mesh_network_delete_remote_node_netkey(uint8_t net_uuid[],
+               uint16_t remote_unicast, uint16_t netkey_idx);
+
+bool _bt_mesh_network_save_remote_node_appkey(uint8_t net_uuid[],
+               uint16_t remote_unicast, uint16_t netkey_idx,
+                       uint16_t appkey_idx);
+
+bool _bt_mesh_network_delete_remote_node_appkey(uint8_t net_uuid[],
+               uint16_t remote_unicast, uint16_t netkey_idx,
+                       uint16_t appkey_idx);
+
+bool _bt_mesh_network_save_remote_node_ttl(uint8_t net_uuid[],
+               uint16_t remote_unicast, uint8_t ttl);
+
+int _bt_mesh_network_node_get_netkeys(const char *app_cred,
+               bluetooth_mesh_node_discover_t *node,
+                       GArray **out_param);
+
+int _bt_mesh_network_node_get_appkeys(const char *app_cred, const char *sender,
+               bluetooth_mesh_node_discover_t *node,  GArray **out_param);
+
+int _bt_mesh_network_create_group(const char *app_cred, const char *sender,
+               bluetooth_mesh_network_t *net, bool is_virtual, uint16_t grp_addr,
+                       bluetooth_mesh_network_group_info_t *group);
+
+int _bt_mesh_network_get_groups(const char *app_cred, const char *sender,
+               bluetooth_mesh_network_t *network,  GArray **out_param);
+
+bool _bt_mesh_network_get_label_uuid_from_sub_addr(uint8_t net_uuid[],
+               uint16_t sub_addr, uint8_t label[]);
+
+bool _bt_mesh_node_get_vendor_features(uint8_t net_uuid[],
+               uint16_t unicast, bluetooth_mesh_node_features_t *feats);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index cf64e23..cb11a5b 100644 (file)
@@ -462,65 +462,6 @@ void _bt_mesh_conf_free(_bt_mesh_cdb_t *cfg)
        g_free(cfg);
 }
 
-#if 0
-bool _bt_mesh_cdb_load_keys(_bt_mesh_cdb_t* cfg)
-{
-       json_object *jarray, *jentry;
-       int net_idx, app_idx;
-       int i, key_cnt;
-       json_object *jobj = cfg->jcfg;
-
-       json_object_object_get_ex(jobj, "netKeys", &jarray);
-       if (!jarray ||
-                       json_object_get_type(jarray) != json_type_array)
-               return false;
-
-       key_cnt = json_object_array_length(jarray);
-       if (key_cnt < 0)
-               return false;
-
-       for (i = 0; i < key_cnt; ++i) {
-               int phase;
-
-               jentry = json_object_array_get_idx(jarray, i);
-
-               if (!__mesh_get_int(jentry, "index", &net_idx))
-                       return false;
-
-               _bt_mesh_keys_add_net_key(cfg->uuid,
-                               (uint16_t) net_idx);
-
-               if (!__mesh_get_int(jentry, "phase", &phase))
-                       return false;
-
-               _bt_mesh_keys_set_net_key_phase(cfg,
-                               net_idx, (uint8_t) phase, false);
-       }
-
-       json_object_object_get_ex(jobj, "appKeys", &jarray);
-       if (!jarray || json_object_get_type(jarray) != json_type_array)
-               return false;
-
-       key_cnt = json_object_array_length(jarray);
-       if (key_cnt < 0)
-               return false;
-
-       for (i = 0; i < key_cnt; ++i) {
-
-               jentry = json_object_array_get_idx(jarray, i);
-               if (!__mesh_get_int(jentry, "boundNetKey", &net_idx))
-                       return false;
-
-               if (!__mesh_get_int(jentry, "index", &app_idx))
-                       return false;
-
-               _bt_mesh_keys_add_app_key(cfg->uuid,
-                               (uint16_t) net_idx, (uint16_t) app_idx);
-       }
-       return true;
-}
-#endif
-
 bool _bt_mesh_conf_parse_data(void *cfg,  int k)
 {
        _bt_mesh_cdb_t *conf = (_bt_mesh_cdb_t*) cfg;
diff --git a/bt-service/services/mesh/bt-service-mesh-config-client.c b/bt-service/services/mesh/bt-service-mesh-config-client.c
new file mode 100644 (file)
index 0000000..370ca14
--- /dev/null
@@ -0,0 +1,2416 @@
+/*
+ * 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 <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <ell/ell.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-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-network.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 <oal-hardware.h>
+#include <oal-manager.h>
+#include <oal-event.h>
+#include <oal-adapter-mgr.h>
+#include <oal-device-mgr.h>
+#include <oal-mesh.h>
+
+#include "bt-internal-types.h"
+
+#define MESH_CONFIG_BUFFER_MAX_LEN 100
+
+
+static void __bt_mesh_send_node_browsed_event(int result,
+               bluetooth_mesh_node_discover_t *browse_evt);
+static void __bt_mesh_handle_pending_dev_config_request_info(int result,
+               int service_function, void *param,
+                       unsigned int size);
+
+struct mesh_config_cmd {
+       uint32_t opcode;
+       uint32_t response;
+       const char *descriptor;
+};
+
+static struct l_queue *pending_requests;
+
+struct mesh_pending_request {
+       struct l_timeout *timer;
+       const struct mesh_config_cmd *cmd;
+       uint8_t net_uuid[16];
+       uint16_t addr;
+       void *data;
+};
+
+static struct mesh_config_cmd commands[] = {
+       { MESH_OPCODE_APPKEY_ADD, MESH_OPCODE_APPKEY_STATUS, "AppKeyAdd" },
+       { MESH_OPCODE_APPKEY_DELETE, MESH_OPCODE_APPKEY_STATUS, "AppKeyDelete" },
+       { MESH_OPCODE_APPKEY_GET, MESH_OPCODE_APPKEY_LIST, "AppKeyGet" },
+       { MESH_OPCODE_APPKEY_LIST, MESH_RESPONSE_NONE, "AppKeyList" },
+       { MESH_OPCODE_APPKEY_STATUS, MESH_RESPONSE_NONE, "AppKeyStatus" },
+       { MESH_OPCODE_APPKEY_UPDATE, MESH_OPCODE_APPKEY_STATUS, "AppKeyUpdate" },
+       { MESH_OPCODE_DEV_COMP_GET, MESH_OPCODE_DEV_COMP_STATUS, "DeviceCompositionGet" },
+       { MESH_OPCODE_DEV_COMP_STATUS, MESH_RESPONSE_NONE, "DeviceCompositionStatus" },
+       { MESH_OPCODE_CONFIG_BEACON_GET, MESH_OPCODE_CONFIG_BEACON_STATUS, "BeaconGet" },
+       { MESH_OPCODE_CONFIG_BEACON_SET, MESH_OPCODE_CONFIG_BEACON_STATUS, "BeaconSet" },
+       { MESH_OPCODE_CONFIG_BEACON_STATUS, MESH_RESPONSE_NONE, "BeaconStatus" },
+       { MESH_OPCODE_CONFIG_DEFAULT_TTL_GET, MESH_OPCODE_CONFIG_DEFAULT_TTL_STATUS,
+               "DefaultTTLGet" },
+       { MESH_OPCODE_CONFIG_DEFAULT_TTL_SET, MESH_OPCODE_CONFIG_DEFAULT_TTL_STATUS,
+               "DefaultTTLSet" },
+       { MESH_OPCODE_CONFIG_DEFAULT_TTL_STATUS, MESH_RESPONSE_NONE, "DefaultTTLStatus" },
+       { MESH_OPCODE_CONFIG_FRIEND_GET, MESH_OPCODE_CONFIG_FRIEND_STATUS, "FriendGet" },
+       { MESH_OPCODE_CONFIG_FRIEND_SET, MESH_OPCODE_CONFIG_FRIEND_STATUS, "FrienSet" },
+       { MESH_OPCODE_CONFIG_FRIEND_STATUS, MESH_RESPONSE_NONE, "FriendStatus" },
+       { MESH_OPCODE_CONFIG_PROXY_GET, MESH_OPCODE_CONFIG_PROXY_STATUS, "ProxyGet" },
+       { MESH_OPCODE_CONFIG_PROXY_SET, MESH_OPCODE_CONFIG_PROXY_STATUS, "ProxySet" },
+       { MESH_OPCODE_CONFIG_PROXY_STATUS, MESH_RESPONSE_NONE, "ProxyStatus" },
+       { MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_GET, MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_STATUS,
+               "KeyRefreshPhaseGet" },
+       { MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_SET, MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_STATUS,
+               "KeyRefreshPhaseSet" },
+       { MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_STATUS, MESH_RESPONSE_NONE,
+               "KeyRefreshPhaseStatus" },
+       { MESH_OPCODE_CONFIG_MODEL_PUB_GET, MESH_OPCODE_CONFIG_MODEL_PUB_STATUS, "ModelPubGet" },
+       { MESH_OPCODE_CONFIG_MODEL_PUB_SET, MESH_OPCODE_CONFIG_MODEL_PUB_STATUS, "ModelPubSet" },
+       { MESH_OPCODE_CONFIG_MODEL_PUB_STATUS, MESH_RESPONSE_NONE, "ModelPubStatus" },
+       { MESH_OPCODE_CONFIG_MODEL_PUB_VIRT_SET, MESH_OPCODE_CONFIG_MODEL_PUB_STATUS,
+               "ModelPubVirtualSet" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_ADD, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS, "ModelSubAdd" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_DELETE, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS,
+               "ModelSubDelete" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_DELETE_ALL, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS,
+               "ModelSubDeleteAll" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_OVERWRITE, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS,
+               "ModelSubOverwrite" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_STATUS, MESH_RESPONSE_NONE, "ModelSubStatus" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_ADD, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS,
+               "ModelSubVirtAdd" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_DELETE, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS,
+               "ModelSubVirtDelete" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_OVERWRITE, MESH_OPCODE_CONFIG_MODEL_SUB_STATUS,
+               "ModelSubVirtOverwrite" },
+       { MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_GET, MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_STATUS,
+               "NetworkTransmitGet" },
+       { MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_SET, MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_STATUS,
+               "NetworkTransmitSet" },
+       { MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_STATUS, MESH_RESPONSE_NONE,
+               "NetworkTransmitStatus" },
+       { MESH_OPCODE_CONFIG_RELAY_GET, MESH_OPCODE_CONFIG_RELAY_STATUS, "RelayGet" },
+       { MESH_OPCODE_CONFIG_RELAY_SET, MESH_OPCODE_CONFIG_RELAY_STATUS, "RelaySet" },
+       { MESH_OPCODE_CONFIG_RELAY_STATUS, MESH_RESPONSE_NONE, "RelayStatus" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_GET, MESH_OPCODE_CONFIG_MODEL_SUB_LIST, "ModelSubGet" },
+       { MESH_OPCODE_CONFIG_MODEL_SUB_LIST, MESH_RESPONSE_NONE, "ModelSubList" },
+       { MESH_OPCODE_CONFIG_VEND_MODEL_SUB_GET, MESH_OPCODE_CONFIG_VEND_MODEL_SUB_LIST,
+               "VendorModelSubGet" },
+       { MESH_OPCODE_CONFIG_VEND_MODEL_SUB_LIST, MESH_RESPONSE_NONE, "VendorModelSubList" },
+       { MESH_OPCODE_CONFIG_POLL_TIMEOUT_LIST, MESH_OPCODE_CONFIG_POLL_TIMEOUT_STATUS,
+               "PollTimeoutList" },
+       { MESH_OPCODE_CONFIG_POLL_TIMEOUT_STATUS, MESH_RESPONSE_NONE, "PollTimeoutStatus" },
+       { MESH_OPCODE_CONFIG_HEARTBEAT_PUB_GET, MESH_OPCODE_CONFIG_HEARTBEAT_PUB_STATUS,
+               "HeartbeatPubGet" },
+       { MESH_OPCODE_CONFIG_HEARTBEAT_PUB_SET, MESH_OPCODE_CONFIG_HEARTBEAT_PUB_STATUS,
+               "HeartbeatPubSet" },
+       { MESH_OPCODE_CONFIG_HEARTBEAT_PUB_STATUS, MESH_RESPONSE_NONE, "HeartbeatPubStatus" },
+       { MESH_OPCODE_CONFIG_HEARTBEAT_SUB_GET, MESH_OPCODE_CONFIG_HEARTBEAT_SUB_STATUS,
+               "HeartbeatSubGet" },
+       { MESH_OPCODE_CONFIG_HEARTBEAT_SUB_SET, MESH_OPCODE_CONFIG_HEARTBEAT_SUB_STATUS,
+               "HeartbeatSubSet" },
+       { MESH_OPCODE_CONFIG_HEARTBEAT_SUB_STATUS, MESH_RESPONSE_NONE, "HeartbeatSubStatus" },
+       { MESH_OPCODE_MODEL_APP_BIND, MESH_OPCODE_MODEL_APP_STATUS, "ModelAppBind" },
+       { MESH_OPCODE_MODEL_APP_STATUS, MESH_RESPONSE_NONE, "ModelAppStatus" },
+       { MESH_OPCODE_MODEL_APP_UNBIND, MESH_OPCODE_MODEL_APP_STATUS, "ModelAppUnbind" },
+       { MESH_OPCODE_NETKEY_ADD, MESH_OPCODE_NETKEY_STATUS, "NetKeyAdd" },
+       { MESH_OPCODE_NETKEY_DELETE, MESH_OPCODE_NETKEY_STATUS, "NetKeyDelete" },
+       { MESH_OPCODE_NETKEY_GET, MESH_OPCODE_NETKEY_LIST, "NetKeyGet" },
+       { MESH_OPCODE_NETKEY_LIST, MESH_RESPONSE_NONE, "NetKeyList" },
+       { MESH_OPCODE_NETKEY_STATUS, MESH_RESPONSE_NONE, "NetKeyStatus" },
+       { MESH_OPCODE_NETKEY_UPDATE, MESH_OPCODE_NETKEY_STATUS, "NetKeyUpdate" },
+       { MESH_OPCODE_NODE_IDENTITY_GET, MESH_OPCODE_NODE_IDENTITY_STATUS, "NodeIdentityGet" },
+       { MESH_OPCODE_NODE_IDENTITY_SET, MESH_OPCODE_NODE_IDENTITY_STATUS, "NodeIdentitySet" },
+       { MESH_OPCODE_NODE_IDENTITY_STATUS, MESH_RESPONSE_NONE, "NodeIdentityStatus" },
+       { MESH_OPCODE_NODE_RESET, MESH_OPCODE_NODE_RESET_STATUS, "NodeReset" },
+       { MESH_OPCODE_NODE_RESET_STATUS, MESH_RESPONSE_NONE, "NodeResetStatus" },
+       { MESH_OPCODE_MODEL_APP_GET, MESH_OPCODE_MODEL_APP_LIST, "ModelAppGet" },
+       { MESH_OPCODE_MODEL_APP_LIST, MESH_RESPONSE_NONE, "ModelAppList" },
+       { MESH_OPCODE_VENDOR_MODEL_APP_GET, MESH_OPCODE_VENDOR_MODEL_APP_LIST, "VendorModelAppGet" },
+       { MESH_OPCODE_VENDOR_MODEL_APP_LIST, MESH_RESPONSE_NONE, "VendorModelAppList" }
+};
+
+
+static const struct mesh_config_cmd *__mesh_get_command(uint32_t opcode)
+{
+       uint32_t n;
+
+       for (n = 0; n < L_ARRAY_SIZE(commands); n++) {
+               if (opcode == commands[n].opcode)
+                       return &commands[n];
+       }
+
+       return NULL;
+}
+
+static const char *__mesh_get_opcode_string(uint32_t opcode)
+{
+       const struct mesh_config_cmd *cmd;
+
+       cmd = __mesh_get_command(opcode);
+       if (!cmd)
+               return "Unknown Command Received";
+
+       return cmd->descriptor;
+}
+
+static void __mesh_request_remove(void *a)
+{
+       struct mesh_pending_request *req = a;
+
+       if (req->data)
+               l_free(req->data);
+       l_timeout_remove(req->timer);
+       l_free(req);
+}
+
+static void __bt_mesh_wait_response_timeout(
+               struct l_timeout *timeout, void *user_data)
+{
+       struct mesh_pending_request *req = user_data;
+
+       BT_INFO("Mesh: No response for \"%s\" from %4.4x\n",
+                       req->cmd->descriptor, req->addr);
+
+       /* Node reset case: delete the remote even if there is no response */
+       /* TODO Reset the remote node, as no response is expected on reset command */
+
+
+       switch(req->cmd->opcode) {
+       case MESH_OPCODE_DEV_COMP_GET: {
+               /* Send event with timeout */
+               event_mesh_devkey_message_t *event = \
+                       g_malloc0(sizeof(event_mesh_devkey_message_t));
+               memcpy(event->net_uuid.uuid, req->net_uuid, 16);
+               event->source = req->addr;
+                __bt_mesh_handle_pending_dev_config_request_info(
+                       BLUETOOTH_ERROR_TIMEOUT, BT_MESH_NODE_BROWSE,
+                               event, sizeof(event_mesh_devkey_message_t));
+               g_free(event);
+               break;
+       }
+       case MESH_OPCODE_NETKEY_ADD:
+       case MESH_OPCODE_NETKEY_UPDATE:
+       case MESH_OPCODE_NETKEY_DELETE:
+       case MESH_OPCODE_APPKEY_ADD:
+       case MESH_OPCODE_APPKEY_UPDATE:
+       case MESH_OPCODE_APPKEY_DELETE:
+               /* Send event with timeout */
+                __bt_mesh_handle_pending_dev_config_request_info(
+                       BLUETOOTH_ERROR_TIMEOUT,
+                               BT_MESH_NODE_CONFIGURE_KEY, req->data,
+                                       sizeof(bluetooth_mesh_key_configure_t));
+               break;
+       case MESH_OPCODE_CONFIG_DEFAULT_TTL_GET:
+       case MESH_OPCODE_CONFIG_DEFAULT_TTL_SET:
+               /* Send event with timeout */
+                __bt_mesh_handle_pending_dev_config_request_info(
+                       BLUETOOTH_ERROR_TIMEOUT,
+                               BT_MESH_NODE_TTL_EXECUTE, req->data,
+                                       sizeof(bluetooth_mesh_node_ttl_info_t));
+               break;
+       default:
+               break;
+       }
+       l_queue_remove(pending_requests, req);
+       __mesh_request_remove(req);
+}
+
+static void __bt_mesh_add_request(uint32_t opcode, uint16_t dest,
+                       uint8_t net_uuid[], void *data)
+{
+       struct mesh_pending_request *req;
+       const struct mesh_config_cmd *cmd;
+
+       cmd = __mesh_get_command(opcode);
+       if (!cmd)
+               return;
+
+       req = l_new(struct mesh_pending_request, 1);
+       req->cmd = cmd;
+       req->addr = dest;
+       req->data = data;
+       memcpy(req->net_uuid, net_uuid, 16);
+       req->timer = l_timeout_create(MESH_DEFAULT_RESPONSE_TIMEOUT,
+                       __bt_mesh_wait_response_timeout, req, NULL);
+       l_queue_push_tail(pending_requests, req);
+}
+
+static struct mesh_pending_request *__bt_mesh_get_request_by_response(
+               uint16_t addr, uint8_t net_uuid[],
+                       uint32_t response)
+{
+       const struct l_queue_entry *entry;
+
+       entry = l_queue_get_entries(pending_requests);
+
+       for (; entry; entry = entry->next) {
+               struct mesh_pending_request *req = entry->data;
+
+               if (!memcmp(net_uuid, req->net_uuid, 16) &&
+                               req->addr == addr &&
+                               req->cmd->response == response)
+                       return req;
+       }
+
+       return NULL;
+}
+
+bool _bt_mesh_check_pending_request(uint32_t opcode,
+               uint16_t dest, uint8_t net_uuid[])
+{
+       const struct mesh_config_cmd *cmd;
+       cmd = __mesh_get_command(opcode);
+
+       if (!cmd)
+               return false;
+
+       if (__bt_mesh_get_request_by_response(dest,
+                               net_uuid, cmd->response)) {
+               BT_ERR("Mesh:Another command is pending\n");
+               return true;
+       }
+       return false;
+}
+
+static uint32_t __bt_mesh_print_model_identifier(uint8_t *data,
+               bool vendor, const char *offset)
+{
+       uint32_t mod_id;
+
+       if (!vendor) {
+               mod_id = l_get_le16(data);
+               BT_INFO("%sModel ID\t%4.4x\n", offset, mod_id);
+               mod_id = MESH_VENDOR_ID_MASK | mod_id;
+       } else {
+               mod_id = l_get_le16(data + 2);
+               BT_INFO("%sModel ID\t%4.4x %4.4x\n", offset,
+                               l_get_le16(data), mod_id);
+               mod_id = l_get_le16(data) << 16 | mod_id;
+       }
+
+       return mod_id;
+}
+
+static void __bt_mesh_print_device_composition_data(
+               uint8_t *data, uint16_t len)
+{
+       uint16_t features;
+       int i = 0;
+
+       BT_INFO("Mesh: Received composion:\n");
+
+       /* skip page -- We only support Page Zero */
+       data++;
+       len--;
+
+       BT_INFO("\tCID: %4.4x", l_get_le16(&data[0]));
+       BT_INFO("\tPID: %4.4x", l_get_le16(&data[2]));
+       BT_INFO("\tVID: %4.4x", l_get_le16(&data[4]));
+       BT_INFO("\tCRPL: %4.4x", l_get_le16(&data[6]));
+
+       features = l_get_le16(&data[8]);
+       data += 10;
+       len -= 10;
+
+       BT_INFO("\tFeature support:\n");
+       BT_INFO("\t\trelay: %s\n", (features & MESH_FEATURE_RELAY) ?
+                       "yes" : "no");
+       BT_INFO("\t\tproxy: %s\n", (features & MESH_FEATURE_PROXY) ?
+                       "yes" : "no");
+       BT_INFO("\t\tfriend: %s\n", (features & MESH_FEATURE_FRIEND) ?
+                       "yes" : "no");
+       BT_INFO("\t\tlpn: %s\n", (features & MESH_FEATURE_LPN) ?
+                       "yes" : "no");
+       while (len) {
+               uint8_t m, v;
+
+               BT_INFO("\t Element %d:\n", i);
+               BT_INFO("\t\tlocation: %4.4x\n", l_get_le16(data));
+               data += 2;
+               len -= 2;
+
+               m = *data++;
+               v = *data++;
+               len -= 2;
+
+               if (m)
+                       BT_INFO("\t\tSIG defined models:\n");
+
+               while (len >= 2 && m--) {
+                       __bt_mesh_print_model_identifier(data, false, "\t\t  ");
+                       data += 2;
+                       len -= 2;
+               }
+
+               if (v)
+                       BT_INFO("\t\t Vendor defined models:\n");
+
+               while (len >= 4 && v--) {
+                       __bt_mesh_print_model_identifier(data, true, "\t\t  ");
+                       data += 4;
+                       len -= 4;
+               }
+
+               i++;
+       }
+}
+
+static void __bt_mesh_send_model_publication_status_event(
+               int event, int result,
+                       bluetooth_mesh_model_configure_t *evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &evt,
+                               sizeof(bluetooth_mesh_model_configure_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT, event,
+                               param);
+       }
+}
+
+static void __bt_mesh_send_model_subscription_configure_event(
+               int event, int result,
+                       bluetooth_mesh_model_configure_t *evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &evt,
+                               sizeof(bluetooth_mesh_model_configure_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT, event,
+                               param);
+       }
+}
+
+static void __bt_mesh_send_model_get_subscription_list_event(
+       int result, bluetooth_mesh_model_configure_t *evt)
+{
+       GVariant  *param = NULL;
+       GVariantBuilder *builder = NULL;
+       int i;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               if (evt->sublist_count) {
+                       builder = g_variant_builder_new(G_VARIANT_TYPE("aq"));
+                       for (i = 0; i < evt->sublist_count; i++)
+                               g_variant_builder_add(builder, "q", *evt->sub_list[i]);
+
+                       param = g_variant_new("(isqiui(aq))", result, evt->net_uuid,
+                                       evt->primary_unicast, evt->elem_index, evt->model,
+                                       evt->sublist_count, builder);
+
+                       g_variant_builder_unref(builder);
+               }
+               /* Send event */
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_MODEL_SUBSCRIPTION_LIST,
+                               param);
+
+               if (evt->sublist_count) {
+                       /* Free List data */
+                       for (int i = 0; i < evt->sublist_count; i++)
+                               g_free(evt->sub_list[i]);
+                       g_free(evt->sub_list);
+               }
+       }
+}
+
+static void __bt_mesh_send_model_get_appkey_list_event(int result,
+               bluetooth_mesh_model_configure_t *evt)
+{
+       GVariant  *param = NULL;
+       GVariantBuilder *builder = NULL;
+       int i;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+
+               if (evt->appkeylist_count) {
+                       builder = g_variant_builder_new(G_VARIANT_TYPE("aq"));
+                       for (i = 0; i < evt->appkeylist_count; i++)
+                               g_variant_builder_add(builder, "q", *evt->appkey_list[i]);
+
+                       param = g_variant_new("(isqiui(aq))", result, evt->net_uuid,
+                                       evt->primary_unicast, evt->elem_index, evt->model,
+                                       evt->appkeylist_count, builder);
+
+                       g_variant_builder_unref(builder);
+               }
+
+               /* Send event */
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_MODEL_APPKEY_LIST,
+                               param);
+
+               if (evt->appkeylist_count) {
+                       /* Free List data */
+                       for (int i = 0; i < evt->appkeylist_count; i++)
+                               g_free(evt->appkey_list[i]);
+                       g_free(evt->appkey_list);
+               }
+       }
+}
+
+static void __bt_mesh_send_model_configure_appkey_event(int result,
+               bluetooth_mesh_model_configure_t *evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &evt, sizeof(bluetooth_mesh_model_configure_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_NODE_MODEL_APPKEY_BIND,
+                               param);
+       }
+}
+
+static void __bt_mesh_send_node_ttl_configuration_event(int result,
+               bluetooth_mesh_node_ttl_info_t *ttl_evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &ttl_evt,
+                       sizeof(bluetooth_mesh_node_ttl_info_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_NODE_TTL_CONFIGURED,
+                               param);
+       }
+}
+
+static void __bt_mesh_send_node_key_configuration_event(int result,
+               bluetooth_mesh_key_configure_t *key_evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &key_evt,
+                       sizeof(bluetooth_mesh_key_configure_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_NODE_KEY_CONFIGURED,
+                               param);
+       }
+}
+
+static void __bt_mesh_send_node_get_vendor_features_event(int result,
+               bluetooth_mesh_node_features_t *features_evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &features_evt,
+                               sizeof(bluetooth_mesh_node_features_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_NODE_VENDOR_FEATURES,
+                               param);
+       }
+}
+
+static void __bt_mesh_send_node_browsed_event(int result,
+               bluetooth_mesh_node_discover_t *browse_evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, &browse_evt,
+                               sizeof(bluetooth_mesh_node_discover_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_NODE_BROWSED,
+                               param);
+       }
+}
+
+static void __bt_mesh_handle_pending_dev_config_request_info(int result,
+               int service_function, void *param, unsigned int size)
+{
+       GSList *l;
+       GArray *out_param;
+       invocation_info_t *req_info = NULL;
+
+       for (l = _bt_get_invocation_list(); l != NULL; ) {
+               req_info = l->data;
+               l = g_slist_next(l);
+               if (req_info == NULL ||
+                               req_info->service_function != service_function)
+                       continue;
+
+               switch (service_function) {
+               case BT_MESH_NODE_GET_VENDOR_FEATURES: {
+                       bluetooth_mesh_node_features_t *event;
+                       bluetooth_mesh_node_features_t *req;
+
+                       event = (bluetooth_mesh_node_features_t*) param;
+                       req = (bluetooth_mesh_node_features_t*)req_info->user_data;
+
+                       BT_DBG("Request Sender: [%s]", req_info->sender);
+                       /* Match Network and Remote Node unicast*/
+                       if (!g_strcmp0(event->net_uuid, req->net_uuid) && event->unicast == req->unicast) {
+                               event->unicast = req->unicast;
+                               event->elem_count = req->elem_count;
+
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, event, sizeof(bluetooth_mesh_node_features_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_node_get_vendor_features_event(result, event);
+                       }
+                       break;
+               }
+               case BT_MESH_NODE_BROWSE: {
+                       bluetooth_mesh_node_discover_t *node;
+                       event_mesh_devkey_message_t *event;
+                       uint16_t remote_addr;
+                       uint8_t elem_count;
+                       uint8_t dev_uuid[16];
+                       char net_uuid[BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1];
+
+                       event = (event_mesh_devkey_message_t*) param;
+                       node = (bluetooth_mesh_node_discover_t*)req_info->user_data;
+
+                       _bt_mesh_util_convert_hex_to_string((uint8_t *) event->net_uuid.uuid, 16, net_uuid,
+                                       BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+                       _bt_mesh_util_convert_string_to_hex(node->dev_uuid, strlen(node->dev_uuid), dev_uuid, 16);
+
+                       /* Get Unicast from pending request's Dev UUID and match with event */
+                       if (_bt_mesh_node_get_unicast_from_dev_uuid(event->net_uuid.uuid, dev_uuid, &remote_addr)) {
+
+                               BT_DBG("Request Sender: [%s]", req_info->sender);
+                               /* Match Network and Remote Node unicast*/
+                               if (!g_strcmp0(node->net_uuid, net_uuid) && remote_addr == event->source) {
+                                       out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                                       g_array_append_vals(out_param, node, sizeof(bluetooth_mesh_node_discover_t));
+
+                                       _bt_mesh_node_get_element_count(event->net_uuid.uuid, remote_addr, &elem_count);
+                                       node->unicast = event->source;
+                                       node->count = elem_count;
+
+                                       /* Return DBUS Invocation*/
+                                       _bt_service_method_return(req_info->context, out_param, result);
+                                       _bt_free_info_from_invocation_list(req_info);
+                                       g_free(req_info->user_data);
+                                       g_array_free(out_param, TRUE);
+
+                                       /* Send Event */
+                                       __bt_mesh_send_node_browsed_event(result, node);
+                               }
+                       }
+                       break;
+               }
+               case BT_MESH_NODE_CONFIGURE_KEY: {
+                       bluetooth_mesh_key_configure_t *event;
+                       bluetooth_mesh_key_configure_t *req;
+
+                       event = (bluetooth_mesh_key_configure_t*) param;
+                       req = (bluetooth_mesh_key_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast &&
+                               req->is_netkey == event->is_netkey) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, event, sizeof(bluetooth_mesh_key_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_node_key_configuration_event(result, event);
+                               }
+                       break;
+               }
+               case BT_MESH_NODE_TTL_EXECUTE: {
+                       bluetooth_mesh_node_ttl_info_t *event;
+                       bluetooth_mesh_node_ttl_info_t *req;
+
+                       event = (bluetooth_mesh_node_ttl_info_t*) param;
+                       req = (bluetooth_mesh_node_ttl_info_t*)req_info->user_data;
+                       req->ttl = event->ttl;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->unicast == event->unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_node_ttl_info_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_node_ttl_configuration_event(result, req);
+                       }
+                       break;
+               }
+               case BT_MESH_MODEL_CONFIGURE_APPKEY: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_configure_appkey_event(result, req);
+                       }
+
+                       break;
+               }
+               case BT_MESH_MODEL_GET_APPKEY_LIST: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_get_appkey_list_event(result, event);
+                       }
+                       break;
+               }
+               case BT_MESH_MODEL_GET_SUBSCRIPTION_LIST: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_get_subscription_list_event(result, event);
+                       }
+                       break;
+               }
+               case BT_MESH_MODEL_CONFIG_GROUP_SUB: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+
+                               req->sub_addr = event->sub_addr;
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_subscription_configure_event( \
+                                       BLUETOOTH_EVENT_MESH_MODEL_SUBSCRIPTION_CONFGURED, \
+                                               result, req);
+                       }
+                       break;
+               }
+               case BT_MESH_MODEL_CONFIG_VIRTUAL_GROUP_SUB: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_subscription_configure_event( \
+                                       BLUETOOTH_EVENT_MESH_MODEL_VIRTUAL_SUBSCRIPTION_CONFGURED, \
+                                               result, req);
+                       }
+                       break;
+               }
+               case BT_MESH_MODEL_GET_PUBLICATION: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_publication_status_event( \
+                                       BLUETOOTH_EVENT_MESH_MODEL_PUBLICATION_STATUS, \
+                                               result, event);
+                               }
+                       break;
+               }
+               case BT_MESH_MODEL_SET_PUBLICATION: {
+                       bluetooth_mesh_model_configure_t *event;
+                       bluetooth_mesh_model_configure_t *req;
+
+                       event = (bluetooth_mesh_model_configure_t*) param;
+                       req = (bluetooth_mesh_model_configure_t*)req_info->user_data;
+
+                       if (!g_strcmp0(req->net_uuid, event->net_uuid) &&
+                               req->primary_unicast == event->primary_unicast) {
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, req, sizeof(bluetooth_mesh_model_configure_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_free(req_info->user_data);
+                               g_array_free(out_param, TRUE);
+
+                               /* Send Event */
+                               __bt_mesh_send_model_publication_status_event( \
+                                       BLUETOOTH_EVENT_MESH_MODEL_PUBLICATION_STATUS, \
+                                               result, req);
+                               }
+                       break;
+               }
+               default:
+                       BT_DBG("Unknown function(%d)", service_function);
+                       break;
+               }
+       }
+}
+
+const char *__mesh_status_to_string(uint8_t err)
+{
+       switch (err) {
+       case MESH_STATUS_SUCCESS: return "Success";
+       case MESH_STATUS_INVALID_ADDRESS: return "Invalid Address";
+       case MESH_STATUS_INVALID_MODEL: return "Invalid Model";
+       case MESH_STATUS_INVALID_APPKEY: return "Invalid AppKey";
+       case MESH_STATUS_INVALID_NETKEY: return "Invalid NetKey";
+       case MESH_STATUS_INSUFF_RESOURCES: return "Insufficient Resources";
+       case MESH_STATUS_IDX_ALREADY_STORED: return "Key Idx Already Stored";
+       case MESH_STATUS_INVALID_PUB_PARAM: return "Invalid Publish Parameters";
+       case MESH_STATUS_NOT_SUB_MOD: return "Not a Subscribe Model";
+       case MESH_STATUS_STORAGE_FAIL: return "Storage Failure";
+       case MESH_STATUS_FEATURE_NO_SUPPORT: return "Feature Not Supported";
+       case MESH_STATUS_CANNOT_UPDATE: return "Cannot Update";
+       case MESH_STATUS_CANNOT_REMOVE: return "Cannot Remove";
+       case MESH_STATUS_CANNOT_BIND: return "Cannot bind";
+       case MESH_STATUS_UNABLE_CHANGE_STATE: return "Unable to change state";
+       case MESH_STATUS_CANNOT_SET: return "Cannot set";
+       case MESH_STATUS_UNSPECIFIED_ERROR: return "Unspecified error";
+       case MESH_STATUS_INVALID_BINDING: return "Invalid Binding";
+
+       default: return "Unknown";
+       }
+}
+
+static void __mesh_handle_model_subscription_event(int result,
+               bluetooth_mesh_model_configure_t *param,
+                       const struct mesh_config_cmd *cmd)
+{
+       switch (cmd->opcode) {
+       /* Fall through */
+       case MESH_OPCODE_CONFIG_MODEL_SUB_ADD:
+       case MESH_OPCODE_CONFIG_MODEL_SUB_DELETE:
+       case MESH_OPCODE_CONFIG_MODEL_SUB_OVERWRITE:
+       case MESH_OPCODE_CONFIG_MODEL_SUB_DELETE_ALL:
+               /* Model Bind/UnBind Event */
+       __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_MODEL_CONFIG_GROUP_SUB, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       case MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_ADD:
+       case MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_DELETE:
+       case MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_OVERWRITE:
+       __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_MODEL_CONFIG_VIRTUAL_GROUP_SUB, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       default:
+               break;
+       }
+}
+
+void _bt_mesh_config_client_devkey_msg_handler(
+               event_mesh_devkey_message_t *event)
+{
+       uint32_t opcode;
+       const struct mesh_config_cmd *cmd;
+       uint16_t data_len = event->data_len;
+       uint8_t *data = event->data;
+       int result = BLUETOOTH_ERROR_NONE;
+       uint16_t app_idx;
+       uint16_t addr;
+       uint16_t net_idx;
+       uint16_t elem_addr;
+       uint16_t ele_addr;
+       uint32_t mod_id;
+       int n;
+       struct mesh_pending_request *req;
+
+       if (_bt_mesh_util_opcode_get(data, data_len, &opcode, &n)) {
+               data_len -= n;
+               data += n;
+       } else
+               return;
+
+       BT_INFO("Mesh: Received %s (len %u)",
+               __mesh_get_opcode_string(opcode), data_len);
+
+       req = __bt_mesh_get_request_by_response(event->source,
+               event->net_uuid.uuid, (opcode & ~MESH_OPCODE_UNRELIABLE));
+       if (req) {
+               cmd = req->cmd;
+               __mesh_request_remove(req);
+               l_queue_remove(pending_requests, req);
+       } else
+               cmd = NULL;
+
+
+       switch (opcode & ~MESH_OPCODE_UNRELIABLE) {
+               default:
+                       return;
+       case MESH_OPCODE_CONFIG_MODEL_PUB_STATUS: {
+               if (data_len != 12 && data_len != 14)
+                       break;
+               bluetooth_mesh_model_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_model_configure_t));
+
+               _bt_mesh_util_convert_hex_to_string((uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+               BT_INFO("\nNode %4.4x Model Publication status %s\n",
+                               event->source, __mesh_status_to_string(data[0]));
+
+               if (data[0] != MESH_STATUS_SUCCESS)
+                       break;
+
+               /* Extract Element Address */
+               ele_addr = l_get_le16(data + 1);
+
+               /* Extract Model ID */
+               if (data_len == 14) {
+                       /* vendor Model */
+                       mod_id = l_get_le16(data + 10 + 2);
+                       mod_id = l_get_le16(data) << 16 | mod_id;
+               } else {
+                       /* BT SIG Model */
+                       mod_id = l_get_le16(data + 10);
+                       mod_id = MESH_VENDOR_ID_MASK | mod_id;
+               }
+
+               param.primary_unicast = event->source;
+               param.elem_index = ele_addr - event->source;
+               /* Extract Publish Address */
+               param.pub_addr = l_get_le16(data + 3);
+
+               /* Extract Appkey Index */
+               param.appkey_idx =  l_get_le16(data + 5);
+
+               /* Extract TTL */
+               param.ttl = data[6];
+
+               /* Extract Period */
+               param.period = data[7];
+
+               if (cmd->opcode == MESH_OPCODE_CONFIG_MODEL_PUB_GET)
+                       __bt_mesh_handle_pending_dev_config_request_info(result,
+                               BT_MESH_MODEL_GET_PUBLICATION, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               else
+                       __bt_mesh_handle_pending_dev_config_request_info(result,
+                               BT_MESH_MODEL_SET_PUBLICATION, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       }
+       case MESH_OPCODE_CONFIG_MODEL_SUB_STATUS: {
+               if (data_len != 7 && data_len != 9)
+                       break;
+               bluetooth_mesh_model_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_model_configure_t));
+
+               _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+               BT_INFO("\nNode %4.4x Subscription status %s\n",
+                               event->source, __mesh_status_to_string(data[0]));
+
+               ele_addr = l_get_le16(data + 1);
+               addr = l_get_le16(data + 3);
+               BT_INFO("Element Addr\t%4.4x\n", ele_addr);
+
+               if (data_len == 9) {
+                       /* vendor Model */
+                       mod_id = l_get_le16(data + 5 + 2);
+                       mod_id = l_get_le16(data) << 16 | mod_id;
+               } else {
+                       /* BT SIG Model */
+                       mod_id = l_get_le16(data + 5);
+                       mod_id = MESH_VENDOR_ID_MASK | mod_id;
+               }
+
+               param.primary_unicast = event->source;
+               param.elem_index = ele_addr - event->source;
+               /* Subscription address, unassigned address in case of Delete All command */
+               param.sub_addr = addr;
+               param.model = mod_id;
+               BT_INFO("Subscr Addr\t%4.4x\n", addr);
+               __mesh_handle_model_subscription_event(result, &param, cmd);
+               break;
+       }
+       case MESH_OPCODE_CONFIG_DEFAULT_TTL_STATUS: {
+               if (data_len != 1)
+                       break;
+               bluetooth_mesh_node_ttl_info_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_node_ttl_info_t));
+
+               BT_INFO("Node %4.4x Default TTL %d", event->source, data[0]);
+                _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+               param.unicast = event->source;
+               param.ttl = data[0];
+
+               if (!_bt_mesh_network_save_remote_node_ttl(event->net_uuid.uuid,
+                               event->source,  data[0])) {
+                       result = BLUETOOTH_ERROR_INTERNAL;
+                       BT_INFO("Failed to save node TTL");
+               }
+
+               /* Remote Node TTL event */
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_NODE_TTL_EXECUTE, &param,
+                               sizeof(bluetooth_mesh_node_ttl_info_t));
+               break;
+       }
+       case MESH_OPCODE_MODEL_APP_STATUS: {
+               if (data_len != 7 && data_len != 9)
+                       break;
+               bluetooth_mesh_model_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_model_configure_t));
+
+                _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+               BT_INFO("Node %4.4x: Model App status %s\n", event->source,
+                       __mesh_status_to_string(data[0]));
+               elem_addr = l_get_le16(data + 1);
+               app_idx = l_get_le16(data + 3);
+
+               BT_INFO("Element Addr\t%4.4x", elem_addr);
+               if (data_len == 9) {
+                       /* vendor Model */
+                       mod_id = l_get_le16(data + 5 + 2);
+                       mod_id = l_get_le16(data) << 16 | mod_id;
+               } else {
+                       /* BT SIG Model */
+                       mod_id = l_get_le16(data + 5);
+                       mod_id = MESH_VENDOR_ID_MASK | mod_id;
+               }
+
+               param.primary_unicast = event->source;
+               param.elem_index = elem_addr - event->source;
+               param.appkey_idx = app_idx;
+               param.model = mod_id;
+               BT_INFO("AppIdx\t\t%u (0x%3.3x)\n ", app_idx, app_idx);
+
+               /* Model Bind/UnBind Event */
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_MODEL_CONFIGURE_APPKEY, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       }
+       case MESH_OPCODE_MODEL_APP_LIST: {
+               if (data_len < 5)
+                       break;
+               GArray *garray;
+               int total = 0;
+               bluetooth_mesh_model_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_model_configure_t));
+
+               _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+               garray = g_array_new(FALSE, FALSE, sizeof(gchar));
+
+               BT_INFO("\nNode %4.4x Model AppIdx status %s\n",
+                               event->source, __mesh_status_to_string(data[0]));
+
+               BT_INFO("Element Addr\t%4.4x\n", l_get_le16(data + 1));
+               BT_INFO("Model ID\t%4.4x\n", l_get_le16(data + 3));
+
+               elem_addr = l_get_le16(data + 1);
+               /* BT SIG Model */
+               mod_id = l_get_le16(data + 3);
+               mod_id = MESH_VENDOR_ID_MASK | mod_id;
+
+               param.primary_unicast = event->source;
+               param.elem_index = elem_addr - event->source;
+               param.model = mod_id;
+
+               data += 5;
+               data_len -= 5;
+
+               while (data_len >= 3) {
+                       app_idx = l_get_le16(data) & 0xfff;
+                       g_array_append_vals(garray, &app_idx, sizeof(uint16_t));
+                       BT_INFO("\t%u (0x%3.3x)\n", app_idx, app_idx);
+
+                       app_idx = l_get_le16(data + 1) >> 4;
+                       g_array_append_vals(garray, &app_idx, sizeof(uint16_t));
+                       BT_INFO("\t%u (0x%3.3x)\n", app_idx, app_idx);
+                       data += 3;
+                       data_len -= 3;
+               }
+
+               if (data_len == 2) {
+                       app_idx = l_get_le16(data) & 0xfff;
+                       g_array_append_vals(garray, &app_idx, sizeof(uint16_t));
+                       BT_INFO("\t %u (0x%3.3x)\n", app_idx, app_idx);
+               }
+               total = garray->len / sizeof(uint16_t);
+               param.appkey_list = (uint16_t **)g_malloc0(sizeof(uint16_t*) * garray->len);
+               param.appkeylist_count = total;
+               for (int i = 0; i < total; i++) {
+                       param.appkey_list[i] = g_malloc(sizeof(uint16_t));
+                       *param.appkey_list[i] = g_array_index(garray, uint16_t, i);
+               }
+               g_array_free(garray, TRUE);
+
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_MODEL_GET_APPKEY_LIST, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       }
+       case MESH_OPCODE_CONFIG_MODEL_SUB_LIST: {
+               if (data_len < 5)
+                       break;
+               int total = 0;
+               int i = 0;
+               bluetooth_mesh_model_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_model_configure_t));
+
+               _bt_mesh_util_convert_hex_to_string((uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+               BT_INFO("\nNode %4.4x BT SIG Model Subscription List status %s\n",
+                               event->source, __mesh_status_to_string(data[0]));
+
+               BT_INFO("Element Addr\t%4.4x\n", l_get_le16(data + 1));
+               elem_addr = l_get_le16(data + 1);
+
+               /* BT SIG Model */
+               mod_id = l_get_le16(data + 3);
+               mod_id = MESH_VENDOR_ID_MASK | mod_id;
+               BT_INFO("Model ID\t%4.4x\n", mod_id);
+
+               param.primary_unicast = event->source;
+               param.elem_index = elem_addr - event->source;
+               param.model = mod_id;
+
+               total = data_len -  5;
+               param.sublist_count = total;
+               if (total) {
+                       param.sub_list = (uint16_t **)g_malloc0(sizeof(uint16_t*) * total);
+
+                       i = 5;
+                       for (; i < data_len; i += 2) {
+                               BT_INFO("Subscription Addr \t\t%4.4x\n ", l_get_le16(data + i));
+                               param.sub_list[i] = g_malloc(sizeof(uint16_t));
+                               *param.sub_list[i] = l_get_le16(data + i);
+                       }
+               }
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_MODEL_GET_SUBSCRIPTION_LIST, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       }
+       case MESH_OPCODE_CONFIG_VEND_MODEL_SUB_LIST: {
+               if (data_len < 7)
+                       break;
+               int total = 0;
+               int i = 0;
+               bluetooth_mesh_model_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_model_configure_t));
+
+               _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+               BT_INFO("\nNode %4.4x BT SIG Model Subscription List status %s\n",
+                               event->source, __mesh_status_to_string(data[0]));
+
+               BT_INFO("Element Addr\t%4.4x\n", l_get_le16(data + 1));
+               elem_addr = l_get_le16(data + 1);
+
+               /* VENDOR Model */
+               mod_id = l_get_le16(data + 5);
+               mod_id = l_get_le16(data + 3) << 16 | mod_id;
+
+               BT_INFO("Model ID\t%4.4x\n", mod_id);
+
+               param.primary_unicast = event->source;
+               param.elem_index = elem_addr - event->source;
+               param.model = mod_id;
+
+               total = data_len -  7;
+               param.sublist_count = total;
+               if (total) {
+                       param.sub_list = (uint16_t **)g_malloc0(sizeof(uint16_t*) * total);
+
+                       i = 7;
+                       for (; i < data_len; i += 2) {
+                               BT_INFO("Subscription Addr \t\t%4.4x\n ", l_get_le16(data + i));
+                               param.sub_list[i] = g_malloc(sizeof(uint16_t));
+                               *param.sub_list[i] = l_get_le16(data + i);
+                       }
+               }
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_MODEL_GET_SUBSCRIPTION_LIST, &param,
+                               sizeof(bluetooth_mesh_model_configure_t));
+               break;
+       }
+       case MESH_OPCODE_DEV_COMP_STATUS: {
+               if (data_len < MESH_MINIMUM_COMPOSITION_LEN)
+                       break;
+               bluetooth_mesh_node_features_t features;
+               memset(&features, 0x00, sizeof(bluetooth_mesh_node_features_t));
+
+               __bt_mesh_print_device_composition_data(data, data_len);
+
+               if (!_bt_mesh_network_save_remote_node_composition(
+                       event->net_uuid.uuid, event->source, data, data_len)) {
+                       result = BLUETOOTH_ERROR_INTERNAL;
+                       BT_INFO("Failed to save node composition!");
+               }
+               /* Browse Remote Node event */
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_NODE_BROWSE, event, sizeof(event_mesh_devkey_message_t));
+
+               /* Vendor Features Discover event */
+               _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, features.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+               features.unicast = event->source;
+               _bt_mesh_node_get_vendor_features(event->net_uuid.uuid,
+                       event->source, &features);
+
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_NODE_GET_VENDOR_FEATURES, &features,
+                               sizeof(bluetooth_mesh_node_features_t));
+               break;
+       }
+       case MESH_OPCODE_NETKEY_STATUS: {
+               if (data_len != 3)
+                       break;
+
+               bluetooth_mesh_key_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_key_configure_t));
+
+               BT_INFO("Mesh: Node %4.4x NetKey status %s",
+                       event->source,  __mesh_status_to_string(data[0]));
+               net_idx = l_get_le16(data + 1) & 0xfff;
+
+               BT_INFO("\tNetKey %u (0x%3.3x)", net_idx, net_idx);
+
+               if (data[0] != 0)
+                       break;
+
+               if (!cmd)
+                       break;
+
+               _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+               param.primary_unicast = event->source;
+               param.netkey_idx = net_idx;
+               param.is_netkey = true;
+
+               if (cmd->opcode == MESH_OPCODE_NETKEY_ADD) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_NETKEY_ADD");
+                       if (_bt_mesh_network_save_remote_node_netkey(
+                                       event->net_uuid.uuid, event->source, net_idx)) {
+                               result = BLUETOOTH_ERROR_INTERNAL;
+                               BT_INFO("Failed to save node Netkey!");
+                       }
+                       param.op = BLUETOOTH_MESH_NODE_KEY_ADD;
+               } else if (cmd->opcode == MESH_OPCODE_NETKEY_DELETE) {
+                       if (_bt_mesh_network_delete_remote_node_netkey(
+                                       event->net_uuid.uuid, event->source, net_idx)) {
+                               result = BLUETOOTH_ERROR_INTERNAL;
+                               BT_INFO("Failed to delete node Netkey!");
+                       }
+                       param.op = BLUETOOTH_MESH_NODE_KEY_DELETE;
+               } else if (cmd->opcode == MESH_OPCODE_NETKEY_UPDATE) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_NETKEY_UPDATE");
+                       param.op = BLUETOOTH_MESH_NODE_KEY_UPDATE;
+               }
+               /* Node Net Key Configure event */
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_NODE_CONFIGURE_KEY,
+                               &param, sizeof(bluetooth_mesh_key_configure_t));
+               break;
+       }
+       case MESH_OPCODE_APPKEY_STATUS: {
+               if (data_len != 4)
+                       break;
+
+               bluetooth_mesh_key_configure_t param;
+               memset(&param, 0x00, sizeof(bluetooth_mesh_key_configure_t));
+
+               BT_INFO("Mesh: Node %4.4x AppKey status %s\n", event->source,
+                               __mesh_status_to_string(data[0]));
+               net_idx = l_get_le16(data + 1) & 0xfff;
+               app_idx = l_get_le16(data + 2) >> 4;
+
+               BT_INFO("NetKey\t%u (0x%3.3x)\n", net_idx, net_idx);
+               BT_INFO("AppKey\t%u (0x%3.3x)\n", app_idx, app_idx);
+
+               if (data[0] != MESH_STATUS_SUCCESS)
+                       break;
+
+               if (!cmd)
+                       break;
+
+               _bt_mesh_util_convert_hex_to_string(
+                       (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+               param.primary_unicast = event->source;
+               param.netkey_idx = net_idx;
+               param.appkey_idx = app_idx;
+               param.is_netkey = false;
+
+               if (cmd->opcode == MESH_OPCODE_APPKEY_ADD) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_APPKEY_ADD");
+                       if (_bt_mesh_network_save_remote_node_appkey(
+                               event->net_uuid.uuid, event->source,
+                                       net_idx, app_idx)) {
+                               result = BLUETOOTH_ERROR_INTERNAL;
+                               BT_INFO("Failed to save node Appkey!");
+                       }
+                       param.op = BLUETOOTH_MESH_NODE_KEY_ADD;
+               } else if (cmd->opcode == MESH_OPCODE_APPKEY_DELETE) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_APPKEY_DELETE");
+                       if (_bt_mesh_network_delete_remote_node_appkey(
+                               event->net_uuid.uuid, event->source,
+                                       net_idx, app_idx)) {
+                               result = BLUETOOTH_ERROR_INTERNAL;
+                               BT_INFO("Failed to delete node Appkey!");
+                       }
+                       param.op = BLUETOOTH_MESH_NODE_KEY_DELETE;
+               } else if (cmd->opcode == MESH_OPCODE_APPKEY_UPDATE) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_APPKEY_UPDATE");
+                       param.op = BLUETOOTH_MESH_NODE_KEY_UPDATE;
+               }
+
+               /* Node App Key Configure event */
+               __bt_mesh_handle_pending_dev_config_request_info(result,
+                       BT_MESH_NODE_CONFIGURE_KEY,
+                               &param, sizeof(bluetooth_mesh_key_configure_t));
+               break;
+       }
+       }
+}
+
+static gboolean __bt_mesh_vendor_feature_event_handler(gpointer data)
+{
+       bluetooth_mesh_node_features_t *result = (bluetooth_mesh_node_features_t*) data;
+       __bt_mesh_handle_pending_dev_config_request_info(
+               BLUETOOTH_ERROR_NONE,
+                       BT_MESH_NODE_GET_VENDOR_FEATURES,
+                               result, sizeof(bluetooth_mesh_node_features_t));
+       g_free(result);
+       return FALSE;
+}
+
+int _bt_mesh_node_discover_vendor_features(const char *app_cred, const char *sender,
+               bluetooth_mesh_node_features_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t dest;
+       uint16_t netkey_idx;
+       uint16_t data_len;
+       oal_uuid_t net_uuid;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+                       strlen(req->net_uuid), net_uuid.uuid, 16);
+       /* Check if Node's vendor features are already svaed or not */
+       if (_bt_mesh_node_get_vendor_features(net_uuid.uuid, req->unicast, req)) {
+               /* Schedule event ot Application */
+               bluetooth_mesh_node_features_t *event = \
+                       g_memdup(req, sizeof(bluetooth_mesh_node_features_t));
+               g_idle_add(__bt_mesh_vendor_feature_event_handler, (gpointer) event);
+               return BLUETOOTH_ERROR_NONE;
+       }
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+                       strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       dest = req->unicast;
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(MESH_OPCODE_DEV_COMP_GET,
+                               dest, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Get Subnet index of the rmeote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, dest);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       data_len = _bt_mesh_util_opcode_set(MESH_OPCODE_DEV_COMP_GET,
+                       buffer);
+
+       /* By default, use page 0 */
+       buffer[data_len++] = 0;
+       ret = mesh_conf_send_message(&net_uuid, dest, true,
+                       netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(MESH_OPCODE_DEV_COMP_GET,
+                       dest, net_uuid.uuid, NULL);
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_browse_remote_node(const char *app_cred,
+       const char *sender,
+               bluetooth_mesh_node_discover_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t dest;
+       uint16_t netkey_idx;
+       uint16_t data_len;
+       oal_uuid_t net_uuid;
+       oal_uuid_t dev_uuid;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+               strlen(req->net_uuid), net_uuid.uuid, 16);
+       _bt_mesh_util_convert_string_to_hex(req->dev_uuid,
+               strlen(req->dev_uuid), dev_uuid.uuid, 16);
+
+       /* Get Remote Node unicast address from Dev UUID */
+       if (!_bt_mesh_node_get_unicast_from_dev_uuid(net_uuid.uuid,
+                       dev_uuid.uuid, &dest))
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(MESH_OPCODE_DEV_COMP_GET,
+                       dest, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Get Subnet index of the rmeote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, dest);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       data_len = _bt_mesh_util_opcode_set(MESH_OPCODE_DEV_COMP_GET, buffer);
+
+       /* By default, use page 0 */
+       buffer[data_len++] = 0;
+       ret = mesh_conf_send_message(&net_uuid, dest, true,
+                       netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(MESH_OPCODE_DEV_COMP_GET,
+                       dest, net_uuid.uuid, NULL);
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_model_configure_group_subscription(const char *app_cred,
+               const char *sender, bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       if (req->op != BLUETOOTH_MESH_MODEL_SUB_DELETE_ALL) {
+               /* Subscriptio address sanity check */
+               if ((!MESH_IS_GROUP(req->sub_addr) ||
+                       MESH_IS_ALL_NODES(req->sub_addr)) ||
+                               MESH_IS_VIRTUAL(req->sub_addr)) {
+                       BT_ERR("Mesh: Bad subscription address %x\n",
+                               req->sub_addr);
+                       return BLUETOOTH_ERROR_INVALID_PARAM;
+               }
+       }
+
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid,
+                               req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+               strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       if (req->op == BLUETOOTH_MESH_MODEL_SUB_ADD)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_ADD;
+       else if (req->op == BLUETOOTH_MESH_MODEL_SUB_DELETE)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_DELETE;
+       else if (req->op == BLUETOOTH_MESH_MODEL_SUB_DELETE_ALL)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_DELETE_ALL;
+       else if (req->op == BLUETOOTH_MESH_MODEL_SUB_OVERWRITE)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_OVERWRITE;
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(opcode,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index),
+                       buffer + data_len);
+       data_len += 2;
+
+       /* Subscription address */
+       if (req->op != BLUETOOTH_MESH_MODEL_SUB_DELETE_ALL) {
+               l_put_le16(req->sub_addr, buffer + data_len);
+               data_len += 2;
+       }
+
+       /* Insert Model ID */
+        if (req->model >= 0xFFFF0000) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid, req->primary_unicast, true,
+                       netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast,
+               net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_model_configure_virtual_group_subscription(
+               const char *app_cred, const char *sender,
+                       bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+               strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       if (req->op != BLUETOOTH_MESH_MODEL_SUB_DELETE_ALL) {
+               /* Subscription address sanity check */
+               if ((MESH_IS_GROUP(req->sub_addr) ||
+                       MESH_IS_ALL_NODES(req->sub_addr)) ||
+                               !(MESH_IS_VIRTUAL(req->sub_addr))) {
+                       BT_ERR("Mesh: Bad Virtual subscription address %x\n",
+                               req->sub_addr);
+                       return BLUETOOTH_ERROR_INVALID_PARAM;
+               }
+       }
+
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid,
+                               req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       if (req->op == BLUETOOTH_MESH_MODEL_SUB_ADD)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_ADD;
+       else if (req->op == BLUETOOTH_MESH_MODEL_SUB_DELETE)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_DELETE;
+       else if (req->op == BLUETOOTH_MESH_MODEL_SUB_DELETE_ALL)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_DELETE_ALL;
+       else if (req->op == BLUETOOTH_MESH_MODEL_SUB_OVERWRITE)
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_OVERWRITE;
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(opcode,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index), buffer + data_len);
+       data_len += 2;
+
+       /* Subscription address */
+       if (req->op != BLUETOOTH_MESH_MODEL_SUB_DELETE_ALL) {
+               uint8_t label_uuid[16];
+               if (!_bt_mesh_network_get_label_uuid_from_sub_addr(
+                       net_uuid.uuid, req->sub_addr, label_uuid)) {
+                       BT_ERR("Mesh: Virtual Group Label UUID Not found");
+                       return BLUETOOTH_ERROR_INVALID_PARAM;
+               }
+               memcpy(buffer + data_len, label_uuid, 16);
+               data_len += 16;
+       }
+
+       /* Insert Model ID */
+        if (req->model >= 0xFFFF0000) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid,
+                       req->primary_unicast, true,
+                               netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast,
+               net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_model_get_publication(const char *app_cred, const char *sender,
+               bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+               strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(MESH_OPCODE_CONFIG_MODEL_PUB_GET,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       /* Set Opcode */
+       data_len = _bt_mesh_util_opcode_set(MESH_OPCODE_CONFIG_MODEL_PUB_GET, buffer);
+
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index), buffer + data_len);
+       data_len += 2;
+
+       /* Insert Model ID */
+       if (req->model >= 0xFFFF0000) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid, req->primary_unicast, true, netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(MESH_OPCODE_CONFIG_MODEL_PUB_GET, req->primary_unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_model_set_publication(const char *app_cred, const char *sender,
+               bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t label_uuid[16];
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid, strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       if (req->pub_addr > MESH_ALL_NODES_ADDRESS)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+
+       if (!MESH_IS_GROUP(req->pub_addr) && !MESH_IS_VIRTUAL(req->pub_addr) &&
+                       req->pub_addr != MESH_UNASSIGNED_ADDRESS) {
+               BT_ERR("Mesh: Bad Publication address %x\n", req->pub_addr);
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       if (req->pub_addr != MESH_UNASSIGNED_ADDRESS) {
+               if (MESH_IS_VIRTUAL(req->pub_addr)) {
+                       if(!_bt_mesh_network_get_label_uuid_from_sub_addr(
+                                       net_uuid.uuid, req->pub_addr, label_uuid))
+                               return BLUETOOTH_ERROR_INVALID_PARAM;
+                       opcode = MESH_OPCODE_CONFIG_MODEL_PUB_VIRT_SET;
+
+               } else if (MESH_IS_GROUP(req->pub_addr))
+                       opcode = MESH_OPCODE_CONFIG_MODEL_PUB_SET;
+       }
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(opcode,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(
+                               net_uuid.uuid, req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       /* Set opcode */
+       data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index), buffer + data_len);
+       data_len += 2;
+
+       /* Fill Publication Address */
+       if (MESH_IS_VIRTUAL(req->pub_addr)) {
+               memcpy(buffer + data_len, label_uuid, 16);
+               data_len += 16;
+       } else {
+               l_put_le16(req->pub_addr, buffer + data_len);
+               data_len += 2;
+       }
+
+       /* AppKey index + credential (set to 0) */
+       l_put_le16(req->appkey_idx, buffer + data_len);
+       data_len += 2;
+
+       /* Fill TTL */
+       buffer[data_len++] = req->ttl;
+       /* Publish period  step count and step resolution */
+       buffer[data_len++] = req->period;
+       /* Publish retransmit count & interval steps */
+       buffer[data_len++] = req->retransmit;
+
+       /* Insert Model ID */
+       if (req->model >= 0xFFFF0000) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid,
+                       req->primary_unicast, true,
+                               netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_node_model_get_subscription_list(const char *app_cred, const char *sender,
+               bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid, strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       /* Insert Model ID */
+       if (req->model >= 0xFFFF0000)
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               opcode = MESH_OPCODE_CONFIG_MODEL_SUB_GET;
+       else
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               opcode = MESH_OPCODE_CONFIG_VEND_MODEL_SUB_GET;
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(opcode,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index), buffer + data_len);
+       data_len += 2;
+
+
+       /* Insert Model ID */
+       if (opcode == MESH_OPCODE_CONFIG_MODEL_SUB_GET) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid,
+               req->primary_unicast, true, netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_node_model_get_appkey_list(const char *app_cred, const char *sender,
+               bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid,
+               strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       /* Insert Model ID */
+       if (req->model >= 0xFFFF0000)
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               opcode = MESH_OPCODE_MODEL_APP_GET;
+       else
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               opcode = MESH_OPCODE_VENDOR_MODEL_APP_GET;
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(opcode,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index), buffer + data_len);
+       data_len += 2;
+
+
+       /* Insert Model ID */
+       if (opcode == MESH_OPCODE_MODEL_APP_GET) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid, req->primary_unicast, true, netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_node_model_appkey_execute(const char *app_cred, const char *sender,
+               bluetooth_mesh_model_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid, strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(req->is_bind ? MESH_OPCODE_MODEL_APP_BIND : MESH_OPCODE_MODEL_APP_UNBIND,
+                               req->primary_unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+       /* Get Subnet index of the remote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       if (req->is_bind)
+               opcode = MESH_OPCODE_MODEL_APP_BIND;
+       else
+               opcode = MESH_OPCODE_MODEL_APP_UNBIND;
+
+       data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+       /* Element Address */
+       l_put_le16((req->primary_unicast + req->elem_index), buffer + data_len);
+       data_len += 2;
+
+       /* AppKey Index  */
+       l_put_le16(req->appkey_idx, buffer + data_len);
+       data_len += 2;
+
+       /* Insert Model ID */
+       if (req->model >= 0xFFFF0000) {
+               /* 1st 2 octet Company ID is 0xFFFF means, it is BT SIG Model*/
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       } else {
+               /* Vendor Model, 1st 2 octetes: Company ID, next 2 octets: Vendor Model ID */
+               l_put_le16(req->model & 0xFFFF0000, buffer + data_len);
+               data_len += 2;
+               l_put_le16(req->model & 0x0000FFFF, buffer + data_len);
+               data_len += 2;
+       }
+
+       ret = mesh_conf_send_message(&net_uuid, req->primary_unicast, true, netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_configure_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_ttl_execute_remote_node(const char *app_cred, const char *sender,
+               bluetooth_mesh_node_ttl_info_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       uint16_t data_len;
+       oal_uuid_t net_uuid;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid, strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       /* Check pending request */
+       if (_bt_mesh_check_pending_request(req->is_set ? MESH_OPCODE_CONFIG_DEFAULT_TTL_SET : MESH_OPCODE_CONFIG_DEFAULT_TTL_GET,
+                               req->unicast, net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Get Subnet index of the rmeote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, req->unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       if (req->is_set) {
+               opcode = MESH_OPCODE_CONFIG_DEFAULT_TTL_SET;
+               data_len = _bt_mesh_util_opcode_set(MESH_OPCODE_CONFIG_DEFAULT_TTL_SET, buffer);
+               buffer[data_len++] = req->ttl;
+       } else {
+               opcode = MESH_OPCODE_CONFIG_DEFAULT_TTL_GET;
+               data_len = _bt_mesh_util_opcode_set(MESH_OPCODE_CONFIG_DEFAULT_TTL_GET, buffer);
+       }
+
+       ret = mesh_conf_send_message(&net_uuid, req->unicast, true, netkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_node_ttl_info_t)));
+       return BLUETOOTH_ERROR_NONE;
+}
+
+static bool __bt_mesh_check_pending_key_cmd(uint16_t dest, bool is_netkey,
+               bluetooth_mesh_node_key_conf_e op,  uint8_t net_uuid[], uint32_t *opcode)
+{
+       const struct mesh_config_cmd *cmd;
+
+       if (is_netkey) {
+               switch(op) {
+               case BLUETOOTH_MESH_NODE_KEY_ADD:
+                       cmd = __mesh_get_command(MESH_OPCODE_NETKEY_ADD);
+                       if (!cmd)
+                               return false;
+                       if (__bt_mesh_get_request_by_response(dest, net_uuid, cmd->response)) {
+                               BT_ERR("Mesh:Another Key Configuration command is pending\n");
+                               return true;
+                       }
+                       *opcode = MESH_OPCODE_NETKEY_ADD;
+                       return false;
+               case BLUETOOTH_MESH_NODE_KEY_DELETE:
+                       cmd = __mesh_get_command(MESH_OPCODE_NETKEY_DELETE);
+                       if (!cmd)
+                               return false;
+                       if (__bt_mesh_get_request_by_response(dest, net_uuid, cmd->response)) {
+                               BT_ERR("Mesh:Another Key Configuration command is pending\n");
+                               return true;
+                       }
+                       *opcode = MESH_OPCODE_NETKEY_DELETE;
+                       return false;
+               case BLUETOOTH_MESH_NODE_KEY_UPDATE:
+                       cmd = __mesh_get_command(MESH_OPCODE_NETKEY_UPDATE);
+                       if (!cmd)
+                               return false;
+                       if (__bt_mesh_get_request_by_response(dest, net_uuid, cmd->response)) {
+                               BT_ERR("Mesh:Another Key Configuration command is pending\n");
+                               return true;
+                       }
+                       *opcode = MESH_OPCODE_NETKEY_UPDATE;
+                       return false;
+               }
+       } else {
+               switch(op) {
+               case BLUETOOTH_MESH_NODE_KEY_ADD:
+                       cmd = __mesh_get_command(MESH_OPCODE_APPKEY_ADD);
+                       if (!cmd)
+                               return false;
+                       if (__bt_mesh_get_request_by_response(dest, net_uuid, cmd->response)) {
+                               BT_ERR("Mesh:Another Key Configuration command is pending\n");
+                               return true;
+                       }
+                       *opcode = MESH_OPCODE_APPKEY_ADD;
+                       return false;
+               case BLUETOOTH_MESH_NODE_KEY_DELETE:
+                       cmd = __mesh_get_command(MESH_OPCODE_APPKEY_DELETE);
+                       if (!cmd)
+                               return false;
+                       if (__bt_mesh_get_request_by_response(dest, net_uuid, cmd->response)) {
+                               BT_ERR("Mesh:Another Key Configuration command is pending\n");
+                               return true;
+                       }
+                       *opcode = MESH_OPCODE_APPKEY_DELETE;
+                       return false;
+               case BLUETOOTH_MESH_NODE_KEY_UPDATE:
+                       cmd = __mesh_get_command(MESH_OPCODE_APPKEY_UPDATE);
+                       if (!cmd)
+                               return false;
+                       if (__bt_mesh_get_request_by_response(dest, net_uuid, cmd->response)) {
+                               BT_ERR("Mesh:Another Key Configuration command is pending\n");
+                               return true;
+                       }
+                       *opcode = MESH_OPCODE_APPKEY_UPDATE;
+                       return false;
+               }
+       }
+       return false;
+}
+
+int _bt_mesh_node_configure_key(const char *app_cred, const char *sender,
+               bluetooth_mesh_key_configure_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t netkey_idx;
+       uint16_t bound_netkey_idx = 0x0000;
+       oal_uuid_t net_uuid;
+       uint32_t opcode = 0;
+       bool update;
+       uint16_t data_len;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid, strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       if (req->is_netkey && _bt_mesh_keys_subnet_exists(net_uuid.uuid, req->netkey_idx)) {
+               BT_ERR("Local Subnet not found..");
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
+
+       /* For Appkey Configuration, check for available bound netkey */
+       if (!req->is_netkey) {
+               bound_netkey_idx = _bt_mesh_keys_get_bound_key(net_uuid.uuid, req->appkey_idx);
+               if (bound_netkey_idx == MESH_NET_IDX_INVALID) {
+                       BT_ERR("Local AppKey not found..");
+                       return BLUETOOTH_ERROR_INVALID_PARAM;
+               }
+       }
+
+       /* Check pending request */
+       if (__bt_mesh_check_pending_key_cmd(req->primary_unicast,
+                               req->is_netkey, req->op, net_uuid.uuid, &opcode)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Get Subnet index of the rmeote node for TX encryption */
+       netkey_idx = _bt_mesh_node_get_subnet_idx(net_uuid.uuid, req->primary_unicast);
+       if (netkey_idx == MESH_NET_IDX_INVALID)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       /* Handle Key (App/Net) Delete Commands: Configuration Message  */
+       if (opcode == MESH_OPCODE_NETKEY_DELETE || opcode == MESH_OPCODE_APPKEY_DELETE) {
+               data_len = _bt_mesh_util_opcode_set(opcode, buffer);
+               if (req->is_netkey) {
+                       l_put_le16(req->netkey_idx, buffer + data_len);
+                       data_len += 2;
+               } else {
+                       buffer[data_len] = bound_netkey_idx;
+                       buffer[data_len + 1] = ((bound_netkey_idx >> 8) & 0xf) | ((req->appkey_idx << 4) & 0xf0);
+                       buffer[data_len + 2] = req->appkey_idx >> 4;
+
+                       data_len += 3;
+               }
+               ret = mesh_conf_send_message(&net_uuid, req->primary_unicast, true, netkey_idx, buffer, data_len);
+       } else {
+               /* Handle Key (App/Net) Update & Add Commands: Key Config message  */
+               update = (opcode == MESH_OPCODE_NETKEY_UPDATE || opcode == MESH_OPCODE_APPKEY_UPDATE);
+               ret = mesh_conf_send_key_message(&net_uuid, req->primary_unicast, req->is_netkey,
+                               update, req->is_netkey? req->netkey_idx: req->appkey_idx, netkey_idx);
+       }
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast,  net_uuid.uuid,
+               g_memdup(req, sizeof(bluetooth_mesh_key_configure_t)));
+       return BLUETOOTH_ERROR_NONE;
+}
index ec032f5..5968fc5 100644 (file)
@@ -93,6 +93,18 @@ static gint __mesh_compare_hex_uuid(gconstpointer data,
        return memcmp(u1->node_uuid, u2, 16);
 }
 
+static gint __mesh_compare_app_network_uuid(
+       gconstpointer data, gconstpointer user_data)
+{
+       const _bt_mesh_cdb_t *cdb = data;
+       const uint8_t *net_uuid = user_data;
+
+       retv_if(NULL == cdb, -1);
+       retv_if(NULL == net_uuid, -1);
+
+       return memcmp(net_uuid, cdb->uuid, 16);
+}
+
 static gint __mesh_compare_app_cdb_token(gconstpointer data,
                gconstpointer user_data)
 {
@@ -112,6 +124,31 @@ static gint __mesh_compare_app_cdb_token(gconstpointer data,
        return ret;
 }
 
+static gint __mesh_compare_addr(
+               const void *a, const void *b)
+{
+       const _bt_mesh_group_t *grp = a;
+       uint16_t addr = GPOINTER_TO_UINT(b);
+
+       return grp->grp_addr == addr;
+}
+
+static gint __mesh_compare_group_address(
+               const void *a, const void *b,
+                       void *user_data)
+{
+       const _bt_mesh_group_t *grp0 = a;
+       const _bt_mesh_group_t *grp1 = b;
+
+       if (grp0->grp_addr < grp1->grp_addr)
+               return -1;
+
+       if (grp0->grp_addr > grp1->grp_addr)
+               return 1;
+
+       return 0;
+}
+
 int _bt_mesh_load_app_networks(const char *app_cred)
 {
        int ret = BLUETOOTH_ERROR_NONE;
@@ -447,6 +484,58 @@ int _bt_mesh_network_get_appkeys(const char *app_cred, const char *sender,
                return BLUETOOTH_ERROR_INTERNAL;
 }
 
+int _bt_mesh_network_node_get_netkeys(const char *app_cred,
+       bluetooth_mesh_node_discover_t *node,
+               GArray **out_param)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+       uint8_t net_uuid[16];
+
+       _bt_mesh_util_convert_string_to_hex(node->net_uuid,
+                       strlen(node->net_uuid), net_uuid, 16);
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_get_all_netkeys(cdb_cfg->uuid,
+                               node->unicast, out_param))
+               return BLUETOOTH_ERROR_NONE;
+       else
+               return BLUETOOTH_ERROR_INTERNAL;
+}
+
+int _bt_mesh_network_node_get_appkeys(const char *app_cred,
+               const char *sender, bluetooth_mesh_node_discover_t *node,
+                        GArray **out_param)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+       uint8_t net_uuid[16];
+
+       _bt_mesh_util_convert_string_to_hex(node->net_uuid,
+                       strlen(node->net_uuid), net_uuid, 16);
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_get_all_appkeys(cdb_cfg->uuid,
+                               node->unicast, out_param))
+               return BLUETOOTH_ERROR_NONE;
+       else
+               return BLUETOOTH_ERROR_INTERNAL;
+}
+
 int _bt_mesh_element_get_models(const char *app_cred, const char *sender,
                bluetooth_mesh_network_t *network,  uint16_t unicast,
                        int elem_idx, GArray **out_param)
@@ -756,3 +845,444 @@ int _bt_mesh_network_create(const char *app_cred, const char *sender,
 
        return BLUETOOTH_ERROR_NONE;
 }
+
+bool _bt_mesh_network_save_remote_node_appkey(
+               uint8_t net_uuid[], uint16_t remote_unicast,
+                       uint16_t netkey_idx, uint16_t appkey_idx)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_add_app_key(net_uuid,
+                       remote_unicast, appkey_idx))
+               return _bt_mesh_conf_node_insert_application_key(cdb_cfg,
+                                       remote_unicast, appkey_idx);
+
+       return false;
+}
+
+bool _bt_mesh_network_delete_remote_node_appkey(
+               uint8_t net_uuid[], uint16_t remote_unicast,
+                               uint16_t netkey_idx, uint16_t appkey_idx)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_del_net_key(cdb_cfg,
+                       net_uuid, remote_unicast, appkey_idx))
+               return _bt_mesh_conf_node_delete_application_key(cdb_cfg,
+                               remote_unicast, appkey_idx);
+
+       return false;
+}
+
+bool _bt_mesh_network_save_remote_node_ttl(
+       uint8_t net_uuid[], uint16_t remote_unicast,
+                       uint8_t ttl)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       return _bt_mesh_conf_node_set_timetolive_value(cdb_cfg,
+                               remote_unicast, ttl);
+}
+
+bool _bt_mesh_network_save_remote_node_netkey(
+               uint8_t net_uuid[], uint16_t remote_unicast,
+                               uint16_t netkey_idx)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_add_net_key(net_uuid,
+                       remote_unicast, netkey_idx))
+               return _bt_mesh_conf_node_insert_network_key(cdb_cfg,
+                                       remote_unicast, netkey_idx);
+
+       return false;
+}
+
+bool _bt_mesh_network_delete_remote_node_netkey(
+               uint8_t net_uuid[], uint16_t remote_unicast,
+                       uint16_t netkey_idx)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_del_net_key(cdb_cfg, net_uuid,
+                       remote_unicast, netkey_idx))
+               return _bt_mesh_conf_node_delete_network_key(cdb_cfg,
+                               remote_unicast, netkey_idx);
+       return false;
+}
+
+bool _bt_mesh_network_save_remote_node_composition(
+               uint8_t net_uuid[], uint16_t remote_unicast,
+                               uint8_t *data, uint16_t data_len)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+               __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       return _bt_mesh_conf_set_node_comp_data(cdb_cfg,
+                       remote_unicast, data, data_len);
+}
+
+int _bt_mesh_network_add_remote_node(uint8_t net_uuid[],
+       uint8_t dev_uuid[], uint16_t unicast, uint8_t count)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       _bt_mesh_node_add_node(net_uuid, dev_uuid,
+                       unicast, count, MESH_PRIMARY_NET_IDX);
+
+       /* Add Remote Node entry in CDB */
+       _bt_mesh_conf_insert_node_object(cdb_cfg, /* Dev UUID */ dev_uuid,
+                       count, unicast, MESH_PRIMARY_NET_IDX);
+
+       /* Mark Provisioning state to done */
+       _bt_mesh_set_provisioning_state(true);
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+bool _bt_mesh_node_get_vendor_features(uint8_t net_uuid[],
+       uint16_t unicast, bluetooth_mesh_node_features_t *feats)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       return _bt_mesh_conf_fetch_vendor_specific_info(cdb_cfg,
+                       &feats->vendor_info.companyid, &feats->vendor_info.vendorid,
+                       &feats->vendor_info.versionid, &feats->vendor_info.crpl,
+                       &feats->features.relay, &feats->features.frnd,
+                       &feats->features.proxy, &feats->features.lpn);
+}
+
+int _bt_mesh_network_load(const char *app_cred,
+       const char *sender, const char *token)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       GSList *l;
+       char *dir_path = NULL;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+       oal_mesh_node_t node;
+       GSList *models = NULL;
+
+       /* Check CDB directory exist or not */
+       dir_path = g_strdup_printf(MESH_CDB_DEFAULT_DIR_PATH"/%s/", "default");
+       if (!_bt_mesh_util_is_directory_exists(dir_path)) {
+               BT_ERR("Mesh: CDB dir [%s]does not exist for app", dir_path);
+               g_free(dir_path);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, token,
+                       __mesh_compare_app_cdb_token);
+       if (l) {
+               BT_INFO("Mesh: Already loaded");
+               g_free(dir_path);
+               return BLUETOOTH_ERROR_NONE;
+       } else {
+               BT_INFO("Mesh: Not loaded");
+               /* Attempt to load CDB's present in app's
+                  CDB directory */
+               const char *filename;
+               GDir *dir = g_dir_open(dir_path, 0, NULL);
+               if (!dir) {
+                       BT_ERR("Mesh: Could not open directory");
+                       g_free(dir_path);
+                       return BLUETOOTH_ERROR_INTERNAL;
+               }
+               g_free(dir_path);
+               while ((filename = g_dir_read_name(dir)) != NULL) {
+
+                       if ((g_file_test(filename, G_FILE_TEST_IS_SYMLINK) == TRUE) ||
+                                       (g_str_has_suffix(filename, ".json") == FALSE))
+                               continue;
+
+                       BT_INFO("Mesh: File name [%s]", filename);
+                       cdb_cfg = _bt_mesh_cdb_load(filename, token);
+                       if (cdb_cfg)
+                               break;
+               }
+       }
+
+       if (!cdb_cfg) {
+               BT_ERR("Mesh: Could not find CDB for the token!! Possibly not authorized!!");
+               return BLUETOOTH_ERROR_ACCESS_DENIED;
+       }
+
+       /* Fill the Mesh node info  */
+       memset(&node, 0x00, sizeof(oal_mesh_node_t));
+       memcpy(node.uuid.uuid, cdb_cfg->uuid, sizeof(oal_uuid_t));
+       _bt_mesh_util_convert_string_to_hex(token, strlen(token), node.token.u8, 8);
+       if (!_bt_mesh_conf_get_element_count(cdb_cfg, &node.num_elements)) {
+               _bt_mesh_conf_free(cdb_cfg);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       if (!_bt_mesh_conf_fetch_vendor_specific_info(cdb_cfg,
+                               &node.vendor_info.companyid, &node.vendor_info.vendorid,
+                               &node.vendor_info.versionid, &node.vendor_info.crpl,
+                               &node.vendor_info.relay, &node.vendor_info.frnd,
+                               &node.vendor_info.proxy, &node.vendor_info.lpn)) {
+
+               _bt_mesh_conf_free(cdb_cfg);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       for (int i = 0; i < node.num_elements; i++) {
+               int num_models;
+               uint16_t **model_array = _bt_mesh_conf_get_all_model_info(
+                               cdb_cfg, i, &num_models);
+               if (!model_array) {
+                       _bt_mesh_conf_free(cdb_cfg);
+                       return BLUETOOTH_ERROR_INTERNAL;
+               }
+
+               for (int j = 0; j < num_models; j++) {
+                       bluetooth_mesh_model_t *mod;
+                       mod = g_malloc0(sizeof(bluetooth_mesh_model_t));
+                       mod->elem_index = i;
+                       mod->model_id = *model_array[j];
+                       models = g_slist_append(models, mod);
+               }
+               /* Free all model(s) */
+               for (int j = 0; j < num_models; j++)
+                       g_free(model_array[j]);
+       }
+
+       /* Register Mesh Node */
+       ret = mesh_register_node((oal_mesh_node_t*)&node,
+                       models, true);
+
+       /* Cleanup */
+       g_slist_free_full(models, g_free);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("Mesh: Load Network Failed ret: %d", ret);
+               _bt_mesh_conf_free(cdb_cfg);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Save till Network attached */
+       cdb_list = g_slist_append(cdb_list, cdb_cfg);
+       return ret;
+}
+
+bool _bt_mesh_network_get_label_uuid_from_sub_addr(
+               uint8_t net_uuid[],     uint16_t sub_addr,
+                               uint8_t label[])
+{
+       GSList *l, *l1;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net_uuid,
+                       __mesh_compare_app_network_uuid);
+       if (!l)
+               return false;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       l1 = g_slist_find_custom(cdb_cfg->groups,
+                       GUINT_TO_POINTER(sub_addr), __mesh_compare_addr);
+
+       if (!l1)
+               return false;
+       else {
+               _bt_mesh_group_t *grp = l1->data;
+               memcpy(label, grp->label_uuid, 16);
+       }
+       return true;
+}
+
+int _bt_mesh_network_create_group(const char *app_cred,
+       const char *sender, bluetooth_mesh_network_t *net,
+               bool is_virtual, uint16_t addr,
+                       bluetooth_mesh_network_group_info_t *req)
+{
+       GSList *l, *l1, *l2;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, net->token.token,
+                       __mesh_compare_app_cdb_token);
+       if (!l)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (is_virtual) {
+               uint8_t max_tries = 5;
+               _bt_mesh_group_t *grp = NULL;
+               grp = g_malloc0(sizeof(_bt_mesh_group_t));
+
+retry:
+               l_getrandom(grp->label_uuid, 16);
+               _bt_mesh_util_crypto_create_virtual_address(
+                               grp->label_uuid, &grp->grp_addr);
+
+               /* For simplicity sake, avoid labels that map to the same hash */
+               l1 = g_slist_find_custom(cdb_cfg->groups,
+                               GUINT_TO_POINTER(grp->grp_addr), __mesh_compare_addr);
+
+               if (!l1) {
+                       l2 = g_slist_insert_sorted_with_data(cdb_cfg->groups,
+                                       grp, __mesh_compare_group_address, NULL);
+                       if (l2) {
+                               _bt_mesh_conf_insert_group_info(cdb_cfg, grp);
+                               req->is_virtual = true;
+                               req->group_addr = grp->grp_addr;
+                               _bt_mesh_util_convert_hex_to_string(
+                                               (uint8_t *) grp->label_uuid, 16, req->label_uuid,
+                                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+                               return BLUETOOTH_ERROR_NONE;
+                       }
+               }
+
+               max_tries--;
+               if (max_tries)
+                       goto retry;
+
+               g_free(grp);
+               /* Failed to create a unique hash */
+               return BLUETOOTH_ERROR_INTERNAL;
+       } else {
+               if (!MESH_IS_GROUP(addr))
+                       return BLUETOOTH_ERROR_INVALID_PARAM;
+
+               l1 = g_slist_find_custom(cdb_cfg->groups,
+                               GUINT_TO_POINTER(addr), __mesh_compare_addr);
+
+               if (l1) {
+                       _bt_mesh_group_t *grp = l1->data;
+                       req->is_virtual = false;
+                       req->group_addr = grp->grp_addr;
+               } else {
+                       /* Group is not present */
+                       _bt_mesh_group_t *grp = g_malloc0(sizeof(_bt_mesh_group_t));
+                       grp->grp_addr = addr;
+                       _bt_mesh_conf_insert_group_info(cdb_cfg, grp);
+                       l = g_slist_insert_sorted_with_data(cdb_cfg->groups, grp,
+                                       __mesh_compare_group_address, NULL);
+                       req->is_virtual = false;
+                       req->group_addr = grp->grp_addr;
+               }
+
+       }
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_network_get_groups(const char *app_cred, const char *sender,
+               bluetooth_mesh_network_t *network,
+                       GArray **out_param)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, network->token.token,
+                       __mesh_compare_app_cdb_token);
+       if (!l)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       for (l = cdb_cfg->groups; l; l = l->next) {
+               _bt_mesh_group_t *group = l->data;
+
+               g_array_append_vals(*out_param,
+                               &group->grp_addr, sizeof(uint16_t));
+       }
+
+       return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_mesh_network_get_nodes(const char *app_cred,
+               const char *sender, bluetooth_mesh_network_t *network,
+                       GArray **out_param)
+{
+       GSList *l;
+       _bt_mesh_cdb_t *cdb_cfg = NULL;
+
+       /* Find CDB */
+       l = g_slist_find_custom(cdb_list, network->token.token,
+                       __mesh_compare_app_cdb_token);
+       if (!l)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       cdb_cfg = (_bt_mesh_cdb_t*)l->data;
+
+       if (_bt_mesh_node_get_all(cdb_cfg->uuid, out_param))
+               return BLUETOOTH_ERROR_NONE;
+       else
+               return BLUETOOTH_ERROR_INTERNAL;
+}
index acffb35..f0d6099 100644 (file)
@@ -62,6 +62,17 @@ struct mesh_key_index {
        uint16_t idx;
 };
 
+static bool __mesh_match_bound_key(const void *a, const void *b)
+{
+       uint16_t app_idx = L_PTR_TO_UINT(a);
+       const struct mesh_key_index *data = b;
+
+       uint16_t net_idx = L_PTR_TO_UINT(b);
+
+       return (net_idx == _bt_mesh_keys_get_bound_key(
+                               (uint8_t*)data->uuid, app_idx));
+}
+
 static bool __mesh_match_node_dev_uuid(const void *a, const void *b)
 {
        const struct _bt_mesh_node_t *node = a;
@@ -299,6 +310,45 @@ bool _bt_mesh_node_set_model(uint8_t net_uuid[],
        return true;
 }
 
+bool _bt_mesh_node_del_net_key(_bt_mesh_cdb_t *cfg,
+       uint8_t net_uuid[], uint16_t addr,
+               uint16_t net_idx)
+{
+       struct _bt_mesh_node_t *rmt;
+       void *data;
+       struct mesh_network_t *network;
+       struct mesh_key_index *user_data;
+
+       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 (!l_queue_remove(rmt->net_keys, L_UINT_TO_PTR(net_idx)))
+               return false;
+
+       user_data = g_malloc0(sizeof(struct mesh_key_index));
+       memcpy(user_data->uuid, net_uuid, 16);
+       user_data->idx = net_idx;
+
+       data = l_queue_remove_if(rmt->app_keys,
+                       __mesh_match_bound_key, user_data);
+       while (data) {
+               uint16_t app_idx = (uint16_t) L_PTR_TO_UINT(data);
+
+               _bt_mesh_conf_node_delete_application_key(cfg, rmt->unicast, app_idx);
+               data = l_queue_remove_if(rmt->app_keys,
+                               __mesh_match_bound_key, user_data);
+       }
+
+       g_free(user_data);
+       return true;
+}
+
 bool _bt_mesh_node_get_all_appkeys(uint8_t net_uuid[],
                uint16_t unicast, GArray **out)
 {
index 08fe99a..9307c0e 100644 (file)
@@ -131,8 +131,6 @@ uint16_t _bt_mesh_util_opcode_set(uint32_t opcode,
 bool _bt_mesh_util_opcode_get(const uint8_t *buf,
                uint16_t sz, uint32_t *opcode, int *n)
 {
-       BT_INFO("Mesh: Opcode Get DatLen [%d] Buf0 [0x%x]",
-                       sz, buf[0]);
        if (!n || !opcode || sz < 1) return false;
 
        switch (buf[0] & 0xc0) {