--- /dev/null
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Abhay Agarwal <ay.agarwal@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 "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 "bt-service-mesh-config-client.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_handle_pending_msg_request_info(int result,
+ int service_function, void *param,
+ unsigned int size);
+
+struct mesh_msg_cmd {
+ uint32_t opcode;
+ uint32_t response;
+ const char *descriptor;
+};
+
+static struct l_queue *pending_msg_requests;
+
+struct mesh_pending_request {
+ struct l_timeout *timer;
+ const struct mesh_msg_cmd *cmd;
+ uint8_t net_uuid[16];
+ uint16_t addr;
+ void *data;
+};
+
+static struct mesh_msg_cmd commands[] = {
+ { MESH_OPCODE_MODEL_GENERIC_ONOFF_GET, MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS, "ModelGenericOnoffGet" },
+ { MESH_OPCODE_MODEL_GENERIC_ONOFF_SET, MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS, "ModelGenericOnoffSet" },
+ { MESH_OPCODE_MODEL_GENERIC_ONOFF_SET_UNACK, MESH_RESPONSE_NONE, "ModelGenericOnoffSetUnack" },
+ { MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS, MESH_RESPONSE_NONE, "ModelGenericOnoffStatus" }
+};
+
+
+static const struct mesh_msg_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_msg_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);
+
+
+ switch(req->cmd->opcode) {
+ case MESH_OPCODE_MODEL_GENERIC_ONOFF_GET:
+ case MESH_OPCODE_MODEL_GENERIC_ONOFF_SET:
+ /* Send event with timeout */
+ __bt_mesh_handle_pending_msg_request_info(
+ BLUETOOTH_ERROR_TIMEOUT,
+ BT_MESH_MODEL_EXECUTE_MSG, req->data,
+ sizeof(bluetooth_mesh_model_msg_t));
+ break;
+ default:
+ break;
+ }
+ BT_INFO("Mesh: Number of pending requests [%u] Remove the req",
+ l_queue_length(pending_msg_requests));
+ l_queue_remove(pending_msg_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_msg_cmd *cmd;
+ char uuid_str[33];
+
+ cmd = __mesh_get_command(opcode);
+ if (!cmd)
+ return;
+ _bt_mesh_util_convert_hex_to_string((uint8_t *) net_uuid, 16, uuid_str,
+ BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+ BT_INFO("Mesh: Net UUID[%s]",uuid_str);
+
+ BT_INFO("Mesh: Adding command opcode [0x%2.2x] response [0x%2.2x]",
+ cmd->opcode, cmd->response);
+ 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);
+
+ if (!pending_msg_requests)
+ pending_msg_requests = l_queue_new();
+ l_queue_push_tail(pending_msg_requests, req);
+ BT_INFO("Mesh: Number of pending requests [%u]", l_queue_length(pending_msg_requests));
+}
+
+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;
+ char uuid_str[33];
+ char uuid_str1[33];
+
+ BT_INFO("Mesh: Number of pending requests [%u]", l_queue_length(pending_msg_requests));
+ entry = l_queue_get_entries(pending_msg_requests);
+
+ for (; entry; entry = entry->next) {
+ struct mesh_pending_request *req = entry->data;
+
+ /* Test */
+ BT_INFO("Mesh: Req addr [0x%4.4x] req opcode [0x%4.4x] res [0x%4.4x]", req->addr, req->cmd->opcode, req->cmd->response);
+ BT_INFO("Mesh: Current req addr [0x%4.4x] res [0x%4.4x]", addr, response);
+ _bt_mesh_util_convert_hex_to_string((uint8_t *) net_uuid, 16, uuid_str,
+ BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+ BT_INFO("Mesh: Net UUID[%s]",uuid_str);
+
+ _bt_mesh_util_convert_hex_to_string((uint8_t *) req->net_uuid, 16, uuid_str1,
+ BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+ BT_INFO("Mesh: Net UUID1[%s]",uuid_str1);
+ 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_msg_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 void __bt_mesh_send_model_msg_event(int result,
+ bluetooth_mesh_model_msg_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_msg_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_MODEL_MSG_EXECUTED,
+ param);
+ }
+}
+
+static void __bt_mesh_handle_pending_msg_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_MODEL_EXECUTE_MSG: {
+ bluetooth_mesh_model_msg_t *event;
+ bluetooth_mesh_model_msg_t *req;
+
+ event = (bluetooth_mesh_model_msg_t*) param;
+ req = (bluetooth_mesh_model_msg_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->primary_unicast == req->primary_unicast) {
+ event->elem_index = req->elem_index;
+
+ /* Send Event */
+ __bt_mesh_send_model_msg_event(result, event);
+
+ out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+ g_array_append_vals(out_param, event, sizeof(bluetooth_mesh_model_msg_t));
+
+ /* Return DBUS Invocation*/
+ _bt_service_method_return(req_info->context, out_param, result);
+ _bt_free_info_from_invocation_list(req_info);
+ g_array_free(out_param, TRUE);
+ }
+ break;
+ }
+ default:
+ BT_DBG("Unknown function(%d)", service_function);
+ break;
+ }
+ }
+}
+
+void _bt_mesh_msg_handler(event_mesh_message_t *event)
+{
+ uint32_t opcode;
+ uint16_t data_len = event->data_len;
+ uint8_t *data = event->data;
+ int n;
+ const struct mesh_msg_cmd *cmd;
+ struct mesh_pending_request *req;
+
+ int result = BLUETOOTH_ERROR_NONE;
+
+ if (_bt_mesh_util_opcode_get(data, data_len, &opcode, &n)) {
+ BT_INFO("Mesh: Opcode of response data [0x%2.2x], actual data len [%d]", opcode, n);
+ data_len -= n;
+ data += n;
+ } else
+ return;
+
+ for (int msg_idx = 0; msg_idx < data_len; msg_idx++ ) {
+ BT_INFO("Mesh: Message data[%d]: [%2.2X]", msg_idx, data[msg_idx]);
+ }
+
+ BT_INFO("Mesh: Received %s (len %u) opcode [0x%2.2x]",
+ __mesh_get_opcode_string(opcode), data_len, opcode);
+
+ req = __bt_mesh_get_request_by_response(event->source,
+ event->net_uuid.uuid, (opcode & ~MESH_OPCODE_UNRELIABLE));
+
+ if (req) {
+ BT_INFO("Mesh: Got Request");
+ cmd = req->cmd;
+ __mesh_request_remove(req);
+ l_queue_remove(pending_msg_requests, req);
+ } else
+ cmd = NULL;
+
+ bluetooth_mesh_model_msg_t param;
+ memset(¶m, 0x00, sizeof(bluetooth_mesh_model_msg_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);
+
+ param.primary_unicast = event->source;
+ param.elem_index = 0;
+ param.appkey_idx = event->key_idx;
+ param.msg_len = data_len*2;
+ _bt_mesh_util_convert_hex_to_string(
+ (uint8_t *) data, data_len, param.msg,
+ param.msg_len + 1);
+
+ param.appkey_idx = event->key_idx;
+ param.opcode = opcode;
+ BT_INFO("Send response");
+
+ switch (opcode & ~MESH_OPCODE_UNRELIABLE) {
+ default:
+ return;
+ case MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS: {
+ BT_INFO("Received Generic On off status");
+
+ BT_INFO("Mesh: Node %4.4x", event->source);
+ if (!cmd) {
+ BT_INFO("No pending req for this status");
+ break;
+ }
+ if (cmd->opcode == MESH_OPCODE_MODEL_GENERIC_ONOFF_GET) {
+ BT_INFO("Mesh: Resp recvd: MESH_OPCODE_MODEL_GENERIC_ONOFF_GET");
+ } else if (cmd->opcode == MESH_OPCODE_MODEL_GENERIC_ONOFF_SET) {
+ BT_INFO("Mesh: Resp recvd: MESH_OPCODE_MODEL_GENERIC_ONOFF_SET");
+ } else {
+ BT_INFO("Request opcode do not match !");
+ }
+ }
+ }
+ __bt_mesh_handle_pending_msg_request_info(result,
+ BT_MESH_MODEL_EXECUTE_MSG, ¶m,
+ sizeof(bluetooth_mesh_model_msg_t));
+
+}
+
+int _bt_mesh_node_model_execute_msg(const char *app_cred, const char *sender,
+ bluetooth_mesh_model_msg_t *req)
+{
+ int ret = OAL_STATUS_SUCCESS;
+ uint16_t appkey_idx;
+ oal_uuid_t net_uuid;
+ uint16_t data_len;
+ uint32_t opcode = 0;
+ uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+ uint8_t msg[BLUETOOTH_MESH_MODEL_MSG_LENGTH_MAX + 1];
+
+ /* If Scanning is going on */
+ if (_bt_mesh_is_provisioning() ||
+ _bt_mesh_is_scanning()) {
+ BT_ERR("Device is buzy..");
+ return BLUETOOTH_ERROR_DEVICE_BUSY;
+ }
+
+ /* Check pending request */
+ opcode = req->opcode;
+ if (_bt_mesh_check_pending_request(opcode, req->primary_unicast,
+ net_uuid.uuid)) {
+ 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);
+
+ appkey_idx = req->appkey_idx;
+
+ /* Update data buffer */
+ data_len = _bt_mesh_util_opcode_set(req->opcode, buffer);
+
+ BT_DBG("Mesh: Model string msg opcode: 0x%2.2X msg_len: %d",
+ req->opcode, req->msg_len);
+ if (req->msg_len > 0) {
+ /* Convert Mesh msg to hex*/
+ BT_DBG("Mesh: Model string msg opcode: 0x%2.2X msg_len: %d, msg: %s",
+ req->opcode, strlen(req->msg), req->msg);
+ _bt_mesh_util_convert_string_to_hex(req->msg, strlen(req->msg), msg, (req->msg_len)/2);
+
+ for (int msg_idx = 0; msg_idx < (req->msg_len)/2; msg_idx++)
+ BT_DBG("Mesh: Model hex msg[%d]: msg: 0x%2.2X", msg_idx, msg[msg_idx]);
+
+ /* Append model msg */
+ if (req->msg_len > 0) {
+ memcpy(buffer + data_len, msg, req->msg_len);
+ data_len += req->msg_len;
+ }
+ }
+
+ ret = mesh_model_send_message(&net_uuid, req->primary_unicast, appkey_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_msg_t)));
+
+ return BLUETOOTH_ERROR_NONE;
+}