From: DoHyun Pyun Date: Tue, 7 Feb 2017 01:23:58 +0000 (+0900) Subject: Merge latest tizen_3.0 bug fix codes X-Git-Tag: submit/tizen/20170220.233016~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F33%2F113233%2F1;p=platform%2Fupstream%2Fbluez.git Merge latest tizen_3.0 bug fix codes ---------------------------------------------------- commit 385eeab470fd6a0f79a001095df02d6948135ad8 Author: Anupam Roy Date: Fri Jan 6 18:06:38 2017 +0530 ---------------------------------------------------- Change-Id: I38052f22d141bf780dab8f7258abd5fa740a64b9 Signed-off-by: DoHyun Pyun --- diff --git a/Makefile.plugins b/Makefile.plugins index abe387f..8514c8c 100644 --- a/Makefile.plugins +++ b/Makefile.plugins @@ -66,10 +66,10 @@ builtin_sources += profiles/network/manager.c \ profiles/network/connection.h \ profiles/network/connection.c -if WEARABLE -builtin_modules += -builtin_sources += -else +#if WEARABLE +#builtin_modules += +#builtin_sources += +#else if TIZEN_HID_PLUGIN builtin_modules += input builtin_sources += profiles/input/manager.c \ @@ -89,7 +89,7 @@ builtin_sources += profiles/input/hog.c profiles/input/uhid_copy.h \ EXTRA_DIST += profiles/input/suspend-dummy.c endif endif -endif +#endif if EXPERIMENTAL if TIZEN_HEALTH_PLUGIN @@ -129,6 +129,12 @@ builtin_sources += profiles/proximity/main.c profiles/proximity/manager.h \ profiles/proximity/immalert.c endif +if TIZEN_TDS_PLUGIN +builtin_modules += tds +builtin_sources += profiles/tds/manager.c profiles/tds/tds.h \ + profiles/tds/tds.c +endif + if TIZEN_UNUSED_PLUGIN builtin_modules += alert builtin_sources += profiles/alert/server.c diff --git a/configure.ac b/configure.ac index 0363b14..fa23e13 100644 --- a/configure.ac +++ b/configure.ac @@ -261,6 +261,10 @@ AC_ARG_ENABLE(proximity, AC_HELP_STRING([--enable-proximity], [Enable PROXIMITY Plugin]), [enable_proximity=${enableval}]) AM_CONDITIONAL(TIZEN_PROXIMITY_PLUGIN, test "${enable_proximity}" = "yes") +AC_ARG_ENABLE(tds, AC_HELP_STRING([--enable-tds], + [Enable TDS Plugin]), [enable_tds=${enableval}]) +AM_CONDITIONAL(TIZEN_TDS_PLUGIN, test "${enable_tds}" = "yes") + AC_ARG_ENABLE(tizenunusedplugin, AC_HELP_STRING([--enable-tizenunusedplugin], [Enable Unused Plugin]), [enable_tizenunusedplugin=${enableval}]) AM_CONDITIONAL(TIZEN_UNUSED_PLUGIN, test "${enable_tizenunusedplugin}" = "yes") diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index 54ab0f4..b58c486 100644 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -277,7 +277,7 @@ gboolean g_dbus_emit_signal_valist(DBusConnection *connection, const char *path, const char *interface, const char *name, int type, va_list args); -#ifdef GATT_NO_RELAY +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY gboolean g_dbus_emit_signal_to_dest(DBusConnection *connection, const char *dest, const char *path, const char *interface, const char *name, int type, ...); diff --git a/gdbus/object.c b/gdbus/object.c index ba5e4fd..cbda9a6 100644 --- a/gdbus/object.c +++ b/gdbus/object.c @@ -1674,7 +1674,7 @@ gboolean g_dbus_emit_signal(DBusConnection *connection, return result; } -#ifdef GATT_NO_RELAY +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY static gboolean g_dbus_emit_signal_valist_to_dest(DBusConnection *connection, const char *dest, const char *path, const char *interface, const char *name, int type, va_list args) diff --git a/monitor/uuid.c b/monitor/uuid.c index b123ebe..90e35e1 100644 --- a/monitor/uuid.c +++ b/monitor/uuid.c @@ -169,7 +169,7 @@ static struct { { 0x1823, "HTTP Proxy" }, { 0x1824, "Transport Discovery" }, { 0x1825, "Object Transfer" }, - /* 0x1824 to 0x27ff undefined */ + /* 0x1826 to 0x27ff undefined */ { 0x2800, "Primary Service" }, { 0x2801, "Secondary Service" }, { 0x2802, "Include" }, @@ -500,8 +500,8 @@ static struct { { 0xfe8a, "Apple, Inc." }, { 0xfe89, "B&O Play A/S" }, { 0xfe88, "SALTO SYSTEMS S.L." }, - { 0xfe87, "Qingdao Yeelink Information Technology Co., Ltd. ( 青岛亿联客信息技术有限公司 )" }, - { 0xfe86, "HUAWEI Technologies Co., Ltd. ( 华为技术有限公司 )" }, + { 0xfe87, "Qingdao Yeelink Information Technology Co., Ltd. ( ?’岛亿联客信?????œ‰?å…¬??)" }, + { 0xfe86, "HUAWEI Technologies Co., Ltd. ( ?Žä¸º?€??œ‰?å…¬??)" }, { 0xfe85, "RF Digital Corp" }, { 0xfe84, "RF Digital Corp" }, { 0xfe83, "Blue Bite" }, diff --git a/packaging/bluetoothd_upgrade.sh b/packaging/500.bluez_upgrade.sh similarity index 100% rename from packaging/bluetoothd_upgrade.sh rename to packaging/500.bluez_upgrade.sh diff --git a/packaging/bluez.spec b/packaging/bluez.spec index 7acc706..95cb9a1 100644 --- a/packaging/bluez.spec +++ b/packaging/bluez.spec @@ -300,7 +300,7 @@ ln -sf ../bluetooth-frwk.service %{buildroot}%{_libpath}/systemd/system/multi-us #endif mkdir -p %{buildroot}%{upgrade_script_path} -cp -f packaging/bluetoothd_upgrade.sh %{buildroot}%{upgrade_script_path} +cp -f packaging/500.bluez_upgrade.sh %{buildroot}%{upgrade_script_path} %post -n libbluetooth -p /sbin/ldconfig @@ -339,7 +339,7 @@ popd #%{_sbindir}/hid2hci %dir /usr/lib/udev /usr/lib/udev/* -%{upgrade_script_path}/bluetoothd_upgrade.sh +%{upgrade_script_path}/500.bluez_upgrade.sh #test -2 %exclude /%{_libpath}/systemd/system/bluetooth.service diff --git a/profiles/tds/manager.c b/profiles/tds/manager.c new file mode 100644 index 0000000..6d13ee3 --- /dev/null +++ b/profiles/tds/manager.c @@ -0,0 +1,68 @@ +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2016 Samsung Electronics Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "lib/bluetooth.h" +#include "lib/uuid.h" +#include "src/plugin.h" + +#include "gdbus/gdbus.h" + +#include "src/adapter.h" +#include "src/profile.h" + +#include "tds.h" + +int tds_provider_adapter_probe(struct btd_profile *p, + struct btd_adapter *adapter) +{ + tds_register_provider_interface(adapter); + return 0; +} + +void tds_provider_adapter_remove(struct btd_profile *p, + struct btd_adapter *adapter) +{ + tds_unregister_provider_interface(adapter); +} + +static struct btd_profile tds_provider = { + .name = "TDS Provider GATT Driver", + .remote_uuid = GATT_UUID, + .adapter_probe = tds_provider_adapter_probe, + .adapter_remove = tds_provider_adapter_remove, +}; + +static int tds_provider_init(void) +{ + return btd_profile_register(&tds_provider); +} + +static void tds_provider_exit(void) +{ + btd_profile_unregister(&tds_provider); +} + +BLUETOOTH_PLUGIN_DEFINE(tds, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + tds_provider_init, tds_provider_exit) diff --git a/profiles/tds/tds.c b/profiles/tds/tds.c new file mode 100644 index 0000000..786bf3d --- /dev/null +++ b/profiles/tds/tds.c @@ -0,0 +1,785 @@ +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2016 Samsung Electronics Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include + +#include + +#include +#include + +#include "lib/bluetooth.h" +#include "lib/sdp.h" +#include "lib/uuid.h" +#include "src/plugin.h" + +#include "gdbus/gdbus.h" + +#include "src/error.h" +#include "src/log.h" +#include "src/adapter.h" + +#include "attrib/gattrib.h" +#include "attrib/att.h" +#include "attrib/gatt.h" +#include "attrib/att-database.h" +#include "attrib/gatt-service.h" + +#include "src/shared/gatt-server.h" +#include "src/attrib-server.h" +#include "src/device.h" +#include "src/profile.h" +#include "src/attio.h" +#include "src/dbus-common.h" + +#include "tds.h" + +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/att.h" + #include "btio/btio.h" +#include "src/gatt-database.h" +#endif + + +#define TDS_USER_CHARACTERITIC_UUID 0x2af6 +#define TDS_USER_CHARACTERITIC_DESCRIPTOR_UUID 0x2a56 + +/* TDS Block Data */ +struct tds_block_data { + uint8_t *val; + unsigned int len; +}; + +/* pointer to User characteristic data */ +static struct tds_block_data *ptr = NULL; + +/* Adapter Instance for the provider */ +struct tds_service_adapter { + struct btd_adapter *adapter; + struct gatt_db_attribute *service; + GSList *connected_devices; +}; + +static GSList *tds_service_adapters; + +struct connected_device { + struct btd_device *device; + struct tds_service_adapter *adapter; + guint callback_id; + uint16_t gatt_chr_handle; + unsigned int timeout_id; + bool tds_control_point_ccc_enabled; +}; + +static int tds_adapter_cmp(gconstpointer a, gconstpointer b) +{ + const struct tds_service_adapter *tdsadapter = a; + const struct btd_adapter *adapter = b; + + if (tdsadapter->adapter == adapter) + return 0; + + return -1; +} + +static struct tds_service_adapter * +find_tds_service_adapter(struct btd_adapter *adapter) +{ + GSList *l = g_slist_find_custom(tds_service_adapters, adapter, + tds_adapter_cmp); + if (!l) + return NULL; + + return l->data; +} + +static int device_cmp(gconstpointer a, gconstpointer b) +{ + const struct connected_device *condev = a; + const struct btd_device *device = b; + + if (condev->device == device) + return 0; + + return -1; +} + +static struct connected_device * +find_connected_device(struct tds_service_adapter *adapter, struct btd_device *device) +{ + GSList *l = g_slist_find_custom(adapter->connected_devices, device, + device_cmp); + if (!l) + return NULL; + + return l->data; +} + +static void indication_cfm_cb(void *user_data) +{ + struct connected_device *condev = user_data; + DBG("Received confirmation of Indication Confirmation"); + g_dbus_emit_signal(btd_get_dbus_connection(), device_get_path(condev->device), + TDS_SERVICE_PROVIDER_INTERFACE, "TdsActivationIndCnfm", + DBUS_TYPE_INVALID); +} + +static DBusMessage *tds_activation_response(DBusConnection *connection, + DBusMessage *msg, void *user_data) +{ + struct connected_device *condev = user_data; + uint8_t *value; + int32_t len = 0; + uint8_t result = 0x04; /* Operation Failed */ + int k; /* Debug */ + uint8_t *pdu = NULL; + + DBG("+"); + if (condev->tds_control_point_ccc_enabled == false) { + DBG("CCCD is disabled, can not send indication to remote device"); + return dbus_message_new_method_return(msg); + } + + if (condev->timeout_id == 0) { + DBG("Timer is not running: either no request pending or response came late!!"); + return btd_error_failed(msg, "TDS Activation Request not pending"); + } + + /* Remove & reset Timer */ + g_source_remove(condev->timeout_id); + condev->timeout_id = 0; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_BYTE, &result, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len, + DBUS_TYPE_INVALID)) + return btd_error_invalid_args(msg); + + DBG("Result [0x%x] data length [%d]", result, len); + + for(k=0; k < len ; k++) + DBG("Data[%d] = [0x%x]", k, value[k]); + + switch(result) { + case 0x00: + DBG("Success"); + break; + case 0x02: + DBG("Invalid Parameter"); + break; + case 0x03: + DBG("Unsupported Organization ID"); + break; + case 0x04: + DBG("Operation Failed"); + break; + default: + return btd_error_invalid_args(msg); + } + + pdu = g_malloc0(sizeof(uint8_t)* (2+ len)); + pdu[0] = 0x01; /* Opcode - TDS Control Point Activation Request */ + pdu[1] = result; + + if (len > 0) { + memcpy(pdu+2, value, len); + } else { + DBG("TDS Response with no parameters"); + } + + DBG("Send Indication to device [%s], chr handle [%d]", device_get_path(condev->device), condev->gatt_chr_handle); + + if (!bt_gatt_server_send_indication(btd_device_get_gatt_server(condev->device), + condev->gatt_chr_handle, + pdu, (2+len), indication_cfm_cb, condev, NULL)) + DBG("Sending Indication Failed!!"); + else + DBG("Sending Indication Successful, wait for confirmation!!"); + + g_free(pdu); + DBG("-"); + return dbus_message_new_method_return(msg); +} + +static void tds_client_remove_condev(struct connected_device *condev) +{ + struct tds_service_adapter *a; + + if (!condev) + return; + + a = condev->adapter; + + if (condev->callback_id && condev->device) + btd_device_remove_attio_callback(condev->device, + condev->callback_id); + + if (condev->device) + btd_device_unref(condev->device); + + a->connected_devices = g_slist_remove(a->connected_devices, condev); + g_free(condev); +} + +static void tds_client_disc_cb(gpointer user_data) +{ + struct connected_device *condev = user_data; + + if (!condev) + return; + + /* Unregister Interface */ + g_dbus_unregister_interface(btd_get_dbus_connection(), + device_get_path(condev->device), + TDS_SERVICE_PROVIDER_INTERFACE); + + DBG("TDS Client remove device %p", condev->device); + tds_client_remove_condev(condev); +} + +static const GDBusSignalTable tds_signals[] = { + { GDBUS_SIGNAL("TdsActivationRequested", + GDBUS_ARGS({ "org_id", "y"}, + { "TdsDataBlock", "ay"})) }, + { GDBUS_SIGNAL("TdsActivationIndCnfm", NULL) }, +}; + +static const GDBusMethodTable tds_methods[] = { + { GDBUS_ASYNC_METHOD("TdsActivationResponse", + GDBUS_ARGS({ "result", "y" }, { "response_param", "ay" }), NULL, + tds_activation_response) }, + { } +}; + +static bool indication_wait_cb(gpointer user_data) +{ + struct connected_device *condev = (struct connected_device *)user_data; + uint16_t len = 2; + uint8_t pdu[2]; + DBG("Indication Timer Expired!!"); + condev->timeout_id = 0; + + if (!condev->tds_control_point_ccc_enabled) { + DBG("CCCD is not Enabled!! No need to send indication"); + return false; + } else { + DBG("CCCD is Enabled!!..Send Indication with Operation Failed!"); + } + + pdu[0] = 0x01; /* Op Code: Activation Request */ + pdu[1] = 0x04; /* Result: Operation Failed*/ + + DBG("Send Indication to device [%s], chr handle [%d]", device_get_path(condev->device), condev->gatt_chr_handle); + + if (!bt_gatt_server_send_indication(btd_device_get_gatt_server(condev->device), + condev->gatt_chr_handle, + pdu, len, indication_cfm_cb, condev, NULL)) + DBG("Sending Indication Failed!!"); + else + DBG("Sending Indication Successful, wait for confirmation!!"); + + return false; +} + +static void tds_control_point_char_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + DBG("len [%d]", len); + DBG("Opcode [%d]", opcode); + DBG("TRansaction ID [%d]", id); + DBG("Offset [%d]", offset); + + uint8_t ecode = 0; + struct btd_device *device = NULL; + struct tds_service_adapter *tsadapter = user_data; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + struct connected_device *condev = NULL; + int k; + const uint8_t *param = NULL; + + if (!value || len < 2) { + ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto done; + } + + if (offset != 0) { + ecode = BT_ATT_ERROR_INVALID_OFFSET; + goto done; + } + + if (!bt_att_get_remote_addr(att, &bdaddr, &bdaddr_type)) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + device = btd_adapter_get_device(tsadapter->adapter, &bdaddr, bdaddr_type); + + if (!device) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + DBG("Device path [%s]", device_get_path(device)); + + /* Create Connected device and Register SIgnal Interface */ + condev = find_connected_device(tsadapter, device); + + if (!condev) { + DBG("Device is NULL..create device"); + condev = g_new0(struct connected_device, 1); + condev->device = btd_device_ref(device); + condev->adapter = tsadapter; + condev->callback_id = btd_device_add_attio_callback(device, + NULL, tds_client_disc_cb, condev); + + tsadapter->connected_devices = g_slist_append(tsadapter->connected_devices, + condev); + DBG("added connected dev %p", device); + /* Register Signal on Device Interface */ + if (!g_dbus_register_interface(btd_get_dbus_connection(), device_get_path(device), + TDS_SERVICE_PROVIDER_INTERFACE, + tds_methods, tds_signals, + NULL, + condev, NULL)) { + error("Unable to register TDS Activation Signal"); + tds_client_remove_condev(condev); + goto done; + } + } + + if (condev->timeout_id) { + DBG("Already one activation request is under progress from device [%s]", device_get_path(device)); + ecode = BT_ERROR_ALREADY_IN_PROGRESS; + goto done; + } + + condev->gatt_chr_handle = gatt_db_attribute_get_handle(attrib); + DBG("Characteristic Attribute handle [0x%x]", condev->gatt_chr_handle); + + /* Write value should be anyone of 0x00, 0x01, 0x02 */ + switch(value[0]) { + case 0x00: { + DBG("Opcode reserved for future use"); + ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; + goto done; + } + case 0x01: { + DBG("TDS Control Point Activation Request"); + break; + } + default: { + DBG("Invalid Opcode [0x%x]", value[0]); + ecode = 0x80; + goto done; + } + } + + for(k=0; k < len; k++) + DBG("@@TDS Control Point [%d] 0x%x", k, value[k]); + + /* Success case*/ + if (gatt_db_attribute_write_result(attrib, id, ecode)) { + DBG("TDS Control Point Activation write resp sent successfully!!"); + /* Emit Signal */ + len = len -2; + + if (len > 0) { + param = &value[2]; + } + g_dbus_emit_signal(btd_get_dbus_connection(), device_get_path(device), + TDS_SERVICE_PROVIDER_INTERFACE, "TdsActivationRequested", + DBUS_TYPE_BYTE, &value[1], + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, ¶m, len, + DBUS_TYPE_INVALID); + + /* Start timer for max 10 seconds to wait for Indication from app */ + if (condev->tds_control_point_ccc_enabled) { + DBG("Control point is enabled for device [%s] start the Indication Timer", device_get_path(device)); + if (condev->timeout_id) + g_source_remove(condev->timeout_id); + condev->timeout_id = g_timeout_add(10000, (GSourceFunc)indication_wait_cb, condev); + } else { + DBG("Control point is Not enabled for device [%s] Dont start the Indication Timer",device_get_path(device)); + } + } else { + DBG("TDS Control Point Activation write resp sending failed!!!"); + } + + return; +done: + gatt_db_attribute_write_result(attrib, id, ecode); +} + +static void tds_user_data_descriptor_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + DBG("TDS User Characteritsic descriptor Read requested.."); + + if (!ptr) { + DBG("TDS Block data still not set"); + gatt_db_attribute_read_result(attrib, id, 0, NULL, 0); + } else { + gatt_db_attribute_read_result(attrib, id, 0, ptr->val, ptr->len); + } +} + +static void tds_control_point_ccc_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct tds_service_adapter *adapter = user_data; + struct btd_device *device = NULL; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + struct connected_device *condev = NULL; + uint8_t ecode = 0; + uint8_t value[2]; + DBG("TDS Control Point CCC Read requested.."); + + if (!bt_att_get_remote_addr(att, &bdaddr, &bdaddr_type)) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + device = btd_adapter_get_device(adapter->adapter, &bdaddr, bdaddr_type); + + if (!device) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + DBG("Device path [%s]", device_get_path(device)); + + /* Create Connected device and Register Signal Interface */ + condev = find_connected_device(adapter, device); + if (!condev) { + DBG("Device is not created yet, default CCCD value is Disabled"); + value[0] = 0x00; + } else { + DBG("CCCD is [%s] for device [%s]", condev->tds_control_point_ccc_enabled ? "Enabled" : "Disabled", device_get_path(device)); + value[0] = condev->tds_control_point_ccc_enabled; + } + + value[1] = 0x00; + +done: + gatt_db_attribute_read_result(attrib, id, ecode, value, 2); +} + + +static void tds_user_char_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + uint8_t value[1]; + DBG("TDS user char Read requested.."); + value[0] = 0x01; + gatt_db_attribute_read_result(attrib, id, 0, value, 1); +} + +static void tds_control_point_ccc_write_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct tds_service_adapter *adapter = user_data; + struct btd_device *device = NULL; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + struct connected_device *condev = NULL; + uint8_t ecode = 0; + DBG("TDS Control Point CCC Write requested..len [%d] val [0x%x] val [0x%x]", len, value[0], value[1]); + + if (!value || len != 2) { + ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto done; + } + + if (offset) { + ecode = BT_ATT_ERROR_INVALID_OFFSET; + goto done; + } + + if (!bt_att_get_remote_addr(att, &bdaddr, &bdaddr_type)) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + device = btd_adapter_get_device(adapter->adapter, &bdaddr, bdaddr_type); + + if (!device) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + DBG("Device path [%s]", device_get_path(device)); + + /* Create Connected device and Register Signal Interface */ + condev = find_connected_device(adapter, device); + + if (!condev) { + DBG("Device is NULL..create device"); + condev = g_new0(struct connected_device, 1); + condev->device = btd_device_ref(device); + condev->adapter = adapter; + condev->callback_id = btd_device_add_attio_callback(device, + NULL, tds_client_disc_cb, condev); + + adapter->connected_devices = g_slist_append(adapter->connected_devices, + condev); + DBG("added connected dev %p", device); + + /* Register Signal on Device Interface */ + if (!g_dbus_register_interface(btd_get_dbus_connection(), device_get_path(device), + TDS_SERVICE_PROVIDER_INTERFACE, + tds_methods, tds_signals, + NULL, + condev, NULL)) { + error("Unable to register TDS Activation Signal"); + tds_client_remove_condev(condev); + goto done; + } + } + + if (value[0] == 0x00) { + DBG("CCCD is Disabled by Client [%s]", device_get_path(device)); + condev->tds_control_point_ccc_enabled = false; + } else if (value[0] == 0x02) { /* Indication */ + if (condev->tds_control_point_ccc_enabled) { + DBG("TDS Control point CCCD Already Enabled\n"); + goto done; + } + + DBG("CCCD is Enabled by Client [%s]", device_get_path(device)); + condev->tds_control_point_ccc_enabled = true; + } else + ecode = 0x80; + + DBG("TDS Server: Control Point Enabled: [%s]\n", + condev->tds_control_point_ccc_enabled ? "true" : "false"); + +done: + gatt_db_attribute_write_result(attrib, id, ecode); +} + +void tds_service_unregister(struct tds_service_adapter *tsadapter) +{ + DBG("TDS Service UnRegister.."); + struct gatt_db *db; + + /* Remove registered service */ + if (tsadapter->service) { + db = (struct gatt_db *) btd_gatt_database_get_db(btd_adapter_get_database(tsadapter->adapter)); + gatt_db_remove_service(db, tsadapter->service); + } + + if (ptr) { + g_free(ptr->val); + g_free(ptr); + ptr = NULL; + } +} + +void tds_service_register(struct tds_service_adapter *tsadapter) +{ + DBG("TDS Service Register.."); + struct gatt_db_attribute *service, *char_tds_control, *char_user_char, *desc_tds_ccc, *desc_user; + struct gatt_db *db; + + bt_uuid_t uuid; + bt_uuid16_create(&uuid, TRANSPORT_DISCOVERY_SERVICE_UUID); + + db = (struct gatt_db *) btd_gatt_database_get_db(btd_adapter_get_database(tsadapter->adapter)); + + /* + * TDS Primary Service + */ + service = gatt_db_add_service(db, &uuid, true, 7); + if (!service) + goto err; + + tsadapter->service = service; + DBG("TDS Primary Service added"); + + /* + * TDS Control Point characteristic. + */ + bt_uuid16_create(&uuid, TDS_CONTROL_POINT_CHARACTERISTIC_UUID); + char_tds_control = gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE | BT_GATT_CHRC_PROP_INDICATE, + NULL, /* Non Readable */ + tds_control_point_char_write, tsadapter); + + if (!char_tds_control) + goto err; + DBG("TDS Control Point char added"); + + + bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); + desc_tds_ccc = gatt_db_service_add_descriptor(char_tds_control, &uuid, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, + tds_control_point_ccc_read_cb, + tds_control_point_ccc_write_cb, tsadapter); + + if (!desc_tds_ccc) + goto err; + DBG("TDS Control Point CCCD added"); + /* + * TDS User characteristic. + */ + bt_uuid16_create(&uuid, TDS_USER_CHARACTERITIC_UUID); + char_user_char = gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_NONE, + BT_ATT_PERM_READ, + tds_user_char_read_cb, + NULL, /* Non Writable */ + NULL); + + if (!char_user_char) + goto err; + + DBG("TDS User Characteristic added"); + bt_uuid16_create(&uuid, TDS_USER_CHARACTERITIC_DESCRIPTOR_UUID); + desc_user = gatt_db_service_add_descriptor(char_user_char, &uuid, + BT_ATT_PERM_READ, + tds_user_data_descriptor_read_cb, + NULL, /* Non Writable */ + tsadapter); + if (!desc_user) + goto err; + + DBG("TDS User Char Descriptor added..."); + gatt_db_service_set_active(service, true); + + DBG("TDS Service activated"); + return; + +err: + error("Error adding TDS service"); + tds_service_unregister(tsadapter); +} + +static DBusMessage *register_tds_proider(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + DBG("TDS Provider Register"); + struct tds_service_adapter *tsadapter = user_data; + + if (tsadapter->adapter == NULL) { + DBG("Adapter is NULL"); + return btd_error_invalid_args(msg); + } + + tds_service_register(tsadapter); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *set_tds_block_data(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + uint8_t *value; + int32_t len = 0; + + DBG("Set TDS Block data"); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len, + DBUS_TYPE_INVALID)) + return btd_error_invalid_args(msg); + + /*TODO Max length to be checked*/ + if (len < 1) + return btd_error_invalid_args(msg); + + if (ptr) { + g_free(ptr->val); + g_free(ptr); + } + ptr = g_malloc0(sizeof(struct tds_block_data)); + ptr->val = g_memdup(value, len); + ptr->len = len; + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *unregister_tds_provider(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct tds_service_adapter *tsadapter = user_data; + + if (tsadapter->adapter == NULL) { + DBG("Adapter is NULL"); + return btd_error_invalid_args(msg); + } + + tds_service_unregister(tsadapter); + return dbus_message_new_method_return(msg); +} + +static const GDBusMethodTable tds_provider_adapter_methods[] = { + { GDBUS_METHOD("RegisterTdsProvider", NULL, NULL, + register_tds_proider) }, + { GDBUS_METHOD("UnregisterTdsProvider", NULL, NULL, + unregister_tds_provider) }, + { GDBUS_METHOD("SetTdsBlockData", + GDBUS_ARGS({ "value", "ay" }), NULL, + set_tds_block_data) }, + { } +}; + +void tds_unregister_provider_interface(struct btd_adapter *adapter) +{ + struct tds_service_adapter *tsadapter = find_tds_service_adapter(adapter); + if (!tsadapter) + return; + tds_service_unregister(tsadapter); + + tds_service_adapters = g_slist_remove(tds_service_adapters, tsadapter); + g_free(tsadapter); +} + +void tds_register_provider_interface(struct btd_adapter *adapter) +{ + struct tds_service_adapter *tsadapter; + const char *path = adapter_get_path(adapter); + + tsadapter = g_new0(struct tds_service_adapter, 1); + tsadapter->adapter = adapter; + + g_dbus_register_interface(btd_get_dbus_connection(), path, + TDS_SERVICE_PROVIDER_INTERFACE, + tds_provider_adapter_methods, + NULL, NULL, tsadapter, NULL); + tds_service_adapters = g_slist_append(tds_service_adapters, tsadapter); +} diff --git a/profiles/tds/tds.h b/profiles/tds/tds.h new file mode 100644 index 0000000..85b9b10 --- /dev/null +++ b/profiles/tds/tds.h @@ -0,0 +1,34 @@ +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011 Nokia Corporation + * Copyright (C) 2011 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define TRANSPORT_DISCOVERY_SERVICE_UUID 0x1824 +#define TDS_CONTROL_POINT_CHARACTERISTIC_UUID 0x2abc + +#define TDS_USER_CHARACTERITIC_UUID 0x2af6 +#define TDS_USER_CHARACTERITIC_DESCRIPTOR_UUID 0x2a56 + +#define TDS_SERVICE_PROVIDER_INTERFACE "org.bluez.TdsServiceProvider1" + +void tds_register_provider_interface(struct btd_adapter *adapter); + +void tds_unregister_provider_interface(struct btd_adapter *adapter); diff --git a/src/adapter.c b/src/adapter.c index 0180b5e..5b6b1a6 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -4019,7 +4019,6 @@ static DBusMessage *adapter_stop_le_discovery(DBusConnection *conn, adapter->le_discovery_idle_timeout = 0; } #endif - if (!(adapter->current_settings & MGMT_SETTING_POWERED)) return btd_error_not_ready(msg); diff --git a/src/device.c b/src/device.c index 377e51a..04bc170 100644 --- a/src/device.c +++ b/src/device.c @@ -6356,6 +6356,20 @@ done: attio_cleanup(device); } +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY +static void att_mtu_changed(uint16_t mtu, void *user_data) +{ + struct btd_device *device = user_data; + + DBG("att mtu changed %d", mtu); + + g_dbus_emit_signal(dbus_conn, device->path, + DEVICE_INTERFACE, "AttMtuChanged", + DBUS_TYPE_UINT16, &mtu, + DBUS_TYPE_INVALID); +} +#endif + static void register_gatt_services(struct btd_device *device) { struct browse_req *req = device->browse; @@ -6504,6 +6518,15 @@ static void gatt_server_init(struct btd_device *device, struct gatt_db *db) error("Failed to initialize bt_gatt_server"); bt_gatt_server_set_debug(device->server, gatt_debug, NULL, NULL); + +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY + if (!bt_gatt_server_set_mtu_changed(device->server, + att_mtu_changed, + device, NULL)) { + DBG("Failed to set mtu changed handler"); + return; + } +#endif } static bool local_counter(uint32_t *sign_cnt, void *user_data) diff --git a/src/gatt-client.c b/src/gatt-client.c index bb3b8b7..87e363c 100644 --- a/src/gatt-client.c +++ b/src/gatt-client.c @@ -1247,7 +1247,6 @@ void gatt_characteristic_value_changed(struct notify_client *client, const uint8 char *chrc_path = strdup(chrc->path); dbus_int32_t result = 0; -#ifdef GATT_NO_RELAY g_dbus_emit_signal_to_dest(btd_get_dbus_connection(), client->owner, chrc_path, GATT_CHARACTERISTIC_IFACE, "GattValueChanged", @@ -1255,14 +1254,6 @@ void gatt_characteristic_value_changed(struct notify_client *client, const uint8 DBUS_TYPE_STRING, &chrc_path, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len, DBUS_TYPE_INVALID); -#else - g_dbus_emit_signal(btd_get_dbus_connection(), chrc->path, - GATT_CHARACTERISTIC_IFACE, "GattValueChanged", - DBUS_TYPE_INT32, &result, - DBUS_TYPE_STRING, &chrc_path, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len, - DBUS_TYPE_INVALID); -#endif if (chrc_path) free(chrc_path); diff --git a/src/gatt-database.c b/src/gatt-database.c index 46be5a8..c734edb 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -2508,19 +2508,17 @@ struct write_without_response_data { static void write_without_response_setup_cb(DBusMessageIter *iter, void *user_data) { -#ifdef TIZEN_FEATURE_BLUEZ_MODIFY + DBusMessageIter array; +#ifndef TIZEN_FEATURE_BLUEZ_MODIFY + struct iovec *iov = user_data; +#else struct write_without_response_data *write_data = user_data; struct iovec *iov = write_data->iov; char dst_addr[18]; char *addr_str = dst_addr; uint16_t offset = 0; gboolean response_needed = FALSE; -#else - struct iovec *iov = user_data; -#endif - DBusMessageIter array; -#ifdef TIZEN_FEATURE_BLUEZ_MODIFY ba2str(&write_data->dst_addr, dst_addr); dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &addr_str); dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &write_data->id); @@ -2534,6 +2532,7 @@ static void write_without_response_setup_cb(DBusMessageIter *iter, dbus_message_iter_close_container(iter, &array); } +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY static void send_write_without_response(struct gatt_db_attribute *attrib, struct bt_att *att, GDBusProxy *proxy, unsigned int id, @@ -2541,14 +2540,11 @@ static void send_write_without_response(struct gatt_db_attribute *attrib, { struct iovec iov; uint8_t ecode = 0; -#ifdef TIZEN_FEATURE_BLUEZ_MODIFY struct write_without_response_data write_data; -#endif iov.iov_base = (uint8_t *) value; iov.iov_len = len; -#ifdef TIZEN_FEATURE_BLUEZ_MODIFY write_data.id = id; write_data.iov = &iov; get_dst_info(att, &write_data.dst_addr, &write_data.dst_addr_type); @@ -2557,15 +2553,28 @@ static void send_write_without_response(struct gatt_db_attribute *attrib, write_without_response_setup_cb, NULL, &write_data, NULL)) ecode = BT_ATT_ERROR_UNLIKELY; + + gatt_db_attribute_write_result(attrib, id, ecode); +} #else +static void send_write_without_response(struct gatt_db_attribute *attrib, + GDBusProxy *proxy, unsigned int id, + const uint8_t *value, size_t len) +{ + struct iovec iov; + uint8_t ecode = 0; + + iov.iov_base = (uint8_t *) value; + iov.iov_len = len; + if (!g_dbus_proxy_method_call(proxy, "WriteValue", write_without_response_setup_cb, NULL, &iov, NULL)) ecode = BT_ATT_ERROR_UNLIKELY; -#endif gatt_db_attribute_write_result(attrib, id, ecode); } +#endif static void chrc_write_cb(struct gatt_db_attribute *attrib, unsigned int id, uint16_t offset, diff --git a/src/profile.c b/src/profile.c index 93917d8..c5bd97f 100644 --- a/src/profile.c +++ b/src/profile.c @@ -857,7 +857,7 @@ \ \ \ - \ + \ \ \ \ diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index 3c6d7a8..9f4e075 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -1181,7 +1181,7 @@ static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data) } util_debug(client->debug_callback, client->debug_data, - "MTU exchange complete, with MTU: %u", + "att client MTU exchange complete, with MTU: %u", bt_att_get_mtu(client->att)); discover: diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c index e978645..53c60f3 100644 --- a/src/shared/gatt-server.c +++ b/src/shared/gatt-server.c @@ -110,6 +110,12 @@ struct bt_gatt_server { bt_gatt_server_debug_func_t debug_callback; bt_gatt_server_destroy_func_t debug_destroy; void *debug_data; + +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY + bt_gatt_server_mtu_changed_callback_t mtu_chngd_callback; + bt_gatt_server_destroy_func_t mtu_chngd_destroy; + void *mtu_chngd_data; +#endif }; static void bt_gatt_server_free(struct bt_gatt_server *server) @@ -1304,7 +1310,7 @@ static void exchange_mtu_cb(uint8_t opcode, const void *pdu, } client_rx_mtu = get_le16(pdu); -#ifndef __TIZEN_PACTH__ +#ifndef TIZEN_FEATURE_BLUEZ_MODIFY final_mtu = MAX(MIN(client_rx_mtu, server->mtu), BT_ATT_DEFAULT_LE_MTU); /* Respond with the server MTU */ @@ -1326,10 +1332,13 @@ static void exchange_mtu_cb(uint8_t opcode, const void *pdu, put_le16(server->mtu, rsp_pdu); bt_att_send(server->att, BT_ATT_OP_MTU_RSP, rsp_pdu, 2, NULL, NULL, NULL); + + if (server->mtu_chngd_callback) + server->mtu_chngd_callback(final_mtu, server->mtu_chngd_data); #endif util_debug(server->debug_callback, server->debug_data, - "MTU exchange complete, with MTU: %u", final_mtu); + "att server MTU exchange complete, with MTU: %u", final_mtu); } static bool gatt_server_register_att_handlers(struct bt_gatt_server *server) @@ -1581,3 +1590,23 @@ bool bt_gatt_server_send_indication(struct bt_gatt_server *server, return result; } + +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY +bool bt_gatt_server_set_mtu_changed(struct bt_gatt_server *server, + bt_gatt_server_mtu_changed_callback_t callback, + void *user_data, + bt_gatt_server_destroy_func_t destroy) +{ + if (!server) + return false; + + if (server->mtu_chngd_destroy) + server->mtu_chngd_destroy(server->mtu_chngd_data); + + server->mtu_chngd_callback = callback; + server->mtu_chngd_destroy = destroy; + server->mtu_chngd_data = user_data; + + return true; +} +#endif diff --git a/src/shared/gatt-server.h b/src/shared/gatt-server.h index 0e480e1..c61eabe 100644 --- a/src/shared/gatt-server.h +++ b/src/shared/gatt-server.h @@ -50,3 +50,14 @@ bool bt_gatt_server_send_indication(struct bt_gatt_server *server, bt_gatt_server_conf_func_t callback, void *user_data, bt_gatt_server_destroy_func_t destroy); + +#ifdef TIZEN_FEATURE_BLUEZ_MODIFY +typedef void (*bt_gatt_server_mtu_changed_callback_t)(uint16_t mtu, + void *user_data); + +bool bt_gatt_server_set_mtu_changed(struct bt_gatt_server *server, + bt_gatt_server_mtu_changed_callback_t callback, + void *user_data, + bt_gatt_server_destroy_func_t destroy); + +#endif