From ab6f4b7b98524a2bdb95a37826e93ad4b63e7138 Mon Sep 17 00:00:00 2001 From: Anupam Roy Date: Thu, 25 Jun 2020 20:30:54 +0530 Subject: [PATCH] Mesh: Add HAL implementation This patch adds following - Implements the HAL interface for Mesh Network & Node configurations. - Implements HAL DBUS handler interfaces for communicating with Mesh daemon Change-Id: I4bcf3e3e7d18911ed676c09ffa6d3fae421937da Signed-off-by: Anupam Roy --- bt-oal/bluez_hal/CMakeLists.txt | 2 + bt-oal/bluez_hal/src/bt-hal-mesh-dbus-handler.c | 2205 +++++++++++++++++++++++ bt-oal/bluez_hal/src/bt-hal-mesh.c | 344 ++++ bt-oal/bluez_hal/src/bt-hal-mesh.h | 33 + 4 files changed, 2584 insertions(+) create mode 100644 bt-oal/bluez_hal/src/bt-hal-mesh-dbus-handler.c create mode 100644 bt-oal/bluez_hal/src/bt-hal-mesh.c create mode 100644 bt-oal/bluez_hal/src/bt-hal-mesh.h diff --git a/bt-oal/bluez_hal/CMakeLists.txt b/bt-oal/bluez_hal/CMakeLists.txt index 08fad30..2ac18ae 100644 --- a/bt-oal/bluez_hal/CMakeLists.txt +++ b/bt-oal/bluez_hal/CMakeLists.txt @@ -35,6 +35,8 @@ SET(SRCS ./src/bt-hal-gatt-client.c ./src/bt-hal-hf-client.c ./src/bt-hal-hf-client-dbus-handler.c +./src/bt-hal-mesh.c +./src/bt-hal-mesh-dbus-handler.c ) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) diff --git a/bt-oal/bluez_hal/src/bt-hal-mesh-dbus-handler.c b/bt-oal/bluez_hal/src/bt-hal-mesh-dbus-handler.c new file mode 100644 index 0000000..db099aa --- /dev/null +++ b/bt-oal/bluez_hal/src/bt-hal-mesh-dbus-handler.c @@ -0,0 +1,2205 @@ +/* + * Bluetooth HAL + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + * + * @author: Anupam Roy + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bt-hal-mesh-dbus-handler.h" +#include "bt-hal-dbus-common-utils.h" +#include "bt-hal-internal.h" + +#include + +#define BT_HAL_UUID_LEN 16 +#define BT_HAL_BLUEZ_MESH_NAME "org.bluez.mesh" + +#define BT_HAL_MESH_NETWORK_INTERFACE "org.bluez.mesh.Network1" +#define BT_HAL_MESH_NODE_INTERFACE "org.bluez.mesh.Node1" +#define BT_HAL_MESH_MANAGEMENT_INTERFACE "org.bluez.mesh.Management1" +#define BT_HAL_MESH_ELEMENT_INTERFACE "org.bluez.mesh.Element1" +#define BT_HAL_MESH_APPLICATION_INTERFACE "org.bluez.mesh.Application1" +#define BT_HAL_MESH_PROVISION_AGENT_INTERFACE "org.bluez.mesh.ProvisionAgent1" +#define BT_HAL_MESH_PROVISIONER_INTERFACE "org.bluez.mesh.Provisioner1" +#define BT_HAL_MESH_ERROR_INTERFACE "org.bluez.mesh.Error" + +#define BT_HAL_MESH_MAX_DEVKEY_BUF_SIZE 2048 + +static const char *dbus_err_args = "org.freedesktop.DBus.Error.InvalidArgs"; +static const char *dbus_err_fail = "org.freedesktop.DBus.Error.Failed"; + +static struct l_dbus *dbus = NULL; +static struct l_dbus_client *client = NULL; + +static struct l_dbus_proxy *net_proxy; +static struct l_dbus_message *agent_msg; + +static handle_stack_msg mesh_event_cb = NULL; + + +struct subnet_key_request { + uint16_t idx; + const char *str; +}; + +struct app_key_request { + uint16_t net_idx; + uint16_t app_idx; + const char *str; +}; + +struct configuration_request { + const char *ele_path; + bool rmt; + bool is_dev_key; + uint16_t dst; + uint16_t idx; + uint8_t *data; + uint16_t len; +}; + +struct key_config_request { + const char *ele_path; + uint16_t dst; + uint16_t key_req_idx; + uint16_t idx; + bool update_req; +}; + +struct mesh_provision_auth_action { + const char *action; + bt_hal_mesh_auth_variant_e auth_type; +}; + +static struct mesh_provision_auth_action auth_table[] = { + { "blink", BT_HAL_MESH_AUTH_REQ_BLINK_COUNT_INPUT}, + { "beep", BT_HAL_MESH_AUTH_REQ_BEEP_COUNT_INPUT}, + { "vibrate", BT_HAL_MESH_AUTH_REQ_VIBRATE_COUNT_INPUT}, + { "in-numeric", BT_HAL_MESH_AUTH_REQ_NUMERIC_INPUT}, + { "in-alpha", BT_HAL_MESH_AUTH_REQ_ALPHANUMERIC_INPUT}, + { "twist", BT_HAL_MESH_AUTH_TWIST_COUNT_DISPLAY}, + { "push", BT_HAL_MESH_AUTH_PUSH_COUNT_DISPLAY}, + { "out-numeric", BT_HAL_MESH_AUTH_NUMERIC_DISPLAY}, + { "out-alpha", BT_HAL_MESH_AUTH_ALPHANUMERIC_DISPLAY}, + { "static-oob", BT_HAL_MESH_AUTH_REQ_OOB_STATIC_KEY_INPUT}, +}; + + +static uint8_t __bt_mesh_util_get_prov_error_code(char *prov_err_str) +{ + uint8_t ret = 0; + + if (!g_strcmp0(prov_err_str, "success")) + ret = BT_HAL_MESH_PROV_ERR_SUCCESS; + else if (!g_strcmp0(prov_err_str, "bad-pduread")) + ret = BT_HAL_MESH_PROV_ERR_INVALID_PDU; + else if (!g_strcmp0(prov_err_str, "confirmation-failed")) + ret = BT_HAL_MESH_PROV_ERR_CONFIRM_FAILED; + else if (!g_strcmp0(prov_err_str, "out-of-resources")) + ret = BT_HAL_MESH_PROV_ERR_INSUF_RESOURCE; + else if (!g_strcmp0(prov_err_str, "decryption-error")) + ret = BT_HAL_MESH_PROV_ERR_DECRYPT_FAILED; + else if (!g_strcmp0(prov_err_str, "cannot-assign-addresses")) + ret = BT_HAL_MESH_PROV_ERR_CANT_ASSIGN_ADDR; + else if (!g_strcmp0(prov_err_str, "timeout")) + ret = BT_HAL_MESH_PROV_ERR_TIMEOUT; + else if (!g_strcmp0(prov_err_str, "unexpected-error")) + ret = BT_HAL_MESH_PROV_ERR_UNEXPECTED_ERR; + + return ret; +} + +static bt_hal_mesh_auth_variant_e __mesh_get_authentication_type(char *str) +{ + int len = strlen(str); + int sz = L_ARRAY_SIZE(auth_table); + int i; + + for (i = 0; i < sz; ++i) + if (len == strlen(auth_table[i].action) && + !strcmp(str, auth_table[i].action)) + break; + + return auth_table[i].auth_type; +} + +enum mesh_dbus_interface_e { + MESH_APP_IFACE, + MESH_PROV_IFACE, + MESH_AGENT_IFACE, + MESH_ELEMENT_IFACE, +}; + +typedef enum mesh_dbus_interface_e mesh_dbus_interface_e; + +struct meshcfg_model { + uint16_t elem_index; + uint32_t model; +}; + +typedef struct meshcfg_model meshcfg_model; + +struct meshcfg_el { + char *path; + uint16_t index; + GSList *models; +}; + +typedef struct meshcfg_el meshcfg_el; + +struct meshcfg_app { + /* Remember Proxies & dbus paths */ + char *path; + char *agent_path; + struct l_dbus_proxy *proxy; + struct l_dbus_proxy *mgmt_proxy; + + /* Local node Info */ + GSList *elements; + uint16_t cid; + uint16_t pid; + uint16_t vid; + uint16_t crpl; + uint8_t uuid[16]; + union { + uint64_t u64; + uint8_t u8[8]; + } token; + bool is_prov; + /* Caps */ + bool static_oob; + bool public_oob; + uint16_t out_oob; + uint16_t in_oob; + struct l_dbus_message *msg; + guint scan_timer_id; +}; + +typedef struct meshcfg_app meshcfg_app; + +/* Will contain critical data related to local Mesh Network */ +GSList *mesh_apps; + + +struct meshcfg_node { + const char *path; + struct l_dbus_proxy *proxy; + struct l_dbus_proxy *mgmt_proxy; + union { + uint64_t u64; + uint8_t u8[8]; + } token; +}; + +typedef struct meshcfg_node meshcfg_node; + +static void __mesh_append_byte_array(struct l_dbus_message_builder *builder, + unsigned char *data, unsigned int len) +{ + unsigned int i; + + l_dbus_message_builder_enter_array(builder, "y"); + + for (i = 0; i < len; i++) + l_dbus_message_builder_append_basic(builder, 'y', &(data[i])); + + l_dbus_message_builder_leave_array(builder); +} + +static gint __mesh_compare_network_uuid(gconstpointer data, gconstpointer user_data) +{ + const meshcfg_app *app = (meshcfg_app*) data; + uint8_t uuid[16]; + memcpy(uuid, (uint8_t*) user_data, 16); + + return memcmp(uuid, app->uuid, sizeof(bt_uuid_t)); +} + +static unsigned char* __mesh_get_net_uuid_from_dbus_proxy_path( + const char *dbus_path) +{ + char uuid[33]; + size_t sz; + + memcpy(uuid, (void*)&dbus_path[20], sizeof(uuid)); + uuid[32] = '\0'; + INFO("Mesh: Net UUID string [%s]", uuid); + return l_util_from_hexstring(uuid, &sz); +} + +static unsigned char* __mesh_get_net_uuid_from_path( + const char *dbus_path, bool is_prov, + mesh_dbus_interface_e iface) +{ + char uuid[33]; + size_t sz; + + switch(iface) { + case MESH_APP_IFACE: + case MESH_PROV_IFACE: { + memcpy(uuid, is_prov ? (void*) &dbus_path[16] : (void*) &dbus_path[17], 32); + uuid[32] = '\0'; + return l_util_from_hexstring(uuid, &sz); + } + case MESH_AGENT_IFACE: { + memcpy(uuid, is_prov ? (void*) &dbus_path[22] : (void*) &dbus_path[23], 32); + uuid[32] = '\0'; + return l_util_from_hexstring(uuid, &sz); + } + case MESH_ELEMENT_IFACE: { + memcpy(uuid, is_prov ? (void*) &dbus_path[16] : (void*) &dbus_path[17], 32); + uuid[32] = '\0'; + return l_util_from_hexstring(uuid, &sz); + } + default: + return NULL; + } +} + +static void __mesh_hal_free_elements(gpointer data) +{ + meshcfg_el *element = (meshcfg_el*) data; + g_free(element->path); + if (element->models) + g_slist_free_full(element->models, g_free); + g_free(element); +} + +static void __bt_hal_mesh_destroy_app_object(gpointer data) +{ + + meshcfg_app *app = (meshcfg_app*) data; + if (!app) + return; + + mesh_apps = g_slist_remove(mesh_apps, app); + g_free(app->path); + g_free(app->agent_path); + + if (app->elements) + g_slist_free_full(app->elements, __mesh_hal_free_elements); + g_free(app); +} + +static void __mesh_client_connected(struct l_dbus *dbus, void *user_data) +{ + ERR("MESH: D-Bus client connected\n"); +} + +static void __mesh_client_disconnected(struct l_dbus *dbus, void *user_data) +{ + ERR("MESH: D-Bus client disconnected, possibly meshd exited \n"); + /* TODO: Send event to app about meshd termination & then remove all mesh apps */ + if (mesh_apps) { + g_slist_free_full(mesh_apps, __bt_hal_mesh_destroy_app_object); + mesh_apps = NULL; + } +} + +static gint __compare_proxy_path(gconstpointer data, gconstpointer user_data) +{ + int ret = 0; + char *app_uuid_path; + const meshcfg_app *app = (meshcfg_app*) data; + char *path = (char *) user_data; + INFO("Mesh: proxy path compare: path [%s]", path); + INFO("Mesh: App Path path [%s]", app->path); + if (!path) + return -1; + + app_uuid_path = l_util_hexstring(app->uuid, 16); + INFO("Mesh:App UUID string [%s]", app_uuid_path); + char **strings = g_strsplit(path, "node", 2); + + INFO("Mesh:String 0 [%s]", strings[0]); + INFO("Mesh:String 1 [%s]", strings[1]); + ret = g_strcmp0(strings[1], app_uuid_path); + g_free(strings[0]); + g_free(strings[1]); + l_free(app_uuid_path); + return ret; +} + +static gint __compare_element_index(gconstpointer data, gconstpointer user_data) +{ + const meshcfg_el *elem = data; + uint16_t elem_index = GPOINTER_TO_UINT(user_data); + if (!elem) + return 1; + + return (elem->index == elem_index ? 0: -1); +} + +static void __mesh_proxy_added(struct l_dbus_proxy *proxy, void *user_data) +{ + const char *interface = l_dbus_proxy_get_interface(proxy); + const char *path = l_dbus_proxy_get_path(proxy); + + INFO("MESH: Proxy added: %s (%s)\n", interface, path); + + if (!strcmp(interface, BT_HAL_MESH_NETWORK_INTERFACE)) { + + /* Save Global proxy */ + net_proxy = proxy; + return; + } + + if (!strcmp(interface, BT_HAL_MESH_MANAGEMENT_INTERFACE)) { + GSList *l; + meshcfg_app *app; + INFO("Mesh: Number of mesh app present in list [%d]", + g_slist_length(mesh_apps)); + l = g_slist_find_custom(mesh_apps, path, __compare_proxy_path); + if (l) { + app = l->data; + app->mgmt_proxy = proxy; + } else { + ERR("Mesh: app not found for Mgmt proxy"); + } + return; + } + + if (!strcmp(interface, BT_HAL_MESH_NODE_INTERFACE)) { + + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, path, __compare_proxy_path); + if (l) { + app = l->data; + app->mgmt_proxy = proxy; + } else { + ERR("Mesh: app not found for Node proxy"); + } + return; + } +} + +static void __mesh_proxy_removed(struct l_dbus_proxy *proxy, void *user_data) +{ + const char *interface = l_dbus_proxy_get_interface(proxy); + const char *path = l_dbus_proxy_get_path(proxy); + + INFO("Proxy removed: %s (%s)\n", interface, path); + + if (!strcmp(interface, BT_HAL_MESH_NETWORK_INTERFACE)) { + INFO("Mesh: Network Interface removed,, possibly meshd terminated.\n"); + /*TODO: Send event to app about stop of Mesh service & then remove all apps */ + if (mesh_apps) { + g_slist_free_full(mesh_apps, __bt_hal_mesh_destroy_app_object); + mesh_apps = NULL; + return; + } + } else if (!strcmp(interface, BT_HAL_MESH_NODE_INTERFACE)) { + INFO("Mesh: Node Interface removed,, possibly node has left network.\n"); + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, path, __compare_proxy_path); + if (l) { + app = l->data; + /*TODO: Send event to app about removal of a mesh local node */ + __bt_hal_mesh_destroy_app_object(app); + } else { + ERR("Mesh: app not found for Mgmt proxy"); + } + return; + } else if (!strcmp(interface, BT_HAL_MESH_MANAGEMENT_INTERFACE)) { + INFO("Mesh: Managament Interface removed,, possibly node has left network.\n"); + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, path, __compare_proxy_path); + if (l) { + app = l->data; + /*TODO: Send event to app about removal of + a mesh local node: first send event, then destroy mesh object */ + __bt_hal_mesh_destroy_app_object(app); + } else { + ERR("Mesh: app not found for Mgmt proxy"); + } + return; + } +} + +static void __mesh_dbus_client_ready(struct l_dbus_client *client, + void *user_data) +{ + INFO("Mesh: D-Bus client ready: bluetooth-meshd connected \n"); + /* TODO: Book keeping */ +} + +static void __mesh_ready_callback(void *user_data) +{ + INFO("Mesh: Connected to D-Bus\n"); + if (!l_dbus_object_manager_enable(dbus, "/")) + ERR("Mesh: Failed to register the ObjectManager\n"); +} + +bool _bt_hal_mesh_stack_init(void) +{ + INFO("Mesh: Connect with meshd"); + /* Connect with meshd */ + dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS); + if (!dbus) + return false; + + if (!l_dbus_set_ready_handler(dbus, __mesh_ready_callback, NULL, NULL)) + return false; + + client = l_dbus_client_new(dbus, + BT_HAL_BLUEZ_MESH_NAME, "/org/bluez/mesh"); + if (!client) + return false; + + if (!l_dbus_client_set_connect_handler(client, + __mesh_client_connected, NULL, NULL)) + return false; + + if (!l_dbus_client_set_disconnect_handler(client, + __mesh_client_disconnected, NULL, + NULL)) + return false; + if (!l_dbus_client_set_proxy_handlers(client, + __mesh_proxy_added, __mesh_proxy_removed, + NULL, NULL, NULL)) + return false; + if (!l_dbus_client_set_ready_handler(client, + __mesh_dbus_client_ready, NULL, NULL)) + return false; + + INFO("Mesh: Stack Init watchers registered with meshd"); + return true; +} + +/* To send stack event to hal-mesh handler */ +void _bt_hal_mesh_register_dbus_handler_cb(handle_stack_msg cb) +{ + mesh_event_cb = cb; +} + +/* To send stack event to hal-mesh handler */ +void _bt_hal_mesh_unregister_dbus_handler_cb() +{ + mesh_event_cb = NULL; +} + +static bool __mesh_get_companyid(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_app *app = (meshcfg_app*) user_data; + if (!app) + return false; + + l_dbus_message_builder_append_basic(builder, 'q', &app->cid); + + return true; +} + +static bool __mesh_get_productid(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_app *app = (meshcfg_app*) user_data; + if (!app) + return false; + l_dbus_message_builder_append_basic(builder, 'q', &app->pid); + + return true; +} + +static bool __mesh_get_versionid(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_app *app = (meshcfg_app*) user_data; + if (!app) + return false; + l_dbus_message_builder_append_basic(builder, 'q', &app->vid); + + return true; +} + +static bool __mesh_get_crpl(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_app *app = (meshcfg_app*) user_data; + if (!app) + return false; + l_dbus_message_builder_append_basic(builder, 'q', &app->crpl); + + return true; +} + +static void __send_network_attach_event(void *param, uint8_t status) +{ + struct hal_ev_mesh_network_attached ev; + meshcfg_app *app = (meshcfg_app*)param; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.uuid, app->uuid, sizeof(app->uuid)); + memcpy(ev.token, app->token.u8, 8); + + ev.status = status; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_NETWORK_ATTACHED, + (void*)&ev, sizeof(ev)); +} + +static void __bt_hal_mesh_attach_node_reply(struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, void *user_data) +{ + struct l_dbus_message_iter iter_cfg; + meshcfg_app *app = (meshcfg_app*) user_data; + INFO("Mesh: Attach Node Reply: App path [%s] Agent Path [%s]", + app->path, app->agent_path); + + if (l_dbus_message_is_error(msg)) { + const char *name; + l_dbus_message_get_error(msg, &name, NULL); + ERR("Mesh: Failed to attach node: %s", name); + goto failed; + + } + + if (!l_dbus_message_get_arguments(msg, "oa(ya(qa{sv}))", + &app->path, &iter_cfg)) + goto failed; + + INFO("Mesh: Attached with path %s\n", app->path); + __send_network_attach_event(app, BT_STATUS_SUCCESS); + return; +failed: + __send_network_attach_event(app, BT_STATUS_FAIL); + /* Destroy mesh app object */ + __bt_hal_mesh_destroy_app_object(app); +} + +static void __bt_hal_mesh_attach_node_setup(struct l_dbus_message *msg, + void *user_data) +{ + meshcfg_app *app = (meshcfg_app*) user_data; + + l_dbus_message_set_arguments(msg, "ot", app->path, + l_get_be64(app->token.u8)); +} + + +static void __bt_hal_mesh_attach_node(void *user_data) +{ + if (!l_dbus_proxy_method_call(net_proxy, "Attach", + __bt_hal_mesh_attach_node_setup, + __bt_hal_mesh_attach_node_reply, + user_data, + NULL)) { + ERR("Mesh: Node attach failed!!"); + /* Node could not be attached */ + __send_network_attach_event(user_data, BT_STATUS_FAIL); + /* Destroy mesh app object */ + __bt_hal_mesh_destroy_app_object((meshcfg_app*)user_data); + } +} + +static struct l_dbus_message *__mesh_node_join_complete(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + char *str; + uint64_t tmp; + + meshcfg_app *app = (meshcfg_app*) user_data; + INFO("Mesh: Join Complete"); + + /* Return error */ + if (!l_dbus_message_get_arguments(message, "t", &tmp)) { + + /* Send Network creation fail event */ + __send_network_attach_event(app, BT_STATUS_FAIL); + + /* Destroy mesh app object */ + __bt_hal_mesh_destroy_app_object(app); + + return l_dbus_message_new_error(message, dbus_err_args, NULL); + } + + /* Save token */ + app->token.u64 = l_get_be64(&tmp); + str = l_util_hexstring(&app->token.u8[0], 8); + INFO("Mesh: Created new node with token %s\n", str); + l_free(str); + + /* Athenticate the node */ + l_idle_oneshot(__bt_hal_mesh_attach_node, app, NULL); + return l_dbus_message_new_method_return(message); +} + +static void __bt_hal_mesh_foreach_model_getter(gpointer data, + gpointer user_data) +{ + struct l_dbus_message_builder *builder = (struct l_dbus_message_builder *) user_data; + meshcfg_model *model_info = (meshcfg_model*) data; + + l_dbus_message_builder_append_basic(builder, 'q', &model_info->model); +} + +static bool __mesh_model_getter(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_el *element = (meshcfg_el*) user_data; + + l_dbus_message_builder_enter_array(builder, "q"); + g_slist_foreach(element->models, + __bt_hal_mesh_foreach_model_getter, builder); + + l_dbus_message_builder_leave_array(builder); + + return true; +} + +/*TODO: Vendor Model handling is currently not Handled */ +static bool __mesh_vendor_model_getter(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + l_dbus_message_builder_enter_array(builder, "(qq)"); + l_dbus_message_builder_leave_array(builder); + + return true; +} + +static bool __mesh_element_index_getter(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_el *element = (meshcfg_el*) user_data; + l_dbus_message_builder_append_basic(builder, 'y', &element->index); + + return true; +} + + +static struct l_dbus_message *__mesh_device_message_received(struct l_dbus *dbus, + struct l_dbus_message *msg, void *user_data) +{ + struct l_dbus_message_iter iter; + uint16_t src, idx; + uint8_t *data; + uint32_t n; + bool rmt; + const char *dbus_path; + uint16_t size; + uint8_t *net_uuid; + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(dbus_path, true, MESH_ELEMENT_IFACE); + uint8_t buf[BT_HAL_MESH_MAX_DEVKEY_BUF_SIZE]; + struct hal_ev_mesh_devkey_message_event *ev = (void *)buf; + + INFO("Mesh: app path [%s]", dbus_path); + + memset(buf, 0, sizeof(buf)); + size = (uint16_t) sizeof(*ev); + memcpy(ev->net_uuid, net_uuid, 16); + g_free(net_uuid); + + if (!l_dbus_message_get_arguments(msg, "qbqay", &src, &rmt, &idx, + &iter)) { + ERR("Mesh: Cannot parse received message"); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + if (!l_dbus_message_iter_get_fixed_array(&iter, &data, &n)) { + ERR("Mesh: Cannot parse received message: data"); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + INFO("Mesh: Received dev key message (len %u):", n); + ev->source_addr = src; + ev->is_remote_devkey = rmt; + ev->netkey_idx = idx; + ev->data_len = n; + memcpy(ev->data, buf, n); + size += n; + + /* Send DevKeyMessage Received event */ + if (mesh_event_cb) { + mesh_event_cb(HAL_EV_MESH_DEVKEY_MESSAGE_EVENT, (void*)buf, size); + } + return l_dbus_message_new_method_return(msg); +} + +static void __bt_hal_mesh_setup_ele_iface(struct l_dbus_interface *iface) +{ + INFO("Mesh: Setup element interface properties & methods"); + /* Properties */ + l_dbus_interface_property(iface, "Index", 0, "y", __mesh_element_index_getter, + NULL); + l_dbus_interface_property(iface, "VendorModels", 0, "a(qq)", + __mesh_vendor_model_getter, NULL); + l_dbus_interface_property(iface, "Models", 0, "aq", __mesh_model_getter, NULL); + + /* Methods */ + l_dbus_interface_method(iface, "DevKeyMessageReceived", 0, + __mesh_device_message_received, "", "qbqay", "source", + "remote", "net_index", "data"); + /* TODO: Other methods */ +} + +static struct l_dbus_message *__mesh_scan_result_received(struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct l_dbus_message_iter iter, opts; + meshcfg_app *app = (meshcfg_app*) user_data; + int16_t rssi; + uint32_t n; + uint8_t *prov_data; + char *str; + const char *sig = "naya{sv}"; + + /* Find network uuid from dbus path */ + struct hal_ev_mesh_scan_result ev; + + if (!app->scan_timer_id) { + /* Scan is not running */ + INFO("Got scan result, but scan is already stopped"); + return l_dbus_message_new_method_return(msg); + } + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, app->uuid, 16); + + if (!l_dbus_message_get_arguments(msg, sig, &rssi, &iter, &opts)) { + ERR("Mesh: Cannot parse scan results"); + ev.status = BT_STATUS_FAIL; + if (mesh_event_cb) { + mesh_event_cb(HAL_EV_MESH_SCAN_RESULT, (void*)&ev, sizeof(ev)); + } + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + if (!l_dbus_message_iter_get_fixed_array(&iter, &prov_data, &n) || + n < 16) { + ERR("Mesh: Cannot parse scan result: data"); + ev.status = BT_STATUS_FAIL; + if (mesh_event_cb) { + mesh_event_cb(HAL_EV_MESH_SCAN_RESULT, (void*)&ev, sizeof(ev)); + } + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + INFO("Mesh: Scan result:\n"); + INFO("Mesh: Scan rssi = [%d]\n", rssi); + str = l_util_hexstring_upper(prov_data, 16); + INFO("Mesh: Scan UUID = [%s]\n", str); + l_free(str); + + if (n >= 18) { + str = l_util_hexstring_upper(prov_data + 16, 2); + INFO("Mesh: Scan OOB = [%s]\n", str); + l_free(str); + } + + if (n >= 22) { + str = l_util_hexstring_upper(prov_data + 18, 4); + INFO("Mesh: Scan URI hash = [%s]\n", str); + l_free(str); + } + + /* 16 octet Dev UUID */ + memcpy(ev.dev_uuid, prov_data, 16); + + /* 2 octet Dev OOB Info */ + memcpy(ev.oob_info, prov_data + 16, 2); + + /* 4 octet URI Hash */ + memcpy(ev.uri_hash, prov_data + 18, 4); + + ev.rssi = rssi; + + ev.status = BT_STATUS_SUCCESS; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_SCAN_RESULT, + (void*)&ev, sizeof(ev)); + + return l_dbus_message_new_method_return(msg); +} + +static struct l_dbus_message *__mesh_request_provisioner_call( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + uint8_t cnt; + struct hal_ev_mesh_provision_finished ev; + struct hal_ev_mesh_provision_data_request req; + meshcfg_app *app = user_data; + + memset(&ev, 0, sizeof(ev)); + memset(&req, 0, sizeof(req)); + memcpy(ev.net_uuid, app->uuid, 16); + memcpy(req.net_uuid, app->uuid, 16); + + if (!l_dbus_message_get_arguments(msg, "y", &cnt)) { + ERR("Mesh: Cannot parse request for prov data"); + /* Send Event */ + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + app->msg = msg; + req.count = cnt; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_DATA_REQUEST, + (void*)&ev, sizeof(ev)); + + l_dbus_message_ref(msg); + return NULL; +} + +static struct l_dbus_message *__mesh_node_add_completed( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct l_dbus_message_iter iter; + int16_t unicast; + uint8_t cnt; + uint32_t n; + uint8_t *uuid; + struct hal_ev_mesh_provision_finished ev; + const char *dbus_path; + uint8_t *net_uuid; + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(dbus_path, + true, MESH_PROV_IFACE); + + INFO("Mesh: app path [%s]", dbus_path); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + g_free(net_uuid); + + if (!l_dbus_message_get_arguments(msg, "ayqy", &iter, &unicast, &cnt)) { + ERR("Mesh: Cannot parse add node complete message"); + /* Send Event */ + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + if (!l_dbus_message_iter_get_fixed_array(&iter, &uuid, &n) || + n != 16) { + ERR("Mesh: Cannot parse add node complete message: uuid"); + /* Send Event */ + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + /* Send Event */ + ev.status = BT_STATUS_SUCCESS; + ev.reason = BT_HAL_MESH_PROV_ERR_SUCCESS; + memcpy(ev.dev_uuid, uuid, 16); + ev.unicast = unicast; + ev.count = cnt; + + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + + return l_dbus_message_new_method_return(msg); +} + +static struct l_dbus_message *__mesh_node_add_failed( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct l_dbus_message_iter iter; + uint32_t n; + uint8_t *uuid; + char *str, *reason; + struct hal_ev_mesh_provision_finished ev; + const char *dbus_path; + + uint8_t *net_uuid; + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(dbus_path, + true, MESH_PROV_IFACE); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + g_free(net_uuid); + if (!l_dbus_message_get_arguments(msg, "ays", &iter, &reason)) { + ERR("Mesh: Cannot parse add node failed message"); + /* Send Event */ + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + if (!l_dbus_message_iter_get_fixed_array(&iter, &uuid, &n) || + n != 16) { + ERR("Mesh:Cannot parse add node failed message: uuid"); + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + INFO("Mesh: Provisioning failed:\n"); + str = l_util_hexstring_upper(uuid, 16); + INFO("Mesh: UUID = [%s] Reason [%s]", str, reason); + l_free(str); + + ev.status = BT_STATUS_FAIL; + ev.reason = __bt_mesh_util_get_prov_error_code(str); + memcpy(ev.dev_uuid, uuid, 16); + + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + + return l_dbus_message_new_method_return(msg); +} + +static void __bt_hal_mesh_setup_prov_iface(struct l_dbus_interface *interface) +{ + INFO("Mesh: Setup provisioner interface properties & methods"); + l_dbus_interface_method(interface, "ScanResult", 0, + __mesh_scan_result_received, "", + "naya{sv}", "rssi", "data", "options"); + + l_dbus_interface_method(interface, "RequestProvData", 0, + __mesh_request_provisioner_call, + "qq", "y", "net_index", "unicast", "count"); + + l_dbus_interface_method(interface, "AddNodeComplete", 0, + __mesh_node_add_completed, "", "ayqy", + "uuid", "unicast", "count"); + + l_dbus_interface_method(interface, "AddNodeFailed", 0, + __mesh_node_add_failed, + "", "ays", "uuid", "reason"); +} + +static void __bt_hal_mesh_setup_app_iface(struct l_dbus_interface *iface) +{ + INFO("Mesh: Setup application interface properties & methods"); + + l_dbus_interface_property(iface, "CompanyID", 0, "q", + __mesh_get_companyid, + NULL); + l_dbus_interface_property(iface, "VersionID", 0, "q", + __mesh_get_versionid, + NULL); + l_dbus_interface_property(iface, "ProductID", 0, "q", + __mesh_get_productid, + NULL); + l_dbus_interface_property(iface, "CRPL", 0, "q", + __mesh_get_crpl, NULL); + l_dbus_interface_method(iface, "JoinComplete", 0, + __mesh_node_join_complete, + "", "t", "token"); + + /* TODO: Methods */ +} + +static void __mesh_fill_in_capabilities(meshcfg_app *app, + struct l_dbus_message_builder *builder) +{ + if (app->in_oob & 0x08) + l_dbus_message_builder_append_basic(builder, 's', "in-alpha"); + if (app->in_oob & 0x04) + l_dbus_message_builder_append_basic(builder, 's', "in-numeric"); + if (app->in_oob & 0x02) + l_dbus_message_builder_append_basic(builder, 's', "twist"); + if (app->in_oob & 0x01) + l_dbus_message_builder_append_basic(builder, 's', "push"); +} + +static void __mesh_fill_out_capabilities(meshcfg_app *app, + struct l_dbus_message_builder *builder) +{ + if (app->out_oob & 0x10) + l_dbus_message_builder_append_basic(builder, 's', "out-alpha"); + if (app->out_oob & 0x08) + l_dbus_message_builder_append_basic(builder, 's', "out-numeric"); + if (app->out_oob & 0x04) + l_dbus_message_builder_append_basic(builder, 's', "vibrate"); + if (app->out_oob & 0x02) + l_dbus_message_builder_append_basic(builder, 's', "beep"); + if (app->out_oob & 0x01) + l_dbus_message_builder_append_basic(builder, 's', "blink"); +} + +static bool __mesh_agent_capability_getter( + struct l_dbus *dbus,struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + meshcfg_app *app; + app = user_data; + INFO("Mesh: app path [%s]", app->path); + INFO("Mesh: Agent path [%s]", app->agent_path); + + if (!l_dbus_message_builder_enter_array(builder, "s")) { + return false; + } + + __mesh_fill_out_capabilities(app, builder); + __mesh_fill_in_capabilities(app, builder); + + if (app->static_oob) + l_dbus_message_builder_append_basic(builder, + 's', "static-oob"); + + + l_dbus_message_builder_leave_array(builder); + INFO("Mesh: __agent_capability_getter: Success"); + return true; +} + +static struct l_dbus_message *__mesh_agent_display_string_request( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct hal_ev_mesh_authentication_request ev; + char *str; + uint8_t *net_uuid; + const char *dbus_path; + meshcfg_app *app; + app = user_data; + INFO("Mesh: app path [%s]", app->path); + INFO("Mesh: Agent path [%s]", app->agent_path); + + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(app->agent_path, + true, MESH_AGENT_IFACE); + + INFO("Mesh: app path [%s]", dbus_path); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + + if (!l_dbus_message_get_arguments(msg, "s", &str)) { + ERR("Mesh: Cannot parse \"DisplayString\" arguments"); + struct hal_ev_mesh_provision_finished ev; + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + + g_free(net_uuid); + + return l_dbus_message_new_error(msg, dbus_err_fail, NULL); + } + + INFO("Mesh:[OUT] AlphaNumeric Authentication: Value [%s]", str); + ev.auth_type = BT_HAL_MESH_AUTH_ALPHANUMERIC_DISPLAY; + g_strlcpy(ev.auth_value, str, sizeof(ev.auth_value)); + + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_AUTHENTICATION_REQUEST, + (void*)&ev, sizeof(ev)); + + g_free(net_uuid); + return l_dbus_message_new_method_return(msg); +} + +static struct l_dbus_message *__mesh_agent_display_numeric_request( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + uint32_t n; + struct hal_ev_mesh_authentication_request ev; + char *str; + char *auth_value; + uint8_t *net_uuid; + const char *dbus_path; + meshcfg_app *app; + app = user_data; + INFO("Mesh: app path [%s]", app->path); + INFO("Mesh: Agent path [%s]", app->agent_path); + + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(app->agent_path, + true, MESH_AGENT_IFACE); + + INFO("Mesh: app path [%s]", dbus_path); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + + if (!l_dbus_message_get_arguments(msg, "su", &str, &n)) { + ERR("Mesh: Cannot parse \"DisplayNumeric\" arguments"); + struct hal_ev_mesh_provision_finished ev; + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) { + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + } + g_free(net_uuid); + return l_dbus_message_new_error(msg, dbus_err_fail, NULL); + } + + INFO("Mesh:[OUT] Numeric Authentication type [%s] value [%u]", str, n); + auth_value = l_strdup_printf("%u",n); + ev.auth_type = __mesh_get_authentication_type(str); + g_strlcpy(ev.auth_value, auth_value, sizeof(ev.auth_value)); + + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_AUTHENTICATION_REQUEST, + (void*)&ev, sizeof(ev)); + + g_free(net_uuid); + + return l_dbus_message_new_method_return(msg); +} + +static struct l_dbus_message *__mesh_agent_prompt_numeric_request( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct hal_ev_mesh_authentication_request ev; + char *str; + uint8_t *net_uuid; + const char *dbus_path; + GSList *l; + meshcfg_app *app; + + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(dbus_path, + true, MESH_AGENT_IFACE); + + INFO("Mesh: app path [%s]", dbus_path); + + l = g_slist_find_custom(mesh_apps, net_uuid, + __mesh_compare_network_uuid); + app = l->data; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + g_free(net_uuid); + if (!l_dbus_message_get_arguments(msg, "s", &str)) { + ERR("Mesh: Cannot parse \"PromptNumeric\" arguments"); + + struct hal_ev_mesh_provision_finished ev; + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, app->uuid, 16); + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) { + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + } + return l_dbus_message_new_error(msg, dbus_err_fail, NULL); + } + + INFO("Mesh:[IN] Numeric Authentication type [%s]", str); + + ev.auth_type = __mesh_get_authentication_type(str); + agent_msg = msg; + l_dbus_message_ref(msg); + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_AUTHENTICATION_REQUEST, + (void*)&ev, sizeof(ev)); + + return NULL; +} + +static struct l_dbus_message *__mesh_agent_prompt_static_request( + struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct hal_ev_mesh_authentication_request ev; + char *str; + uint8_t *net_uuid; + const char *dbus_path; + GSList *l; + meshcfg_app *app; + + dbus_path = l_dbus_message_get_path(msg); + net_uuid = __mesh_get_net_uuid_from_path(dbus_path, true, + MESH_AGENT_IFACE); + + INFO("Mesh: app path [%s]", dbus_path); + + l = g_slist_find_custom(mesh_apps, net_uuid, + __mesh_compare_network_uuid); + app = l->data; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + g_free(net_uuid); + if (!l_dbus_message_get_arguments(msg, "s", &str)) { + ERR("Mesh: Cannot parse \"PromptNumeric\" arguments"); + + struct hal_ev_mesh_provision_finished ev; + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, app->uuid, 16); + ev.status = BT_STATUS_FAIL; + ev.reason = BT_HAL_MESH_PROV_ERR_INTERNAL; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_FINISHED, + (void*)&ev, sizeof(ev)); + return l_dbus_message_new_error(msg, dbus_err_fail, NULL); + } + + INFO("Mesh: [IN] AlphaNumeric Authentication type [%s]", str); + + ev.auth_type = __mesh_get_authentication_type(str); + agent_msg = msg; + l_dbus_message_ref(msg); + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_AUTHENTICATION_REQUEST, + (void*)&ev, sizeof(ev)); + + return NULL; +} + +static void __bt_hal_mesh_setup_agent_iface(struct l_dbus_interface *interface) +{ + INFO("Mesh: Setup Agent interface properties & methods"); + l_dbus_interface_property(interface, "Capabilities", 0, "as", + __mesh_agent_capability_getter, + NULL); + /* TODO: Other properties */ + l_dbus_interface_method(interface, "DisplayString", 0, + __mesh_agent_display_string_request, + "", "s", "value"); + l_dbus_interface_method(interface, "DisplayNumeric", 0, + __mesh_agent_display_numeric_request, + "", "su", "type", "number"); + l_dbus_interface_method(interface, "PromptNumeric", 0, + __mesh_agent_prompt_numeric_request, + "u", "s", "number", "type"); + l_dbus_interface_method(interface, "PromptStatic", 0, + __mesh_agent_prompt_static_request, + "ay", "s", "data", "type"); +} + +static void __bt_hal_mesh_register_element_obj(gpointer data, gpointer user_data) +{ + meshcfg_el *elem = (meshcfg_el*) data; + INFO("Mesh: Register Element: Index [%d] elem path [%s]", + elem->index, elem->path); + if (!l_dbus_register_object(dbus, elem->path, NULL, NULL, + BT_HAL_MESH_ELEMENT_INTERFACE, elem, NULL)) { + ERR("Mesh: Failed to register object %s", elem->path); + } +} + +bool __bt_hal_mesh_register_agent(meshcfg_app *ptr) +{ + if (!ptr) + return false; + + if (!l_dbus_register_interface(dbus, BT_HAL_MESH_PROVISION_AGENT_INTERFACE, + __bt_hal_mesh_setup_agent_iface, NULL, false)) { + ERR("Mesh: Unable to register agent interface"); + return false; + } + + INFO("Mesh: Register Agent path [%s]", ptr->agent_path); + if (!l_dbus_register_object(dbus, ptr->agent_path, NULL, NULL, + BT_HAL_MESH_PROVISION_AGENT_INTERFACE, ptr, NULL)) { + ERR("Mesh: Failed to register object %s", ptr->agent_path); + return false; + } + + if (!l_dbus_object_add_interface(dbus, ptr->agent_path, + L_DBUS_INTERFACE_PROPERTIES, NULL)) { + ERR("Mesh: Failed to add interface %s", + L_DBUS_INTERFACE_PROPERTIES); + return false; + } + + return true; +} + +bool __bt_hal_mesh_register_application(meshcfg_app *ptr) +{ + + if (!ptr) + return false; + + if (!l_dbus_register_interface(dbus, BT_HAL_MESH_APPLICATION_INTERFACE, + __bt_hal_mesh_setup_app_iface, NULL, false)) { + ERR("Mesh: Failed to register interface %s", + BT_HAL_MESH_APPLICATION_INTERFACE); + return false; + } + + if (!l_dbus_register_interface(dbus, BT_HAL_MESH_PROVISIONER_INTERFACE, + __bt_hal_mesh_setup_prov_iface, NULL, false)) { + ERR("Mesh: Failed to register interface %s", + BT_HAL_MESH_PROVISIONER_INTERFACE); + return false; + } + + if (!l_dbus_register_object(dbus, ptr->path, NULL, NULL, + BT_HAL_MESH_APPLICATION_INTERFACE, ptr, + BT_HAL_MESH_PROVISIONER_INTERFACE, ptr, + NULL)) { + ERR("Mesh: Failed to register object %s", ptr->path); + return false; + } + + if (!__bt_hal_mesh_register_agent(ptr)) + return false; + + if (!l_dbus_register_interface(dbus, BT_HAL_MESH_ELEMENT_INTERFACE, + __bt_hal_mesh_setup_ele_iface, NULL, false)) { + ERR("Mesh: Failed to register interface %s", + BT_HAL_MESH_ELEMENT_INTERFACE); + return false; + } + + INFO("Mesh: Number of elements to be registsred [%d]", + g_slist_length(ptr->elements)); + + g_slist_foreach(ptr->elements, __bt_hal_mesh_register_element_obj, ptr); + + INFO("Mesh: Add Object manager Interface: app path [%s]", ptr->path); + if (!l_dbus_object_add_interface(dbus, ptr->path, + L_DBUS_INTERFACE_OBJECT_MANAGER, NULL)) { + ERR("Mesh: Failed to add interface %s", + L_DBUS_INTERFACE_OBJECT_MANAGER); + return false; + } + INFO("Mesh: Application Register completed"); + + return true; +} + +static void __bt_mesh_hal_create_element_object(gpointer data, gpointer user_data) +{ + GSList *l; + meshcfg_el *elem; + meshcfg_model *model_info = (meshcfg_model*) data; + meshcfg_app *app = (meshcfg_app*) user_data; + + l = g_slist_find_custom(app->elements, + GUINT_TO_POINTER(model_info->elem_index), __compare_element_index); + if (l) { + elem = l->data; + } else { + elem = g_malloc0(sizeof(meshcfg_el)); + elem->index = model_info->elem_index; + elem->path = g_strdup_printf("%s/elem%u",app->path, elem->index); + app->elements = g_slist_append(app->elements, elem); + INFO("Mesh: Created element index [%d] path [%s]", + elem->index, elem->path); + } + /* Add Model in the element */ + elem->models = g_slist_append(elem->models, model_info); + INFO("Mesh: total models of the element with index [%d] is [%d]", + elem->index, g_slist_length(elem->models)); +} + +meshcfg_app *__bt_hal_mesh_create_app(bt_hal_mesh_node_t *node, + GSList *models, bool is_prov) +{ + uint8_t uuid[16]; + meshcfg_app *app = NULL; + char *uuid_str = NULL; + + uuid_str = l_util_hexstring(node->uuid.uu, sizeof(uuid)); + + app = g_malloc0(sizeof(meshcfg_app)); + memcpy(app->uuid, node->uuid.uu, sizeof(uuid)); + + app->cid = node->vendor_info.companyid; + app->pid = node->vendor_info.vendorid; + app->vid = node->vendor_info.versionid; + app->crpl = node->vendor_info.crpl; + + if (is_prov) { + app->path = g_strdup_printf("/tizen/mesh/cfg/%s", uuid_str); + app->agent_path = g_strdup_printf("/tizen/mesh/cfg/agent/%s", uuid_str); + + } else { + app->path = g_strdup_printf("/tizen/mesh/node/%s", uuid_str); + app->agent_path = g_strdup_printf("/tizen/mesh/node/agent/%s", uuid_str); + } + g_slist_foreach(models, __bt_mesh_hal_create_element_object, app); + + g_free(uuid_str); + app->is_prov = is_prov; + INFO("Mesh: app created"); + return app; +} + +static void __bt_hal_mesh_create_net_reply( + struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, void *user_data) +{ + meshcfg_app *app; + app = (meshcfg_app*) user_data; + + INFO("Mesh: Create Network Reply from Meshd: app path [%s]", app->path); + if (l_dbus_message_is_error(msg)) { + const char *name; + + l_dbus_message_get_error(msg, &name, NULL); + ERR("Mesh: Failed to create network: %s", name); + + /* Send Network creation fail event */ + __send_network_attach_event(app, BT_STATUS_FAIL); + + /* Destroy mesh app object */ + __bt_hal_mesh_destroy_app_object(app); + return; + } +} + +static void __bt_hal_mesh_create_net_setup(struct l_dbus_message *msg, + void *user_data) +{ + meshcfg_app *app; + struct l_dbus_message_builder *builder; + app = (meshcfg_app*) user_data; + + builder = l_dbus_message_builder_new(msg); + + INFO("Mesh: Create Network Setup app path [%s]", app->path); + l_dbus_message_builder_append_basic(builder, 'o', app->path); + __mesh_append_byte_array(builder, app->uuid, 16); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); +} + +static void __mesh_trigger_scan_finished_event(meshcfg_app *app) +{ + struct hal_ev_mesh_scan_state_changed ev; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, app->uuid, 16); + + ev.status = BT_STATUS_SUCCESS; + + ev.state = HAL_MESH_SCAN_STATE_STOPPED; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_SCAN_STATE_CHANGED, + (void*)&ev, sizeof(ev)); +} + +static gboolean __bt_mesh_scan_timer_cb(gpointer user_data) +{ + meshcfg_app *app = (meshcfg_app*) user_data; + __mesh_trigger_scan_finished_event(app); + return false; +} + +void __bt_mesh_enable_scanning_timer(uint8_t *net_uuid, uint16_t secs) +{ + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, net_uuid, + __mesh_compare_network_uuid); + app = l->data; + + if (app->scan_timer_id > 0) { + g_source_remove(app->scan_timer_id); + app->scan_timer_id = 0; + } + + app->scan_timer_id = g_timeout_add_seconds(secs, + __bt_mesh_scan_timer_cb, app); + + return; +} + +static void __mesh_scan_reply(struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, void *user_data) +{ + struct hal_ev_mesh_scan_state_changed ev; + const char *dbus_path; + uint8_t *net_uuid; + dbus_path = l_dbus_proxy_get_path(proxy); + INFO("Mesh: DBUS path [%s]", dbus_path); + net_uuid = __mesh_get_net_uuid_from_dbus_proxy_path(dbus_path); + + uint16_t secs = (uint16_t) L_PTR_TO_UINT(user_data); + INFO("Mesh: Scan duration [%u]", secs); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + + if (l_dbus_message_is_error(msg)) { + const char *name; + l_dbus_message_get_error(msg, &name, NULL); + ERR("Mesh: Failed to start unprovisioned scan: [%s]", name); + ev.status = BT_STATUS_FAIL; + } else { + INFO("Mesh: Unprovisioned scan started\n"); + ev.status = BT_STATUS_SUCCESS; + __bt_mesh_enable_scanning_timer(net_uuid, secs); + } + + ev.state = HAL_MESH_SCAN_STATE_STARTED; + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_SCAN_STATE_CHANGED, + (void*)&ev, sizeof(ev)); + l_free(net_uuid); +} + +static void append_dict_entry_basic(struct l_dbus_message_builder *builder, + const char *key, const char *signature, + const void *data) +{ + if (!builder) + return; + + l_dbus_message_builder_enter_dict(builder, "sv"); + l_dbus_message_builder_append_basic(builder, 's', key); + l_dbus_message_builder_enter_variant(builder, signature); + l_dbus_message_builder_append_basic(builder, signature[0], data); + l_dbus_message_builder_leave_variant(builder); + l_dbus_message_builder_leave_dict(builder); +} + +static void __mesh_scan_setup(struct l_dbus_message *msg, void *user_data) +{ + struct l_dbus_message_builder *builder; + uint16_t secs = (uint16_t) L_PTR_TO_UINT(user_data); + INFO("Mesh: Scan duration [%u]", secs); + + builder = l_dbus_message_builder_new(msg); + l_dbus_message_builder_enter_array(builder, "{sv}"); + append_dict_entry_basic(builder, "Seconds", "q", &secs); + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); +} + + +bt_status_t _bt_hal_mesh_network_set_caps( + bt_uuid_t *net_uuid, bt_hal_mesh_prov_caps_t *caps) +{ + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + /* Fill OOB data */ + app->public_oob = caps->public_oob; + app->static_oob = caps->static_oob; + app->out_oob = caps->out_oob; + app->in_oob = caps->in_oob; + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + + } + return BT_STATUS_SUCCESS; +} + +static void __bt_hal_mesh_add_node_reply( + struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, + void *user_data) +{ + struct hal_ev_mesh_provision_status ev; + const char *dbus_path; + uint8_t *net_uuid; + dbus_path = l_dbus_proxy_get_path(proxy); + INFO("Mesh: DBUS path [%s]", dbus_path); + net_uuid = __mesh_get_net_uuid_from_dbus_proxy_path(dbus_path); + + bt_uuid_t *dev_uuid = (bt_uuid_t*) user_data; + + INFO("Mesh: app path [%s]", dbus_path); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + memcpy(ev.dev_uuid, dev_uuid->uu, 16); + + /* Free User data */ + g_free((void*)dev_uuid); + l_free(net_uuid); + + if (l_dbus_message_is_error(msg)) { + const char *name; + + l_dbus_message_get_error(msg, &name, NULL); + ERR("Mesh: Failed to start provisioning: %s", name); + ev.status = BT_STATUS_FAIL; + } else { + INFO("Mesh: Provisioning started\n"); + ev.status = BT_STATUS_SUCCESS; + } + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_PROVISIONING_STATUS, + (void*)&ev, sizeof(ev)); +} + +static void __bt_hal_mesh_add_node_setup(struct l_dbus_message *msg, + void *user_data) +{ + bt_uuid_t *dev = user_data; + struct l_dbus_message_builder *builder; + + builder = l_dbus_message_builder_new(msg); + __mesh_append_byte_array(builder, dev->uu, 16); + l_dbus_message_builder_enter_array(builder, "{sv}"); + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + + l_free(dev); +} + +bt_status_t _bt_hal_mesh_provision_device( + bt_uuid_t *net_uuid, bt_uuid_t *dev_uuid) +{ + GSList *l; + meshcfg_app *app; + bt_uuid_t *dev; + l = g_slist_find_custom(mesh_apps, net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + dev = g_memdup((gpointer)dev_uuid, 16); + + if (!l_dbus_proxy_method_call(app->mgmt_proxy, "AddNode", + __bt_hal_mesh_add_node_setup, + __bt_hal_mesh_add_node_reply, + (void*)dev, NULL)) + return BT_STATUS_FAIL; + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + + } + return BT_STATUS_SUCCESS; +} + +static void __bt_hal_mesh_subnet_key_setup( + struct l_dbus_message *msg, void *user_data) +{ + struct subnet_key_request *req = user_data; + uint16_t idx = (uint16_t) req->idx; + + l_dbus_message_set_arguments(msg, "q", idx); +} + +static void __bt_hal_mesh_subnet_key_reply(struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, void *user_data) +{ + struct hal_ev_mesh_netkey_execute_event ev; + const char *dbus_path; + uint8_t *net_uuid; + struct subnet_key_request *req = user_data; + const char *method = req->str; + + dbus_path = l_dbus_proxy_get_path(proxy); + INFO("Mesh: DBUS path [%s]", dbus_path); + net_uuid = __mesh_get_net_uuid_from_dbus_proxy_path(dbus_path); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + ev.key_idx = req->idx; + + g_free(net_uuid); + + if (l_dbus_message_is_error(msg)) { + const char *name; + + l_dbus_message_get_error(msg, &name, NULL); + ERR("Mesh: Subnet [%s] failed: error: [%s]", method, name); + ev.status = BT_STATUS_FAIL; + } + + ev.status = BT_STATUS_SUCCESS; + + if (!strcmp("CreateSubnet", method)) { + ev.key_event = HAL_MESH_KEY_ADD; + } else if (!strcmp("DeleteSubnet", method)) { + ev.key_event = HAL_MESH_KEY_DELETE; + } else if (!strcmp("UpdateSubnet", method)) { + ev.key_event = HAL_MESH_KEY_UPDATE; + } + + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_NETKEY_EXECUTE_EVENT, + (void*)&ev, sizeof(ev)); +} + +static bool __mesh_subnet_netkey_command_execute(meshcfg_app *app, + uint16_t index, const char *key_execute_method) +{ + struct subnet_key_request *req; + + req = l_new(struct subnet_key_request, 1); + req->str = key_execute_method; + req->idx = index; + + if (!l_dbus_proxy_method_call(app->mgmt_proxy, key_execute_method, + __bt_hal_mesh_subnet_key_setup, + __bt_hal_mesh_subnet_key_reply, + req, l_free)) + return false; + + return true; +} + +static void __bt_hal_mesh_app_key_setup(struct l_dbus_message *msg, + void *user_data) +{ + struct app_key_request *req = user_data; + uint16_t net_idx = (uint16_t) req->net_idx; + uint16_t app_idx = (uint16_t) req->app_idx; + + l_dbus_message_set_arguments(msg, "qq", net_idx, app_idx); +} + +static void __bt_hal_mesh_app_key_reply(struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, void *user_data) +{ + struct hal_ev_mesh_appkey_execute_event ev; + const char *dbus_path; + uint8_t *net_uuid; + struct app_key_request *req = user_data; + const char *method = req->str; + + dbus_path = l_dbus_proxy_get_path(proxy); + INFO("Mesh: DBUS path [%s]", dbus_path); + net_uuid = __mesh_get_net_uuid_from_dbus_proxy_path(dbus_path); + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.net_uuid, net_uuid, 16); + ev.net_idx = req->net_idx; + ev.app_idx = req->app_idx; + + g_free(net_uuid); + + if (l_dbus_message_is_error(msg)) { + const char *name; + + l_dbus_message_get_error(msg, &name, NULL); + ERR("Mesh: AppKey execute [%s] failed: error: [%s]", method, name); + ev.status = BT_STATUS_FAIL; + } + + ev.status = BT_STATUS_SUCCESS; + + if (!strcmp("CreateAppKey", method)) { + ev.key_event = HAL_MESH_KEY_ADD; + } else if (!strcmp("DeleteAppKey", method)) { + ev.key_event = HAL_MESH_KEY_DELETE; + } else if (!strcmp("UpdateAppKey", method)) { + ev.key_event = HAL_MESH_KEY_UPDATE; + } + + if (mesh_event_cb) + mesh_event_cb(HAL_EV_MESH_APPKEY_EXECUTE_EVENT, (void*)&ev, sizeof(ev)); +} + +static bool __mesh_subnet_appkey_command_execute(meshcfg_app *app, + uint16_t net_idx, uint16_t app_idx, + const char *key_execute_method) +{ + struct app_key_request *req; + + req = l_new(struct app_key_request, 1); + req->str = key_execute_method; + req->net_idx = net_idx; + req->app_idx = app_idx; + + if (!l_dbus_proxy_method_call(app->mgmt_proxy, key_execute_method, + __bt_hal_mesh_app_key_setup, + __bt_hal_mesh_app_key_reply, + req, l_free)) + return false; + + return true; +} + +bt_status_t _bt_hal_mesh_network_subnet_execute(bt_uuid_t *net_uuid, + bt_mesh_key_op_e op, uint16_t netkey_idx) +{ + GSList *l; + meshcfg_app *app; + bool status = true; + l = g_slist_find_custom(mesh_apps, net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + + if (op == BT_MESH_KEY_CREATE) + status = __mesh_subnet_netkey_command_execute(app, + netkey_idx, "CreateSubnet"); + else if (op == BT_MESH_KEY_DELETE) + status = __mesh_subnet_netkey_command_execute(app, + netkey_idx, "DeleteSubnet"); + else if (op == BT_MESH_KEY_UPDATE) + status = __mesh_subnet_netkey_command_execute(app, + netkey_idx, "UpdateSubnet"); + if (!status) + return BT_STATUS_FAIL; + + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + + } + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_network_appkey_execute(bt_uuid_t *net_uuid, + bt_mesh_key_op_e op, uint16_t netkey_idx, uint16_t appkey_idx) +{ + GSList *l; + meshcfg_app *app; + bool status = true; + l = g_slist_find_custom(mesh_apps, net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + + if (op == BT_MESH_KEY_CREATE) + status = __mesh_subnet_appkey_command_execute(app, + netkey_idx, appkey_idx, "CreateAppKey"); + else if (op == BT_MESH_KEY_DELETE) + status = __mesh_subnet_appkey_command_execute(app, + netkey_idx, appkey_idx, "DeleteAppKey"); + else if (op == BT_MESH_KEY_UPDATE) + status = __mesh_subnet_appkey_command_execute(app, + netkey_idx, appkey_idx, "UpdateAppKey"); + if (!status) + return BT_STATUS_FAIL; + + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + + } + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_send_provision_data( + bt_uuid_t *net_uuid, uint16_t netkey_idx, uint16_t unicast) +{ + GSList *l; + meshcfg_app *app; + struct l_dbus_message *msg; + struct l_dbus_message *reply; + + l = g_slist_find_custom(mesh_apps, net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + msg = app->msg; + + reply = l_dbus_message_new_method_return(msg); + l_dbus_message_set_arguments(reply, "qq", netkey_idx, unicast); + l_dbus_send(dbus, reply); + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + } + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_network_scan_cancel(bt_uuid_t *net_uuid) +{ + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, + net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + if (!l_dbus_proxy_method_call(app->mgmt_proxy, + "UnprovisionedScanCancel", + NULL, NULL, NULL, NULL)) + return BT_STATUS_FAIL; + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + } + + /* Stop Scan timer */ + if (app->scan_timer_id > 0) { + g_source_remove(app->scan_timer_id); + app->scan_timer_id = 0; + } + + /* Trigger Scan finished event */ + __mesh_trigger_scan_finished_event(app); + + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_auth_reply(bt_hal_mesh_auth_variant_e auth_type, + const char *auth_value) +{ + uint32_t val_u32; + struct l_dbus_message *reply = NULL; + struct l_dbus_message_builder *builder; + uint8_t alpha[16]; + + /* For Numeric Type Inputs: Numeric, Blink, Beep & Vibrate */ + if (auth_type >= BT_HAL_MESH_AUTH_REQ_NUMERIC_INPUT && + auth_type <= BT_HAL_MESH_AUTH_REQ_VIBRATE_COUNT_INPUT) { + INFO("Mesh: Authentication reply: Numeric ype"); + val_u32 = atoi(auth_value); + reply = l_dbus_message_new_method_return(agent_msg); + l_dbus_message_set_arguments(reply, "u", val_u32); + /* For Alpha-Numeric */ + } else if (auth_type == BT_HAL_MESH_AUTH_REQ_ALPHANUMERIC_INPUT) { + INFO("Mesh: Authentication reply: Alpha-Numeric ype"); + memset(alpha, 0x00, 16); + memcpy(alpha, auth_value, strlen(auth_value)); + reply = l_dbus_message_new_method_return(agent_msg); + builder = l_dbus_message_builder_new(reply); + __mesh_append_byte_array(builder, alpha, 16); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + } + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_network_scan(bt_uuid_t *net_uuid, + bt_hal_mesh_scan_param_t *param) +{ + GSList *l; + meshcfg_app *app; + l = g_slist_find_custom(mesh_apps, net_uuid->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + if (!l_dbus_proxy_method_call(app->mgmt_proxy, "UnprovisionedScan", + __mesh_scan_setup, __mesh_scan_reply, + L_UINT_TO_PTR(param->scan_time), NULL)) + return BT_STATUS_FAIL; + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + } + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_create_network( + bt_hal_mesh_node_t *node, GSList *models, bool is_prov) +{ + meshcfg_app *app; + + INFO("Mesh: Create Network Request"); + /* Create DBUS APP */ + app = __bt_hal_mesh_create_app(node, models, is_prov); + if (!app) + return BT_STATUS_FAIL; + + /* Register DBUS APP */ + if (!__bt_hal_mesh_register_application(app)) { + goto failed; + } + + if (app->token.u64 == 0) { + INFO("Mesh: Create New Network"); + /* Create CFG Network */ + if (!l_dbus_proxy_method_call(net_proxy, "CreateNetwork", + __bt_hal_mesh_create_net_setup, + __bt_hal_mesh_create_net_reply, app, + NULL)) { + ERR("Mesh: Network Create failed!!"); + goto failed; + } + } else { + INFO("Mesh: Attach Node to Network"); + /* Attach to Network */ + if (!l_dbus_proxy_method_call(net_proxy, "Attach", + __bt_hal_mesh_attach_node_setup, + __bt_hal_mesh_attach_node_reply, + app, + NULL)) { + ERR("Mesh: Node attach failed!!"); + goto failed; + } + } + + INFO("Mesh: Node registration request scheudled"); + mesh_apps = g_slist_append(mesh_apps, app); + INFO("Mesh: Total number of apps in list [%d]", + g_slist_length(mesh_apps)); + return BT_STATUS_SUCCESS; +failed: + ERR("Mesh: network can not be created!!"); + __bt_hal_mesh_destroy_app_object(app); + return BT_STATUS_FAIL; +} + +static void __bt_hal_mesh_config_send( + struct l_dbus_message *msg, void *user_data) +{ + struct configuration_request *req = user_data; + struct l_dbus_message_builder *builder; + + builder = l_dbus_message_builder_new(msg); + + l_dbus_message_builder_append_basic(builder, 'o', req->ele_path); + l_dbus_message_builder_append_basic(builder, 'q', &req->dst); + if (req->is_dev_key) + l_dbus_message_builder_append_basic(builder, 'b', &req->rmt); + + l_dbus_message_builder_append_basic(builder, 'q', &req->idx); + __mesh_append_byte_array(builder, req->data, req->len); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); +} + +static void __bt_hal_mesh_key_config_send( + struct l_dbus_message *msg, void *user_data) +{ + struct key_config_request *req = user_data; + struct l_dbus_message_builder *builder; + + builder = l_dbus_message_builder_new(msg); + + l_dbus_message_builder_append_basic(builder, 'o', req->ele_path); + l_dbus_message_builder_append_basic(builder, 'q', &req->dst); + l_dbus_message_builder_append_basic(builder, 'q', &req->key_req_idx); + l_dbus_message_builder_append_basic(builder, 'q', &req->idx); + l_dbus_message_builder_append_basic(builder, 'b', &req->update_req); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); +} + +bt_status_t _bt_hal_mesh_send_key_config_message( + bt_uuid_t *network, uint16_t dest, + bool is_netkey, bool is_update, + uint16_t key_idx, uint16_t netkey_idx) +{ + GSList *l; + GSList *l1; + struct key_config_request *req; + meshcfg_app *app; + meshcfg_el *elem; + const char *key_method = (!is_netkey) ? "AddAppKey" : "AddNetKey"; + /* Source is Config Client Local Node */ + int src_elem_idx = 0; + l = g_slist_find_custom(mesh_apps, network->uu, __mesh_compare_network_uuid); + if (l) { + app = l->data; + l1 = g_slist_find_custom(app->elements, + GUINT_TO_POINTER(src_elem_idx), __compare_element_index); + elem = l1->data; + + req = l_new(struct key_config_request, 1); + req->ele_path = elem->path; + req->dst = dest; + req->key_req_idx = key_idx; + req->idx = netkey_idx; /* Encryption Key index */ + req->update_req = is_update; + + if (!l_dbus_proxy_method_call(app->mgmt_proxy, key_method, + __bt_hal_mesh_key_config_send, NULL, + (void*)req, l_free)) + return BT_STATUS_FAIL; + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + + } + return BT_STATUS_SUCCESS; +} + +bt_status_t _bt_hal_mesh_send_configuration_message( + bt_uuid_t *network, uint16_t dest, + bool is_dev_key, uint16_t netkey_idx, + uint8_t *buf, int len) +{ + GSList *l; + GSList *l1; + struct configuration_request *req; + meshcfg_app *app; + meshcfg_el *elem; + int src_elem_idx = 0; + l = g_slist_find_custom(mesh_apps, network->uu, + __mesh_compare_network_uuid); + if (l) { + app = l->data; + l1 = g_slist_find_custom(app->elements, + GUINT_TO_POINTER(src_elem_idx), + __compare_element_index); + elem = l1->data; + + req = l_new(struct configuration_request, 1); + req->ele_path = elem->path; + req->dst = dest; + req->idx = netkey_idx; + req->data = buf; + req->len = len; + req->rmt = true; + req->is_dev_key = is_dev_key; + + if (!l_dbus_proxy_method_call(app->mgmt_proxy, "DevKeySend", + __bt_hal_mesh_config_send, NULL, + (void*)req, l_free)) + return BT_STATUS_FAIL; + } else { + ERR("Mesh: app not found!!"); + return BT_STATUS_PARM_INVALID; + + } + return BT_STATUS_SUCCESS; +} diff --git a/bt-oal/bluez_hal/src/bt-hal-mesh.c b/bt-oal/bluez_hal/src/bt-hal-mesh.c new file mode 100644 index 0000000..8711b15 --- /dev/null +++ b/bt-oal/bluez_hal/src/bt-hal-mesh.c @@ -0,0 +1,344 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + * + * @author: Anupam Roy + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "bt-hal.h" +#include "bt-hal-log.h" +#include "bt-hal-msg.h" +#include "bt-hal-utils.h" + +#include "bt-hal-mesh-dbus-handler.h" +#include "bt-hal-event-receiver.h" + +static const btmesh_callbacks_t *bt_hal_mesh_cbacks = NULL; + +static bool interface_ready(void) +{ + return bt_hal_mesh_cbacks != NULL; +} + +static void __bt_hal_mesh_network_attached(void *buf, uint16_t len) +{ + struct hal_ev_mesh_network_attached *ev = buf; + if (bt_hal_mesh_cbacks->network_attached_cb) + bt_hal_mesh_cbacks->network_attached_cb(ev->status, + (bt_mesh_token_t*)&ev->token, + (bt_uuid_t*)&ev->uuid); +} + +static void __bt_hal_handle_network_scan_result(void *buf, uint16_t len) +{ + struct hal_ev_mesh_scan_result *ev = buf; + bt_mesh_scan_result_t result; + memset(&result, 0x00, sizeof(bt_mesh_scan_result_t)); + + memcpy(result.dev_uuid.uu, ev->dev_uuid, 16); + memcpy(&result.oob_info, ev->oob_info, 2); + memcpy(&result.uri_hash, ev->uri_hash, 4); + result.rssi = ev->rssi; + + if (bt_hal_mesh_cbacks->scan_result_cb) + bt_hal_mesh_cbacks->scan_result_cb(ev->status, + (bt_uuid_t*)&ev->net_uuid, + (bt_mesh_scan_result_t*)&result); +} + +static void __bt_hal_handle_network_scan_status(void *buf, uint16_t len) +{ + struct hal_ev_mesh_scan_state_changed *ev = buf; + + if (bt_hal_mesh_cbacks->scan_status_cb) + bt_hal_mesh_cbacks->scan_status_cb(ev->state, ev->status, + (bt_uuid_t*)&ev->net_uuid); +} + +static void __bt_hal_handle_network_provisioning_status(void *buf, uint16_t len) +{ + struct hal_ev_mesh_provision_status *ev = buf; + + if (bt_hal_mesh_cbacks->provisioning_status_cb) + bt_hal_mesh_cbacks->provisioning_status_cb(ev->status, + (bt_uuid_t*)&ev->net_uuid, + (bt_uuid_t*)&ev->dev_uuid); +} + +static void __bt_hal_handle_network_provisioning_finished(void *buf, uint16_t len) +{ + struct hal_ev_mesh_provision_finished *ev = buf; + + if (bt_hal_mesh_cbacks->provisioning_finished_cb) + bt_hal_mesh_cbacks->provisioning_finished_cb(ev->status, ev->reason, + (bt_uuid_t*)&ev->net_uuid, (bt_uuid_t*)&ev->dev_uuid, + ev->unicast, ev->count); +} + +static void __bt_hal_handle_network_provisioning_data_requested(void *buf, + uint16_t len) +{ + struct hal_ev_mesh_provision_data_request *ev = buf; + + if (bt_hal_mesh_cbacks->provisioning_data_requested_cb) + bt_hal_mesh_cbacks->provisioning_data_requested_cb( + (bt_uuid_t*)&ev->net_uuid, ev->count); +} + +static void __bt_hal_handle_authentication_requested(void *buf, uint16_t len) +{ + struct hal_ev_mesh_authentication_request *ev = buf; + + if (bt_hal_mesh_cbacks->authentication_requested_cb) + bt_hal_mesh_cbacks->authentication_requested_cb( + (bt_uuid_t*)&ev->net_uuid, ev->auth_type, ev->auth_value); +} + +static void __bt_hal_handle_netkey_execute_event(void *buf, uint16_t len) +{ + struct hal_ev_mesh_netkey_execute_event *ev = buf; + + if (bt_hal_mesh_cbacks->netkey_execute_cb) + bt_hal_mesh_cbacks->netkey_execute_cb(ev->status, + (bt_uuid_t*)&ev->net_uuid, + ev->key_event, ev->key_idx); +} + +static void __bt_hal_handle_appkey_execute_event(void *buf, uint16_t len) +{ + struct hal_ev_mesh_appkey_execute_event *ev = buf; + + if (bt_hal_mesh_cbacks->appkey_execute_cb) + bt_hal_mesh_cbacks->appkey_execute_cb(ev->status, + (bt_uuid_t*)&ev->net_uuid, ev->key_event, + ev->net_idx, ev->app_idx); +} + +static void __bt_hal_handle_devkey_message_received_event(void *buf, uint16_t len) +{ + struct hal_ev_mesh_devkey_message_event *ev = buf; + + if (bt_hal_mesh_cbacks->devkey_msg_cb) + bt_hal_mesh_cbacks->devkey_msg_cb((bt_uuid_t*)&ev->net_uuid, + ev->source_addr, + ev->is_remote_devkey, ev->netkey_idx, + ev->data_len, ev->data); +} + +static void __bt_hal_handle_mesh_events(int message, void *buf, uint16_t len) +{ + DBG("+"); + + if (!interface_ready()) + return; + + switch (message) { + case HAL_EV_MESH_NETWORK_ATTACHED: + DBG("Mesh Event: HAL_EV_MESH_NETWORK_ATTACHED"); + __bt_hal_mesh_network_attached(buf, len); + break; + case HAL_EV_MESH_SCAN_STATE_CHANGED: + DBG("Mesh Event: HAL_EV_MESH_SCAN_STATE_CHANGED"); + __bt_hal_handle_network_scan_status(buf, len); + break; + case HAL_EV_MESH_SCAN_RESULT: + DBG("Mesh Event: HAL_EV_MESH_SCAN_RESULT"); + __bt_hal_handle_network_scan_result(buf, len); + break; + case HAL_EV_MESH_PROVISIONING_STATUS: + DBG("Mesh Event: HAL_EV_MESH_SCAN_RESULT"); + __bt_hal_handle_network_provisioning_status(buf, len); + break; + case HAL_EV_MESH_PROVISIONING_FINISHED: + DBG("Mesh Event: HAL_EV_MESH_PROVISIONING_FINISHED"); + __bt_hal_handle_network_provisioning_finished(buf, len); + break; + case HAL_EV_MESH_PROVISIONING_DATA_REQUEST: + DBG("Mesh Event: HAL_EV_MESH_PROVISIONING_DATA_REQUEST"); + __bt_hal_handle_network_provisioning_data_requested(buf, len); + break; + case HAL_EV_MESH_AUTHENTICATION_REQUEST: + DBG("Mesh Event: HAL_EV_MESH_AUTHENTICATION_REQUEST"); + __bt_hal_handle_authentication_requested(buf, len); + break; + case HAL_EV_MESH_NETKEY_EXECUTE_EVENT: + DBG("Mesh Event: HAL_EV_MESH_NETKEY_EXECUTE_EVENT"); + __bt_hal_handle_netkey_execute_event(buf, len); + break; + case HAL_EV_MESH_APPKEY_EXECUTE_EVENT: + DBG("Mesh Event: HAL_EV_MESH_APPKEY_EXECUTE_EVENT"); + __bt_hal_handle_appkey_execute_event(buf, len); + break; + case HAL_EV_MESH_DEVKEY_MESSAGE_EVENT: + DBG("Mesh Event: HAL_EV_MESH_DEVKEY_MESSAGE_EVENT"); + __bt_hal_handle_devkey_message_received_event(buf, len); + break; + default: + DBG("Mesh Event Currently not handled!!"); + break; + } + + DBG("-"); +} + +static bt_status_t mesh_create_network(bt_hal_mesh_node_t *node, + GSList *models, bool is_prov) +{ + DBG(""); + return _bt_hal_mesh_create_network(node, models, is_prov); +} + +static bt_status_t mesh_scan(bt_uuid_t *network, bt_hal_mesh_scan_param_t *param) +{ + DBG(""); + return _bt_hal_mesh_network_scan(network, param); +} + +static bt_status_t mesh_scan_cancel(bt_uuid_t *network) +{ + DBG(""); + return _bt_hal_mesh_network_scan_cancel(network); +} + +static bt_status_t mesh_set_prov_caps(bt_uuid_t *network, + bt_hal_mesh_prov_caps_t *caps) +{ + DBG(""); + return _bt_hal_mesh_network_set_caps(network, caps); +} + +static bt_status_t mesh_provision_device(bt_uuid_t *network, + bt_uuid_t *dev_uuid) +{ + DBG(""); + return _bt_hal_mesh_provision_device(network, dev_uuid); +} + +static bt_status_t mesh_send_provision_data(bt_uuid_t* network_uuid, + uint16_t netkey_idx, uint16_t unicast) +{ + DBG(""); + return _bt_hal_mesh_send_provision_data(network_uuid, + netkey_idx, unicast); +} + +static bt_status_t mesh_network_subnet_operation(bt_uuid_t* network_uuid, + bt_mesh_key_op_e op, uint16_t netkey_idx) +{ + DBG(""); + return _bt_hal_mesh_network_subnet_execute(network_uuid, + op, netkey_idx); +} + +static bt_status_t mesh_network_appkey_operation(bt_uuid_t* network_uuid, + bt_mesh_key_op_e op, uint16_t netkey_idx, + uint16_t appkey_idx) +{ + DBG(""); + return _bt_hal_mesh_network_appkey_execute(network_uuid, + op, netkey_idx, appkey_idx); +} + +static bt_status_t mesh_auth_reply(bt_hal_mesh_auth_variant_e auth_type, + const char *auth_value) +{ + DBG(""); + return _bt_hal_mesh_auth_reply(auth_type, auth_value); +} + +/* Remote Node operations */ +static bt_status_t mesh_send_configuration_message(bt_uuid_t *network, + uint16_t dest, bool is_dev_key, uint16_t netkey_idx, + uint8_t *buf, int len) +{ + DBG(""); + return _bt_hal_mesh_send_configuration_message(network, dest, + is_dev_key, netkey_idx, buf, len); +} + +static bt_status_t mesh_key_configuration_message(bt_uuid_t *network, + uint16_t dest, bool is_netkey, + bool is_update, uint16_t key_idx, + uint16_t netkey_idx) +{ + DBG(""); + return _bt_hal_mesh_send_key_config_message(network, dest, + is_netkey, is_update, + key_idx, netkey_idx); +} + +static bt_status_t init(btmesh_callbacks_t *callbacks) +{ + DBG(""); + + if (interface_ready()) + return BT_STATUS_SUCCESS; + + bt_hal_mesh_cbacks = callbacks; + INFO("Register Mesh events callback function"); + + _bt_hal_mesh_register_dbus_handler_cb(__bt_hal_handle_mesh_events); + _bt_hal_register_event_handler_cb(HAL_MESH, __bt_hal_handle_mesh_events); + + if (!_bt_hal_mesh_stack_init()) + return BT_STATUS_FAIL; + + return BT_STATUS_SUCCESS; +} + +static void cleanup(void) +{ + DBG(""); + + if (!interface_ready()) + return; + + _bt_hal_mesh_unregister_dbus_handler_cb(); + _bt_hal_unregister_event_handler_cb(HAL_MESH); + + bt_hal_mesh_cbacks = NULL; +} + +static btmesh_interface_t mesh_if = { + .size = sizeof(mesh_if), + .init = init, + .create = mesh_create_network, + .scan = mesh_scan, + .scan_cancel = mesh_scan_cancel, + .capability = mesh_set_prov_caps, + .provision = mesh_provision_device, + .provision_data = mesh_send_provision_data, + .auth_reply = mesh_auth_reply, + .subnet_execute = mesh_network_subnet_operation, + .appkey_execute = mesh_network_appkey_operation, + .config_send = mesh_send_configuration_message, + .key_send = mesh_key_configuration_message, + .cleanup = cleanup +}; + +btmesh_interface_t *bt_get_mesh_interface(void) +{ + return &mesh_if; +} diff --git a/bt-oal/bluez_hal/src/bt-hal-mesh.h b/bt-oal/bluez_hal/src/bt-hal-mesh.h new file mode 100644 index 0000000..2aa7a68 --- /dev/null +++ b/bt-oal/bluez_hal/src/bt-hal-mesh.h @@ -0,0 +1,33 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + * + * @author: Anupam Roy + * + * 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_HAL_MESH_H__ +#define __BT_HAL_MESH_H__ + +#include +#include +#include +#include +#include + +btmesh_interface_t *bt_get_mesh_interface(void); + +#endif //__BT_HAL_MESH_H__ -- 2.7.4