From: Anupam Roy Date: Sun, 28 Jun 2020 14:00:50 +0000 (+0530) Subject: Mesh: Implement Mesh CAPI X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=396c6941686aca7e64646e1522a1f163f0c2585f;p=platform%2Fcore%2Fapi%2Fbluetooth.git Mesh: Implement Mesh CAPI This patch primarily handles following - Create Local node & its elements & models - Create & configure Local Provisioner Network - Scan & Provision device - Configure Keys in local Network - Configure provisioned nodes - Create & configure Mesh Groups - Configure Keys in provisioned nodes TODO: - Events from mesh service - Node Reset functionality Change-Id: I4ccc70a5a904da1e8e2ba62425230b5a87a931b7 Signed-off-by: Anupam Roy --- diff --git a/AUTHORS b/AUTHORS index 46d1687..2b5c658 100755 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Jinmin Jung DoHyun Pyun +Anupam Roy diff --git a/CMakeLists.txt b/CMakeLists.txt index 8318ff5..61f17c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ src/bluetooth-proximity.c src/bluetooth-tds.c src/bluetooth-otp.c src/bluetooth-hrp.c +src/bluetooth-mesh.c ) LIST(APPEND SOURCES src/bluetooth-proximity.c) diff --git a/include/bluetooth_internal.h b/include/bluetooth_internal.h index 5eff9aa..1d87d29 100644 --- a/include/bluetooth_internal.h +++ b/include/bluetooth_internal.h @@ -4292,6 +4292,896 @@ int bt_gatt_enable_data_batching(const char *remote_address, int packet_threshol */ int bt_gatt_disable_data_batching(const char *remote_address); +/* Mesh API */ +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Initializes the Mesh API + * + * @remarks This function must be called before starting use BT Mesh API's. + * You must free all resources of the BT Mesh service by + * calling bt_mesh_deinitialize() + * if Mesh service is no longer needed. + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_initialize(void); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Must be called if BT Mesh service is no longer needed + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_deinitialize(void); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief API to create a arbitrary node. + * Primary element is mandatory element for any node + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_create(bt_mesh_node_features_s *features, + bt_mesh_node_h *node_handle); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Destroys the locally created mesh node + * & all resources contained in it + * + * @remarks: It is not allowed to arbitrarily destroy a locally created node, + * if it is part of a mesh network already. + * @remarks: Destroying a remote node is not supported. + * @remarks: In order to reset a remote provisioned node, use bt_mesh_node_reset() API + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_destroy(bt_mesh_node_h node_handle); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief API to create a mesh element. In case of Mesh Provisioner, + * it will serve as a element of the local node of a Mesh Provisioner. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_create_element(bt_mesh_node_h node_handle, + bt_mesh_element_h *element_handle); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Destroys the locally created mesh element & + * all resources contained in it (Ex: models) + * + * @remarks: It is not allowed to arbitrarily destroy a + * locally created element, if it is part of a mesh network already. + * @remarks: Destroying element of a remote node is not supported. + * @remarks: In order to reset a remote provisioned node, + * use bt_mesh_node_reset() API + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_element_destroy(bt_mesh_element_h element_handle); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief API to create a mesh Model instance. + * In case of Mesh Provisioner, it will serve as a + * Model of one of the elements of the local node of a Mesh Provisioner. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_element_create_model(bt_mesh_element_h element_handle, + bt_mesh_model_id_s *model_id, + bt_mesh_model_h *model_handle); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Destroys the locally created mesh Model + * + * @remarks: It is not allowed to arbitrarily destroy a locally created model, + * if it is part of a mesh network already. + * @remarks: Destroying model of a remote element is not supported. + * @remarks: In order to reset a remote provisioned node, + * use bt_mesh_node_reset() API + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_destroy(bt_mesh_model_h model); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief API to get Model ID from handle. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_get_id(bt_mesh_model_h model, + bt_mesh_model_id_s *model_id); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get Network instance in which node is contained. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_get_network(bt_mesh_node_h node, + bt_mesh_network_h *netkwork); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get node instance in which element is contained. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_element_get_node(bt_mesh_element_h element, + bt_mesh_node_h *node); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get element instance in which model is contained. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_get_element(bt_mesh_model_h model, + bt_mesh_element_h *element); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get Network instance in which node is contained. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_appkey_get_netkey(bt_mesh_appkey_h appkey, + bt_mesh_netkey_h *netkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to create a fresh Local Mesh Provisioner. + * Each Mesh Network will be characterisized + * by only one Mesh Provisioner. Mesh Provisioner will + * contain a Mesh Node which be called "local node". + * CAPI user(application) can create multiple Mesh Network. + * Each network will have a unique Mesh Provisioner + * + * @param: in: config_client, local Mesh Provisioner node + * @param: in: network_name, Mesh Network user friendly Name + * @param: out: token, The token parameter is a hexadecimal string + * of 8 bytes has been assigned to + * the application when it first got provisioned/joined mesh. + * order to authenticate itself and attach to the network as a mesh node. + * @param: out: network, created Mesh Network instance + * + * Note: Once the Mesh Network is successfully created + * OR the 'local Node' is attached, it is *NOT* allowed to + * change Local Node Hierarchy (Add/Delete Element(s), Add/Delete Model(s) etc.) + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_create(bt_mesh_node_h config_client, + const char *network_name, + bt_mesh_network_h *network, + char **token); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to load a previously created Local Mesh Provisioner. + * Each Mesh Network will be characterisized + * by only one Mesh Provisioner. Mesh Provisioner will contain a + * Mesh Config Node which be called "local node". + * CAPI user(application) can create multiple Mesh Network. + * Each network will have a unique Mesh Provisioner + * + * @param: in: token, The token parameter is a 8 byte hexadecimal + * string that has been assigned to the application when it first + * got provisioned/joined mesh. The API will use the token to + * authenticate itself and attach to the network as a mesh node. + * Application should use a valid token to authenticate itself + * as a Mesh Network Provisioner. + * @param: out: network, created Mesh Network instance + * + * Note: Once the Mesh Network is successfully created OR the + * 'local Node' is attached, + * it is *NOT* allowed to change Local Node Hierarchy + * (Add/Delete Element(s), Add/Delete Model(s) etc.) + * + * @see bt_mesh_network_create + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_load(const char *token, + bt_mesh_network_h *network); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Set Mesh Network's user fiendly name. + * + * @see bt_mesh_network_create + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_set_name(bt_mesh_network_h network, + const char *network_name); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get Mesh Network's user fiendly name. + * + * @see bt_mesh_network_create + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_get_name(bt_mesh_network_h network, + char **network_name); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to create and associate a mesh Network Key to Mesh Network + * + * @see bt_mesh_network_create + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_add_netkey(bt_mesh_network_h network, + bt_mesh_netkey_h *netkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get all NetKey(s) attached to the Local Network. + * + * @see bt_mesh_network_create + * @see bt_mesh_network_add_netkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_foreach_netkeys(bt_mesh_network_h network, + bt_mesh_network_netkey_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get global Netkey index from NetKey instance + * + * @see bt_mesh_network_add_netkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_netkey_get_index(bt_mesh_netkey_h netkey, + uint16_t *index); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to update a mesh Network Key. + * + * @see bt_mesh_network_add_netkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_netkey_update(bt_mesh_netkey_h netkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to delete a mesh Network Key. + * + * @remarks It is not allowed to destroy a netkey if it is already + * added to any of nodes in the Mesh Network + * + * @see bt_mesh_network_add_netkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_netkey_delete(bt_mesh_netkey_h netkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to create & associate a Application Key to a Network Key + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_netkey_add_appkey(bt_mesh_netkey_h netkey, + bt_mesh_appkey_h *appkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get all appkeys associated with a NetKey. + * + * @see bt_mesh_netkey_add_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_netkey_foreach_appkeys(bt_mesh_netkey_h netkey, + bt_mesh_appkey_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Get global AppKey index from AppKey instance. + * + * @see bt_mesh_netkey_add_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_appkey_get_index(bt_mesh_appkey_h netkey, + uint16_t *index); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to update a mesh Network Key. + * + * @see bt_mesh_netkey_add_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_appkey_update(bt_mesh_appkey_h appkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to delete a mesh Application Key. + * + * @remarks It is not allowed to destroy an AppKey if it is already + * added to any of nodes in the Mesh Network + * + * @see bt_mesh_netkey_add_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_appkey_delete(bt_mesh_appkey_h appkey); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to get all devices attached to the network. + * Node handle along with its primary unicast address will be returned + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_foreach_devices(bt_mesh_network_h network, + bt_mesh_network_device_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Call to get primary unicast address of the node from its handle + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_get_primary_address(bt_mesh_node_h node, + uint16_t *primary_address); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find each element present in a node + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_foreach_element(bt_mesh_node_h node, + bt_mesh_node_element_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find each models present in an element + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_element_foreach_models(bt_mesh_element_h element, + bt_mesh_element_model_info_cb callback, + void *user_data); + + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to discover unprovisioned device. + * Each unprovisioned device will advertise itself with a unique Device UUID + * + * @remarks scan result will be NULL when scan state is started or finished. + * scan result is valid only when scan state is 'device found' + * + * @see bt_mesh_scanning_state_e + * @see bt_mesh_network_scan_unprovisioned_device_result_cb + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_unprovisioned_device_scan(bt_mesh_network_h network, + bt_mesh_scan_params_s *scan_params, + bt_mesh_network_scan_unprovisioned_device_result_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Stop discovring unprovisioned device. + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_stop_unprovisioned_device_scan(bt_mesh_network_h network); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Set capabilities of a provisioner application. + * Provisioning capabilities will as per Input/Output capabilities of the + * device/application creating the provisioner. + * For e.g, if device/application has Wi-Fi/NFC connectivity and can + * procure Provisioning keys Out-Of-Band over Wi-Fi network/Remote Web URL/NFC Connectivity, + * then following capabilities can be set to true, otherwise left false + * a/ bool public_oob b/ bool static_oob + * Above capabilities indicate whether, Public Key for ECC exchange & Static Key for + * authentication can be procured out-of-band or not + * + * @param: in: network Mesh network instance which represents a provisioner node + * @param: in: capabilities Provisioner capabilities structure + * + * @remarks: A single provisioner network can provision multiple remote devices. + * During security provisioning, capabilities are selected *By Provisioner* + * based on combination of supported capabilities of provisioner & remote nodes together. + * + * @remarks: A mesh network instance represents a single Mesh provisioning node + * & multiple remote provisioned nodes. + * Therefore, setting capabilities one time, for a network or a provisioner node is sufficient. + * Normally, Input/output capabilities do not change over time for a device + * or an application. Incase, it is changed, application is free to refresh the + * capabilities of the Provisioner at any point of time. + * The next provisioning process will automatically consider the refreshed capabilities. + * @remarks: Capabilities can be set one time after local provisioner node is attached to a network. + * + * @see: bt_mesh_provisioner_capabilities_s structure + * @see: bt_mesh_network_create() + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_set_provisioning_capabilities( + bt_mesh_network_h network, + bt_mesh_provisioner_capabilities_s *capabilities); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to provision a device to the Mesh Network + * + * @remarks: In Tizen, only one provisioning process is allowed, + * irrespective of Provisioner or node role. + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_provision_device(bt_mesh_network_h network, + const char *dev_uuid, + bt_mesh_network_device_provision_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Registers a callback that will be invoked when remote + * device requests authentication, during the provisioning process. + * + * @pre Either bt_mesh_network_provision_device() in case of Provisioner role + * or bt_mesh_node_network_join() in case of Node role must be + * called (Node role API is not defined yet) + * + * @param[in] callback callback function which is set, for receiving + * authentication request during provisioning process. + * @param[in] user_data data from application which will be provided in callback. + * + * @remarks: This method is designed common for both Provisioner & Node role. + * @remarks: This callback is not invoked without the local device initiating the process + * of either Provisioning(in case of local provisioner) or + * Joining Network(in case of local node role). + * Therefore, application will be completely aware, when the callback is invoked. + * @remarks: In Tizen, only one provisioning process is allowed, irrespective of Provisioner or node role. + * Therefore, when the callback is invoked, aplication exactly knows following + * a/ whether the process is for provisioner role trying to provision a remote device + * b/ Or process if for local node role, which is inviting remote provisioners + * to join itself to a Mesh Network + * + * @see bt_network_provision_device() + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_authentication_set_request_cb( + bt_mesh_authentication_request_cb callback, + void *user_data); + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Un-registers a callback that will be invoked when + * remote device requests authentication,during the provisioning process + * + * @param[in] callback callback function to be set when + * authentication request is received. + * + * @remarks: This method is designed common for both Provisioner & Node role. + * @see bt_mesh_authentication_set_request_cb() + * @see bt_mesh_authentication_request_cb() + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_authentication_unset_request_cb( + bt_mesh_authentication_request_cb callback); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief API to reply authentication request. + * @remarks This function can be called by application when remote + * device requests authentication due to either of following process + * a/ Local provisioner role trying to provision a remote device + * b/ Local node role, inviting remote provisioners to join itself to a Mesh Network + * @param[in] auth_type Specific authentiation type, for which reply is being sent + * @param[in] value Reply string corresponding to authentication type + * @param[in] auth_reply Accept or cancel ongoing provisioning process + * @pre This function can only be called when application receieves authentication + * callback bt_mesh_authentication_request_cb + * @remarks: value string is valid, when autnetication type is of following + * a/ BT_MESH_AUTH_REQ_ALPHANUMERIC_INPUT + * b/ BT_MESH_AUTH_REQ_NUMERIC_INPUT + * c/ BT_MESH_AUTH_REQ_BLINK_COUNT_INPUT + * d/ BT_MESH_AUTH_REQ_BEEP_COUNT_INPUT + * e/ BT_MESH_AUTH_REQ_VIBRATE_COUNT_INPUT + * f/ BT_MESH_AUTH_REQ_OOB_PUBLIC_KEY_INPUT + * g/ BT_MESH_AUTH_REQ_OOB_STATIC_KEY_INPUT + * + * @remarks: This method is designed common for both Provisioner & Node role. + * @see bt_mesh_authentication_set_request_cb() + * @see bt_mesh_authentication_request_cb() + * @see bt_mesh_authentication_type_e + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_authentication_reply( + bt_mesh_authentication_type_e auth_type, + const char *value, bool auth_reply); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to identify the newly provisioned device + * + * @remarks: After provisioning is done, device must be + * discovered first of all in order to + * use it. If device is successfully discovered, node handle + * will be returned in the callback. + * @see bt_mesh_network_provision_device + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_discover_node(bt_mesh_network_h network, + const char *dev_uuid, + bt_mesh_node_discover_status_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to browse the features of a node. + * Features of the node are returned in callback + * + * @see bt_mesh_network_provision_device + * @see bt_mesh_network_discover_node + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_get_features(bt_mesh_node_h node, + bt_mesh_node_features_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to Add/Update/Delete a NetKey to a node + * + * @see bt_mesh_network_add_netkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_configure_netkey(bt_mesh_node_h node, + bt_mesh_node_key_configuration_e netkey_op, + bt_mesh_netkey_h netkey, + bt_mesh_netkey_status_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to add/update/delete an Application to a node + * + * @see bt_mesh_netkey_add_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_configure_appkey(bt_mesh_node_h node, + bt_mesh_node_key_configuration_e appkey_op, + bt_mesh_appkey_h appkey, + bt_mesh_appkey_status_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find all NetKey(s) attached to a node + * + * @see bt_mesh_node_configure_netkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_foreach_netkeys(bt_mesh_node_h node, + bt_mesh_node_netkey_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find all AppKey(s) bound to a NetKey in a node + * + * @see bt_mesh_node_configure_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_foreach_appkeys(bt_mesh_node_h node, + bt_mesh_netkey_h netkey, + bt_mesh_node_appkey_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Query TTL set to a node in the network + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_get_ttl(bt_mesh_node_h node, + bt_mesh_node_ttl_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Query TTL set to a node in the network + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_node_set_ttl(bt_mesh_node_h node, uint8_t ttl, + bt_mesh_node_ttl_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to bind a locally created application key + * to a Model of a node + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_bind_appkey(bt_mesh_model_h model, + bt_mesh_appkey_h appkey, bt_mesh_model_bind_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to Unbind a locally created application key + * to a Model of a node + * + * @see bt_mesh_model_bind_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_unbind_appkey(bt_mesh_model_h model, + bt_mesh_appkey_h appkey, + bt_mesh_model_unbind_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Async call to find all AppKey(s) bound to a model of a node + * + * @see bt_mesh_model_bind_appkey + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_get_appkey_list(bt_mesh_model_h model, + bt_mesh_model_appkey_list_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Create a Mesh group with a given group address in the Local Network + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_create_group(bt_mesh_network_h network, + uint16_t group_addr, + bt_mesh_group_h *group); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Create a Mesh Virtual group in the Local Network. + * + * @remarks Virtual group label (128-bit UUID) is internally managed by Framework. + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_create_virtual_group(bt_mesh_network_h network, + bt_mesh_group_h *group); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Remove a create Mesh group in the Local Network. + * + * @see bt_mesh_network_create_group + * @see bt_mesh_network_create_virtual_group + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_remove_group(bt_mesh_group_h group); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find all Mesh group(s), that are created in the Local Network. + * + * @remarks Group handles will be returned for each created group. + * @see bt_mesh_network_create_group + * @see bt_mesh_network_create_virtual_group + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_network_foreach_groups(bt_mesh_network_h network, + bt_mesh_network_group_info_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Subscription Add/Delete/Overwrite request to a Model of an element. + * + * @param: in: model_op: Add/Delete/Overwrite + * @param: in: model Model on which subscription operation will be applied + * @param: in: group Mesh Group handle. + * @param: in: callback result of model subscription operation + * request from remote node + * @param: in: user_data async callback data + * + * @see bt_mesh_network_create_group + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_configure_group_subscription( + bt_mesh_model_subscription_op_e model_op, + bt_mesh_model_h model, bt_mesh_group_h group, + bt_mesh_model_subscription_op_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Subscription Add/Delete/Overwrite request of a + * Virtual Group, to Model of an element. + * + * @param: in: model_op: Add/Delete/Overwrite + * @param: in: model Model on which subscription operation will be applied + * @param: in: group Mesh Group handle. + * @param: in: callback result of model subscription operation + * request from remote node + * @param: in: user_data async callback data + * + * @see bt_mesh_network_create_virtual_group + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_configure_virtual_group_subscription( + bt_mesh_model_subscription_op_e model_op, + bt_mesh_model_h model, bt_mesh_group_h group, + bt_mesh_model_subscription_op_cb callback, + void *user_data); + + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find all Subscription list of a model in a node. + * A List of all groups handles will be returned in callback, if success + * + * @remarks Group handles will be returned for each created group. + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_get_subscription_list(bt_mesh_model_h model, + bt_mesh_model_subscription_list_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Add a publiation to a Model of a node. + * + * @param: in: model Model which will generate the Publication message + * @param: in: appkey application key handle which will be used to + * encrypt publication message + * @param: in: group Mesh Group handle. + * @param: in: param Model Publication Parameters + * @param: in: callback result of model publication set request, + * from remote node + * @param: in: user_data async callback data + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_set_publication(bt_mesh_model_h model, + bt_mesh_appkey_h appkey, bt_mesh_group_h group, + bt_mesh_model_pub_params_s *params, + bt_mesh_model_publication_status_cb callback, + void *user_data); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Find Publication, set in model of a node, attached to a Network. + * Publication group handle will be returned in callback, if success + * + * @since_tizen 6.0 + * @privlevel platform + */ +int bt_mesh_model_get_publication(bt_mesh_model_h model, + bt_mesh_model_publication_status_cb callback, + void *user_data); + /** * @} */ diff --git a/include/bluetooth_private.h b/include/bluetooth_private.h index 9715b95..df3e9db 100644 --- a/include/bluetooth_private.h +++ b/include/bluetooth_private.h @@ -36,6 +36,8 @@ #include #endif +#include + #include "bluetooth.h" #include "bluetooth_internal.h" @@ -50,6 +52,9 @@ extern "C" { #define BT_DBG(fmt, args...) SLOGD(fmt, ##args) #define BT_ERR(fmt, args...) SLOGE(fmt, ##args) +#define FUNC_ENTRY BT_DBG("+") +#define FUNC_EXIT BT_DBG("-") + #define OPP_UUID "00001105-0000-1000-8000-00805f9b34fb" #define MAP_UUID "00001134-0000-1000-8000-00805f9b34fb" @@ -168,6 +173,19 @@ typedef enum { BT_EVENT_TDS_ACTIVATION_REQUESTED, /**< TDS - transport activation requested event */ BT_EVENT_TDS_PROVIDER_FOUND_RESULT, /**< TDS - CUSTOM Provider */ BT_EVENT_OTP_SERVER_STATE_CHANGED, /**< OTP - Server Status */ + BT_EVENT_MESH_NETWORK_SCAN_STATE_CHANGED, /**< Mesh - Scan state chanegd event */ + BT_EVENT_MESH_AUTHENTICATION_REQUEST, /**< Mesh - Authentication Request event */ + BT_EVENT_MESH_NETWORK_PROVISIONING_RESULT, /**< Mesh - Provisioning Result event */ + BT_EVENT_MESH_NODE_BROWSING_COMPLETED, /**< Mesh - Node browsing event */ + BT_EVENT_MESH_NODE_VENDOR_FEATURES, /**< Mesh - Node Features event */ + BT_EVENT_MESH_NODE_KEY_CONFIGURATION_COMPLETED, /**< Mesh - Node Key Configuration event */ + BT_EVENT_MESH_NODE_TTL_EXECUTE_COMPLETED, /**< Mesh - Node TTL Get/Set event */ + BT_EVENT_MESH_NODE_MODEL_BIND_APPKEY_COMPLETED, /**< Mesh - Node Model Bind AppKey */ + BT_EVENT_MESH_NODE_MODEL_APPKEY_LIST, /**< Mesh - Model AppKey List */ + BT_EVENT_MESH_NODE_MODEL_SUB_LIST, /**< Mesh - Model Subscription List */ + BT_EVENT_MESH_NODE_MODEL_GROUP_SUB, /**< Mesh - Model Virtual Subscription - Add/Delete/overwrite/DeleteAll */ + BT_EVENT_MESH_NODE_MODEL_GROUP_VIR_SUB, /**< Mesh - Model Virtual Subscription - Add/Delete/overwrite/DeleteAll */ + BT_EVENT_MESH_NODE_MODEL_PUBLICATION, /**< Mesh - Model Publication Status event index */ BT_EVENT_MAX } bt_event_e; @@ -586,6 +604,7 @@ typedef enum { BT_FEATURE_LE, BT_FEATURE_LE_5_0, BT_FEATURE_IPSP, + BT_FEATURE_MESH, BT_FEATURE_AUDIO_CALL, BT_FEATURE_AUDIO_MEDIA, BT_FEATURE_AUDIO_CONTROLLER, @@ -750,6 +769,12 @@ char *_bt_convert_error_to_string(int error); */ char* _bt_convert_uuid_to_uuid128(const char *uuid); +/** + * @internal + * @brief Fill random hex bytes of size num_bytes + */ +bool _bt_get_random_bytes(void *buf, size_t num_bytes); + /** * @internal * @brief Convert the visibility mode @@ -864,6 +889,72 @@ void _bt_gatt_client_event_proxy(int event, gatt_client_event_param_t *param, void *user_data); #endif +/* BT MESH Event handler */ +void _bt_mesh_event_proxy(int event, mesh_event_param_t *param, void *user_data); + +typedef struct { + bool is_local; + bool is_attached; +} bt_mesh_common_handle_s; + +typedef struct { + bool is_local; /**< Is it a provisioner network >*/ + bool is_discovered; /**< Are all provisioned nodes discovered >*/ + char uuid[BT_MESH_UUID_STRING_LEN +1 ]; /** < Network's unique identifier, also the UUID of the local node */ + char token[BT_MESH_TOKEN_STRING_LEN + 1]; /** < Toke of the local node */ + char name[BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1]; /** < name of the enwtork */ + uint16_t num_nodes; /**< including local node */ + GSList *nodes; /**< All nodes attached to the network */ + GSList *netkeys; /**< All netkeys which are created in the local key database by the provisioner */ + GSList *groups; /**< All iGroups created within the network */ +} bt_mesh_network_s; + +typedef struct { + bt_mesh_network_s *parent; + uint16_t addr; + char label_uuid[BT_MESH_UUID_STRING_LEN + 1]; + bool is_virtual; + int ref_count; +} bt_mesh_group_s; + +typedef struct { + bool is_local; + bool is_attached; + bt_mesh_network_s *parent; + char uuid[BT_MESH_UUID_STRING_LEN + 1]; + uint16_t unicast; + bool is_provisioner; + bt_mesh_node_features_s features; + GSList *elements; + GSList *netkeys; + GSList *appkeys; +} bt_mesh_node_s; + +typedef struct { + bool is_local; + bt_mesh_node_s *parent; + uint16_t index; + GSList *models; +} bt_mesh_element_s; + +typedef struct { + bool is_local; + bt_mesh_element_s *parent; + uint32_t id; + uint16_t pub_addr; +} bt_mesh_model_s; + +typedef struct { + bt_mesh_network_s *parent; + uint16_t netkey_index; + GSList *appkeys; +} bt_mesh_netkey_s; + +typedef struct { + bt_mesh_netkey_s *parent; + uint16_t appkey_index; +} bt_mesh_appkey_s; + /** * @ingroup CAPI_NETWORK_BLUETOOTH_LE_MODULE @@ -1037,6 +1128,147 @@ void _bt_otc_connection_state_changed(int result, bluetooth_otc_info_t *otc_info */ void _bt_otp_check_service_changed(char *address, bt_gatt_service_change_t *service_change); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets Mesh network object from network UUID + * @since_tizen 6.0 + */ +bt_mesh_network_s * _bt_mesh_get_network_handle_info(char *net_uuid); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Sets node info and return node object. + * @since_tizen 6.0 + */ +bt_mesh_node_s *_bt_mesh_remote_node_browsed( + char *net_uuid, char *dev_uuid, + uint16_t unicast, int count); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Handle Net Key configure for node. + * @since_tizen 6.0 + */ +bt_mesh_netkey_s *_bt_mesh_handle_node_netkey_configure( + bt_mesh_network_s *network_s, + bt_mesh_node_s *node_s, uint16_t netkey_idx, + bt_mesh_node_key_configuration_e op); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Handle App Key configure for node. + * @since_tizen 6.0 + */ +bt_mesh_appkey_s *_bt_mesh_handle_node_appkey_configure( + bt_mesh_network_s *network_s, + bt_mesh_node_s *node_s, + uint16_t netkey_idx, uint16_t appkey_idx, + bt_mesh_node_key_configuration_e op); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets node info from node prinary unicast address. + * @since_tizen 6.0 + */ +bt_mesh_node_s *_bt_mesh_get_node_from_unicast(char *net_uuid, + uint16_t unicast); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets element object from element index in a node. + * @since_tizen 6.0 + */ +bt_mesh_element_s* _bt_mesh_get_element_from_index( + bt_mesh_node_s *node_s, + int element_index); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets model object from model ID in an element. + * @since_tizen 6.0 + */ +bt_mesh_model_s* _bt_mesh_get_model_from_modelid( + bt_mesh_element_s *element_s, + uint32_t modelid); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets Mesh group object, corresponding to group address + * @since_tizen 6.0 + */ +bt_mesh_group_s* _bt_mesh_network_get_group( + bt_mesh_network_s *network_s, + uint16_t group_addr); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets AppKey object corresponding to AppKey index. + * @since_tizen 6.0 + */ +bt_mesh_appkey_s* _bt_mesh_network_get_appkey_from_index( + bt_mesh_network_s *network_s, + uint16_t appkey_idx); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets Mesh Authentication request string from auth numeric Value. + * @since_tizen 6.0 + */ +char * _bt_mesh_get_auth_string_from_value(int auth); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets Appkey Object attahced to a node, from appkey index. + * @since_tizen 6.0 + */ +bt_mesh_appkey_s* _bt_mesh_node_get_appkey( + bt_mesh_node_s *node_s, + uint16_t appkey_idx); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets element object from node's primary unicast & element index information. + * @since_tizen 6.0 + */ +bt_mesh_element_s * _bt_mesh_get_node_get_element_from_index( + char *net_uuid, + uint16_t unicast, int elem_idx); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Gets model object, from element information. + * @since_tizen 6.0 + */ +bt_mesh_model_s *_bt_mesh_get_node_get_model_from_element( + char *net_uuid, uint16_t unicast, + int elem_idx, uint32_t model); + +/** + * @internal + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Getsgroups handle from subsciprion address. + * @since_tizen 6.0 + */ +bt_mesh_group_s * _bt_mesh_get_group_from_sub( + bt_mesh_network_s *network_s, + bt_mesh_model_s *model_s, + bt_mesh_model_subscription_op_e op, + uint16_t sub_addr); + /** * @ingroup CAPI_NETWORK_BLUETOOTH_AUDIO_AG_MODULE * @brief Called when the battery level of the remote device is changed. diff --git a/include/bluetooth_type_internal.h b/include/bluetooth_type_internal.h index d03eb7c..68383d7 100644 --- a/include/bluetooth_type_internal.h +++ b/include/bluetooth_type_internal.h @@ -1336,6 +1336,494 @@ typedef enum { BT_ADAPTER_LE_ADVERTISING_TX_POWER_ULTRA_LOW = -23 /**< Lowst transmission power level */ } bt_adapter_le_advertising_tx_power_level_e; +/* Mesh Start */ +#define BT_MESH_MAX_UNPROVISIONED_DEVICE_SCAN_TIME 300 +#define BT_MESH_NETWORK_NAME_STRING_MAX_LEN 100 +#define BT_MESH_MAX_PUBISH_PERIOD_STEPS 0x3F +#define BT_MESH_UUID_STRING_LEN 32 +#define BT_MESH_TOKEN_STRING_LEN 16 + +/* Intervals for retransmission of a Publish message: value * 50 msec */ +#define BT_MESH_MAX_PUBISH_RETRANSMIT_INTERVAL_STEPS 0x1F + +/* How many times, restransmission is allowed for a publish message */ +#define BT_MESH_MAX_PUBISH_RETRANSMIT_COUNT 0x7 + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations for the BT SIG Mesh Models + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_MODEL_ID_CFG_SRV = 0x0000, + BT_MESH_MODEL_ID_CFG_CLIENT = 0x0001, + BT_MESH_MODEL_ID_HEALTH_SRV = 0x0002, + BT_MESH_MODEL_ID_HEALTH_CLIENT = 0x0003, + BT_MESH_MODEL_ID_GEN_ONOFF_SRV = 0x1000, + BT_MESH_MODEL_ID_GEN_ONOFF_CLIENT = 0x1001, + BT_MESH_MODEL_ID_GEN_LEVEL_SRV = 0x1002, + BT_MESH_MODEL_ID_GEN_LEVEL_CLI = 0x1003, + BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV = 0x1004, + BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI = 0x1005, + BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV = 0x1006, + BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV = 0x1007, + BT_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI = 0x1008, + BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV = 0x1009, + BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV = 0x100a, + BT_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI = 0x100b, + BT_MESH_MODEL_ID_GEN_BATTERY_SRV = 0x100c, + BT_MESH_MODEL_ID_GEN_BATTERY_CLI = 0x100d, + BT_MESH_MODEL_ID_GEN_LOCATION_SRV = 0x100e, + BT_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV = 0x100f, + BT_MESH_MODEL_ID_GEN_LOCATION_CLI = 0x1010, + BT_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV = 0x1011, + BT_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV = 0x1012, + BT_MESH_MODEL_ID_GEN_USER_PROP_SRV = 0x1013, + BT_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV = 0x1014, + BT_MESH_MODEL_ID_GEN_PROP_CLI = 0x1015, + BT_MESH_MODEL_ID_SENSOR_SRV = 0x1100, + BT_MESH_MODEL_ID_SENSOR_SETUP_SRV = 0x1101, + BT_MESH_MODEL_ID_SENSOR_CLI = 0x1102, + BT_MESH_MODEL_ID_TIME_SRV = 0x1200, + BT_MESH_MODEL_ID_TIME_SETUP_SRV = 0x1201, + BT_MESH_MODEL_ID_TIME_CLI = 0x1202, + BT_MESH_MODEL_ID_SCENE_SRV = 0x1203, + BT_MESH_MODEL_ID_SCENE_SETUP_SRV = 0x1204, + BT_MESH_MODEL_ID_SCENE_CLI = 0x1205, + BT_MESH_MODEL_ID_SCHEDULER_SRV = 0x1206, + BT_MESH_MODEL_ID_SCHEDULER_SETUP_SRV = 0x1207, + BT_MESH_MODEL_ID_SCHEDULER_CLI = 0x1208, + BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV = 0x1300, + BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV = 0x1301, + BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI = 0x1302, + BT_MESH_MODEL_ID_LIGHT_CTL_SRV = 0x1303, + BT_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV = 0x1304, + BT_MESH_MODEL_ID_LIGHT_CTL_CLI = 0x1305, + BT_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV = 0x1306, + BT_MESH_MODEL_ID_LIGHT_HSL_SRV = 0x1307, + BT_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV = 0x1308, + BT_MESH_MODEL_ID_LIGHT_HSL_CLI = 0x1309, + BT_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV = 0x130a, + BT_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV = 0x130b, + BT_MESH_MODEL_ID_LIGHT_XYL_SRV = 0x130c, + BT_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV = 0x130d, + BT_MESH_MODEL_ID_LIGHT_XYL_CLI = 0x130e, + BT_MESH_MODEL_ID_LIGHT_LC_SRV = 0x130f, + BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV = 0x1310, + BT_MESH_MODEL_ID_LIGHT_LC_CLI = 0x1311, + BT_MESH_MODEL_MAX = 0xFFFF, +} bt_mesh_sig_model_id_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations of the Provisioning error codes. + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_PROV_ERR_INTERNAL = -1, + BT_MESH_PROV_ERR_SUCCESS = 0x00, + BT_MESH_PROV_ERR_INVALID_PDU = 0x01, + BT_MESH_PROV_ERR_INVALID_FORMAT = 0x02, + BT_MESH_PROV_ERR_UNEXPECTED_PDU = 0x03, + BT_MESH_PROV_ERR_CONFIRM_FAILED = 0x04, + BT_MESH_PROV_ERR_INSUF_RESOURCE = 0x05, + BT_MESH_PROV_ERR_DECRYPT_FAILED = 0x06, + BT_MESH_PROV_ERR_UNEXPECTED_ERR = 0x07, + BT_MESH_PROV_ERR_CANT_ASSIGN_ADDR = 0x08, + /* Internally generated by Stack */ + BT_MESH_PROV_ERR_TIMEOUT = 0xFF, +} bt_mesh_prov_error_codes_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations of the Unprovisioned scanning state of Provisioner device. + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_SCANNING_STARTED, /**< Scanning is started */ + BT_MESH_SCANNING_FINISHED, /**< Scanning is finished */ + BT_MESH_SCAN_DEVICE_FOUND, /**< The remote Unprovisioned device is found */ +} bt_mesh_scanning_state_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations of 2 octet OOB Information field, + * per Table 3.54, Mesh profile Specification + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_OOB_INFO_OTHER = 0x01, + BT_MESH_OOB_INFO_ELECTRONIC_OR_URI = 0x02, + BT_MESH_OOB_INFO_2D_MACHINE_READABLE_CODE = 0x04, + BT_MESH_OOB_INFO_BAR_CODE = 0x08, + BT_MESH_OOB_INFO_NEAR_FIELD_COMMUNICATION = 0x10, + BT_MESH_OOB_INFO_NUMBER = 0x20, + BT_MESH_OOB_INFO_STRING = 0x40, + /* bit 7 ~ 10 : RFU */ + BT_MESH_OOB_INFO_ON_BOX = 0x800, + BT_MESH_OOB_INFO_INSIDE_BOX = 0x1000, + BT_MESH_OOB_INFO_ON_PIECE_OF_PAPER = 0x2000, + BT_MESH_OOB_INFO_INSIDE_MANUAL = 0x4000, + BT_MESH_OOB_INFO_ON_DEVICE = 0x8000, +} bt_mesh_oob_info_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations of 2 octet OUT OOB Actions + * per Table 5.22, Mesh profile Specification + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_OUT_OOB_METHOD_BLINK = 0x01, + BT_MESH_OUT_OOB_METHOD_BEEP = 0x02, + BT_MESH_OUT_OOB_METHOD_VIBRATE = 0x04, + BT_MESH_OUT_OOB_METHOD_NUMERIC = 0x08, + BT_MESH_OUT_OOB_METHOD_ALPHANUMERIC = 0x10, + /* bit 5 ~ 15 : RFU */ +} bt_mesh_output_oob_action_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations of 2 octet IN OOB Actions + * per Table 5.24, Mesh profile Specification + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_IN_OOB_METHOD_PUSH = 0x01, + BT_MESH_IN_OOB_METHOD_TWIST = 0x02, + BT_MESH_IN_OOB_METHOD_NUMERIC = 0x04, + BT_MESH_IN_OOB_METHOD_ALPHANUMERIC = 0x08, + /* bit 4 ~ 15 : RFU */ +} bt_mesh_input_oob_action_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations of Authentication Types(Input, Output, OOB Keys) + * @since_tizen 6.0 + */ +typedef enum { + /*< Output authentication request types */ + BT_MESH_AUTH_ALPHANUMERIC_DISPLAY = 0, + BT_MESH_AUTH_NUMERIC_DISPLAY, + BT_MESH_AUTH_PUSH_COUNT_DISPLAY, + BT_MESH_AUTH_TWIST_COUNT_DISPLAY, + + /*< Input authentication request types */ + BT_MESH_AUTH_REQ_ALPHANUMERIC_INPUT, + BT_MESH_AUTH_REQ_NUMERIC_INPUT, + BT_MESH_AUTH_REQ_BLINK_COUNT_INPUT, + BT_MESH_AUTH_REQ_BEEP_COUNT_INPUT, + BT_MESH_AUTH_REQ_VIBRATE_COUNT_INPUT, + + /**< OOB Key Inputs */ + BT_MESH_AUTH_REQ_OOB_PUBLIC_KEY_INPUT, + BT_MESH_AUTH_REQ_OOB_STATIC_KEY_INPUT +} bt_mesh_authentication_type_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations for the Step Resolution for Period of Publication message + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_PUBLICATION_STEP_RES_100_MSEC, + BT_MESH_PUBLICATION_STEP_RES_1_SECOND, + BT_MESH_PUBLICATION_STEP_RES_10_SECONDS, + BT_MESH_PUBLICATION_STEP_RES_10_MINS, +} bt_mesh_publish_resolution_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations for the Model Subscription operations + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_MODEL_SUBSCRIPTION_ADD, + BT_MESH_MODEL_SUBSCRIPTION_DELETE, + BT_MESH_MODEL_SUBSCRIPTION_DELETE_ALL, + BT_MESH_MODEL_SUBSCRIPTION_OVERWRITE, +} bt_mesh_model_subscription_op_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations for the Mesh features + * per Table 4.3, Mesh profile Specification + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_FEATURE_RELAY = 0x01, + BT_MESH_FEATURE_PROXY = 0x02, + BT_MESH_FEATURE_FRIEND = 0x04, + BT_MESH_FEATURE_LOWPOWER = 0x08, + /* bit 4 ~ 15 : RFU */ +} bt_mesh_features_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Enumerations for the TTL operation for a node in a network + * @since_tizen 6.0 + */ +typedef enum { + BT_MESH_TTL_GET, + BT_MESH_TTL_SET, +} bt_mesh_node_ttl_operation_e; + + +typedef enum { + BT_MESH_NODE_KEY_ADD, + BT_MESH_NODE_KEY_UPDATE, + BT_MESH_NODE_KEY_DELETE, +} bt_mesh_node_key_configuration_e; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief structure of Model ID + * @since_tizen 6.0 + */ +typedef struct { + uint16_t company_id; /** < 0xFFFF in case of BT SIG Model ID */ + uint16_t model_id; +} bt_mesh_model_id_s; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief structure of Model Publication parameters + * @since_tizen 6.0 + */ +typedef struct { + uint8_t ttl; + uint8_t num_steps; + bt_mesh_publish_resolution_e per_res; + uint8_t retrans_cnt; + uint8_t retrans_step; + //uint16_t pub_addr; +} bt_mesh_model_pub_params_s; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh provisioner or a Mesh Network instance. + * @since_tizen 6.0 + */ +typedef void *bt_mesh_network_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh Network group. + * @since_tizen 6.0 + */ +typedef void *bt_mesh_group_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh node (Local or Remote) + * @since_tizen 6.0 + */ +typedef void *bt_mesh_node_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh element contained in a node. + * @since_tizen 6.0 + */ +typedef void *bt_mesh_element_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh Model (BT SIG or vendor Model) + * @since_tizen 6.0 + */ +typedef void *bt_mesh_model_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh Network or subnetwork Key. + * @since_tizen 6.0 + */ +typedef void *bt_mesh_netkey_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief The handle of a BLE Mesh Application key. + * @since_tizen 6.0 + */ +typedef void *bt_mesh_appkey_h; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Structure of a BLE Mesh Scan result (From a Unprovisioned Device Beacon) + * @since_tizen 6.0 + * @see bt_mesh_network_create() + */ +typedef struct { + char *uuid; /**< Unprovisioned Device UUID */ + int rssi; /**< RSSI signal strength */ + bt_mesh_oob_info_e oob_info; /**< Indicates various method via which OOB Data can be exported by remote node */ + /* TODO Currently mesh daemon does not support URI Hash data. + The structure will be expanded once it is available from stack */ +} bt_mesh_scan_result_s; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Structure of a BLE Mesh Provisioner Capabilities + * @since_tizen 6.0 + * @see bt_mesh_network_set_provisioning_capabilities() + */ +typedef struct { + bool public_oob; /**< Indicates Public Key for ECC Key exchange, can be fetched Out Of Band, */ + bool static_oob; /**< Indicates Static Key for authentication, can be fetched Out-Of-Band*/ + bt_mesh_output_oob_action_e out_oob; /**< Indicates suport for bitmap combination of OUT-OOB actions */ + bt_mesh_input_oob_action_e in_oob; /**< Indicates suport for bitmap combination of IN-OOB actions */ +} bt_mesh_provisioner_capabilities_s; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Structure of a BLE Mesh Unprovisioned Device Scan parameters + * @since_tizen 6.0 + * @see bt_mesh_network_unprovisioned_device_scan() + * @see MAX_UNPROVISIONED_DEVICE_SCAN_TIME + */ +typedef struct { + uint16_t seconds; /**< Current maximum is 300 seconds or 5 minutes */ + /* More parameters to add in future */ +} bt_mesh_scan_params_s; + +/** + * @ingroup CAPI_NETWORK_BLUETOOTH_MESH_MODULE + * @brief Structure of a BLE Mesh Node feature + * @since_tizen 6.0 + * @see bt_mesh_node_get_features() + * @see MAX_UNPROVISIONED_DEVICE_SCAN_TIME + */ +typedef struct { + uint16_t cid; /**< Contains a 16-bit company identifier assigned by the Bluetooth SIG */ + uint16_t pid; /**< Contains a 16-bit vendor-assigned product identifier */ + uint16_t vid; /**< Contains a 16-bit vendor-assigned product version identifier*/ + uint16_t crpl; /**< Contains a 16-bit value representing the minimum number of replay protection list entries in a device*/ + bt_mesh_features_e features; /**< Bit map of Mesh features supported by the node */ +} bt_mesh_node_features_s; + +/* Mesh Callback Signatures */ +typedef void (*bt_mesh_network_create_cb) + (int result, bt_mesh_network_h network, + const char *network_name, void *user_data); + + +typedef void (*bt_mesh_network_load_cb) + (int result, bt_mesh_network_h network, const char *token, + const char *network_name, void *user_data); + + +typedef void (*bt_mesh_network_scan_unprovisioned_device_result_cb) + (int result, bt_mesh_network_h network, + bt_mesh_scanning_state_e state, + bt_mesh_scan_result_s *scan_res, + void *user_data); + +typedef void (*bt_mesh_network_device_provision_cb) + (int result, bt_mesh_network_h network, + const char *dev_uuid, void *user_data); + + +typedef void (*bt_mesh_authentication_request_cb) + (int result, bt_mesh_authentication_type_e auth_type, + char *auth_value, void *user_data); + + +typedef void (*bt_mesh_network_node_reset_cb) + (int result, bt_mesh_network_h network, + const char *dev_uuid, void *user_data); + + +typedef void (*bt_mesh_node_ttl_cb) + (int result, bt_mesh_node_h node, + bt_mesh_node_ttl_operation_e ttl_op, + uint8_t ttl, void *user_data); + +typedef void (*bt_mesh_node_discover_status_cb) + (int result, bt_mesh_network_h network, bt_mesh_node_h node, + void *user_data); + +typedef void (*bt_mesh_node_features_cb) + (int result, bt_mesh_node_h node, + bt_mesh_node_features_s *features, void *user_data); + +typedef bool (*bt_mesh_node_netkey_info_cb) + (int result, bt_mesh_node_h node, int total, + bt_mesh_netkey_h netkey, + uint16_t netkey_index, void *user_data); + +typedef bool (*bt_mesh_node_appkey_info_cb) + (int result, bt_mesh_node_h node, int total, + bt_mesh_netkey_h netkey, bt_mesh_appkey_h appkey, + uint16_t appkey_index, void *user_data); + +typedef bool (*bt_mesh_network_netkey_info_cb) + (int result, bt_mesh_network_h network, + int total, bt_mesh_netkey_h netkey, + uint16_t netkey_index, void *user_data); + +typedef bool (*bt_mesh_appkey_info_cb) + (int result, bt_mesh_network_h network, int total, + bt_mesh_netkey_h netkey, bt_mesh_appkey_h appkey, + uint16_t appkey_index, void *user_data); + +typedef bool (*bt_mesh_network_device_info_cb) + (int result, bt_mesh_network_h network, int total, + const char *dev_uuid, uint16_t primary_unicast, + void *user_data); + +typedef bool (*bt_mesh_node_element_info_cb) + (int result, bt_mesh_node_h node, int total, + bt_mesh_element_h element, + int elem_index, uint16_t element_addr, + void *user_data); + +typedef bool (*bt_mesh_element_model_info_cb) + (int result, bt_mesh_element_h element, int total, + bt_mesh_model_h model, bt_mesh_model_id_s *model_id, + void *user_data); + +typedef void (*bt_mesh_appkey_status_cb) + (int result, bt_mesh_node_key_configuration_e op, + bt_mesh_node_h node, bt_mesh_netkey_h netkey, + bt_mesh_appkey_h appkey, void *user_data); + +typedef void (*bt_mesh_netkey_status_cb) + (int result, bt_mesh_node_key_configuration_e op, bt_mesh_node_h node, + bt_mesh_netkey_h netkey, void *user_data); + +typedef void (*bt_mesh_model_bind_cb) + (int result, bt_mesh_model_h model, bt_mesh_appkey_h appkey, + void *user_data); + +typedef void (*bt_mesh_model_unbind_cb) + (int result, bt_mesh_model_h model, bt_mesh_appkey_h appkey, + void *user_data); + +typedef void (*bt_mesh_model_appkey_list_cb) + (int result, bt_mesh_model_h model, int total, + const GSList *appkeylist, + void *user_data); + +typedef void (*bt_mesh_model_subscription_op_cb) + (int result, bt_mesh_model_subscription_op_e op, + bt_mesh_model_h model, bt_mesh_group_h group, + void *user_data); + + +typedef bool (*bt_mesh_model_subscription_list_cb) + (int result, bt_mesh_model_h model, int total, + const GSList *sub_addr, + void *user_data); + +typedef void (*bt_mesh_model_publication_status_cb) + (int result, bt_mesh_model_h model, bt_mesh_group_h group, + bt_mesh_appkey_h appkey, void *user_data); + +typedef bool (*bt_mesh_network_group_info_cb) + (int result, bt_mesh_network_h network, int total, + bt_mesh_group_h group, void *user_data); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/bluetooth-common.c b/src/bluetooth-common.c index 9326803..7a1af8b 100644 --- a/src/bluetooth-common.c +++ b/src/bluetooth-common.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include +#include #include #include #include @@ -670,6 +672,25 @@ char *_bt_convert_error_to_string(int error) return "UNKNOWN"; /* LCOV_EXCL_LINE */ } +bool _bt_get_random_bytes(void *buf, size_t num_bytes) +{ + ssize_t len; + int fd; + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) + return false; + + len = read(fd, buf, num_bytes); + + close(fd); + + if (len < 0) + return false; + + return true; +} + /* LCOV_EXCL_START */ char *_bt_convert_uuid_to_uuid128(const char *uuid) { @@ -1245,6 +1266,18 @@ static bt_gatt_server_notification_sent_cb __bt_gatt_attribute_get_notification_ } #endif +void _bt_mesh_event_proxy(int event, mesh_event_param_t *param, void *user_data) +{ + if (!param) + return; + bluetooth_event_param_t new_param; + new_param.event = param->event; + new_param.param_data = param->param_data; + new_param.result = param->result; + new_param.user_data = NULL; + __bt_event_proxy(event, &new_param, user_data); +} + static void __bt_free_bt_device_connection_info_s(bt_device_connection_info_s *conn_info) { if (conn_info == NULL) diff --git a/src/bluetooth-mesh.c b/src/bluetooth-mesh.c new file mode 100644 index 0000000..a848b26 --- /dev/null +++ b/src/bluetooth-mesh.c @@ -0,0 +1,3311 @@ +/* + * 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 "bluetooth.h" +#include "bluetooth_internal.h" +#include "bluetooth_private.h" +#include "bluetooth-mesh-api.h" + +#define BT_MESH_MAX_NETWORKS 5 +#define BT_MESH_MAX_ELEMENTS 32767 +#define BT_MESH_MAX_MODELS 32767 +#define BT_MESH_MAX_NODES 32767 +#define BT_MESH_MAX_SUBNETS 4096 + +static bool is_mesh_initialized = false; + +/**< List of Local handles >*/ +GSList *networks; +GSList *node_list; +GSList *element_list; +GSList *model_list; +GSList *appkey_list; +GSList *netkey_list; +GSList *group_list; + + +#define BT_CHECK_MESH_SUPPORT() \ +{ \ + BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); \ + BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_LE); \ + BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_MESH); \ +} + +#define BT_CHECK_MESH_INIT_STATUS() \ + if (__bt_check_mesh_init_status() == BT_ERROR_NOT_INITIALIZED) { \ + LOGE("[%s] NOT_INITIALIZED(0x%08x)", __FUNCTION__, BT_ERROR_NOT_INITIALIZED); \ + return BT_ERROR_NOT_INITIALIZED; \ + } + + +#define BT_CHECK_MESH_REMOTE(handle) \ +{ if (handle->is_local) return BT_ERROR_OPERATION_FAILED; } + + +#define BT_CHECK_MESH_LOCAL(handle) \ +{ if (!handle->is_local) return BT_ERROR_OPERATION_FAILED; } + + +#define BT_CHECK_MESH_IS_ATTACHED(handle) \ +{ if (handle->is_attached) return BT_ERROR_OPERATION_FAILED; } + +#define BT_MESH_VALIDATE_HANDLE(h1, list) \ +{ \ + GSList *l; \ + bool valid = FALSE; \ + for (l = list; l; l = g_slist_next(l)) { \ + void *h2 = (void *)l->data; \ + if (h1 == h2) { \ + BT_INFO("Handle matched [%p]", h2); \ + valid = TRUE; break; \ + } \ + } \ + if (valid == FALSE) { \ + BT_ERR("Handle [%p] did not match with any stored handles!!", h1); \ + return BT_ERROR_INVALID_PARAMETER; \ + } \ +} \ + +size_t __bt_mesh_util_convert_hex_to_string(uint8_t *in, + size_t in_len, char *out, size_t out_len) +{ + static const char hexdigits[] = "0123456789abcdef"; + size_t i; + + if (in_len * 2 > (out_len - 1)) + return 0; + + for (i = 0; i < in_len; i++) { + out[i * 2] = hexdigits[in[i] >> 4]; + out[i * 2 + 1] = hexdigits[in[i] & 0xf]; + } + + out[in_len * 2] = '\0'; + return i; +} + +static int __compare_node_primary_unicast(gconstpointer a, gconstpointer b) +{ + const bt_mesh_node_s *node = a; + uint16_t index = GPOINTER_TO_UINT(b); + + return (node->unicast - index); +} + +static int __compare_node_element_index(gconstpointer a, gconstpointer b) +{ + const bt_mesh_element_s *element = a; + int index = GPOINTER_TO_UINT(b); + + return (element->index - index); +} + +static int __compare_network_group_address(gconstpointer a, gconstpointer b) +{ + const bt_mesh_group_s *group = a; + uint16_t group_addr = GPOINTER_TO_UINT(b); + + return (group->addr - group_addr); +} + +static int __compare_model_id(gconstpointer a, gconstpointer b) +{ + const bt_mesh_model_s *model_s = a; + uint32_t model = GPOINTER_TO_UINT(b); + + return (model_s->id - model); +} + +static int __compare_netkey_index(gconstpointer a, gconstpointer b) +{ + const bt_mesh_netkey_s *nk = a; + uint16_t netkey_index = GPOINTER_TO_UINT(b); + + return (nk->netkey_index - netkey_index); +} + +static int __simple_compare(gconstpointer a, gconstpointer b) +{ + if (a == b) + return 0; + else + return 1; +} + +static int __compare_appkey_index(gconstpointer a, gconstpointer b) +{ + const bt_mesh_appkey_s *ak = a; + uint16_t appkey_index = GPOINTER_TO_UINT(b); + + return (ak->appkey_index - appkey_index); +} + +static int __compare_element_index(gconstpointer a, gconstpointer b) +{ + const bt_mesh_element_s *elem = a; + uint16_t element_index = GPOINTER_TO_UINT(b); + + return (elem->index - element_index); +} + +static bt_mesh_netkey_s * __bt_mesh_network_is_netkey_added( + bt_mesh_network_s *network_s, uint16_t netkey_idx) +{ + GSList *l; + + l = g_slist_find_custom(network_s->netkeys, GUINT_TO_POINTER(netkey_idx), + (GCompareFunc)__compare_netkey_index); + if (!l) + return NULL; + + return (bt_mesh_netkey_s*) l->data; +} + +bt_mesh_element_s *_bt_mesh_get_element_from_index( + bt_mesh_node_s *node_s, int element_index) +{ + GSList *l; + + l = g_slist_find_custom(node_s->elements, GUINT_TO_POINTER(element_index), + (GCompareFunc)__compare_element_index); + if (!l) + return NULL; + + return (bt_mesh_element_s*) l->data; +} + +bt_mesh_appkey_s *_bt_mesh_network_get_appkey_from_index( + bt_mesh_network_s *network_s, uint16_t appkey_idx) +{ + GSList *l, *l1; + + for (l = network_s->netkeys; l; l = l->next) { + bt_mesh_netkey_s *netkey_s = l->data; + + l1 = g_slist_find_custom(netkey_s->appkeys, GUINT_TO_POINTER(appkey_idx), + (GCompareFunc)__compare_appkey_index); + + if (l1) + return l1->data; + } + return NULL; +} + +bt_mesh_model_s *_bt_mesh_get_model_from_modelid( + bt_mesh_element_s *element_s, uint32_t modelid) +{ + GSList *l; + + l = g_slist_find_custom(element_s->models, GUINT_TO_POINTER(modelid), + (GCompareFunc)__compare_model_id); + if (!l) + return NULL; + + return (bt_mesh_model_s*) l->data; +} + +bt_mesh_group_s* _bt_mesh_network_get_group( + bt_mesh_network_s *network_s, uint16_t group_addr) +{ + GSList *l; + bt_mesh_group_s *group_s = NULL; + + /* Unassigned address */ + if (group_addr == 0x0000) + return NULL; + + l = g_slist_find_custom(network_s->groups, GUINT_TO_POINTER(group_addr), + (GCompareFunc) __compare_network_group_address); + if (!l) { + group_s = g_malloc0(sizeof(bt_mesh_group_s)); + group_s->addr = group_addr; + if (group_addr >= 0x8000 && group_addr <= 0xbfff) + group_s->is_virtual = true; + else + group_s->is_virtual = false; + group_s->parent = network_s; + + if (g_slist_append(network_s->groups, group_s)) + BT_INFO("Mesh: Group created"); + + group_list = g_slist_append(group_list, group_s); + } else + group_s = l->data; + + return group_s; +} + +bt_mesh_appkey_s* _bt_mesh_node_get_appkey( + bt_mesh_node_s *node_s, uint16_t appkey_idx) +{ + GSList *l; + + l = g_slist_find_custom(node_s->appkeys, GUINT_TO_POINTER(appkey_idx), + (GCompareFunc)__compare_appkey_index); + if (!l) + return NULL; + + return (bt_mesh_appkey_s*) l->data; +} + +static bt_mesh_appkey_s *__bt_mesh_network_is_appkey_added( + bt_mesh_network_s *network_s, + uint16_t netkey_idx, + uint16_t appkey_idx) +{ + GSList *l, *l1; + const bt_mesh_netkey_s *netkey; + + l = g_slist_find_custom(network_s->netkeys, GUINT_TO_POINTER(netkey_idx), + (GCompareFunc)__compare_netkey_index); + if (!l) + return NULL; + netkey = l->data; + + l1 = g_slist_find_custom(netkey->appkeys, GUINT_TO_POINTER(appkey_idx), + (GCompareFunc)__compare_appkey_index); + if (!l1) + return NULL; + + return (bt_mesh_appkey_s*) l1->data; +} + +int __bt_check_mesh_init_status(void) +{ + if (is_mesh_initialized != true) { + BT_ERR("NOT_INITIALIZED(0x%08x)", BT_ERROR_NOT_INITIALIZED); + return BT_ERROR_NOT_INITIALIZED; + } + + return BT_ERROR_NONE; +} + +/* Local static */ +static void __bt_mesh_free_models(void *data) +{ + bt_mesh_model_s *model = (bt_mesh_model_s*)data; + model_list = g_slist_remove(model_list, model); + g_free(model); +} + +static void __bt_mesh_free_elements(void *data) +{ + bt_mesh_element_s *elem = (bt_mesh_element_s*)data; + element_list = g_slist_remove(element_list, elem); + g_slist_free_full(elem->models, __bt_mesh_free_models); + g_free(elem); +} + +static gint __bt_mesh_compare_net_uuid(gpointer *a, gpointer *b) +{ + bt_mesh_network_s *net = (bt_mesh_network_s *)a; + char *net_uuid = (char *)b; + return g_strcmp0(net->uuid, net_uuid); +} + + +static void __bt_mesh_insert_elements_in_node( + bt_mesh_node_s *node, uint16_t unicast, + int num_elements, bool is_local) +{ + bt_mesh_element_s *element_s; + + for (int i = 0; i < num_elements; i++) { + element_s = g_malloc0(sizeof(bt_mesh_element_s)); + element_s->is_local = is_local; + element_s->parent = node; + element_s->index = i; + node->elements = g_slist_append(node->elements, element_s); + element_list = g_slist_append(element_list, element_s); + } +} + +bt_mesh_appkey_s *_bt_mesh_handle_node_appkey_configure( + bt_mesh_network_s *network_s, + bt_mesh_node_s *node_s, uint16_t netkey_idx, + uint16_t appkey_idx, + bt_mesh_node_key_configuration_e op) +{ + bt_mesh_appkey_s *appkey_s; + + appkey_s = __bt_mesh_network_is_appkey_added( + network_s, netkey_idx, appkey_idx); + + /* AppKey with index not found in network */ + if (!appkey_s) { + BT_ERR("Mesh: Exceptional case: AppKey not found in Network"); + return NULL; + } + + if (op == BT_MESH_NODE_KEY_ADD) { + if (!g_slist_find_custom(node_s->appkeys,(gconstpointer) appkey_s, + (GCompareFunc)__simple_compare)) { + node_s->appkeys = g_slist_append(node_s->appkeys, appkey_s); + } else + BT_INFO("Mesh: AppKey Already added"); + return appkey_s; + } else if (op == BT_MESH_NODE_KEY_DELETE) { + node_s->appkeys = g_slist_remove(node_s->appkeys, appkey_s); + return NULL; + } else /* Node NetKey update */ + return appkey_s; +} + +bt_mesh_netkey_s *_bt_mesh_handle_node_netkey_configure( + bt_mesh_network_s *network_s, + bt_mesh_node_s *node_s, uint16_t netkey_idx, + bt_mesh_node_key_configuration_e op) +{ + bt_mesh_netkey_s *netkey_s; + + netkey_s = __bt_mesh_network_is_netkey_added(network_s, netkey_idx); + + /* Netkey with index not found in network */ + if (!netkey_s) { + BT_ERR("Mesh: Exceptional case: Netkey not found in Network"); + return NULL; + } + + if (op == BT_MESH_NODE_KEY_ADD) { + if (!g_slist_find_custom(node_s->netkeys,(gconstpointer) netkey_s, + (GCompareFunc)__simple_compare)) { + node_s->netkeys = g_slist_append(node_s->netkeys, netkey_s); + } else + BT_INFO("Mesh: NetKey Already added"); + return netkey_s; + } else if (op == BT_MESH_NODE_KEY_DELETE) { + node_s->netkeys = g_slist_remove(node_s->netkeys, netkey_s); + return NULL; + } else /* Node NetKey update */ + return netkey_s; +} + +bt_mesh_group_s * _bt_mesh_get_group_from_sub( + bt_mesh_network_s *network_s, bt_mesh_model_s *model_s, + bt_mesh_model_subscription_op_e op, uint16_t sub_addr) +{ + GSList *l; + bt_mesh_group_s *group_s = NULL; + l = g_slist_find_custom(network_s->groups, GUINT_TO_POINTER(sub_addr), + (GCompareFunc) __compare_network_group_address); + if (l) + group_s = l->data; + + if (op == BT_MESH_MODEL_SUBSCRIPTION_DELETE_ALL) + BT_INFO("Mesh: Event for BT_MESH_MODEL_SUBSCRIPTION_DELETE_ALL"); + if (op == BT_MESH_MODEL_SUBSCRIPTION_ADD) + BT_INFO("Mesh: Event for BT_MESH_MODEL_SUBSCRIPTION_ADD"); + if (op == BT_MESH_MODEL_SUBSCRIPTION_DELETE) + BT_INFO("Mesh: Event for BT_MESH_MODEL_SUBSCRIPTION_DELETE"); + if (op == BT_MESH_MODEL_SUBSCRIPTION_OVERWRITE) + BT_INFO("Mesh: Event for BT_MESH_MODEL_SUBSCRIPTION_OVERWRITE"); + + return group_s; +} + +bt_mesh_model_s *_bt_mesh_get_node_get_model_from_element( + char *net_uuid, uint16_t unicast, + int elem_idx, uint32_t model) +{ + GSList *l, *l1, *l2, *l3; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bt_mesh_element_s *element_s; + + l = g_slist_find_custom(networks, net_uuid, + (GCompareFunc)__bt_mesh_compare_net_uuid); + if (!l) + return NULL; + + network_s = l->data; + + l1 = g_slist_find_custom(network_s->nodes, GUINT_TO_POINTER(unicast), + (GCompareFunc)__compare_node_primary_unicast); + if (!l1) + return NULL; + + node_s = l1->data; + + l2 = g_slist_find_custom(node_s->elements, GUINT_TO_POINTER(elem_idx), + (GCompareFunc)__compare_node_element_index); + if (!l2) + return NULL; + + element_s = (bt_mesh_element_s*) l->data; + + + l3 = g_slist_find_custom(element_s->models, GUINT_TO_POINTER(model), + (GCompareFunc) __compare_model_id); + if (!l3) + return NULL; + + return (bt_mesh_model_s*) l->data; +} + +bt_mesh_element_s * _bt_mesh_get_node_get_element_from_index(char *net_uuid, + uint16_t unicast, int elem_idx) +{ + GSList *l, *l1, *l2; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + + l = g_slist_find_custom(networks, net_uuid, + (GCompareFunc)__bt_mesh_compare_net_uuid); + if (!l) + return NULL; + + network_s = l->data; + + l1 = g_slist_find_custom(network_s->nodes, GUINT_TO_POINTER(unicast), + (GCompareFunc)__compare_node_primary_unicast); + if (!l1) + return NULL; + + node_s = l1->data; + + l2 = g_slist_find_custom(node_s->elements, GUINT_TO_POINTER(elem_idx), + (GCompareFunc)__compare_node_element_index); + if (!l2) + return NULL; + + return (bt_mesh_element_s*) l->data; +} + +bt_mesh_node_s *_bt_mesh_get_node_from_unicast(char *net_uuid, uint16_t unicast) +{ + GSList *l, *l1; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + + l = g_slist_find_custom(networks, net_uuid, (GCompareFunc)__bt_mesh_compare_net_uuid); + if (!l) + return NULL; + + network_s = l->data; + + l1 = g_slist_find_custom(network_s->nodes, GUINT_TO_POINTER(unicast), + (GCompareFunc)__compare_node_primary_unicast); + if (!l1) + return NULL; + + node_s = l1->data; + return node_s; +} + +bt_mesh_node_s *_bt_mesh_remote_node_browsed(char *net_uuid, char *dev_uuid, + uint16_t unicast, int count) +{ + GSList *l, *l1; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + + l = g_slist_find_custom(networks, net_uuid, (GCompareFunc)__bt_mesh_compare_net_uuid); + if (!l) + return NULL; + + network_s = l->data; + + l1 = g_slist_find_custom(network_s->nodes, GUINT_TO_POINTER(unicast), + (GCompareFunc)__compare_node_primary_unicast); + if (l1) { + node_s = l1->data; + g_strlcpy(node_s->uuid, dev_uuid, sizeof(node_s->uuid)); + } else { + node_s = g_malloc0(sizeof(bt_mesh_node_s)); + node_s->parent = network_s; + node_s->unicast = unicast; + node_s->is_attached = true; + if (node_s->unicast == 0x0001) { + node_s->is_local = true; + node_s->is_provisioner = true; + } + g_strlcpy(node_s->uuid, dev_uuid, sizeof(node_s->uuid)); + __bt_mesh_insert_elements_in_node(node_s, unicast, + count, node_s->is_local? true : false); + network_s->nodes = g_slist_append(network_s->nodes, node_s); + node_list = g_slist_append(node_list, node_s); + } + return node_s; +} + +bt_mesh_network_s * _bt_mesh_get_network_handle_info(char *net_uuid) +{ + GSList *l; + + l = g_slist_find_custom(networks, net_uuid, (GCompareFunc)__bt_mesh_compare_net_uuid); + if (!l) + return NULL; + + return (bt_mesh_network_s*)l->data; +} + +char * _bt_mesh_get_auth_string_from_value(int auth) +{ + switch(auth) { + case BT_MESH_AUTH_ALPHANUMERIC_DISPLAY: + BT_INFO("Mesh: ALPHANUMERIC_DISPLAY"); + return "ALPHANUMERIC_DISPLAY"; + case BT_MESH_AUTH_NUMERIC_DISPLAY: + BT_INFO("Mesh: NUMERIC_DISPLAY"); + return "NUMERIC_DISPLAY"; + case BT_MESH_AUTH_PUSH_COUNT_DISPLAY: + BT_INFO("Mesh: PUSH_COUNT_DISPLAY"); + return "PUSH_COUNT_DISPLAY"; + case BT_MESH_AUTH_TWIST_COUNT_DISPLAY: + BT_INFO("Mesh: TWIST_COUNT_DISPLAY"); + return "TWIST_COUNT_DISPLAY"; + + /*< Input authentication request types */ + case BT_MESH_AUTH_REQ_ALPHANUMERIC_INPUT: + BT_INFO("Mesh: REQ_ALPHANUMERIC_INPUT"); + return "REQ_ALPHANUMERIC_INPUT"; + case BT_MESH_AUTH_REQ_NUMERIC_INPUT: + BT_INFO("Mesh: REQ_NUMERIC_INPUT"); + return "REQ_NUMERIC_INPUT"; + case BT_MESH_AUTH_REQ_BLINK_COUNT_INPUT: + BT_INFO("Mesh: REQ_BLINK_COUNT_INPUT"); + return "REQ_BLINK_COUNT_INPUT"; + case BT_MESH_AUTH_REQ_BEEP_COUNT_INPUT: + BT_INFO("Mesh: REQ_BEEP_COUNT_INPUT"); + return "REQ_BEEP_COUNT_INPUT"; + case BT_MESH_AUTH_REQ_VIBRATE_COUNT_INPUT: + BT_INFO("Mesh: REQ_VIBRATE_COUNT_INPUT"); + return "REQ_VIBRATE_COUNT_INPUT"; + + /**< OOB Key Inputs */ + case BT_MESH_AUTH_REQ_OOB_PUBLIC_KEY_INPUT: + BT_INFO("Mesh: OOB_PUBLIC_KEY_INPUT"); + return "OOB_PUBLIC_KEY_INPUT"; + case BT_MESH_AUTH_REQ_OOB_STATIC_KEY_INPUT: + BT_INFO("Mesh: OOB_STATIC_KEY_INPUT"); + return "OOB_STATIC_KEY_INPUT"; + default: + return ""; + } +} + +/* Mesh API */ +int bt_mesh_initialize(void) +{ + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + + int ret = BT_ERROR_NONE; + + BT_INFO("Is Mesh initialized:[%s]", + is_mesh_initialized ? "TRUE": "FALSE"); + + if (is_mesh_initialized) { + BT_ERR("Mesh is initialized"); + return BT_ERROR_NONE; + } + + if (!is_mesh_initialized) { + ret = _bt_get_error_code(bluetooth_mesh_init( + _bt_mesh_event_proxy, NULL)); + + if (ret != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", + _bt_convert_error_to_string(ret), ret); + return BT_ERROR_OPERATION_FAILED; + } + + is_mesh_initialized = true; + return BT_ERROR_NONE; + } + + BT_INFO("Mesh is already initialized"); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_deinitialize(void) +{ + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + int error; + + error = bluetooth_mesh_deinit(); + error = _bt_get_error_code(error); + if (BT_ERROR_NONE != error) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error), error); + + is_mesh_initialized = false; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_node_create(bt_mesh_node_features_s *features, + bt_mesh_node_h *node_handle) +{ + FUNC_ENTRY; + bt_mesh_node_s *node = NULL; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node_handle); + BT_CHECK_INPUT_PARAMETER(features); + + node = g_malloc0(sizeof(bt_mesh_node_s)); + if (!node) { + BT_ERR("g_malloc0 failed"); + return BT_ERROR_OUT_OF_MEMORY; + } + + node->is_local = true; + node->features = *features; + node->unicast = 0x0001; + + node_list = g_slist_append(node_list, node); + *node_handle = (bt_mesh_node_h)node; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_node_destroy(bt_mesh_node_h node_handle) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node_handle); + + bt_mesh_node_s *node = (bt_mesh_node_s*)node_handle; + + BT_MESH_VALIDATE_HANDLE(node, node_list); + + /* It is NOT allowed to destroy attached node: Do Reset */ + BT_CHECK_MESH_IS_ATTACHED(node); + + node_list = g_slist_remove(node_list, node); + g_slist_free_full(node->elements, __bt_mesh_free_elements); + g_free(node); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +static void __bt_mesh_generate_element(bt_mesh_node_s *node_s, + bt_mesh_element_s *elem_s) +{ + GSList *l; + uint16_t index = 0; + + for (l = node_s->elements; l; l = l->next) { + bt_mesh_element_s *el = (bt_mesh_element_s*)l->data; + if (el->index != index) + break; + index++; + } + elem_s->index = index; + node_s->elements = g_slist_insert(node_s->elements, elem_s, index); +} + +int bt_mesh_node_create_element(bt_mesh_node_h node_handle, + bt_mesh_element_h *element_handle) +{ + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node_handle); + BT_CHECK_INPUT_PARAMETER(element_handle); + + bt_mesh_node_s *node = (bt_mesh_node_s*)node_handle; + bt_mesh_element_s *element = NULL; + + BT_INFO("Mesh: Element creation request"); + BT_MESH_VALIDATE_HANDLE(node, node_list); + + /* It is NOT allowed to add an element to a already attached node */ + BT_CHECK_MESH_IS_ATTACHED(node); + + /* Check num elements already present in the node */ + if (g_slist_length(node->elements) >= BT_MESH_MAX_ELEMENTS) + return BT_ERROR_QUOTA_EXCEEDED; + + + element = g_malloc0(sizeof(bt_mesh_element_s)); + if (!element) { + BT_ERR("g_malloc0 failed"); + return BT_ERROR_OUT_OF_MEMORY; + } + + element->is_local = true; + element->parent = node; + + __bt_mesh_generate_element(node, element); + element_list = g_slist_append(element_list, element); + *element_handle = (bt_mesh_element_h)element; + + BT_INFO("Mesh: Element created successfully: element index [%d]", element->index); + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_element_destroy(bt_mesh_element_h element_handle) +{ + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(element_handle); + BT_MESH_VALIDATE_HANDLE(element_handle, element_list); + + bt_mesh_node_s *node = (bt_mesh_node_s*)((bt_mesh_element_s*)element_handle)->parent; + bt_mesh_element_s *element = (bt_mesh_element_s*)element_handle; + + /* It is NOT allowed to destroy remote element */ + BT_CHECK_MESH_LOCAL(node); + + /* It is NOT allowed to destroy an attahced element */ + BT_CHECK_MESH_IS_ATTACHED(node); + + element_list = g_slist_remove(element_list, element); + node->elements = g_slist_remove(node->elements, element); + + g_slist_free_full(element->models, __bt_mesh_free_models); + g_free(element); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_element_create_model( + bt_mesh_element_h element_handle, + bt_mesh_model_id_s *model_id, + bt_mesh_model_h *model_handle) +{ + FUNC_ENTRY; + uint32_t mod_id; + bt_mesh_element_s *element = (bt_mesh_element_s*)element_handle; + bt_mesh_model_s *model = NULL; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(element_handle); + BT_CHECK_INPUT_PARAMETER(model_id); + BT_CHECK_INPUT_PARAMETER(model_handle); + BT_MESH_VALIDATE_HANDLE(element_handle, element_list); + + bt_mesh_node_s *node = (bt_mesh_node_s*)((bt_mesh_element_s*)element_handle)->parent; + + /* It is NOT allowed to add model to a remote element */ + BT_CHECK_MESH_LOCAL(node); + + /* It is NOT allowed to add a Model to a already attached node */ + BT_CHECK_MESH_IS_ATTACHED(node); + + BT_INFO("Mesh: Model creation request: Company ID [0x%2.2x] Model ID [0x%2.2x]", + model_id->company_id, model_id->model_id); + + mod_id = model_id->company_id; + mod_id <<= 16; + mod_id |= model_id->model_id; + /* Allow configuration server model only in primary element */ + if ((model_id->model_id == BT_MESH_MODEL_ID_CFG_SRV) && + element->index != 0) + return BT_ERROR_OPERATION_FAILED; + + /* Check num models already present in the element */ + if (g_slist_length(element->models) >= BT_MESH_MAX_MODELS) + return BT_ERROR_QUOTA_EXCEEDED; + + /* Don't allow multiple instance of same model in an element */ + if (g_slist_find_custom(element->models, GUINT_TO_POINTER(mod_id), + (GCompareFunc)__compare_model_id)) + return BT_ERROR_ALREADY_DONE; + + model = g_malloc0(sizeof(bt_mesh_model_s)); + if (!model) { + BT_ERR("g_malloc0 failed"); + return BT_ERROR_OUT_OF_MEMORY; + } + + model->is_local = true; + model->parent = element; + model->id = mod_id; + + BT_INFO("Mesh: Model ID [0x%2.2x]", model_id->model_id); + BT_INFO("Mesh: Company ID [0x%2.2x]", model_id->company_id); + BT_INFO("Mesh: MOD [0x%4.4x]", model->id); + + model_list = g_slist_append(model_list, model); + element->models = g_slist_append(element->models, model); + *model_handle = (bt_mesh_model_h)model; + + BT_INFO("Mesh: Model created successfully"); + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_model_destroy(bt_mesh_model_h model_handle) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model_handle); + + bt_mesh_node_s *node = (bt_mesh_node_s*)((bt_mesh_element_s*)((bt_mesh_model_s*)model_handle)->parent)->parent; + bt_mesh_model_s *model = (bt_mesh_model_s*)model_handle; + bt_mesh_element_s *element = model->parent; + + BT_MESH_VALIDATE_HANDLE(model, model_list); + BT_MESH_VALIDATE_HANDLE(element, element_list); + + /* It is NOT allowed to destroy remote model */ + BT_CHECK_MESH_LOCAL(node); + + /* It is NOT allowed to destroy an attahced model */ + BT_CHECK_MESH_IS_ATTACHED(node); + + model_list = g_slist_remove(model_list, model); + element->models = g_slist_remove(element->models, model); + g_free(model); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_model_get_id(bt_mesh_model_h model_handle, + bt_mesh_model_id_s *model_id) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model_handle); + BT_CHECK_INPUT_PARAMETER(model_id); + + bt_mesh_model_s *model = (bt_mesh_model_s*)model_handle; + BT_MESH_VALIDATE_HANDLE(model, model_list); + + BT_INFO("Mesh: Model ID [0x%4.4x]", model->id); + model_id->company_id = model->id >> 16; + model_id->model_id = model->id; + BT_INFO("Mesh: CID [0x%2.2x]", model_id->company_id); + BT_INFO("Mesh: MID [0x%2.2x]", model_id->model_id); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_node_get_network(bt_mesh_node_h node_handle, bt_mesh_network_h *network) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node_handle); + BT_CHECK_INPUT_PARAMETER(network); + + bt_mesh_node_s *node = (bt_mesh_node_s*)node_handle; + BT_MESH_VALIDATE_HANDLE(node_handle, node_list); + + *network = node->parent; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_element_get_node(bt_mesh_element_h element_handle, + bt_mesh_node_h *node) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(element_handle); + BT_CHECK_INPUT_PARAMETER(node); + + bt_mesh_element_s *element = (bt_mesh_element_s*)element_handle; + BT_MESH_VALIDATE_HANDLE(element, element_list); + + *node = element->parent; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_model_get_element(bt_mesh_model_h model_handle, + bt_mesh_element_h *element) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model_handle); + BT_CHECK_INPUT_PARAMETER(element); + + bt_mesh_model_s *model = (bt_mesh_model_s*)model_handle; + BT_MESH_VALIDATE_HANDLE(model, model_list); + + *element = model->parent; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_appkey_get_netkey(bt_mesh_appkey_h appkey_handle, + bt_mesh_netkey_h *netkey) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(appkey_handle); + BT_CHECK_INPUT_PARAMETER(netkey); + + bt_mesh_appkey_s *appkey = (bt_mesh_appkey_s*)appkey_handle; + BT_MESH_VALIDATE_HANDLE(appkey, appkey_list); + + *netkey = appkey->parent; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +/* Async API's to bt-service & stack */ +int bt_mesh_network_create(bt_mesh_node_h config_client, + const char *network_name, + bt_mesh_network_h *network, char **token) +{ + FUNC_ENTRY; + int error_code = BT_ERROR_NONE; + GSList *l1, *l2; + int i, j; + int offset = 0; + int num_models = 0; + bluetooth_mesh_network_t net; + bluetooth_mesh_node_t param_node; + bluetooth_mesh_model_t **param_model; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(config_client); + BT_CHECK_INPUT_PARAMETER(network_name); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(token); + + BT_INFO("Mesh: Create Network: Name [%s]", network_name); + bt_mesh_node_s *node = (bt_mesh_node_s*)config_client; + + BT_MESH_VALIDATE_HANDLE(node, node_list); + + /* Error if remote node*/ + BT_CHECK_MESH_LOCAL(node); + + /* It is NOT allowed to create network out of a already attahced node */ + BT_CHECK_MESH_IS_ATTACHED(node); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + if (strlen(network_name) >= BT_MESH_NETWORK_NAME_STRING_MAX_LEN) + return BT_ERROR_INVALID_PARAMETER; + + /* Node in network should contain at-least one element */ + if (!g_slist_length(node->elements)) { + BT_INFO("Mesh: No element present in Node: NOT ALLOWED!!"); + return BT_ERROR_INVALID_PARAMETER; + } + + /* Element in Node should contain at-least one Model */ + for (l1 = node->elements; l1 != NULL; l1 = l1->next) { + bt_mesh_element_s *el = l1->data; + int models = 0; + models = g_slist_length(el->models); + BT_INFO("Mesh: Num models element [%u] has is [%d]", el->index, models); + if (!models) { + BT_INFO("Mesh: No Model present in element: NOT ALLOWED!!"); + return BT_ERROR_INVALID_PARAMETER; + } + /* If Primary element does not contain CFG SRV model, create and append */ + if (el->index == 0x0000) { + uint32_t mod_id = 0xFFFF0000; /* CFG SRV */ + + if (!g_slist_find_custom(el->models, GUINT_TO_POINTER(mod_id), + (GCompareFunc)__compare_model_id)) { + bt_mesh_model_s *model_s; + BT_ERR("Mesh: Primary element does not contain CFG SRV Model:Add it!"); + model_s = g_malloc0(sizeof(bt_mesh_model_s)); + + model_s->is_local = true; + model_s->parent = el; + model_s->id = mod_id; + + model_list = g_slist_append(model_list, model_s); + el->models = g_slist_append(el->models, model_s); + num_models++; + } else + BT_INFO("Mesh: CFG SRV model is already added in primary element"); + } + num_models += models; + } + + /* Check currently created network */ + if (g_slist_length(networks) >= BT_MESH_MAX_NETWORKS) + return BT_ERROR_QUOTA_EXCEEDED; + + memset(¶m_node, 0x00, sizeof(bluetooth_mesh_node_t)); + memcpy(¶m_node.vendor_info, &(node->features), sizeof(node->features)); + param_node.num_elements = g_slist_length(node->elements); + param_node.primary_unicast = 0x0001; + _bt_get_random_bytes(param_node.uuid, 16); + + BT_INFO("Mesh: Total Models [%d]", num_models); + param_model = (bluetooth_mesh_model_t**)g_malloc0(num_models * sizeof(bluetooth_mesh_model_t*)); + + for (l1 = node->elements, i = 0; l1 != NULL; l1 = l1->next, i++) { + bt_mesh_element_s *e = l1->data; + + for (l2 = e->models, j = 0; l2 != NULL; l2 = l2->next, j++) { + bt_mesh_model_s *m = l2->data; + param_model[j+offset] = g_malloc0(sizeof(bluetooth_mesh_model_t)); + param_model[j+offset]->elem_index = i; + param_model[j+offset]->model_id = m->id; + + } + offset += g_slist_length(e->models); + } + + BT_INFO("Mesh: Send Network create Request to FRWK"); + error_code = _bt_get_error_code(bluetooth_mesh_network_create(network_name, ¶m_node, + num_models, param_model, &net)); + if (error_code != BT_ERROR_NONE) { + BT_INFO("Mesh: Network could not be created!!"); + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + + /* Cleanup */ + for (int i = 0; i < num_models; i++) + g_free(param_model[i]); + + return error_code; + } + + BT_INFO("Mesh: Network created successfully"); + + /* Create Network object & fill data in network */ + network_s = g_malloc0(sizeof(bt_mesh_network_s)); + network_s->num_nodes = 1; + network_s->is_local = true; + network_s->is_discovered = true; + + /* Fill network name, token & UUID */ + __bt_mesh_util_convert_hex_to_string((uint8_t *)param_node.uuid, 16, + network_s->uuid, sizeof(network_s->uuid)); + g_strlcpy(network_s->token, net.token.token, 17); + g_strlcpy(network_s->name, network_name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + network_s->nodes = g_slist_append(network_s->nodes, node); + BT_INFO("Mesh: Network Name [%s]", network_s->name); + BT_INFO("Mesh: Network Token[%s]", network_s->token); + BT_INFO("Mesh: Network UUID [%s]", network_s->uuid); + + /* Create primary Netkey object */ + netkey_s = g_malloc0(sizeof(bt_mesh_netkey_s)); + netkey_s->parent = network_s; + netkey_s->netkey_index = 0x0000; /* Primary index */ + network_s->netkeys = g_slist_append(network_s->netkeys, netkey_s); + netkey_list = g_slist_append(netkey_list, netkey_s); + + /* Fill Config Client Node Data */ + node->is_attached = true; + node->is_provisioner = true; + __bt_mesh_util_convert_hex_to_string((uint8_t *)param_node.uuid, + 16, node->uuid, sizeof(node->uuid)); + node->unicast = 0x0001; + node->parent = network_s; + + /* Prepare Out parameters */ + *token = network_s->token; + *network = (bt_mesh_network_h)network_s; + + /* Save network in list */ + networks = g_slist_append(networks, network_s); + + /* Clean up memory */ + for (int i = 0; i < num_models; i++) + g_free(param_model[i]); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_network_load(const char *token, bt_mesh_network_h *network) +{ + int error_code = BT_ERROR_NONE; + bluetooth_mesh_network_t net; + bt_mesh_network_s *network_s; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(token); + BT_CHECK_INPUT_PARAMETER(network); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + error_code = _bt_get_error_code(bluetooth_mesh_network_load(token, &net)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + /* Create Network object */ + network_s = g_malloc0(sizeof(bt_mesh_network_s)); + network_s->is_local = true; + g_strlcpy(network_s->uuid, net.uuid, 33); + g_strlcpy(network_s->token, token, 17); + g_strlcpy(network_s->name, net.name.name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + networks = g_slist_append(networks, network_s); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_network_get_name(bt_mesh_network_h network, char **network_name) +{ + bt_mesh_network_s *network_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(network_name); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + network_s = (bt_mesh_network_s*)network; + *network_name = strdup(network_s->name); + if (*network_name == NULL) { + BT_ERR("OUT_OF_MEMORY(0x%08x)", + BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_network_set_name(bt_mesh_network_h network, const char *network_name) +{ + int error_code = BT_ERROR_NONE; + bluetooth_mesh_network_t net; + bt_mesh_network_s* network_s; + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(network_name); + + network_s = (bt_mesh_network_s*)network; + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + BT_INFO("Mesh: Set Network Name [%s]", network_name); + error_code = _bt_get_error_code(bluetooth_mesh_network_set_name(&net)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + BT_INFO("Mesh: Network Name set successfully [%s]", network_name); + g_strlcpy(network_s->name, network_name, sizeof(network_s->name)); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_network_add_netkey(bt_mesh_network_h network, + bt_mesh_netkey_h *netkey) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + bluetooth_mesh_network_t net; + uint16_t netkey_idx; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(netkey); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_add_netkey(&net, &netkey_idx)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + BT_INFO("Mesh: Subnet Key created: Index [%d]", netkey_idx); + /* Create Netkey object */ + netkey_s = g_malloc0(sizeof(bt_mesh_netkey_s)); + netkey_s->parent = network_s; + netkey_s->netkey_index = netkey_idx; + network_s->netkeys = g_slist_append(network_s->netkeys, netkey_s); + netkey_list = g_slist_append(netkey_list, netkey_s); + *netkey = (bt_mesh_netkey_h)netkey_s; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_network_foreach_netkeys(bt_mesh_network_h network, + bt_mesh_network_netkey_info_cb callback, void *user_data) +{ + bluetooth_mesh_network_t net; + GPtrArray *netkeys = NULL; + GSList *l; + int error_code = BT_ERROR_NONE; + uint16_t *netkey_idx = NULL; + int i; + int total; + bt_mesh_network_s *network_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + netkeys = g_ptr_array_new(); + if (netkeys == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_get_all_netkey(&net, &netkeys)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(netkeys, TRUE); + return error_code; + } + + for (i = 0; i < netkeys->len; i++) { + netkey_idx = g_ptr_array_index(netkeys, i); + if (netkey_idx) { + /* Create and insert netkey object in list */ + if (!__bt_mesh_network_is_netkey_added(network_s, *netkey_idx)) { + bt_mesh_netkey_s *nk; + nk = g_malloc0(sizeof(bt_mesh_netkey_s)); + nk->parent = network_s; + nk->netkey_index = *netkey_idx; + network_s->netkeys = g_slist_append(network_s->netkeys, nk); + netkey_list = g_slist_append(netkey_list, nk); + } + + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + total = g_slist_length(network_s->netkeys); + if (total == 0) { + BT_INFO("Mesh: No netkey added in network"); + callback(BT_ERROR_NONE, (bt_mesh_network_h)network_s, total, + NULL, 0xFFFF, user_data); + } + for (l = network_s->netkeys; l != NULL; l = g_slist_next(l)) { + bt_mesh_netkey_s *netkey; + netkey = l->data; + + if (!callback(BT_ERROR_NONE, (bt_mesh_network_h)network_s, total, + (bt_mesh_netkey_h) netkey, + netkey->netkey_index, user_data)) { + break; + } + } + + g_ptr_array_foreach(netkeys, (GFunc)g_free, NULL); + g_ptr_array_free(netkeys, TRUE); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_netkey_get_index(bt_mesh_netkey_h netkey, uint16_t *index) +{ + bt_mesh_netkey_s *netkey_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(netkey); + BT_CHECK_INPUT_PARAMETER(index); + + BT_MESH_VALIDATE_HANDLE(netkey, netkey_list); + + netkey_s = (bt_mesh_netkey_s*)netkey; + *index = netkey_s->netkey_index; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_netkey_update(bt_mesh_netkey_h netkey) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + bluetooth_mesh_network_t net; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(netkey); + + netkey_s = (bt_mesh_netkey_s*)netkey; + network_s = netkey_s->parent; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(netkey_s, netkey_list); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_update_netkey( + &net, netkey_s->netkey_index)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_netkey_delete(bt_mesh_netkey_h netkey) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + bluetooth_mesh_network_t net; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(netkey); + + netkey_s = (bt_mesh_netkey_s*)netkey; + network_s = netkey_s->parent; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(netkey_s, netkey_list); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_delete_netkey(&net, netkey_s->netkey_index)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + network_s->netkeys = g_slist_remove(network_s->netkeys, netkey_s); + netkey_list = g_slist_remove(netkey_list, netkey_s); + g_slist_free_full(netkey_s->appkeys, g_free); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_netkey_add_appkey(bt_mesh_netkey_h netkey, + bt_mesh_appkey_h *appkey) +{ + int error_code = BT_ERROR_NONE; + uint16_t appkey_idx; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + bt_mesh_appkey_s *appkey_s; + bluetooth_mesh_network_t net; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(netkey); + BT_CHECK_INPUT_PARAMETER(appkey); + + netkey_s = (bt_mesh_netkey_s*)netkey; + network_s = netkey_s->parent; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(netkey_s, netkey_list); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_add_appkey( + &net, netkey_s->netkey_index, &appkey_idx)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + /* Create Appkey object */ + appkey_s = g_malloc0(sizeof(bt_mesh_appkey_s)); + appkey_s->parent = netkey_s; + appkey_s->appkey_index = appkey_idx; + netkey_s->appkeys = g_slist_append(netkey_s->appkeys, appkey_s); + appkey_list = g_slist_append(appkey_list, appkey_s); + *appkey = (bt_mesh_appkey_h)appkey_s; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_appkey_update(bt_mesh_appkey_h appkey) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + bt_mesh_appkey_s *appkey_s; + bluetooth_mesh_network_t net; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(appkey); + + appkey_s = (bt_mesh_appkey_s*)appkey; + netkey_s = appkey_s->parent; + network_s = netkey_s->parent; + + BT_MESH_VALIDATE_HANDLE(appkey_s, appkey_list); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_update_appkey( + &net, netkey_s->netkey_index, appkey_s->appkey_index)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_appkey_delete(bt_mesh_appkey_h appkey) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_netkey_s *netkey_s; + bt_mesh_appkey_s *appkey_s; + bluetooth_mesh_network_t net; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(appkey); + + appkey_s = (bt_mesh_appkey_s*)appkey; + netkey_s = appkey_s->parent; + network_s = netkey_s->parent; + + BT_MESH_VALIDATE_HANDLE(appkey_s, appkey_list); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_delete_appkey( + &net, netkey_s->netkey_index, appkey_s->appkey_index)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + /* Delete Appkey Object */ + netkey_s->appkeys = g_slist_remove(netkey_s->appkeys, appkey_s); + appkey_list = g_slist_remove(appkey_list, appkey_s); + g_free(appkey_s); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_netkey_foreach_appkeys(bt_mesh_netkey_h netkey, + bt_mesh_appkey_info_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_netkey_s *netkey_s; + bt_mesh_network_s *network_s; + bluetooth_mesh_network_t net; + int total; + int i; + GSList *l; + GPtrArray *appkeys = NULL; + uint16_t *appkey_idx = NULL; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(netkey); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(netkey, netkey_list); + + netkey_s = (bt_mesh_netkey_s*)netkey; + network_s = netkey_s->parent; + + appkeys = g_ptr_array_new(); + if (appkeys == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + BT_INFO("Mesh: Find all Appkeys for Netkey : index [%d]", netkey_s->netkey_index); + error_code = _bt_get_error_code(bluetooth_mesh_netkey_get_all_appkey( + &net, netkey_s->netkey_index, &appkeys)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(appkeys, TRUE); + return error_code; + } + for (i = 0; i < appkeys->len; i++) { + appkey_idx = g_ptr_array_index(appkeys, i); + if (appkey_idx) { + /* Create and insert netkey object in list */ + if (!__bt_mesh_network_is_appkey_added(network_s, netkey_s->netkey_index, *appkey_idx)) { + bt_mesh_appkey_s *key; + key = g_malloc0(sizeof(bt_mesh_appkey_s)); + key->parent = netkey_s; + key->appkey_index = *appkey_idx; + netkey_s->appkeys = g_slist_append(netkey_s->appkeys, key); + appkey_list = g_slist_append(appkey_list, key); + } + + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + total = g_slist_length(netkey_s->appkeys); + BT_INFO("Mesh: Total appkeys [%d]", total); + + if (!total) { + BT_INFO("Mesh: No AppKey added in NetKey yet!"); + callback(BT_ERROR_NONE, (bt_mesh_network_h) network_s, total, + (bt_mesh_netkey_h) netkey_s, NULL, + 0xFFFF, user_data); + return BT_ERROR_NONE; + } + + + for (l = netkey_s->appkeys; l; l = g_slist_next(l)) { + bt_mesh_appkey_s *appkey_s; + appkey_s = l->data; + if (!callback(BT_ERROR_NONE, (bt_mesh_network_h) network_s, total, + (bt_mesh_netkey_h) netkey_s, (bt_mesh_appkey_h) appkey_s, + appkey_s->appkey_index, user_data)) + break; + } + + g_ptr_array_foreach(appkeys, (GFunc)g_free, NULL); + g_ptr_array_free(appkeys, TRUE); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_appkey_get_index(bt_mesh_appkey_h appkey, uint16_t *index) +{ + bt_mesh_appkey_s *appkey_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(appkey); + BT_CHECK_INPUT_PARAMETER(index); + + BT_MESH_VALIDATE_HANDLE(appkey, appkey_list); + + appkey_s = (bt_mesh_appkey_s*)appkey; + *index = appkey_s->appkey_index; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +/* Sync API's to bt-service: Discovery API's */ +int bt_mesh_network_foreach_devices(bt_mesh_network_h network, + bt_mesh_network_device_info_cb callback, void *user_data) +{ + bluetooth_mesh_network_t net; + bluetooth_mesh_node_info_t *node_info; + GPtrArray *nodes = NULL; + int error_code = BT_ERROR_NONE; + int i; + bt_mesh_network_s *network_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + nodes = g_ptr_array_new(); + if (nodes == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_get_all_nodes(&net, &nodes)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(nodes, TRUE); + return error_code; + } + + BT_INFO("Mesh: Total number of Devices found [%d]", nodes->len); + for (i = 0; i < nodes->len; i++) { + node_info = g_ptr_array_index(nodes, i); + if (node_info) { + if (!callback(BT_ERROR_NONE, (bt_mesh_network_h)network_s, nodes->len, + node_info->dev_uuid, node_info->primary_unicast, user_data)) { + break; + } + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + g_ptr_array_foreach(nodes, (GFunc)g_free, NULL); + g_ptr_array_free(nodes, TRUE); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_node_get_primary_address(bt_mesh_node_h node, + uint16_t *primary_address) +{ + bt_mesh_node_s *node_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(primary_address); + + BT_MESH_VALIDATE_HANDLE(node, node_list); + + node_s = (bt_mesh_node_s*) node; + *primary_address = node_s->unicast; + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_node_foreach_element(bt_mesh_node_h node, + bt_mesh_node_element_info_cb callback, void *user_data) +{ + bt_mesh_node_s *node_s; + int total = 0; + GSList *l; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(node, node_list); + node_s = (bt_mesh_node_s*) node; + + /* Only for Node which is attached to the Network */ +#if 0 + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; +#endif + total = g_slist_length(node_s->elements); + if (!total) { + callback(BT_ERROR_NONE, (bt_mesh_node_h) node, total, + (bt_mesh_element_h) NULL, -1, 0xFFFF, user_data); + + } + + for (l = node_s->elements; l; l = g_slist_next(l)) { + bt_mesh_element_s *element_s; + element_s = l->data; + if (!callback(BT_ERROR_NONE, (bt_mesh_node_h) node, total, + (bt_mesh_element_h)element_s, element_s->index, + (node_s->unicast + element_s->index), user_data)) + break; + } + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_element_foreach_models(bt_mesh_element_h element, + bt_mesh_element_model_info_cb callback, void *user_data) +{ + bluetooth_mesh_network_t net; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bt_mesh_element_s *element_s; + + GPtrArray *models = NULL; + uint32_t *model_info; + int error_code = BT_ERROR_NONE; + int i; + int total; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(element); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(element, element_list); + + element_s = (bt_mesh_element_s*) element; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + /* Only for local Node */ + if (node_s->is_local) { + GSList *l; + BT_INFO("Mesh: Local element"); + + total = g_slist_length(element_s->models); + if (!total) + callback(BT_ERROR_NONE, (bt_mesh_element_h)element_s, 0, + (bt_mesh_model_h) NULL, NULL, user_data); + + for (l = element_s->models; l; l = l->next) { + bt_mesh_model_s *model_s = l->data; + bt_mesh_model_id_s modid; + + modid.company_id = model_s->id >> 16; + modid.model_id = model_s->id; + + if (!callback(BT_ERROR_NONE, (bt_mesh_element_h)element_s, total, + (bt_mesh_model_h) model_s, + &modid, user_data)) { + break; + } + } + FUNC_EXIT; + return BT_ERROR_NONE; + } + + models = g_ptr_array_new(); + if (models == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_element_get_all_models(&net, + /* Node identity */node_s->unicast, + /* eleement identity */element_s->index, + /*Output*/ &models)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(models, TRUE); + return error_code; + } + + total = models->len; + for (i = 0; i < models->len; i++) { + model_info = g_ptr_array_index(models, i); + if (model_info) { + /* Create and insert model object in list */ + bt_mesh_model_s *mod; + bt_mesh_model_id_s modid; + mod = g_malloc0(sizeof(bt_mesh_model_s)); + mod->parent = element_s; + if (node_s->unicast == 0x0001) { + mod->is_local = true; + } + mod->id = *model_info; + element_s->models = g_slist_append(element_s->models, mod); + model_list = g_slist_append(model_list, mod); + + modid.company_id = *model_info >> 16; + modid.model_id = *model_info; + /* Send Callback */ + if (!callback(BT_ERROR_NONE, (bt_mesh_element_h)element_s, total, + (bt_mesh_model_h) mod, + &modid, user_data)) { + break; + } + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + g_ptr_array_foreach(models, (GFunc)g_free, NULL); + g_ptr_array_free(models, TRUE); + + FUNC_EXIT; + return error_code; +} + +/* Provisioning & capabilities related*/ +int bt_mesh_network_unprovisioned_device_scan(bt_mesh_network_h network, + bt_mesh_scan_params_s *scan_params, + bt_mesh_network_scan_unprovisioned_device_result_cb callback, + void *user_data) +{ + bt_mesh_network_s *network_s; + bluetooth_mesh_network_t net; + int error_code = BT_ERROR_NONE; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(scan_params); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_scan( + &net, (bluetooth_mesh_scan_param_t*) scan_params)); + + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + _bt_set_cb(BT_EVENT_MESH_NETWORK_SCAN_STATE_CHANGED, callback, user_data); + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_stop_unprovisioned_device_scan(bt_mesh_network_h network) +{ + bt_mesh_network_s *network_s; + bluetooth_mesh_network_t net; + int error_code = BT_ERROR_NONE; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_cancel_scan(&net)); + + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_network_set_provisioning_capabilities(bt_mesh_network_h network, + bt_mesh_provisioner_capabilities_s *capabilities) +{ + bt_mesh_network_s *network_s; + bluetooth_mesh_network_t net; + bluetooth_mesh_provisioner_caps_t caps; + int error_code = BT_ERROR_NONE; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(capabilities); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + memset(&caps, 0x00, sizeof(bluetooth_mesh_provisioner_caps_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + caps.public_oob = capabilities->public_oob; + caps.static_oob = capabilities->static_oob; + caps.out_oob = capabilities->out_oob; + caps.in_oob = capabilities->in_oob; + + error_code = _bt_get_error_code(bluetooth_mesh_network_set_capabilities( + &net,(bluetooth_mesh_provisioner_caps_t*) &caps)); + + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_network_provision_device(bt_mesh_network_h network, + const char *dev_uuid, + bt_mesh_network_device_provision_cb callback, + void *user_data) +{ + bt_mesh_network_s *network_s; + bluetooth_mesh_provisioning_request_t req; + int error_code = BT_ERROR_NONE; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(dev_uuid); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + network_s = (bt_mesh_network_s*)network; + memset(&req, 0x00, sizeof(bluetooth_mesh_provisioning_request_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + g_strlcpy(req.dev_uuid, dev_uuid, 33); + + BT_INFO("Mesh: Provision Device [%s]", dev_uuid); + error_code = _bt_get_error_code(bluetooth_mesh_network_provision_device(&req)); + + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + _bt_set_cb(BT_EVENT_MESH_NETWORK_PROVISIONING_RESULT, callback, user_data); + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_authentication_set_request_cb(bt_mesh_authentication_request_cb callback, void *user_data) +{ + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(callback); + + _bt_set_cb(BT_EVENT_MESH_AUTHENTICATION_REQUEST, callback, user_data); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_authentication_unset_request_cb(bt_mesh_authentication_request_cb callback) +{ + FUNC_ENTRY; + + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(callback); + + _bt_unset_cb(BT_EVENT_MESH_AUTHENTICATION_REQUEST); + + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_authentication_reply(bt_mesh_authentication_type_e auth_type, const char *value, bool auth_reply) +{ + int error_code = BT_ERROR_NONE; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(value); + + error_code = _bt_get_error_code(bluetooth_mesh_authentication_reply(auth_type, value, auth_reply)); + if (error_code != BT_ERROR_NONE) + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_network_discover_node(bt_mesh_network_h network, + const char *dev_uuid, bt_mesh_node_discover_status_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bluetooth_mesh_node_discover_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(dev_uuid); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + + /* Check if node with dev_uuid is already created */ + network_s = (bt_mesh_network_s*)network; + memset(&req, 0x00, sizeof(bluetooth_mesh_node_discover_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + g_strlcpy(req.dev_uuid, dev_uuid, 33); + + error_code = _bt_get_error_code(bluetooth_mesh_browse_remote_node(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_BROWSING_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_node_configure_netkey(bt_mesh_node_h node, bt_mesh_node_key_configuration_e netkey_op, + bt_mesh_netkey_h netkey, bt_mesh_netkey_status_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bt_mesh_netkey_s *netkey_s; + bluetooth_mesh_key_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(netkey); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + network_s = node_s->parent; + netkey_s = (bt_mesh_netkey_s*) netkey; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(netkey_s, netkey_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + /* Return error, if netkey is not present in the specific network */ + if (netkey_s->parent != network_s) + return BT_ERROR_INVALID_PARAMETER; + +#if 0 + /* Return Already done, if netkey is present in the node */ + if (g_slist_find_custom(node_s->netkeys,(gconstpointer) netkey_s, + (GCompareFunc)__simple_compare)) + return BT_ERROR_ALREADY_DONE; +#endif + memset(&req, 0x00, sizeof(bluetooth_mesh_key_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.netkey_idx = netkey_s->netkey_index; + req.is_netkey = true; + req.op = (bluetooth_mesh_node_key_conf_e) netkey_op; + + BT_INFO("Mesh: Add NetKey Idx [%d] to node", req.netkey_idx); + error_code = _bt_get_error_code(bluetooth_mesh_node_configure_key(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_KEY_CONFIGURATION_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_node_configure_appkey(bt_mesh_node_h node, bt_mesh_node_key_configuration_e appkey_op, + bt_mesh_appkey_h appkey, bt_mesh_appkey_status_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bt_mesh_netkey_s *netkey_s; + bt_mesh_appkey_s *appkey_s; + bluetooth_mesh_key_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(appkey); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + network_s = node_s->parent; + appkey_s = (bt_mesh_appkey_s*) appkey; + netkey_s = (bt_mesh_netkey_s*) appkey_s->parent; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(appkey_s, appkey_list); + BT_MESH_VALIDATE_HANDLE(netkey_s, netkey_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + /* Return error, if netkey is not present in the specific network */ + if (netkey_s->parent != network_s) + return BT_ERROR_INVALID_PARAMETER; + + /* Return Already done, if appkey is present in the node */ + if (g_slist_find_custom(node_s->appkeys,(gconstpointer) appkey_s, + (GCompareFunc)__simple_compare)) + return BT_ERROR_ALREADY_DONE; + + memset(&req, 0x00, sizeof(bluetooth_mesh_key_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.netkey_idx = netkey_s->netkey_index; + req.appkey_idx = appkey_s->appkey_index; + req.is_netkey = false; + req.op = (bluetooth_mesh_node_key_conf_e) appkey_op; + + error_code = _bt_get_error_code(bluetooth_mesh_node_configure_key(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_KEY_CONFIGURATION_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + + +/* Remote Node Operations: CONFIG: Non Key */ +int bt_mesh_node_get_features(bt_mesh_node_h node, bt_mesh_node_features_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bluetooth_mesh_node_features_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + network_s = (bt_mesh_network_s*) node_s->parent; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + + memset(&req, 0x00, sizeof(bluetooth_mesh_node_features_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.unicast = node_s->unicast; + req.elem_count = node_s->unicast; + + error_code = _bt_get_error_code(bluetooth_mesh_node_browse_vendor_features(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_VENDOR_FEATURES, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_node_get_ttl(bt_mesh_node_h node, bt_mesh_node_ttl_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bluetooth_mesh_node_ttl_info_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + network_s = node_s->parent; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_node_ttl_info_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.unicast = node_s->unicast; + req.is_set = false; + + error_code = _bt_get_error_code(bluetooth_mesh_node_ttl_execute(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_TTL_EXECUTE_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_node_set_ttl(bt_mesh_node_h node, uint8_t ttl, bt_mesh_node_ttl_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bluetooth_mesh_node_ttl_info_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + network_s = node_s->parent; + BT_CHECK_INPUT_PARAMETER(network_s); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_node_ttl_info_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.unicast = node_s->unicast; + req.is_set = true; + req.ttl = ttl; + + error_code = _bt_get_error_code(bluetooth_mesh_node_ttl_execute(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_TTL_EXECUTE_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_node_foreach_netkeys(bt_mesh_node_h node, bt_mesh_node_netkey_info_cb callback, void *user_data) +{ + GPtrArray *netkeys = NULL; + GSList *l; + int error_code = BT_ERROR_NONE; + uint16_t *netkey_idx = NULL; + int i; + int total; + bluetooth_mesh_node_discover_t req; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + network_s = node_s->parent; + + BT_CHECK_INPUT_PARAMETER(network_s); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + netkeys = g_ptr_array_new(); + if (netkeys == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + memset(&req, 0x00, sizeof(bluetooth_mesh_node_discover_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.unicast = node_s->unicast; + + error_code = _bt_get_error_code(bluetooth_mesh_node_get_all_netkeys(&req, &netkeys)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(netkeys, TRUE); + return error_code; + } + + BT_INFO("Mesh: Total netkeys added in node is [%d]", netkeys->len); + for (i = 0; i < netkeys->len; i++) { + bt_mesh_netkey_s *netkey_local; + netkey_idx = g_ptr_array_index(netkeys, i); + BT_INFO("Mesh: NetKey IDX [0x%2.2x]", *netkey_idx); + if (netkey_idx) { + /* Check if netkey index is present in network or not */ + netkey_local = __bt_mesh_network_is_netkey_added(network_s, *netkey_idx); + if (!netkey_local) { + BT_ERR("Mesh: Network does not contain the netKey index, possibly reloaded"); + /* Create Netkey object */ + netkey_local = g_malloc0(sizeof(bt_mesh_netkey_s)); + netkey_local->parent = network_s; + netkey_local->netkey_index = *netkey_idx; + network_s->netkeys = g_slist_append(network_s->netkeys, netkey_local); + netkey_list = g_slist_append(netkey_list, netkey_local); + + if (!g_slist_find_custom(node_s->netkeys, GUINT_TO_POINTER(*netkey_idx), + (GCompareFunc)__compare_netkey_index)) + node_s->netkeys = g_slist_append(node_s->netkeys, netkey_local); + } else { + /* Check if netkey index is present in target node or not */ + if (!g_slist_find_custom(node_s->netkeys,(gconstpointer) netkey_local, + (GCompareFunc)__simple_compare)) { + node_s->netkeys = g_slist_append(node_s->netkeys, netkey_local); + } else { + /* DO NOTHING*/ + BT_INFO("Mesh: Netkey is already added in node"); + } + } + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + total = g_slist_length(node_s->netkeys); + if (total == 0) { + BT_ERR("Mesh: Unexpcted: No netkey added in node!!"); + callback(BT_ERROR_NONE, (bt_mesh_node_h)node_s, total, + NULL, 0xFFFF, user_data); + } + for (l = node_s->netkeys; l != NULL; l = g_slist_next(l)) { + bt_mesh_netkey_s *netkey; + netkey = l->data; + + if (!callback(BT_ERROR_NONE, (bt_mesh_node_h)node_s, total, + (bt_mesh_netkey_h) netkey, + netkey->netkey_index, user_data)) { + break; + } + } + + g_ptr_array_foreach(netkeys, (GFunc)g_free, NULL); + g_ptr_array_free(netkeys, TRUE); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_node_foreach_appkeys(bt_mesh_node_h node, bt_mesh_netkey_h netkey, + bt_mesh_node_appkey_info_cb callback, void *user_data) +{ + GPtrArray *appkeys = NULL; + GSList *l; + int error_code = BT_ERROR_NONE; + int i; + int total; + bluetooth_mesh_node_discover_t req; + uint16_t *appkey_idx = NULL; + bt_mesh_network_s *network_s; + bt_mesh_node_s *node_s; + bt_mesh_netkey_s *netkey_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(node); + BT_CHECK_INPUT_PARAMETER(netkey); + BT_CHECK_INPUT_PARAMETER(callback); + + node_s = (bt_mesh_node_s*) node; + network_s = node_s->parent; + netkey_s = (bt_mesh_netkey_s*) netkey; + + BT_CHECK_INPUT_PARAMETER(network_s); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(netkey_s, netkey_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + appkeys = g_ptr_array_new(); + if (appkeys == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + memset(&req, 0x00, sizeof(bluetooth_mesh_node_discover_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.unicast = node_s->unicast; + req.netkey_idx = netkey_s->netkey_index; + + error_code = _bt_get_error_code(bluetooth_mesh_node_get_all_appkeys(&req, &appkeys)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(appkeys, TRUE); + return error_code; + } + + BT_INFO("Mesh: Total appkeys found in Node [%d]", appkeys->len); + for (i = 0; i < appkeys->len; i++) { + bt_mesh_appkey_s *appkey_local; + appkey_idx = g_ptr_array_index(appkeys, i); + BT_INFO("Mesh: AppKey index [0x%2.2x]", *appkey_idx); + if (appkey_idx) { + /* Check if netkey index is present in network or not */ + appkey_local = __bt_mesh_network_is_appkey_added(network_s, netkey_s->netkey_index, *appkey_idx); + + if (!appkey_local) { + BT_ERR("Mesh: Network does not AppKey index, possibly Network reloaded!!"); + /* Create Netkey object */ + appkey_local = g_malloc0(sizeof(bt_mesh_netkey_s)); + appkey_local->parent = netkey_s; + appkey_local->appkey_index = *appkey_idx; + netkey_s->appkeys = g_slist_append(netkey_s->appkeys, appkey_local); + appkey_list = g_slist_append(appkey_list, appkey_local); + + if (!g_slist_find_custom(node_s->appkeys, GUINT_TO_POINTER(*appkey_idx), + (GCompareFunc)__compare_appkey_index)) + node_s->appkeys = g_slist_append(node_s->appkeys, appkey_local); + } else { + /* Check if netkey index is present in target node or not */ + if (!g_slist_find_custom(node_s->appkeys, GUINT_TO_POINTER(*appkey_idx), + (GCompareFunc)__compare_appkey_index)) { + node_s->appkeys = g_slist_append(node_s->appkeys, appkey_local); + } else { + /* DO NOTHING*/ + BT_INFO("Mesh: AppKey is already added in node"); + } + } + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + total = g_slist_length(node_s->appkeys); + if (total == 0) { + BT_ERR("Mesh:Possible: No appkey added in node!!"); + callback(BT_ERROR_NONE, (bt_mesh_node_h)node_s, total, + (bt_mesh_netkey_h) netkey_s, NULL, 0xFFFF, user_data); + } + for (l = node_s->appkeys; l != NULL; l = g_slist_next(l)) { + bt_mesh_appkey_s *appkey_s; + appkey_s = l->data; + + if (!callback(BT_ERROR_NONE, (bt_mesh_node_h)node_s, total, + (bt_mesh_netkey_h) netkey, (bt_mesh_appkey_h) appkey_s, + appkey_s->appkey_index, user_data)) { + break; + } + } + + g_ptr_array_foreach(appkeys, (GFunc)g_free, NULL); + g_ptr_array_free(appkeys, TRUE); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_model_bind_appkey(bt_mesh_model_h model, + bt_mesh_appkey_h appkey, bt_mesh_model_bind_cb callback, + void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_network_s *network_s; + bt_mesh_appkey_s *appkey_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(appkey); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + appkey_s = (bt_mesh_appkey_s*) appkey; + network_s = (bt_mesh_network_s*) node_s->parent; + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(appkey_s, appkey_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_model_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.elem_index = element_s->index; + req.model = model_s->id; + req.appkey_idx = appkey_s->appkey_index; + req.is_bind = true; + + error_code = _bt_get_error_code(bluetooth_mesh_model_configure_appkey(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_BIND_APPKEY_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_model_unbind_appkey(bt_mesh_model_h model, bt_mesh_appkey_h appkey, + bt_mesh_model_unbind_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_appkey_s *appkey_s; + bt_mesh_network_s *network_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(appkey); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + appkey_s = (bt_mesh_appkey_s*) appkey; + network_s = (bt_mesh_network_s*) node_s->parent; + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(appkey_s, appkey_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_model_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.elem_index = element_s->index; + req.model = model_s->id; + req.appkey_idx = appkey_s->appkey_index; + req.is_bind = false; + + error_code = _bt_get_error_code(bluetooth_mesh_model_configure_appkey(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_BIND_APPKEY_COMPLETED, callback, user_data); + return BT_ERROR_NONE; +} + +int bt_mesh_model_get_appkey_list(bt_mesh_model_h model, + bt_mesh_model_appkey_list_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_network_s *network_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + BT_CHECK_INPUT_PARAMETER(model_s); + BT_CHECK_INPUT_PARAMETER(element_s); + BT_CHECK_INPUT_PARAMETER(node_s); + BT_CHECK_INPUT_PARAMETER(network_s); + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_model_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.elem_index = element_s->index; + req.model = model_s->id; + + error_code = _bt_get_error_code(bluetooth_mesh_model_get_all_appkeys(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_APPKEY_LIST, callback, user_data); + return error_code; +} + +int bt_mesh_network_foreach_groups(bt_mesh_network_h network, + bt_mesh_network_group_info_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bluetooth_mesh_network_t net; + bt_mesh_network_s *network_s; + GPtrArray *groups = NULL; + GSList *l; + uint16_t *group_addr = NULL; + int i; + int total; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + BT_CHECK_INPUT_PARAMETER(callback); + + BT_MESH_VALIDATE_HANDLE(network, networks); + + groups = g_ptr_array_new(); + if (groups == NULL) { + BT_ERR("Mesh: OUT_OF_MEMORY(0x%08x)", BT_ERROR_OUT_OF_MEMORY); + return BT_ERROR_OUT_OF_MEMORY; + } + + network_s = (bt_mesh_network_s*)network; + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_get_all_groups(&net, &groups)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + g_ptr_array_free(groups, TRUE); + return error_code; + } + + for (i = 0; i < groups->len; i++) { + group_addr = g_ptr_array_index(groups, i); + if (group_addr) { + /* Find or create group in network list */ + if (!_bt_mesh_network_get_group(network_s, *group_addr)) { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } else { + BT_ERR("Mesh: OPERATION_FAILED(0x%08x)", + BT_ERROR_OPERATION_FAILED); + error_code = BT_ERROR_OPERATION_FAILED; + break; + } + } + + total = g_slist_length(network_s->groups); + if (total == 0) { + BT_INFO("Mesh: No Groups added in network"); + callback(BT_ERROR_NONE, (bt_mesh_network_h)network_s, total, + NULL, user_data); + } + for (l = network_s->groups; l != NULL; l = g_slist_next(l)) { + bt_mesh_group_s *group_s; + group_s = l->data; + + if (!callback(BT_ERROR_NONE, (bt_mesh_network_h)network_s, total, + (bt_mesh_group_h) group_s, + user_data)) + break; + } + + g_ptr_array_foreach(groups, (GFunc)g_free, NULL); + g_ptr_array_free(groups, TRUE); + + FUNC_EXIT; + return error_code; +} + +int bt_mesh_network_create_virtual_group(bt_mesh_network_h network, + bt_mesh_group_h *group) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_group_s *group_s; + bluetooth_mesh_network_group_info_t req; + bluetooth_mesh_network_t net; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + + network_s = (bt_mesh_network_s*) network; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + memset(&req, 0x00, sizeof(bluetooth_mesh_network_group_info_t)); + + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_create_group(&net, true, 0x0000, &req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + group_s = g_malloc0(sizeof(bt_mesh_group_s)); + group_s->addr = req.group_addr; + group_s->is_virtual = true; + group_s->parent = network_s; + if (g_slist_append(network_s->groups, group_s)) + BT_INFO("Mesh: Group created"); + + __bt_mesh_util_convert_hex_to_string((uint8_t *)req.label_uuid, 16, + group_s->label_uuid, sizeof(group_s->label_uuid)); + + group_list = g_slist_append(group_list, group_s); + *group = (bt_mesh_group_h) group_s; + FUNC_EXIT; + return error_code; +} + +int bt_mesh_network_remove_group(bt_mesh_group_h group) +{ + bt_mesh_network_s *network_s; + bt_mesh_group_s *group_s; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_INPUT_PARAMETER(group); + + group_s = (bt_mesh_group_s*) group; + network_s = group_s->parent; + + BT_MESH_VALIDATE_HANDLE(group_s, group_list); + + network_s->groups = g_slist_remove(network_s->groups, group_s); + group_list = g_slist_remove(group_list, group_s); + + g_free(group_s); + FUNC_EXIT; + return BT_ERROR_NONE; +} + +int bt_mesh_network_create_group(bt_mesh_network_h network, + uint16_t grp_addr, bt_mesh_group_h *group) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_network_s *network_s; + bt_mesh_group_s *group_s; + bluetooth_mesh_network_t net; + bluetooth_mesh_network_group_info_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(network); + + network_s = (bt_mesh_network_s*) network; + + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + memset(&net, 0x00, sizeof(bluetooth_mesh_network_t)); + memset(&req, 0x00, sizeof(bluetooth_mesh_network_group_info_t)); + + /* Fill Network Info */ + g_strlcpy(net.uuid, network_s->uuid, 33); + g_strlcpy(net.token.token, network_s->token, 17); + g_strlcpy(net.name.name, network_s->name, BT_MESH_NETWORK_NAME_STRING_MAX_LEN + 1); + + error_code = _bt_get_error_code(bluetooth_mesh_network_create_group(&net, false, grp_addr, &req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + group_s = g_malloc0(sizeof(bt_mesh_group_s)); + group_s->addr = grp_addr; + group_s->is_virtual = false; + group_s->parent = network_s; + if (g_slist_append(network_s->groups, group_s)) + BT_INFO("Mesh: Group created"); + + group_list = g_slist_append(group_list, group_s); + *group = (bt_mesh_group_h) group_s; + FUNC_EXIT; + return error_code; +} + + +int bt_mesh_model_configure_group_subscription(bt_mesh_model_subscription_op_e model_op, + bt_mesh_model_h model, bt_mesh_group_h group, + bt_mesh_model_subscription_op_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_network_s *network_s; + bt_mesh_group_s *group_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(group); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + group_s = (bt_mesh_group_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + /* Check group belongs to the same network */ + if (network_s != group_s->parent) + return BT_ERROR_INVALID_PARAMETER; + + /* Check group is non virtual */ + if (group_s->is_virtual) + return BT_ERROR_INVALID_PARAMETER; + + BT_CHECK_INPUT_PARAMETER(element_s); + BT_CHECK_INPUT_PARAMETER(node_s); + BT_CHECK_INPUT_PARAMETER(network_s); + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(group_s, group_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + if (model_op != BT_MESH_MODEL_SUBSCRIPTION_DELETE_ALL) + req.sub_addr = group_s->addr; + req.is_virtual_sub = false; + req.op = model_op; + + error_code = _bt_get_error_code(bluetooth_mesh_model_configure_group_sub(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_GROUP_SUB, callback, user_data); + return error_code; +} + +int bt_mesh_model_configure_virtual_group_subscription(bt_mesh_model_subscription_op_e model_op, + bt_mesh_model_h model, bt_mesh_group_h group, + bt_mesh_model_subscription_op_cb callback, + void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_network_s *network_s; + bt_mesh_group_s *group_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(group); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + group_s = (bt_mesh_group_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + /* Check group belongs to the same network */ + if (network_s != group_s->parent) + return BT_ERROR_INVALID_PARAMETER; + + /* Check group is non virtual */ + if (!group_s->is_virtual) + return BT_ERROR_INVALID_PARAMETER; + + BT_CHECK_INPUT_PARAMETER(element_s); + BT_CHECK_INPUT_PARAMETER(node_s); + BT_CHECK_INPUT_PARAMETER(network_s); + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(group_s, group_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + if (model_op != BT_MESH_MODEL_SUBSCRIPTION_DELETE_ALL) + req.sub_addr = group_s->addr; + + req.is_virtual_sub = true; + req.op = model_op; + + error_code = _bt_get_error_code(bluetooth_mesh_model_configure_virtual_group_sub(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_GROUP_VIR_SUB, callback, user_data); + return error_code; +} + +int bt_mesh_model_get_subscription_list(bt_mesh_model_h model, + bt_mesh_model_subscription_list_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_network_s *network_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + BT_CHECK_INPUT_PARAMETER(model_s); + BT_CHECK_INPUT_PARAMETER(element_s); + BT_CHECK_INPUT_PARAMETER(node_s); + BT_CHECK_INPUT_PARAMETER(network_s); + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_model_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.elem_index = element_s->index; + req.model = model_s->id; + + error_code = _bt_get_error_code(bluetooth_mesh_model_get_subscriptopn_list(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_APPKEY_LIST, callback, user_data); + return error_code; +} + +int bt_mesh_model_set_publication(bt_mesh_model_h model, bt_mesh_appkey_h appkey, + bt_mesh_group_h group, + bt_mesh_model_pub_params_s *params, + bt_mesh_model_publication_status_cb callback, + void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_appkey_s *appkey_s; + bt_mesh_network_s *network_s; + bt_mesh_group_s *group_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(appkey); + BT_CHECK_INPUT_PARAMETER(group); + BT_CHECK_INPUT_PARAMETER(params); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + appkey_s = (bt_mesh_appkey_s*) appkey; + group_s = (bt_mesh_group_s*) group; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + if (group_s->parent != network_s) + return BT_ERROR_INVALID_PARAMETER; + + if (params->num_steps > BT_MESH_MAX_PUBISH_PERIOD_STEPS) + return BT_ERROR_INVALID_PARAMETER; + if (params->retrans_cnt > BT_MESH_MAX_PUBISH_RETRANSMIT_COUNT) + return BT_ERROR_INVALID_PARAMETER; + if (params->retrans_step > BT_MESH_MAX_PUBISH_RETRANSMIT_INTERVAL_STEPS) + return BT_ERROR_INVALID_PARAMETER; + + BT_CHECK_INPUT_PARAMETER(element_s); + BT_CHECK_INPUT_PARAMETER(node_s); + BT_CHECK_INPUT_PARAMETER(network_s); + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + BT_MESH_VALIDATE_HANDLE(appkey_s, appkey_list); + BT_MESH_VALIDATE_HANDLE(group_s, group_list); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_model_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.elem_index = element_s->index; + req.model = model_s->id; + req.appkey_idx = appkey_s->appkey_index; + req.pub_addr = group_s->addr; + + req.ttl = params->ttl; + req.period = params->num_steps; + req.period = req.period << 2; + req.period |= params->per_res; + req.retransmit = params->retrans_cnt; + req.retransmit = req.retransmit << 5; + req.retransmit |= params->retrans_step; + + error_code = _bt_get_error_code(bluetooth_mesh_model_set_publication(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_PUBLICATION, callback, user_data); + return error_code; +} + +int bt_mesh_model_get_publication(bt_mesh_model_h model, + bt_mesh_model_publication_status_cb callback, void *user_data) +{ + int error_code = BT_ERROR_NONE; + bt_mesh_model_s *model_s; + bt_mesh_element_s *element_s; + bt_mesh_node_s *node_s; + bt_mesh_network_s *network_s; + bluetooth_mesh_model_configure_t req; + + FUNC_ENTRY; + BT_CHECK_MESH_SUPPORT(); + BT_CHECK_MESH_INIT_STATUS(); + BT_CHECK_INPUT_PARAMETER(model); + BT_CHECK_INPUT_PARAMETER(callback); + + model_s = (bt_mesh_model_s*) model; + element_s = (bt_mesh_element_s*) model_s->parent; + node_s = (bt_mesh_node_s*) element_s->parent; + network_s = (bt_mesh_network_s*) node_s->parent; + + BT_CHECK_INPUT_PARAMETER(model_s); + BT_CHECK_INPUT_PARAMETER(element_s); + BT_CHECK_INPUT_PARAMETER(node_s); + BT_CHECK_INPUT_PARAMETER(network_s); + + BT_MESH_VALIDATE_HANDLE(model_s, model_list); + BT_MESH_VALIDATE_HANDLE(element_s, element_list); + BT_MESH_VALIDATE_HANDLE(node_s, node_list); + BT_MESH_VALIDATE_HANDLE(network_s, networks); + + /* Return error, if node is not attached */ + if (!node_s->is_attached) + return BT_ERROR_INVALID_PARAMETER; + + memset(&req, 0x00, sizeof(bluetooth_mesh_model_configure_t)); + + g_strlcpy(req.net_uuid, network_s->uuid, 33); + req.primary_unicast = node_s->unicast; + req.elem_index = element_s->index; + req.model = model_s->id; + + error_code = _bt_get_error_code(bluetooth_mesh_model_get_publication(&req)); + if (error_code != BT_ERROR_NONE) { + BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); + return error_code; + } + + FUNC_EXIT; + _bt_set_cb(BT_EVENT_MESH_NODE_MODEL_PUBLICATION, callback, user_data); + return error_code; +}