Merge latest tizen_3.0 bug fix codes 33/113233/1
authorDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 7 Feb 2017 01:23:58 +0000 (10:23 +0900)
committerDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 7 Feb 2017 01:25:22 +0000 (10:25 +0900)
----------------------------------------------------
commit 385eeab470fd6a0f79a001095df02d6948135ad8
Author: Anupam Roy <anupam.r@samsung.com>
Date:   Fri Jan 6 18:06:38 2017 +0530
----------------------------------------------------

Change-Id: I38052f22d141bf780dab8f7258abd5fa740a64b9
Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
18 files changed:
Makefile.plugins
configure.ac
gdbus/gdbus.h
gdbus/object.c
monitor/uuid.c
packaging/500.bluez_upgrade.sh [moved from packaging/bluetoothd_upgrade.sh with 100% similarity]
packaging/bluez.spec
profiles/tds/manager.c [new file with mode: 0644]
profiles/tds/tds.c [new file with mode: 0644]
profiles/tds/tds.h [new file with mode: 0644]
src/adapter.c
src/device.c
src/gatt-client.c
src/gatt-database.c
src/profile.c
src/shared/gatt-client.c
src/shared/gatt-server.c
src/shared/gatt-server.h

index abe387f..8514c8c 100644 (file)
@@ -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
index 0363b14..fa23e13 100644 (file)
@@ -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")
index 54ab0f4..b58c486 100644 (file)
@@ -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, ...);
index ba5e4fd..cbda9a6 100644 (file)
@@ -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)
index b123ebe..90e35e1 100644 (file)
@@ -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. ( ?\92å²\9b亿è\81\94客信?????\9c\89?\90å\85¬??)" },
+       { 0xfe86, "HUAWEI Technologies Co., Ltd. ( ?\8e为?\80??\9c\89?\90å\85¬??)"                                 },
        { 0xfe85, "RF Digital Corp"                             },
        { 0xfe84, "RF Digital Corp"                             },
        { 0xfe83, "Blue Bite"                                   },
index 7acc706..95cb9a1 100644 (file)
@@ -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 (file)
index 0000000..6d13ee3
--- /dev/null
@@ -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 <config.h>
+#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 (file)
index 0000000..786bf3d
--- /dev/null
@@ -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 <config.h>
+#endif
+
+
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <time.h>
+
+#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, &param, 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 (file)
index 0000000..85b9b10
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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);
index 0180b5e..5b6b1a6 100644 (file)
@@ -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);
 
index 377e51a..04bc170 100644 (file)
@@ -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)
index bb3b8b7..87e363c 100644 (file)
@@ -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);
index 46be5a8..c734edb 100644 (file)
@@ -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,
index 93917d8..c5bd97f 100644 (file)
                <sequence>      \
                        <sequence>      \
                                <uint8 value=\"0x22\" />                \
-                               <text encoding=\"hex\" value=\"05010902a10185010901a100050919012903150025017501950381027505950181010501093009311581257f750895028106a10285010938950175081581257f8106c0c0c005010906a1018502a100050719e029e71500250175019508810295087508150025650507190029658100c0c0\" />  \
+                               <text encoding=\"hex\" value=\"05010902a10185010901a100050919012903150025017501950381027505950181010501093009311581257f750895028106a10285010938950175081581257f8106c0c0c005010906a1018502a100050719e029e71500250175019508810295087508150025650507190029658100c0c005010905A10185030901A1000930093109330934150026FF00350046FF0075089504810209397504950115002507463B016614008142750195048103050919012910750195108102C0C0\" />      \
                        </sequence>     \
                </sequence>     \
        </attribute>    \
index 3c6d7a8..9f4e075 100644 (file)
@@ -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:
index e978645..53c60f3 100644 (file)
@@ -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
index 0e480e1..c61eabe 100644 (file)
@@ -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