--- /dev/null
+/*
+ * 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, ¶m,
+ 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, ¶m,
+ 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(¶m, 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, ¶m,
+ sizeof(bluetooth_mesh_model_configure_t));
+ else
+ __bt_mesh_handle_pending_dev_config_request_info(result,
+ BT_MESH_MODEL_SET_PUBLICATION, ¶m,
+ 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(¶m, 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, ¶m, cmd);
+ break;
+ }
+ case MESH_OPCODE_CONFIG_DEFAULT_TTL_STATUS: {
+ if (data_len != 1)
+ break;
+ bluetooth_mesh_node_ttl_info_t param;
+ memset(¶m, 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, ¶m,
+ 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(¶m, 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, ¶m,
+ 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(¶m, 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, ¶m,
+ 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(¶m, 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, ¶m,
+ 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(¶m, 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, ¶m,
+ 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(¶m, 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,
+ ¶m, sizeof(bluetooth_mesh_key_configure_t));
+ break;
+ }
+ case MESH_OPCODE_APPKEY_STATUS: {
+ if (data_len != 4)
+ break;
+
+ bluetooth_mesh_key_configure_t param;
+ memset(¶m, 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,
+ ¶m, 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;
+}