oal-gatt.c
oal-hf-client.c
oal-mesh.c
+oal-tds.c
common/oal-utils.c
common/oal-common.c
common/oal-event-dispatcher.c
./src/bt-hal-hf-client-dbus-handler.c
./src/bt-hal-mesh.c
./src/bt-hal-mesh-dbus-handler.c
+./src/bt-hal-tds.c
+./src/bt-hal-tds-dbus-handler.c
)
SET(PREFIX ${CMAKE_INSTALL_PREFIX})
DBG("After Manuf Data: Index [%d]", index);
}
+ /* Transport Discovery Data */
+ if (adv_param_setup.tds_data_len > 0) {
+ adv_data[index] = 1 + adv_param_setup.tds_data_len;
+ adv_data[index+1] = 0x26;
+ memcpy(&adv_data[index+2], adv_param_setup.tds_data, adv_param_setup.tds_data_len);
+ index += (2 + adv_param_setup.tds_data_len);
+ length += (2 + adv_param_setup.tds_data_len);
+ DBG("After Transport Discovery Data: Index [%d]", index);
+ }
+
for (i = 0; i < length; i++)
snprintf(&adv_data_str[i * 2], 3, "%02X", adv_data[i]);
INFO("Set adv data. Index [%d] length [%d] Data[%s]", index, length, adv_data_str);
#endif
#include <bt-hal-hf-client.h>
#include <bt-hal-mesh.h>
+#include <bt-hal-tds.h>
#define enum_prop_to_hal(prop, hal_prop, type) do { \
static type e; \
return bt_get_mesh_interface();
}
+ if (!strcmp(profile_id, BT_PROFILE_TDS_ID))
+ return bt_get_tds_interface();
+
return NULL;
}
#define BT_HAL_MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
#define BT_HAL_OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
#define BT_HAL_HEADSET_INTERFACE "org.bluez.Headset"
-
+#define BT_HAL_TDS_PROVIDER_INTERFACE "org.bluez.TdsServiceProvider1"
#define BT_HAL_INTERFACES_ADDED "InterfacesAdded"
#define BT_HAL_INTERFACES_REMOVED "InterfacesRemoved"
#include "bt-hal-gatt-server.h"
#include "bt-hal-gatt-client.h"
#include "bt-hal-adapter-dbus-handler.h"
+#include "bt-hal-tds.h"
#include "bt-internal-types.h"
}
}
+static void __bt_hal_handle_tds_provider_event(GVariant *parameters, const char *signal_name, const char *path)
+{
+ if (signal_name == NULL)
+ return;
+
+ if (strcasecmp(signal_name, "TdsActivationRequested") == 0) {
+ GVariant *value = NULL;
+ int len = 0;
+ unsigned char *buffer = NULL;
+ unsigned char org_id;
+
+ g_variant_get(parameters, "(y@ay)", &org_id, &value);
+ DBG("org_id: 0x%.2x", org_id);
+ len = g_variant_get_size(value);
+ if (len > 0) {
+ int i;
+ buffer = (unsigned char *)g_variant_get_data(value);
+ for (i = 0; i < len; i++)
+ DBG("0x%.2x", buffer[i]);
+ }
+
+ /* Send event only registered client */
+ _bt_tds_handle_activation_request(path, org_id, buffer, len);
+ g_variant_unref(value);
+ }
+}
+
static gboolean __bt_hal_event_manager(gpointer data)
{
bt_hal_event_type_t bt_event = 0x00;
} else if (g_strcmp0(param->interface_name, BT_HAL_GATT_SERVICE_INTERFACE) == 0) {
DBG("Manager Event: Interface Name: BT_HAL_GATT_SERVICE_INTERFACE");
__bt_hal_handle_gatt_service_event(param->parameters, param->signal_name);
+ } else if (g_strcmp0(param->interface_name, BT_HAL_TDS_PROVIDER_INTERFACE) == 0) {
+ DBG("Manager Event: Interface Name: BT_HAL_TDS_PROVIDER_INTERFACE");
+ __bt_hal_handle_tds_provider_event(param->parameters, param->signal_name, param->object_path);
}
done:
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <dlog.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+#include "bt-hal-utils.h"
+#include "bt-hal-dbus-common-utils.h"
+#include "bt-hal-tds-dbus-handler.h"
+
+bt_status_t _bt_hal_tds_register_provider()
+{
+ GDBusConnection *gconn;
+ char *adapter_path;
+ GDBusProxy *provider_proxy;
+ GVariant *result;
+ GError *error = NULL;
+
+ gconn = _bt_hal_get_system_gconn();
+ if (gconn == NULL)
+ return BT_STATUS_FAIL;
+
+ adapter_path = _bt_hal_get_adapter_path();
+ if (adapter_path == NULL)
+ return BT_STATUS_FAIL;
+
+ provider_proxy = g_dbus_proxy_new_sync(gconn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME, adapter_path,
+ BT_HAL_TDS_PROVIDER_INTERFACE, NULL, NULL);
+ g_free(adapter_path);
+ if (provider_proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ result = g_dbus_proxy_call_sync(provider_proxy, "RegisterTdsProvider",
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+ if (result == NULL) {
+ if (error != NULL) {
+ ERR("Error occured in Proxy call [%s]\n", error->message);
+ g_error_free(error);
+ }
+ g_object_unref(provider_proxy);
+ return BT_STATUS_FAIL;
+ }
+ g_variant_unref(result);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_tds_unregister_provider()
+{
+ GDBusConnection *gconn;
+ char *adapter_path;
+ GDBusProxy *provider_proxy;
+ GVariant *result;
+ GError *error = NULL;
+
+ gconn = _bt_hal_get_system_gconn();
+ if (gconn == NULL)
+ return BT_STATUS_FAIL;
+
+ adapter_path = _bt_hal_get_adapter_path();
+ if (adapter_path == NULL)
+ return BT_STATUS_FAIL;
+
+ provider_proxy = g_dbus_proxy_new_sync(gconn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME, adapter_path,
+ BT_HAL_TDS_PROVIDER_INTERFACE, NULL, NULL);
+ g_free(adapter_path);
+ if (provider_proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ result = g_dbus_proxy_call_sync(provider_proxy, "UnregisterTdsProvider",
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+ if (result == NULL) {
+ if (error != NULL) {
+ ERR("Error occured in Proxy call [%s]\n", error->message);
+ g_error_free(error);
+ }
+ g_object_unref(provider_proxy);
+ return BT_STATUS_FAIL;
+ }
+ g_variant_unref(result);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_tds_set_block_data(unsigned char *data, unsigned int data_len)
+{
+ GDBusConnection *gconn;
+ char *adapter_path;
+ GDBusProxy *provider_proxy;
+ GVariant *result;
+ GError *error = NULL;
+ GVariantBuilder *builder;
+ GVariant *temp;
+ int i;
+
+ gconn = _bt_hal_get_system_gconn();
+ if (gconn == NULL)
+ return BT_STATUS_FAIL;
+
+ adapter_path = _bt_hal_get_adapter_path();
+ if (adapter_path == NULL)
+ return BT_STATUS_FAIL;
+
+ /* Create block data */
+ builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ for (i = 0; i < data_len; i++)
+ g_variant_builder_add(builder, "y", data[i]);
+ temp = g_variant_new("ay", builder);
+ g_variant_builder_unref(builder);
+
+ provider_proxy = g_dbus_proxy_new_sync(gconn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME, adapter_path,
+ BT_HAL_TDS_PROVIDER_INTERFACE, NULL, NULL);
+ g_free(adapter_path);
+ if (provider_proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ result = g_dbus_proxy_call_sync(provider_proxy, "SetTdsBlockData",
+ g_variant_new("(@ay)", temp),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+ if (result == NULL) {
+ if (error != NULL) {
+ ERR("Error occured in Proxy call [%s]\n", error->message);
+ g_error_free(error);
+ }
+ g_object_unref(provider_proxy);
+ return BT_STATUS_FAIL;
+ }
+ g_variant_unref(result);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_tds_send_activation_response(unsigned char response,
+ unsigned char *data, unsigned int data_len)
+{
+ GDBusConnection *gconn;
+ char *adapter_path;
+ GDBusProxy *provider_proxy;
+ GVariant *result;
+ GError *error = NULL;
+ GVariantBuilder *builder;
+ GVariant *temp;
+ int i;
+
+ gconn = _bt_hal_get_system_gconn();
+ if (gconn == NULL)
+ return BT_STATUS_FAIL;
+
+ adapter_path = _bt_hal_get_adapter_path();
+ if (adapter_path == NULL)
+ return BT_STATUS_FAIL;
+
+ /* Create response data */
+ builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ for (i = 0; i < data_len; i++)
+ g_variant_builder_add(builder, "y", data[i]);
+ temp = g_variant_new("ay", builder);
+ g_variant_builder_unref(builder);
+
+ provider_proxy = g_dbus_proxy_new_sync(gconn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME, adapter_path,
+ BT_HAL_TDS_PROVIDER_INTERFACE, NULL, NULL);
+ g_free(adapter_path);
+ if (provider_proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ result = g_dbus_proxy_call_sync(provider_proxy, "TdsActivationResponse",
+ g_variant_new("(y@ay)", response, temp),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+ if (result == NULL) {
+ if (error != NULL) {
+ ERR("Error occured in Proxy call [%s]\n", error->message);
+ g_error_free(error);
+ }
+ g_object_unref(provider_proxy);
+ return BT_STATUS_FAIL;
+ }
+ g_variant_unref(result);
+
+ return BT_STATUS_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _BT_HAL_TDS_DBUS_HANDLER_H_
+#define _BT_HAL_TDS_DBUS_HANDLER_H_
+
+#include <glib.h>
+#include <hardware/bt_tds.h>
+
+#include "bt_tds.h"
+
+bt_status_t _bt_hal_tds_register_provider();
+bt_status_t _bt_hal_tds_unregister_provider();
+bt_status_t _bt_hal_tds_set_block_data(unsigned char *data, unsigned int data_len);
+bt_status_t _bt_hal_tds_send_activation_response(unsigned char response,
+ unsigned char *data, unsigned int data_len);
+
+#endif /* _BT_HAL_TDS_DBUS_HANDLER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlog.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_tds.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+#include "bt-hal-utils.h"
+#include "bt-hal-tds-dbus-handler.h"
+#include "bt-hal-dbus-common-utils.h"
+
+static const bttds_callbacks_t *bt_hal_tds_callbacks = NULL;
+
+static bool interface_ready(void)
+{
+ return bt_hal_tds_callbacks != NULL;
+}
+
+void _bt_tds_handle_activation_request(const char *path,
+ unsigned char org_id, unsigned char *buf, int len)
+{
+ char address[BT_HAL_ADDRESS_STRING_SIZE];
+ _bt_hal_convert_device_path_to_address(path, address);
+
+ if (bt_hal_tds_callbacks->activation_requested_cb)
+ bt_hal_tds_callbacks->activation_requested_cb(address, org_id, buf, len);
+}
+
+static bt_status_t init(bttds_callbacks_t *callbacks)
+{
+ DBG("");
+
+ if (interface_ready())
+ return BT_STATUS_SUCCESS;
+
+ bt_hal_tds_callbacks = callbacks;
+ INFO("Register TDS events callback function");
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t tds_register_provider()
+{
+ DBG("");
+ return _bt_hal_tds_register_provider();
+}
+
+static bt_status_t tds_unregister_provider()
+{
+ DBG("");
+ return _bt_hal_tds_unregister_provider();
+}
+
+static bt_status_t tds_set_block_data(unsigned char *data, unsigned int data_len)
+{
+ DBG("");
+ return _bt_hal_tds_set_block_data(data, data_len);
+}
+
+static bt_status_t tds_send_activation_response(unsigned char response,
+ unsigned char *data, unsigned int data_len)
+{
+ DBG("");
+ return _bt_hal_tds_send_activation_response(response, data, data_len);
+}
+
+static void cleanup(void)
+{
+ DBG("");
+
+ if (!interface_ready())
+ return;
+
+ bt_hal_tds_callbacks = NULL;
+}
+
+static const bttds_interface_t tds_if = {
+ .size = sizeof(tds_if),
+ .init = init,
+ .register_provider = tds_register_provider,
+ .unregister_provider = tds_unregister_provider,
+ .set_block_data = tds_set_block_data,
+ .send_activation_response = tds_send_activation_response,
+ .cleanup = cleanup
+};
+
+const bttds_interface_t *bt_get_tds_interface()
+{
+ return &tds_if;
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __BT_HAL_TDS_H__
+#define __BT_HAL_TDS_H__
+
+#include <stdint.h>
+#include <glib.h>
+#include <unistd.h>
+#include <dlog.h>
+#include <stdio.h>
+#include <hardware/bt_tds.h>
+
+bool _bt_hal_tds_interface_ready(void);
+void _bt_tds_handle_activation_request(const char *path,
+ unsigned char org_id, unsigned char *buf, int len);
+bttds_interface_t *bt_get_tds_interface(void);
+
+#endif /* __BT_HAL_TDS_H__ */
#define BT_PROFILE_MESH_ID "mesh"
#define BT_PROFILE_AV_RC_ID "avrcp"
#define BT_PROFILE_AV_RC_CTRL_ID "avrcp_ctrl"
+#define BT_PROFILE_TDS_ID "tds"
#define BT_MANUFACTURER_DATA_LENGTH_MAX 31 /**< This specifies the Maximum manufacturer data Length>*/
/** Bluetooth Address */
uint8_t chnl_map;
uint8_t tx_power;
uint8_t timeout_s;
+ char* tds_data;
+ uint16_t tds_data_len;
} btgatt_adv_param_setup_t;
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIZEN_INCLUDE_BT_TDS_H
+#define TIZEN_INCLUDE_BT_TDS_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/** Callback Signatures */
+typedef void (*activation_requested_callback)(char *address, unsigned char org_id, unsigned char *data, unsigned int data_len);
+
+/** BT-TDS callback structure. */
+typedef struct {
+ activation_requested_callback activation_requested_cb;
+} bttds_callbacks_t;
+
+/** Represents the standard BT-TDS interface. */
+typedef struct {
+ size_t size;
+ bt_status_t (*init)(bttds_callbacks_t *callbacks);
+ bt_status_t (*register_provider)(void);
+ bt_status_t (*unregister_provider)(void);
+ bt_status_t (*set_block_data)(unsigned char *data, unsigned int data_len);
+ bt_status_t (*send_activation_response)(unsigned char response, unsigned char *data, unsigned int data_len);
+ void (*cleanup)(void);
+} bttds_interface_t;
+
+__END_DECLS
+
+#endif /* TIZEN_INCLUDE_BT_TDS_H */
EVENT(OAL_EVENT_MESH_APPKEY_EXECUTE_EVENT) /* AppKey Operations (Add/Update/Delete) Event */\
EVENT(OAL_EVENT_MESH_DEVKEY_MESSAGE_RECEIVED) /* DevKey message received Event */\
EVENT(OAL_EVENT_MESH_MODEL_MESSAGE_RECEIVED) /* Message received Event */\
+ EVENT(OAL_EVENT_TDS_ACTIVATION_REQUESTED) /* Message received Event */\
EVENT(OAL_EVENT_END) /* End of event*/\
notif_event_avrcp_ct_play_status_t play_status;
} event_avrcp_ct_play_status_t;
+#define TDS_ACTIVATION_DATA_LENGTH 100
+typedef struct {
+ char address[BT_ADDRESS_STR_LEN];
+ unsigned char org_id;
+ unsigned char tds_data[TDS_ACTIVATION_DATA_LENGTH];
+ unsigned int data_len;
+} event_tds_activation_requested_t;
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
uint8_t chnl_map;
uint16_t tx_power;
uint8_t timeout_s;
+ char* tds_data;
+ uint16_t tds_data_len;
} oal_ble_multi_adv_param_setup_t;
typedef struct {
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _OAL_TDS_H_
+#define _OAL_TDS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+oal_status_t tds_enable(void);
+oal_status_t tds_disable(void);
+oal_status_t tds_provider_register();
+oal_status_t tds_provider_unregister();
+oal_status_t tds_provider_set_block_data(unsigned char *data, unsigned int data_len);
+oal_status_t tds_provider_send_activation_response(unsigned char response, unsigned char *data, unsigned int data_len);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* OAL_TDS_H_ */
adv_setup.chnl_map = adv_param_setup->chnl_map;
adv_setup.tx_power = adv_param_setup->tx_power;
adv_setup.timeout_s = adv_param_setup->timeout_s;
+ adv_setup.tds_data = adv_param_setup->tds_data;
+ adv_setup.tds_data_len = adv_param_setup->tds_data_len;
adv_setup.server_if = instance_id;
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * 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 <dlog.h>
+#include <bluetooth.h>
+#include "bt_tds.h"
+#include "oal-event.h"
+#include "oal-internal.h"
+#include "oal-manager.h"
+#include "oal-utils.h"
+#include "oal-common.h"
+#include "oal-tds.h"
+
+#define CHECK_OAL_TDS_ENABLED() \
+ do { \
+ if (tds_api == NULL) { \
+ BT_ERR("TDS Not Enabled"); \
+ return OAL_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+static const bttds_interface_t *tds_api;
+
+static void tds_activation_requested_cb(char *address, unsigned char org_id, unsigned char *data, unsigned int data_len)
+{
+ event_tds_activation_requested_t *event = g_malloc0(sizeof(event_tds_activation_requested_t));
+ g_strlcpy(event->address, address, BT_ADDRESS_STR_LEN);
+ event->org_id = org_id;
+ memcpy(event->tds_data, data, sizeof(event->tds_data));
+ event->data_len = data_len;
+
+ send_event(OAL_EVENT_TDS_ACTIVATION_REQUESTED, event, sizeof(event_tds_activation_requested_t));
+}
+
+static bttds_callbacks_t tds_callbacks = {
+ .activation_requested_cb = tds_activation_requested_cb,
+};
+
+oal_status_t tds_enable(void)
+{
+ const bt_interface_t * blued_api;
+ int ret;
+
+ /* Get stack interface */
+ blued_api = (const bt_interface_t *)adapter_get_stack_interface();
+
+ if (blued_api == NULL) {
+ BT_ERR("Stack is not initialized");
+ return OAL_STATUS_NOT_READY;
+ }
+
+ if (tds_api) {
+ BT_WARN("TDS Interface is already initialized...");
+ return OAL_STATUS_ALREADY_DONE;
+ }
+
+ tds_api = (const bttds_interface_t *)blued_api->get_profile_interface(BT_PROFILE_TDS_ID);
+ if (tds_api == NULL) {
+ BT_ERR("TDS interface failed");
+ return OAL_STATUS_INTERNAL_ERROR;
+ }
+
+ if ((ret = tds_api->init(&tds_callbacks)) != BT_STATUS_SUCCESS) {
+ BT_ERR("Error: Unable to initialise TDS :%s", status2string(ret));
+ tds_api->cleanup();
+ tds_api = NULL;
+ return convert_to_oal_status(ret);
+ }
+
+ BT_INFO("TDS successfully initialized");
+ return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t tds_disable(void)
+{
+ if (tds_api) {
+ tds_api->cleanup();
+ tds_api = NULL;
+ }
+
+ return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t tds_provider_send_activation_response(unsigned char response,
+ unsigned char *data, unsigned int data_len)
+{
+ int ret;
+ API_TRACE();
+ CHECK_OAL_TDS_ENABLED();
+
+ ret = tds_api->send_activation_response(response, data, data_len);
+ if (ret != BT_STATUS_SUCCESS) {
+ BT_ERR("send_activation_response() failed: %s", status2string(ret));
+ return convert_to_oal_status(ret);
+ }
+ return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t tds_provider_set_block_data(unsigned char *data, unsigned int data_len)
+{
+ int ret;
+ API_TRACE();
+ CHECK_OAL_TDS_ENABLED();
+
+ ret = tds_api->set_block_data(data, data_len);
+ if (ret != BT_STATUS_SUCCESS) {
+ BT_ERR("set_block_data() failed: %s", status2string(ret));
+ return convert_to_oal_status(ret);
+ }
+ return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t tds_provider_unregister()
+{
+ int ret;
+ API_TRACE();
+ CHECK_OAL_TDS_ENABLED();
+
+ ret = tds_api->unregister_provider();
+ if (ret != BT_STATUS_SUCCESS) {
+ BT_ERR("unregister_provider() failed: %s", status2string(ret));
+ return convert_to_oal_status(ret);
+ }
+ return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t tds_provider_register()
+{
+ int ret;
+ API_TRACE();
+ CHECK_OAL_TDS_ENABLED();
+
+ ret = tds_api->register_provider();
+ if (ret != BT_STATUS_SUCCESS) {
+ BT_ERR("register_provider() failed: %s", status2string(ret));
+ return convert_to_oal_status(ret);
+ }
+ return OAL_STATUS_SUCCESS;
+}
./services/mesh/bt-service-mesh-main.c
./services/mesh/bt-service-mesh-config-client.c
./services/mesh/bt-service-mesh-model.c
+./services/tds/bt-service-tds.c
)
IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_FEATURE_BT_OBEX")
#include "bt-service-oob.h"
#include "bt-service-battery-monitor.h"
#include "bt-service-mesh-common.h"
+#include "bt-service-tds.h"
#include <oal-hardware.h>
#include <oal-manager.h>
/* Free allocated slot or server instance from stack to be used for other advertisng */
result = _bt_unregister_server_instance(sender, adv_handle);
+ /* Advertising disabled, notify TDS */
+ _bt_tds_handle_adv_disabled(sender);
+
/* Free data */
g_free(info->sender);
g_free(info);
if (event->status != OAL_STATUS_SUCCESS)
result = BLUETOOTH_ERROR_INTERNAL;
+ /* Check whether this request is from TDS or not */
+ _bt_tds_set_advertising_data_completed_cb(sender, adv_handle);
+
info = g_malloc0(sizeof(bt_pending_adv_data_set_t));
info->sender = sender;
info->adv_handle = adv_handle;
memcpy(&adv_setup->appearance, (ptr + 2), (len - 1));
break;
}
+ case 0x26: { /* Transport Discovery Data */
+ adv_setup->tds_data = g_malloc0(sizeof(char) * len - 1);
+ memcpy(adv_setup->tds_data, ptr + 2, len - 1);
+ adv_setup->tds_data_len = len - 1;
+ break;
+ }
default:
BT_ERR("Unknown type: %x", type);
break;
#include "bt-service-hiddevice.h"
#include "bt-service-socket.h"
#include "bt-service-hdp.h"
+#include "bt-service-tds.h"
/* OAL headers */
#include <oal-event.h>
if (ret != BLUETOOTH_ERROR_NONE)
BT_ERR("_bt_gatt_init Failed");
+ ret = _bt_tds_init();
+ if (ret != BLUETOOTH_ERROR_NONE)
+ BT_ERR("_bt_tds_init Failed");
+
/* Initialize HF Client */
ret = _bt_audio_initialize(BT_HFP_MODULE);
if (ret != BLUETOOTH_ERROR_NONE)
#include "bt-service-hidhost.h"
#include "bt-service-rfcomm.h"
#include "bt-service-hdp.h"
+#include "bt-service-tds.h"
/*Obex*/
#include "bt-service-obex-server.h"
break;
}
+ case BT_TDS_PROVIDER_REGISTER: {
+ char *sender = NULL;
+
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+ result = _bt_tds_provider_register(sender);
+
+ break;
+ }
+
+ case BT_TDS_PROVIDER_UNREGISTER: {
+ char *sender = NULL;
+
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+ result = _bt_tds_provider_unregister(sender);
+
+ break;
+ }
+
+ case BT_TDS_PROVIDER_SET_MANUF_DATA: {
+ char *sender = NULL;
+ unsigned int length = 0;
+ bluetooth_advertising_data_t manuf_data;
+
+ __bt_service_get_parameters(in_param1,
+ &length, sizeof(unsigned int));
+ __bt_service_get_parameters(in_param2,
+ &manuf_data, sizeof(bluetooth_advertising_data_t));
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+
+ result = _bt_tds_provider_set_manuf_data(sender, manuf_data.data, length);
+ break;
+ }
+
+ case BT_TDS_PROVIDER_CREATE: {
+ char *sender = NULL;
+ unsigned int tds_handle = 0;
+ int transport;
+
+ __bt_service_get_parameters(in_param1,
+ &tds_handle, sizeof(unsigned int));
+ __bt_service_get_parameters(in_param2,
+ &transport, sizeof(int));
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+ result = _bt_tds_provider_transport_create(sender, transport, tds_handle);
+
+ break;
+ }
+
+ case BT_TDS_PROVIDER_DESTROY: {
+ char *sender = NULL;
+ unsigned int tds_handle = 0;
+
+ __bt_service_get_parameters(in_param1,
+ &tds_handle, sizeof(unsigned int));
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+ result = _bt_tds_provider_transport_remove(sender, tds_handle);
+
+ break;
+ }
+
+ case BT_TDS_PROVIDER_SET_TRANSPORT_DATA: {
+ char *sender = NULL;
+ unsigned int tds_handle = 0;
+ int transport_state = 0;
+ bluetooth_tds_data_t tds_data;
+
+ __bt_service_get_parameters(in_param1,
+ &tds_handle, sizeof(unsigned int));
+ __bt_service_get_parameters(in_param2,
+ &transport_state, sizeof(int));
+ __bt_service_get_parameters(in_param3,
+ &tds_data, sizeof(bluetooth_tds_data_t));
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+
+ result = _bt_tds_provider_set_transport_data(sender, tds_handle,
+ transport_state, tds_data.data, tds_data.length);
+ break;
+ }
+
+ case BT_TDS_SEND_ACTIVATION_RESPONSE: {
+ bluetooth_device_address_t address = { {0} };
+ bluetooth_tds_data_t tds_data;
+ char *sender = NULL;
+ unsigned int tds_handle = 0;
+ int response;
+
+ __bt_service_get_parameters(in_param1,
+ &tds_handle, sizeof(unsigned int));
+ __bt_service_get_parameters(in_param2,
+ &response, sizeof(int));
+ __bt_service_get_parameters(in_param3, &address,
+ sizeof(bluetooth_device_address_t));
+ __bt_service_get_parameters(in_param4,
+ &tds_data, sizeof(bluetooth_tds_data_t));
+ sender = (char *)g_dbus_method_invocation_get_sender(context);
+
+ result = _bt_tds_provider_send_activation_response(sender, tds_handle,
+ &address, response, tds_data.data, tds_data.length);
+ break;
+ }
+
case BT_MESH_INIT:
sender = (char*)g_dbus_method_invocation_get_sender(context);
BT_INFO("Mesh: Init by [%s]", sender);
/* Mesh App Termination */
_bt_check_mesh_app_termination(name);
+
+ /* Stop the Transport Discovery service */
+ _bt_tds_stop_by_terminated_process(name);
}
static void __bt_service_bus_acquired_handler(GDBusConnection *connection,
static _bt_service_event_handler_callback adapter_gatt_cb;
static _bt_service_event_handler_callback hf_client_cb;
static _bt_service_event_handler_callback mesh_cb;
+static _bt_service_event_handler_callback tds_cb;
void _bt_service_register_event_handler_callback(
bt_service_module_t module, _bt_service_event_handler_callback cb)
BT_INFO("Register BT_MESH_MODULE callback");
mesh_cb = cb;
break;
+ case BT_TDS_MODULE:
+ BT_INFO("Register BT_TDS_MODULE callback");
+ tds_cb = cb;
+ break;
default:
BT_INFO("Unknown module");
}
BT_INFO("Un-Register BT_MESH_MODULE callback");
mesh_cb = NULL;
break;
+ case BT_TDS_MODULE:
+ BT_INFO("Un-Register BT_TDS_MODULE callback");
+ tds_cb = NULL;
+ break;
default:
BT_INFO("Unknown module");
}
if (mesh_cb)
mesh_cb(event_type, event_data);
break;
+ case OAL_EVENT_TDS_ACTIVATION_REQUESTED:
+ BT_INFO("TDS: Event");
+ if (tds_cb)
+ tds_cb(event_type, event_data);
+ break;
default:
BT_ERR("Unhandled Event: %d", event_type);
break;
BT_LE_AD_TYPE_LIST_16_BIT_SERVICE_SOLICITATION_UUIDS = 0x14,
BT_LE_AD_TYPE_LIST_128_BIT_SERVICE_SOLICITATION_UUIDS = 0x15,
BT_LE_AD_TYPE_SERVICE_DATA = 0x16,
+ BT_LE_AD_TYPE_TRANSPORT_DISCOVERY_DATA = 0x26,
BT_LE_AD_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF,
} bt_le_ad_type_t;
BT_ADAPTER_LE_MODULE,
BT_GATT_MODULE,
BT_MESH_MODULE,
+ BT_TDS_MODULE,
} bt_service_module_t;
void _bt_service_oal_event_receiver(int event_type, gpointer event_data, gsize len);
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _BT_SERVICE_TDS_H_
+#define _BT_SERVICE_TDS_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include "bluetooth-api.h"
+#include "oal-tds.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _bt_tds_init(void);
+int _bt_tds_provider_register(const char *sender);
+int _bt_tds_provider_unregister(const char *sender);
+int _bt_tds_provider_transport_create(const char *sender,
+ int transport, unsigned int tds_handle);
+int _bt_tds_provider_transport_remove(const char *sender,
+ unsigned int tds_handle);
+int _bt_tds_provider_set_manuf_data(char *sender,
+ unsigned char *data, unsigned int len);
+int _bt_tds_provider_set_transport_data(char *sender,
+ int tds_handle, int transport_state,
+ unsigned char *data, unsigned int len);
+int _bt_tds_provider_send_activation_response(char *sender,
+ unsigned int tds_handle, bluetooth_device_address_t *address,
+ int response, unsigned char *data, unsigned int len);
+
+void _bt_tds_set_advertising_data_completed_cb(char *sender, int adv_handle);
+void _bt_tds_handle_activation_request(const char *path,
+ unsigned char org_id, unsigned char *buf, int len);
+void _bt_tds_stop_by_terminated_process(const char *name);
+void _bt_tds_handle_adv_disabled(const char *sender);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _BT_SERVICE_TDS_H_*/
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <dlog.h>
+#include <string.h>
+
+#include "bluetooth-api.h"
+#include "bt-internal-types.h"
+
+#include "bt-service-common.h"
+#include "bt-service-core-adapter.h"
+#include "bt-service-core-adapter-le.h"
+#include "bt-service-event.h"
+#include "bt-service-event-receiver.h"
+#include "bt-service-core-adapter.h"
+#include "bt-service-util.h"
+#include "bt-service-tds.h"
+
+#include <oal-hardware.h>
+#include <oal-event.h>
+#include <oal-tds.h>
+
+#define TDS_CONTROL_POINT_RESPONSE_SUCCESS 0x00
+#define TDS_CONTROL_POINT_RESPONSE_OP_CODE_NOT_SUPPORTED 0x01
+#define TDS_CONTROL_POINT_RESPONSE_INVALID_PARAMETER 0x02
+#define TDS_CONTROL_POINT_RESPONSE_UNSUPPORTED_ORG_ID 0x03
+#define TDS_CONTROL_POINT_RESPONSE_OPERATION_FAILED 0x04
+
+#define BT_ADV_FLAG_LEN 3
+#define TDS_DATA_LEN_MAX 1024
+#define NUM_TDS_PROVIDER_MAX 10
+#define TDS_MANUF_DATA_LEN_MAX 29
+
+typedef enum {
+ TDS_ROLE_UNSPECIFIED = 0,
+ TDS_ROLE_SEEKER,
+ TDS_ROLE_PROVIDER,
+ TDS_ROLE_SEEKER_PROVIDER
+} bt_tds_role_t;
+
+typedef struct {
+ unsigned int tds_handle;
+ bt_tds_role_t role;
+ bluetooth_tds_transport_t transport;
+ bluetooth_tds_transport_state_t state;
+ unsigned int data_len;
+ unsigned char *data;
+} bt_tds_transport_info_t;
+
+typedef struct {
+ char *sender;
+ int adv_handle;
+ unsigned int manuf_data_len;
+ unsigned char *manuf_data;
+ GSList *transports;
+ int set_adv_data_requested;
+ int set_scan_resp_data_requested;
+} bt_tds_provider_t;
+
+GSList *provider_list = NULL;
+static int assigned_adv_handle;
+static gboolean adv_handle_used[NUM_TDS_PROVIDER_MAX];
+static gboolean tds_enabled;
+
+static void __bt_init_adv_handle(void)
+{
+ assigned_adv_handle = 0;
+ memset(adv_handle_used, 0x00, sizeof(adv_handle_used));
+}
+
+static int __bt_provider_get_adv_handle(void)
+{
+ int index;
+
+ index = assigned_adv_handle + 1;
+
+ if (index >= NUM_TDS_PROVIDER_MAX)
+ index = 0;
+
+ while (adv_handle_used[index] == TRUE) {
+ if (index == assigned_adv_handle) {
+ /* No available ID */
+ BT_ERR("All adv_handles are used");
+ return -1;
+ }
+
+ index++;
+
+ if (index >= NUM_TDS_PROVIDER_MAX)
+ index = 0;
+ }
+
+ assigned_adv_handle = index;
+ adv_handle_used[index] = TRUE;
+
+ return assigned_adv_handle;
+}
+
+static void __bt_provider_delete_adv_handle(int handle)
+{
+ ret_if(handle >= NUM_TDS_PROVIDER_MAX);
+ ret_if(handle < 0);
+
+ adv_handle_used[handle] = FALSE;
+}
+
+static unsigned char __bt_tds_get_organization_id(int transport)
+{
+ BT_INFO("transport: %d", transport);
+
+ switch (transport) {
+ case BLUETOOTH_TDS_TRANSPORT_BT:
+ return 0x01;
+ case BLUETOOTH_TDS_TRANSPORT_CUSTOM:
+ return 0x02;
+ default:
+ BT_ERR("Invaid transport");
+ return 0x00;
+ }
+}
+
+static int __bt_tds_get_transport(unsigned char org_id)
+{
+ BT_INFO("org_id: %d", org_id);
+
+ switch (org_id) {
+ case 0x01:
+ return BLUETOOTH_TDS_TRANSPORT_BT;
+ case 0x02:
+ return BLUETOOTH_TDS_TRANSPORT_CUSTOM;
+ default:
+ BT_ERR("Invaid org_id");
+ return BLUETOOTH_TDS_TRANSPORT_INVALID;
+ }
+}
+
+static unsigned char __bt_tds_set_role(unsigned char flag, bt_tds_role_t role)
+{
+
+ BT_INFO("Flag: 0x%x, Role: %d", flag, role);
+
+ switch (role) {
+ case TDS_ROLE_UNSPECIFIED:
+ flag = flag & 0xFC;
+ break;
+ case TDS_ROLE_SEEKER:
+ flag = flag & 0xFC;
+ flag = flag | 0x01;
+ break;
+ case TDS_ROLE_PROVIDER:
+ flag = flag & 0xFC;
+ flag = flag | 0x02;
+ break;
+ case TDS_ROLE_SEEKER_PROVIDER:
+ flag = flag & 0xFC;
+ flag = flag | 0x03;
+ break;
+ default:
+ BT_ERR("Invalid role received");
+ }
+
+ return flag;
+}
+
+static int __bt_tds_get_role(unsigned char flag)
+{
+
+ BT_INFO("Flag: 0x%x", flag);
+
+ if (0x03 == (flag & 0x03))
+ return TDS_ROLE_SEEKER_PROVIDER;
+ else if (0x02 == (flag & 0x02))
+ return TDS_ROLE_PROVIDER;
+ else if (0x01 == (flag & 0x01))
+ return TDS_ROLE_SEEKER;
+ else
+ return TDS_ROLE_UNSPECIFIED;
+}
+
+static unsigned char __bt_tds_set_transport_data_incomplete(
+ unsigned char flag, gboolean state)
+{
+ BT_INFO("Flag: 0x%x, Data state: %d", flag, state);
+
+ if (state)
+ flag = flag | 0x04; /* Set incomplete bit to 1 */
+ else
+ flag = flag & 0xFB; /* Set incomplete bit to 0 */
+
+ return flag;
+}
+
+static unsigned char __bt_tds_set_transport_state(
+ unsigned char flag, bluetooth_tds_transport_state_t state)
+{
+ BT_INFO("Flag: 0x%x, Transport state: %d", flag, state);
+
+ switch (state) {
+ case BLUETOOTH_TDS_TRANSPORT_STATE_OFF:
+ flag = flag & 0xE7;
+ break;
+ case BLUETOOTH_TDS_TRANSPORT_STATE_ON:
+ flag = flag & 0xE7;
+ flag = flag | 0x08;
+ break;
+ case BLUETOOTH_TDS_TRANSPORT_STATE_UNAVAILABLE:
+ flag = flag & 0xE7;
+ flag = flag | 0x10;
+ break;
+ case BLUETOOTH_TDS_TRANSPORT_STATE_RESERVED:
+ flag = flag & 0xE7;
+ flag = flag | 0x18;
+ break;
+ default:
+ BT_ERR("Invalid transport state received");
+ }
+
+ return flag;
+}
+
+static unsigned char __bt_tds_get_activation_response_code(int result)
+{
+ unsigned char resp;
+
+ switch (result) {
+ case BLUETOOTH_ERROR_NONE:
+ resp = TDS_CONTROL_POINT_RESPONSE_SUCCESS; /* Success */
+ break;
+ case BLUETOOTH_ERROR_INVALID_PARAM:
+ resp = TDS_CONTROL_POINT_RESPONSE_INVALID_PARAMETER; /*Invalid Parameter */
+ break;
+ case BLUETOOTH_ERROR_NOT_SUPPORT:
+ resp = TDS_CONTROL_POINT_RESPONSE_UNSUPPORTED_ORG_ID; /* Unsupported Organization ID*/
+ break;
+ case BLUETOOTH_ERROR_INTERNAL:
+ resp = TDS_CONTROL_POINT_RESPONSE_OPERATION_FAILED; /* */
+ break;
+ default:
+ BT_INFO("Unknown response code: %d received", result);
+ resp = TDS_CONTROL_POINT_RESPONSE_OPERATION_FAILED;
+ }
+
+ return resp;
+}
+
+static bt_tds_provider_t* __bt_tds_provider_find_from_list(const char *sender)
+{
+ GSList *l;
+
+ retv_if(sender == NULL, NULL);
+
+ for (l = provider_list; l != NULL; l = g_slist_next(l)) {
+ bt_tds_provider_t *provider = l->data;
+ if (provider && (g_strcmp0(provider->sender, sender) == 0))
+ return provider;
+ }
+
+ return NULL;
+}
+
+static unsigned char* __bt_tds_provider_get_tds_blocks(unsigned int *length)
+{
+ GSList *l;
+ GSList *l1;
+ unsigned int len = 0;
+ unsigned char data[TDS_DATA_LEN_MAX] = { 0, };
+
+ retv_if(length == NULL, NULL);
+
+ for (l = provider_list; NULL != l; l = g_slist_next(l)) {
+ bt_tds_provider_t *provider = l->data;
+
+ if (!provider)
+ continue;
+
+ for (l1 = provider->transports; l1 != NULL; l1 = g_slist_next(l1)) {
+ bt_tds_transport_info_t *transport_info = l1->data;
+
+ if (!transport_info || !transport_info->data)
+ continue;
+
+ if (len + transport_info->data_len > sizeof(data)) {
+ BT_ERR("Could not set complete the tds data, size exceeded");
+ break;
+ }
+
+ memcpy(&(data[len]), transport_info->data, transport_info->data_len);
+ len += transport_info->data_len;
+ }
+ }
+
+ *length = len;
+ BT_INFO("length = %d", *length);
+ return g_memdup(data, *length);
+}
+
+static void __bt_tds_set_scan_resp_data(bt_tds_provider_t *provider)
+{
+ bluetooth_scan_resp_data_t scan_resp;
+ char *name;
+ int adv_handle = 0;
+ int len = 0;
+ int ret;
+
+ BT_DBG("+");
+
+ name = provider->sender;
+ adv_handle = provider->adv_handle;
+
+ if (provider->manuf_data_len > 0) {
+ scan_resp.data[len++] = provider->manuf_data_len + 1;
+ scan_resp.data[len++] = BT_LE_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
+ memcpy(&(scan_resp.data[len]), provider->manuf_data, provider->manuf_data_len);
+ len += provider->manuf_data_len;
+ }
+
+ if (len <= (BLUETOOTH_SCAN_RESP_DATA_LENGTH_MAX - 2)) {
+ /* Include name */
+ scan_resp.data[len++] = 1;
+ scan_resp.data[len++] = BT_LE_AD_TYPE_COMPLETE_LOCAL_NAME;
+ }
+
+ ret = _bt_set_scan_response_data(name, adv_handle, &scan_resp, len, FALSE);
+ if (ret != BLUETOOTH_ERROR_NONE)
+ BT_ERR("Failed to set scan response data. ret: %d", ret);
+
+ BT_DBG("-");
+}
+
+/* If multi adv supported set each provider's data in seperate adv slot */
+static int __bt_tds_provider_get_tds_multi_adv_data(bt_tds_provider_t *provider, guint8 *adv_data)
+{
+ GSList *l;
+ unsigned int len = 0;
+ unsigned int max_adv_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - BT_ADV_FLAG_LEN;
+ int count;
+
+ retv_if(provider == NULL, -1);
+ retv_if(adv_data == NULL, -1);
+
+ count = g_slist_length(provider->transports);
+ adv_data[1] = BT_LE_AD_TYPE_TRANSPORT_DISCOVERY_DATA;
+ len = 2;
+
+ for (l = provider->transports; l != NULL; l = g_slist_next(l)) {
+ bt_tds_transport_info_t *transport_info = l->data;
+
+ if (!transport_info || !transport_info->data)
+ continue;
+
+ if ((len + transport_info->data_len < max_adv_len - 3) ||
+ (count <= 1 && (len + transport_info->data_len < max_adv_len))) {
+ memcpy(&(adv_data[len]), transport_info->data, transport_info->data_len);
+ len += transport_info->data_len;
+ } else {
+ /* Not able to accomodated complete data in adv pkt */
+ adv_data[len++] = transport_info->data[0]; /* Organization Id */
+ adv_data[len++] = __bt_tds_set_transport_data_incomplete(
+ transport_info->data[1], TRUE);
+ adv_data[len++] = 0; /* Set Transport data len = 0 */
+ break;
+ }
+
+ count--;
+ }
+
+ BT_INFO("len = %d", len);
+ if (len <= 2)
+ return -1; /* No data */
+
+ adv_data[0] = len - 1;
+ return len;
+}
+
+void _bt_tds_set_advertising_data_completed_cb(char *sender, int adv_handle)
+{
+ bt_tds_provider_t *provider;
+
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return;
+
+ if (provider->set_adv_data_requested) {
+ provider->set_adv_data_requested = FALSE;
+ BT_DBG("Setting adv data completed. Set response data");
+ __bt_tds_set_scan_resp_data(provider);
+ provider->set_scan_resp_data_requested = TRUE;
+ /* _bt_tds_set_advertising_data_completed_cb() will be called */
+ return;
+ }
+
+ if (provider->set_scan_resp_data_requested) {
+ bluetooth_advertising_params_t param = {0, };
+ int ret;
+
+ provider->set_scan_resp_data_requested = FALSE;
+ BT_DBG("Setting response data completed. Start advertising");
+
+ param.interval_min = 500;
+ param.interval_max = 500;
+ param.filter_policy = BLUETOOTH_ALLOW_SCAN_CONN_ALL;
+ param.type = BLUETOOTH_ADV_CONNECTABLE;
+
+ ret = _bt_set_custom_advertising(sender, adv_handle, TRUE, ¶m, FALSE);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to enable advertising. ret: %d", ret);
+ return;
+ }
+ }
+}
+
+static int __bt_tds_set_advertising(bt_tds_provider_t *provider)
+{
+ bluetooth_advertising_data_t adv;
+ char *name;
+ int adv_handle;
+ int length;
+ int ret;
+ int i;
+
+ BT_DBG("+");
+
+ name = provider->sender;
+ adv_handle = provider->adv_handle;
+
+ /* Get updated TDS advertising data */
+ length = __bt_tds_provider_get_tds_multi_adv_data(provider, adv.data);
+ if (length == 0)
+ return BLUETOOTH_ERROR_NONE;
+
+ for (i = 0; i < length; i++)
+ BT_DBG("adv_data: 0x%x", adv.data[i]);
+
+ ret = _bt_set_advertising_data(name, adv_handle, &adv, length, FALSE);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to set advertising data. ret: %d", ret);
+ return ret;
+ }
+ provider->set_adv_data_requested = TRUE;
+ /* _bt_tds_set_advertising_data_completed_cb() will be called */
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static int __bt_tds_disable_advertising(bt_tds_provider_t *provider)
+{
+ char *name;
+ int adv_handle;
+ int ret;
+
+ BT_DBG("+");
+
+ name = provider->sender;
+ adv_handle = provider->adv_handle;
+
+ /* First try to disable adv in case already advertising */
+ ret = _bt_set_advertising(name, adv_handle, FALSE, FALSE);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_DBG("Failed to disable advertising. ret: %d", ret);
+ ret = __bt_tds_set_advertising(provider);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to enable advertising. ret: %d", ret);
+ return ret;
+ }
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static int __bt_tds_provider_update_transport_data(bt_tds_provider_t *provider)
+{
+ unsigned char *buf = NULL;
+ unsigned int length = 0;
+ int ret;
+
+ BT_DBG("+");
+
+ buf = __bt_tds_provider_get_tds_blocks(&length);
+ retv_if(length == 0, BLUETOOTH_ERROR_NONE);
+ retv_if(buf == NULL, BLUETOOTH_ERROR_INTERNAL);
+
+ ret = tds_provider_set_block_data(buf, length);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("tds_provider_register() failed. ret: %d", ret);
+ return ret;
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static void __bt_free_tds_transport_info(gpointer data, gpointer user_data)
+{
+ bt_tds_transport_info_t *transport_info = data;
+
+ ret_if(transport_info == NULL);
+
+ BT_DBG("+");
+
+ g_free(transport_info->data);
+ g_free(transport_info);
+
+ BT_DBG("-");
+}
+
+static bt_tds_transport_info_t * __bt_tds_find_transport_info(
+ bt_tds_provider_t *provider, unsigned int handle)
+{
+ GSList *l;
+
+ retv_if(provider == NULL, NULL);
+
+ for (l = provider->transports; l != NULL; l = g_slist_next(l)) {
+ bt_tds_transport_info_t *transport_info = l->data;
+
+ if (!transport_info)
+ continue;
+
+ if (transport_info->tds_handle == handle)
+ return transport_info;
+ }
+
+ return NULL;
+}
+
+int _bt_tds_provider_register(const char *sender)
+{
+ bt_tds_provider_t *provider;
+ int ret;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ if (__bt_tds_provider_find_from_list(sender))
+ return BLUETOOTH_ERROR_ALREADY_INITIALIZED;
+
+ if (0 == g_slist_length(provider_list)) {
+ if (tds_enabled == FALSE) {
+ ret = tds_enable();
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("tds_enable() failed. ret: %d", ret);
+ return ret;
+ }
+ tds_enabled = TRUE;
+ }
+
+ ret = tds_provider_register();
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("tds_provider_register() failed. ret: %d", ret);
+ return ret;
+ }
+ /* Init adv_handle list */
+ __bt_init_adv_handle();
+ }
+
+ provider = g_malloc0(sizeof(bt_tds_provider_t));
+ provider->sender = g_strdup(sender);
+ provider->adv_handle = __bt_provider_get_adv_handle();
+ if (0 > provider->adv_handle) {
+ g_free(provider->sender);
+ g_free(provider);
+ return BLUETOOTH_ERROR_INTERNAL;
+ }
+
+ provider_list = g_slist_append(provider_list, provider);
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_tds_provider_unregister(const char *sender)
+{
+ bt_tds_provider_t *provider = NULL;
+ int ret;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return BLUETOOTH_ERROR_NOT_INITIALIZED;
+
+ if (1 == g_slist_length(provider_list)) {
+ ret = tds_provider_unregister();
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("tds_provider_register() failed. ret: %d", ret);
+ return ret;
+ }
+ }
+
+ /* Disable advertisement for sender */
+ ret = _bt_set_advertising(provider->sender, provider->adv_handle, FALSE, FALSE);
+ if (ret != BLUETOOTH_ERROR_NONE)
+ BT_ERR("Failed to disable advertising. ret: %d", ret);
+
+ provider_list = g_slist_remove(provider_list, provider);
+ g_slist_foreach(provider->transports, __bt_free_tds_transport_info, NULL);
+ g_slist_free(provider->transports);
+ __bt_provider_delete_adv_handle(provider->adv_handle);
+ g_free(provider->sender);
+ g_free(provider);
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_tds_provider_transport_create(const char *sender, int transport, unsigned int tds_handle)
+{
+ bt_tds_transport_info_t *transport_info;
+ bt_tds_provider_t *provider = NULL;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ if (BLUETOOTH_TDS_TRANSPORT_BT > transport ||
+ BLUETOOTH_TDS_TRANSPORT_INVALID <= transport) {
+ BT_ERR("transport value: %d not in range", transport);
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ BT_DBG("+");
+
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return BLUETOOTH_ERROR_NOT_INITIALIZED;
+
+ transport_info = g_malloc0(sizeof(bt_tds_transport_info_t));
+ transport_info->transport = transport;
+ transport_info->tds_handle = tds_handle;
+ transport_info->role = TDS_ROLE_PROVIDER;
+ transport_info->state = BLUETOOTH_TDS_TRANSPORT_STATE_OFF;
+ provider->transports = g_slist_append(provider->transports, transport_info);
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_tds_provider_transport_remove(const char *sender, unsigned int tds_handle)
+{
+ bt_tds_provider_t *provider = NULL;
+ bt_tds_transport_info_t *transport_info;
+ int ret;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return BLUETOOTH_ERROR_NOT_INITIALIZED;
+
+ transport_info = __bt_tds_find_transport_info(provider, tds_handle);
+ if (!transport_info)
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+
+ provider->transports = g_slist_remove(provider->transports, transport_info);
+ __bt_free_tds_transport_info(transport_info, NULL);
+
+ /* Set/update transport data in gatt db */
+ ret = __bt_tds_provider_update_transport_data(provider);
+ if (BLUETOOTH_ERROR_NONE != ret) {
+ BT_ERR("Failed to update transport data. ret: %d", ret);
+ return ret;
+ }
+
+ /*
+ * Disable advertising here. Later on receiving advertising disabled event,
+ * advertising will be enabled again with updated advertising data.
+ */
+ ret = __bt_tds_disable_advertising(provider);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to enable advertising. ret: %d", ret);
+ return ret;
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_tds_provider_set_manuf_data(char *sender, unsigned char *data, unsigned int len)
+{
+ bt_tds_provider_t *provider;
+ int ret;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if(len == 0 || len > TDS_MANUF_DATA_LEN_MAX, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if(data == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ BT_INFO("sender: %s", sender);
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return BLUETOOTH_ERROR_NOT_INITIALIZED;
+
+ /*
+ * Set manufacturer data and disable advertising here. Later on receiving advertising
+ * disabled event, advertising will be enabled again with updated advertising data.
+ */
+ g_free(provider->manuf_data);
+ provider->manuf_data_len = len;
+ provider->manuf_data = g_malloc0(provider->manuf_data_len);
+ memcpy(provider->manuf_data, data, len);
+
+ ret = __bt_tds_disable_advertising(provider);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to enable advertising. ret: %d", ret);
+ return ret;
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_tds_provider_set_transport_data(char *sender, int tds_handle,
+ int transport_state, unsigned char *data, unsigned int len)
+{
+ bt_tds_provider_t *provider;
+ bt_tds_transport_info_t *transport_info;
+ int ret;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if(len > 0 && data == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ if (BLUETOOTH_TDS_TRANSPORT_STATE_OFF > transport_state ||
+ BLUETOOTH_TDS_TRANSPORT_STATE_RESERVED <= transport_state) {
+ BT_ERR("transport_state value: %d not in range", transport_state);
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ BT_INFO("sender: %s, tds_handle: 0x%x", sender, tds_handle);
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return BLUETOOTH_ERROR_NOT_INITIALIZED;
+
+ transport_info = __bt_tds_find_transport_info(provider, tds_handle);
+ if (!transport_info)
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+
+ transport_info->state = transport_state;
+ g_free(transport_info->data);
+ transport_info->data_len = len + 3;
+ transport_info->data = g_malloc0(transport_info->data_len);
+ /* TDS Orgnazition Id */
+ transport_info->data[0] = __bt_tds_get_organization_id(transport_info->transport);
+ /* TDS block flag */
+ if (TDS_ROLE_SEEKER_PROVIDER != __bt_tds_get_role(transport_info->data[1]))
+ transport_info->data[1] = __bt_tds_set_role(transport_info->data[1], transport_info->role);
+ transport_info->data[1] = __bt_tds_set_transport_data_incomplete(transport_info->data[1], FALSE);
+ transport_info->data[1] = __bt_tds_set_transport_state(transport_info->data[1], transport_state);
+ /* TDS block data length */
+ transport_info->data[2] = len;
+ memcpy(&(transport_info->data[3]), data, len);
+
+ /* Set/update transport data in gatt db */
+ ret = __bt_tds_provider_update_transport_data(provider);
+ if (BLUETOOTH_ERROR_NONE != ret) {
+ BT_ERR("Failed to update transport data. ret: %d", ret);
+ return ret;
+ }
+
+ /*
+ * Disable advertising here. Later on receiving advertising disabled event,
+ * advertising will be enabled again with updated advertising data.
+ */
+ ret = __bt_tds_disable_advertising(provider);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to enable advertising. ret: %d", ret);
+ return ret;
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static int __bt_tds_send_activation_response(char *address,
+ unsigned char response, unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ retv_if(address == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if(data == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ ret = tds_provider_send_activation_response(response, data, len);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("tds_provider_register() failed. ret: %d", ret);
+ return ret;
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+int _bt_tds_provider_send_activation_response(char *sender, unsigned int tds_handle,
+ bluetooth_device_address_t *address, int response, unsigned char *data, unsigned int len)
+{
+ bt_tds_provider_t *provider;
+ bt_tds_transport_info_t *transport_info;
+ unsigned char resp;
+ char addr[BT_ADDRESS_STRING_SIZE];
+ int ret;
+
+ retv_if(sender == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if(address == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if(data == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ BT_DBG("+");
+
+ BT_INFO("sender: %s, tds_handle: 0x%x", sender, tds_handle);
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider)
+ return BLUETOOTH_ERROR_NOT_INITIALIZED;
+
+ transport_info = __bt_tds_find_transport_info(provider, tds_handle);
+ if (!transport_info)
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+
+ if (BLUETOOTH_ERROR_NONE == response) {
+ /* Activation success, set transport state enabled */
+ _bt_tds_provider_set_transport_data(provider->sender,
+ transport_info->transport, BLUETOOTH_TDS_TRANSPORT_STATE_ON,
+ transport_info->data, transport_info->data_len);
+ }
+
+ _bt_convert_addr_type_to_string(addr, address->addr);
+ resp = __bt_tds_get_activation_response_code(response);
+
+ ret = __bt_tds_send_activation_response(addr, resp, data, len);
+ if (ret != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Failed to send activation response. ret: %d", ret);
+ return ret;
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static void __bt_tds_handle_activation_request(char *address,
+ unsigned char org_id, unsigned char *data, int data_len)
+{
+ int transport;
+ GVariant *tds_data;
+ GVariant *param;
+ int count = 0;
+ GSList *l;
+ GSList *l1;
+
+ ret_if(address == NULL);
+ ret_if(data_len > 0 && data == NULL);
+
+ transport = __bt_tds_get_transport(org_id);
+ if (BLUETOOTH_TDS_TRANSPORT_INVALID == transport)
+ goto err;
+
+ BT_DBG("Address: %s, transport: 0x%x", address, transport);
+ tds_data = g_variant_new_from_data((const GVariantType *)"ay",
+ data, data_len, TRUE, NULL, NULL);
+ param = g_variant_new("(si@ay)", address, transport, tds_data);
+
+ /* Find provider with transport type in list and send event to them */
+ for (l = provider_list; l != NULL; l = g_slist_next(l)) {
+ bt_tds_provider_t *provider = l->data;
+ if (!provider)
+ continue;
+
+ for (l1 = provider->transports; l1 != NULL; l1 = g_slist_next(l1)) {
+ bt_tds_transport_info_t *transport_info = l1->data;
+
+ if (transport_info && transport_info->transport == transport) {
+ _bt_send_event_to_dest(provider->sender, BT_TDS_EVENT,
+ BLUETOOTH_EVENT_TDS_ACTIVATION_REQUESTED, param);
+ count++;
+ }
+ }
+ }
+ g_variant_unref(tds_data);
+
+ /* If no provider found for transport type, send error */
+ if (0 == count)
+ goto err;
+
+ BT_DBG("-");
+ return;
+err:
+ /* send activation response as error to bluez */
+ __bt_tds_send_activation_response(address,
+ TDS_CONTROL_POINT_RESPONSE_UNSUPPORTED_ORG_ID, NULL, 0);
+}
+
+void _bt_tds_stop_by_terminated_process(const char *name)
+{
+ bt_tds_provider_t *provider = NULL;
+
+ provider = __bt_tds_provider_find_from_list(name);
+ if (!provider)
+ return;
+
+ _bt_tds_provider_unregister(provider->sender);
+}
+
+void _bt_tds_handle_adv_disabled(const char *sender)
+{
+ bt_tds_provider_t *provider = NULL;
+
+ ret_if(sender == NULL);
+ BT_INFO("sender: %s", sender);
+
+ provider = __bt_tds_provider_find_from_list(sender);
+ if (!provider) {
+ BT_ERR("Provider not found");
+ return;
+ }
+
+ __bt_tds_set_advertising(provider);
+}
+
+static void __bt_tds_event_handler(int event_type, gpointer event_data)
+{
+ BT_INFO("OAL event = %d", event_type);
+
+ switch (event_type) {
+ case OAL_EVENT_TDS_ACTIVATION_REQUESTED: {
+ event_tds_activation_requested_t *data = event_data;
+ __bt_tds_handle_activation_request(data->address, data->org_id,
+ data->tds_data, data->data_len);
+ }
+ break;
+ }
+}
+
+int _bt_tds_init(void)
+{
+ /* Register TDS event handler */
+ _bt_service_register_event_handler_callback(BT_TDS_MODULE, __bt_tds_event_handler);
+ return BLUETOOTH_ERROR_NONE;
+}