#include <stdbool.h>
#include <stddef.h>
#include <string.h>
+#include <fcntl.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-adapter-le.h"
#include "bt-hal-event-receiver.h"
+#define NUMBER_OF_FLAGS 10
+
+#define GATT_SERV_INTERFACE "org.bluez.GattService1"
+#define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1"
+#define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1"
+
+#define BT_GATT_SERVICE_NAME "org.frwk.gatt_service"
+#define GATT_SERV_OBJECT_PATH "/service"
+
+static GDBusProxy *manager_gproxy = NULL;
+
/************************************************************************************
** Static variables
************************************************************************************/
extern const btgatt_callbacks_t *bt_gatt_callbacks;
+guint owner_id;
+GDBusConnection *g_conn = NULL;
+//GDBusConnection *conn = NULL;
+GDBusNodeInfo *manager_node_info = NULL;
+guint manager_id;
+
+/* Global handles which needs to be incremented during each addition */
+static int gatt_service_handle = 10;
+static int gatt_char_handle = 20;
+static int gatt_desc_handle = 30;
+
+struct gatt_service_info {
+ gchar *serv_path;
+ guint serv_id;
+ gchar *service_uuid;
+ guint manager_id;
+ guint prop_id;
+ GSList *char_data;
+ gboolean is_svc_registered;
+ gboolean is_svc_primary;
+ int service_handle;
+};
+
+struct gatt_char_info {
+ gchar *char_path;
+ guint char_id;
+ gchar *char_uuid;
+ gchar *char_value;
+ gchar *char_flags[NUMBER_OF_FLAGS];
+ int value_length;
+ int flags_length;
+ int char_handle;
+ GSList *desc_data;
+};
+
+struct gatt_desc_info {
+ gchar *desc_path;
+ guint desc_id;
+ gchar *desc_uuid;
+ gchar *desc_value;
+ gchar *desc_flags[NUMBER_OF_FLAGS];
+ int value_length;
+ int flags_length;
+ int desc_handle;
+};
+
+/**
+ * GATT Server Request type
+ */
+typedef enum {
+ BT_HAL_GATT_REQUEST_TYPE_READ = 0x00, /* Read Requested */
+ BT_HAL_GATT_REQUEST_TYPE_WRITE = 0x01, /* Write Requested */
+ BT_HAL_GATT_REQUEST_TYPE_EXEC_WRITE = 0x02, /* Exec Write Requested */
+} bt_gatt_request_type_e;
+
+struct gatt_req_info {
+ gchar *attr_path;
+ gchar *svc_path;
+ guint request_id;
+ guint offset;
+ bt_gatt_request_type_e request_type; /* Read or Write request */
+ GDBusMethodInvocation *context;
+};
+
+struct gatt_server_app {
+ int slot;
+ char *app_path;
+ GSList *services;
+};
+
+/* Linked List of gatt server app's */
+static GSList *gatt_server_apps = NULL;
+
+static GSList *gatt_services = NULL;
+
+static int conn_id = 0;
+
+/* Linked List of connected Remote GATT clients */
+static GSList *gatt_client_info_list = NULL;
+
+/* GATT Client Info List Structure */
+struct gatt_client_info_t {
+ int connection_id; /* This value will uniquely identify a GATT client-server connection */
+ int instance_id; /* This value unique identifies a GATT server instance */
+ char *addr; /* Remote GATT client address */
+ GSList *gatt_req_info_list; /* List of transactions per Connection*/
+};
+
+static handle_stack_msg event_cb = NULL;
+
+typedef struct {
+ uint32_t instance_data;
+ bt_uuid_t uuid;
+} hal_register_server_data;
+
+typedef struct {
+ uint32_t instance_data;
+ uint32_t srvc_hdl;
+ bt_uuid_t uuid;
+ uint8_t is_primary;
+} hal_gatt_service_added;
+
+typedef struct {
+ uint32_t instance_data;
+ uint32_t srvc_hdl;
+} hal_gatt_service_started;
+
+typedef struct {
+ uint32_t instance_data;
+ uint32_t srvc_hdl;
+} hal_gatt_service_deleted;
+
+typedef struct {
+ uint32_t instance_data;
+ uint32_t srvc_hdl;
+ uint32_t char_hdl;
+ bt_uuid_t uuid;
+} hal_gatt_char_added;
+
+typedef struct {
+ uint32_t instance_data;
+ uint32_t srvc_hdl;
+ uint32_t desc_hdl;
+ bt_uuid_t uuid;
+} hal_gatt_desc_added;
+
+#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\
+{\
+ ERR("%s: BTGATT not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+} else {\
+ DBG("%s", __FUNCTION__);\
+}
+
+static gboolean __bt_hal_gatt_service_added_cb(gpointer user_data);
+
+static void __bt_hal_gatt_deinit(char *app_path);
+
+static void __bt_hal_register_application_cb(GObject *object,
+ GAsyncResult *res, gpointer user_data);
+
+static void __bt_hal_unregister_application_cb(GObject *object, GAsyncResult *res,
+ gpointer user_data);
+
+static GDBusProxy *__bt_gatt_gdbus_get_gatt_manager_proxy(const gchar *service,
+ const gchar *path, const gchar *interface);
+
+/* Introspection data for the service we are exporting */
+static const gchar service_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.freedesktop.DBus.Properties'>"
+" <property type='s' name='UUID' access='read'>"
+" </property>"
+" <property type='b' name='primary' access='read'>"
+" </property>"
+" <property type='o' name='Device' access='read'>"
+" </property>"
+" <property type='ao' name='Characteristics' access='read'>"
+" </property>"
+" <property type='s' name='Includes' access='read'>"
+" </property>"
+" </interface>"
+"</node>";
+
+/* Introspection data for the characteristics we are exporting */
+static const gchar characteristics_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.bluez.GattCharacteristic1'>"
+" <method name='ReadValue'>"
+" <arg type='s' name='address' direction='in'/>"
+" <arg type='y' name='id' direction='in'/>"
+" <arg type='q' name='offset' direction='in'/>"
+" <arg type='ay' name='Value' direction='out'/>"
+" </method>"
+" <method name='WriteValue'>"
+" <arg type='s' name='address' direction='in'/>"
+" <arg type='y' name='id' direction='in'/>"
+" <arg type='q' name='offset' direction='in'/>"
+" <arg type='ay' name='value' direction='in'/>"
+" </method>"
+" <method name='StartNotify'>"
+" </method>"
+" <method name='StopNotify'>"
+" </method>"
+" <method name='IndicateConfirm'>"
+" <arg type='s' name='address' direction='in'/>"
+" <arg type='b' name='complete' direction='in'/>"
+" </method>"
+" </interface>"
+" <interface name='org.freedesktop.DBus.Properties'>"
+" <property type='s' name='UUID' access='read'>"
+" </property>"
+" <property type='o' name='Service' access='read'>"
+" </property>"
+" <property type='ay' name='Value' access='readwrite'>"
+" </property>"
+" <property type='b' name='Notifying' access='read'>"
+" </property>"
+" <property type='as' name='Flags' access='read'>"
+" </property>"
+" <property type='s' name='Unicast' access='read'>"
+" </property>"
+" <property type='ao' name='Descriptors' access='read'>"
+" </property>"
+" </interface>"
+"</node>";
+
+/* Introspection data for the descriptor we are exporting */
+static const gchar descriptor_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.bluez.GattDescriptor1'>"
+" <method name='ReadValue'>"
+" <arg type='s' name='address' direction='in'/>"
+" <arg type='u' name='id' direction='in'/>"
+" <arg type='q' name='offset' direction='in'/>"
+" <arg type='ay' name='Value' direction='out'/>"
+" </method>"
+" <method name='WriteValue'>"
+" <arg type='s' name='address' direction='in'/>"
+" <arg type='u' name='id' direction='in'/>"
+" <arg type='q' name='offset' direction='in'/>"
+" <arg type='b' name='response_needed' direction='in'/>"
+" <arg type='ay' name='value' direction='in'/>"
+" </method>"
+" </interface>"
+" <interface name='org.freedesktop.DBus.Properties'>"
+" <property type='s' name='UUID' access='read'>"
+" </property>"
+" <property type='o' name='Characteristic' access='read'>"
+" </property>"
+" <property type='ay' name='Value' access='read'>"
+" </property>"
+" <property type='as' name='Flags' access='read'>"
+" </property>"
+" </interface>"
+"</node>";
+
+
+static const gchar manager_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.freedesktop.DBus.ObjectManager'>"
+" <method name='GetManagedObjects'>"
+" <arg type='a{oa{sa{sv}}}' name='object_paths_interfaces_and_properties' direction='out'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+GSList *_bt_get_service_list_from_server(int instance)
+{
+ GSList *l;
+ INFO("Number of GATT Server apps [%d]", g_slist_length(gatt_server_apps));
+ INFO("Find App with slot [%d]", instance);
+
+ for (l = gatt_server_apps; l; l = g_slist_next(l)) {
+ struct gatt_server_app *app = (struct gatt_server_app *)l->data;
+
+ if (app->slot == instance) {
+ INFO("App slot [%d] Found, Number of services registered [%d]",
+ app->slot, g_slist_length(app->services));
+ return app->services;
+ }
+ }
+ return NULL;
+}
+
+void _bt_remote_service_from_gatt_server(int instance, int service_handle)
+{
+ GSList *l;
+ GSList *l1;
+
+ for (l = gatt_server_apps; l; l = g_slist_next(l)) {
+ struct gatt_server_app *app = (struct gatt_server_app *)l->data;
+
+ if (app->slot == instance) {
+ for (l1 = app->services; l1; l1 = g_slist_next(l1)) {
+ struct gatt_service_info *srv = (struct gatt_service_info *)l1->data;
+ if (srv->service_handle == service_handle) {
+ app->services = g_slist_remove(app->services, srv);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void _bt_hal_update_gatt_service_in_gatt_server(int slot, struct gatt_service_info *serv_info)
+{
+ GSList *l;
+ for (l = gatt_server_apps; l; l = g_slist_next(l)) {
+ struct gatt_server_app *app = (struct gatt_server_app *)l->data;
+
+ if (app->slot == slot) {
+ INFO("Updating service in GATT server's service list service handle [%d] slot [%d]",
+ serv_info->service_handle, slot);
+ app->services = g_slist_append(app->services, serv_info);
+ }
+ }
+}
+
+static struct gatt_client_info_t *__bt_find_remote_gatt_client_info(char *address)
+{
+ GSList *l;
+ struct gatt_client_info_t *info = NULL;
+
+ for (l = gatt_client_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (struct gatt_client_info_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (!g_strcmp0(info->addr, address)) {
+ INFO("Remote GATT client found addr[%s]", info->addr);
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static struct gatt_client_info_t *__bt_find_remote_gatt_client_info_from_conn(int conn_id)
+{
+ GSList *l;
+ struct gatt_client_info_t *info = NULL;
+
+ for (l = gatt_client_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (struct gatt_client_info_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (info->connection_id == conn_id) {
+ INFO("Remote GATT client found addr[%s]", info->addr);
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static struct gatt_req_info *__bt_find_remote_gatt_client_request_info(int conn_id, int trans_id)
+{
+ GSList *l;
+ GSList *l1;
+
+ struct gatt_client_info_t *info = NULL;
+ struct gatt_req_info *info1 = NULL;
+
+ for (l = gatt_client_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (struct gatt_client_info_t*)l->data;
+
+ if (info == NULL)
+ continue;
+ if (info->connection_id == conn_id) {
+
+ for (l1 = info->gatt_req_info_list; l1; l1 = g_slist_next(l1)) {
+
+ info1 = (struct gatt_req_info*)l1->data;
+ if (info1 == NULL)
+ continue;
+
+ if (info1->request_id == trans_id) {
+ INFO("Remote GATT client found addr[%s]", info->addr);
+ return info1;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void _bt_hal_gatt_connected_state_event(gboolean is_connected, char *address)
+{
+ struct hal_ev_gatt_server_connected ev;
+ struct gatt_client_info_t *conn_info = NULL;
+ int instance = -1;
+ memset(&ev, 0, sizeof(ev));
+
+ /* Find Server Instance */
+ _bt_hal_get_gatt_server_instance_initialized(&instance);
+ if (instance == -1) {
+ ERR("Not even a single GATT server is registered");
+ return;
+ }
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+
+ /* Create Connection ID */
+ /* Check if device is already in connected list */
+ conn_info = __bt_find_remote_gatt_client_info(address);
+
+
+ /* If disconnected, and conn info found, then remove conn info */
+ if (is_connected == FALSE) {
+ DBG("GATT Disconnected");
+ if (conn_info) {
+ INFO("Remove GATT client info from List..");
+ /* Remove info from List */
+ gatt_client_info_list = g_slist_remove(gatt_client_info_list, conn_info);
+ INFO("Total num of connected GATT clients [%d]", g_slist_length(gatt_client_info_list));
+
+ if (!event_cb)
+ ERR("GATT callback not registered");
+ else {
+ DBG("GATT callback registered: server if [%d] Is Connected [%d] addr[%s] conn ID [%d]",
+ conn_info->instance_id, is_connected, conn_info->addr, conn_info->connection_id);
+ ev.conn_id = conn_info->connection_id;
+ ev.server_instance = conn_info->instance_id;
+ ev.connected = is_connected;
+
+ event_cb(HAL_EV_GATT_SERVER_CONNECTED, (void *)&ev, sizeof(ev));
+ }
+ g_free(conn_info->addr);
+ g_free(conn_info);
+ }
+ /* If connected, and conn info NOT found, then add conn info */
+ } else {
+ if (!conn_info) {
+ /* Save Connection info */
+ conn_info = g_new0(struct gatt_client_info_t, 1);
+ conn_info->addr = g_strdup(address);
+ INFO("Added GATT client addr[%s]", conn_info->addr);
+ conn_info->connection_id = ++conn_id;
+ conn_info->instance_id = instance;
+ gatt_client_info_list = g_slist_append(gatt_client_info_list, conn_info);
+ INFO("Total num of connected GATT clients [%d]", g_slist_length(gatt_client_info_list));
+
+ if (!event_cb)
+ ERR("GATT callback not registered");
+ else {
+ DBG("GATT callback registered: server if [%d] Is Connected [%d] addr[%s] conn ID [%d]",
+ conn_info->instance_id, is_connected, conn_info->addr, conn_info->connection_id);
+ ev.conn_id = conn_info->connection_id;
+ ev.server_instance = conn_info->instance_id;
+ ev.connected = is_connected;
+
+ event_cb(HAL_EV_GATT_SERVER_CONNECTED, (void *)&ev, sizeof(ev));
+ }
+ }
+ }
+ /* Send GATT connected or disconnected event */
+}
+
+static struct gatt_service_info *__bt_gatt_find_gatt_service_from_char(const char *char_path, int *char_hdl)
+{
+ GSList *l1, *l2;
+
+ for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
+ struct gatt_service_info *serv_info = l1->data;
+
+ for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
+ struct gatt_char_info *char_info = l2->data;
+
+ if (g_strcmp0(char_info->char_path, char_path)
+ == 0) {
+ *char_hdl = char_info->char_handle;
+ return serv_info;
+ }
+ }
+ }
+ ERR("Gatt service not found");
+ return NULL;
+}
+
+char *__bt_gatt_find_char_path_from_handle(int char_hdl)
+{
+ GSList *l1, *l2;
+
+ for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
+ struct gatt_service_info *serv_info = l1->data;
+
+ for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
+ struct gatt_char_info *char_info = l2->data;
+
+ if (char_info->char_handle == char_hdl) {
+ return char_info->char_path;
+ }
+ }
+ }
+ ERR("Not found");
+ return NULL;
+}
+
+struct gatt_char_info *__bt_gatt_find_char_info_from_handle(int char_hdl)
+{
+ GSList *l1, *l2;
+
+ for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
+ struct gatt_service_info *serv_info = l1->data;
+
+ for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
+ struct gatt_char_info *char_info = l2->data;
+
+ if (char_info->char_handle == char_hdl) {
+ return char_info;
+ }
+ }
+ }
+ ERR("Not found");
+ return NULL;
+}
+
+static struct gatt_service_info *__bt_gatt_find_gatt_service_from_desc(const char *desc_path, int *desc_hdl)
+{
+ GSList *l1, *l2, *l3;
+
+ for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
+ struct gatt_service_info *serv_info = l1->data;
+
+ for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
+ struct gatt_char_info *char_info = l2->data;
+
+ for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
+ struct gatt_desc_info *desc_info = l3->data;
+
+ if (g_strcmp0(desc_info->desc_path, desc_path)
+ == 0) {
+ *desc_hdl = desc_info->desc_handle;
+ return serv_info;
+ }
+ }
+ }
+ }
+ ERR("Gatt service not found");
+ return NULL;
+}
+
+static void __bt_gatt_manager_method_call(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GSList *l = NULL;
+
+ if (g_strcmp0(method_name, "GetManagedObjects") == 0) {
+ GVariantBuilder *builder;
+ GVariantBuilder *inner_builder1 = NULL;
+ GVariant *svc_char = NULL;
+ GSList *l4;
+ GSList *gatt_services = NULL;
+ int *instance;
+ instance = (int*)user_data;
+
+ DBG("Getting values for service, chars and descriptors");
+ DBG("GATT Server App for which services are requested [%d]", *instance);
+
+ /*Main Builder */
+ builder = g_variant_builder_new(
+ G_VARIANT_TYPE("a{oa{sa{sv}}}"));
+
+
+ gatt_services = _bt_get_service_list_from_server(*instance);
+
+ if (g_slist_length(gatt_services) == 0) {
+ ERR("No registered GATT services!!!!");
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ for (l = gatt_services; l != NULL; l = l->next) {
+ GVariantBuilder *svc_builder = NULL;
+ GVariantBuilder *inner_builder = NULL;
+ struct gatt_service_info *serv_info = l->data;
+ INFO("GATT Service fetched handle [%d]", serv_info->service_handle);
+
+ /* Prepare inner builder for GattService1 interface */
+ DBG("Creating builder for service");
+ svc_builder = g_variant_builder_new(
+ G_VARIANT_TYPE("a{sa{sv}}"));
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(inner_builder, "{sv}", "UUID",
+ g_variant_new_string(serv_info->service_uuid));
+
+ g_variant_builder_add(inner_builder, "{sv}", "Primary",
+ g_variant_new_boolean(serv_info->is_svc_primary));
+
+ /*Characteristics*/
+ inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
+ DBG("Adding Charatarisitcs list");
+ for (l4 = serv_info->char_data; l4 != NULL; l4 = l4->next) {
+ struct gatt_char_info *char_info = l4->data;
+ INFO("GATT Char handle [%d] found in GATT service handle [%d]",
+ char_info->char_handle, serv_info->service_handle);
+ g_variant_builder_add(inner_builder1, "o",
+ char_info->char_path);
+ DBG("%s", char_info->char_path);
+ }
+
+ svc_char = g_variant_new("ao", inner_builder1);
+ g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
+ svc_char);
+
+ g_variant_builder_add(svc_builder, "{sa{sv}}",
+ GATT_SERV_INTERFACE,
+ inner_builder);
+
+ g_variant_builder_add(builder, "{oa{sa{sv}}}",
+ serv_info->serv_path,
+ svc_builder);
+
+ g_variant_builder_unref(inner_builder1);
+
+ /* Prepare inner builder for GattCharacteristic1 interface */
+
+ GSList *l2 = serv_info->char_data;
+ DBG("Creating builder for characteristics \n");
+
+ if (l2 == NULL)
+ DBG("characteristic data is NULL");
+
+ for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
+
+ GVariantBuilder *char_builder = NULL;
+ GVariantBuilder *inner_builder = NULL;
+ GVariantBuilder *builder1 = NULL;
+ GVariantBuilder *builder2 = NULL;
+ GVariantBuilder *builder3 = NULL;
+ GVariant *char_val = NULL;
+ GVariant *flags_val = NULL;
+ GVariant *char_desc = NULL;
+ char *unicast = NULL;
+ gboolean notify = FALSE;
+ int i = 0;
+
+ char_builder = g_variant_builder_new(
+ G_VARIANT_TYPE(
+ "a{sa{sv}}"));
+ inner_builder = g_variant_builder_new(
+ G_VARIANT_TYPE(
+ "a{sv}"));
+
+ struct gatt_char_info *char_info = l2->data;
+ if (char_info == NULL) {
+ ERR("char_info is NULL");
+ continue;
+ }
+
+ /*Uuid*/
+ g_variant_builder_add(inner_builder, "{sv}", "UUID",
+ g_variant_new_string(char_info->char_uuid));
+ /*Service*/
+ g_variant_builder_add(inner_builder, "{sv}", "Service",
+ g_variant_new("o", serv_info->serv_path));
+ /*Value*/
+ builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+
+ if (char_info->char_value != NULL) {
+ for (i = 0; i < char_info->value_length; i++) {
+ g_variant_builder_add(builder1, "y",
+ char_info->char_value[i]);
+ }
+ char_val = g_variant_new("ay", builder1);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "Value", char_val);
+ }
+ /*Flags*/
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
+ for (i = 0; i < char_info->flags_length; i++) {
+ g_variant_builder_add(builder2, "s",
+ char_info->char_flags[i]);
+ }
+
+ flags_val = g_variant_new("as", builder2);
+ g_variant_builder_add(inner_builder, "{sv}", "Flags",
+ flags_val);
+
+ /* Notifying */
+ g_variant_builder_add(inner_builder, "{sv}", "Notifying",
+ g_variant_new("b", notify));
+
+ /* Unicast */
+ unicast = g_strdup("00:00:00:00:00:00");
+ g_variant_builder_add(inner_builder, "{sv}", "Unicast",
+ g_variant_new("s", unicast));
+
+ /*Descriptors*/
+ builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
+ DBG("Adding Descriptors list");
+
+ for (l4 = char_info->desc_data; l4 != NULL; l4 = l4->next) {
+ struct gatt_desc_info *desc_info = l4->data;
+ INFO("GATT Descriptor handle [%d] found inside GATT Char handle [%d] found in GATT service handle [%d]",
+ desc_info->desc_handle, char_info->char_handle, serv_info->service_handle);
+ g_variant_builder_add(builder3, "o",
+ desc_info->desc_path);
+ DBG("%s", desc_info->desc_path);
+ }
+
+ char_desc = g_variant_new("ao", builder3);
+ g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
+ char_desc);
+
+ g_variant_builder_add(char_builder, "{sa{sv}}",
+ GATT_CHAR_INTERFACE , inner_builder);
+ g_variant_builder_add(builder, "{oa{sa{sv}}}",
+ char_info->char_path, char_builder);
+
+ /*Prepare inner builder for GattDescriptor1 interface*/
+
+ GSList *l3 = char_info->desc_data;
+
+ if (l3 == NULL)
+ DBG("descriptor data is NULL");
+
+ for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
+
+ DBG("Creating builder for descriptor \n");
+
+ GVariantBuilder *desc_builder = NULL;
+ GVariantBuilder *inner_builder = NULL;
+ GVariantBuilder *builder1 = NULL;
+ GVariantBuilder *builder2 = NULL;
+ GVariant *desc_val = NULL;
+
+ desc_builder = g_variant_builder_new(
+ G_VARIANT_TYPE(
+ "a{sa{sv}}"));
+ inner_builder = g_variant_builder_new(
+ G_VARIANT_TYPE(
+ "a{sv}"));
+
+ struct gatt_desc_info *desc_info = l3->data;
+ if (desc_info == NULL) {
+ ERR("desc_info is NULL");
+ continue;
+ }
+
+ /*Uuid*/
+ g_variant_builder_add(inner_builder,
+ "{sv}", "UUID",
+ g_variant_new_string(
+ desc_info->desc_uuid));
+
+ /*Characteristic*/
+ g_variant_builder_add(inner_builder, "{sv}",
+ "Characteristic",
+ g_variant_new("o",
+ char_info->char_path));
+
+ /*Value*/
+ builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+
+ if (desc_info->desc_value != NULL) {
+ for (i = 0; i < desc_info->value_length; i++) {
+ g_variant_builder_add(builder1, "y",
+ desc_info->desc_value[i]);
+ }
+ desc_val = g_variant_new("ay", builder1);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "Value", desc_val);
+ }
+
+ /*Flags*/
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ for (i = 0; i < desc_info->flags_length; i++) {
+ g_variant_builder_add(builder2, "s",
+ desc_info->desc_flags[i]);
+ }
+
+ flags_val = g_variant_new("as", builder2);
+ g_variant_builder_add(inner_builder, "{sv}", "Flags",
+ flags_val);
+
+ g_variant_builder_add(desc_builder, "{sa{sv}}",
+ GATT_DESC_INTERFACE,
+ inner_builder);
+
+ g_variant_builder_add(builder, "{oa{sa{sv}}}",
+ desc_info->desc_path,
+ desc_builder);
+
+ /*unref descriptor builder pointers*/
+ g_variant_builder_unref(builder1);
+ g_variant_builder_unref(builder2);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(desc_builder);
+ }
+
+ if (unicast)
+ g_free(unicast);
+ /*unref char builder pointers*/
+ g_variant_builder_unref(builder1);
+ g_variant_builder_unref(builder2);
+ g_variant_builder_unref(builder3);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(char_builder);
+ }
+
+ /*unref service builder pointers*/
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(svc_builder);
+
+ }
+ /* Return builder as method reply */
+ DBG("Sending gatt service builder values to Bluez");
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new(
+ "(a{oa{sa{sv}}})",
+ builder));
+ }
+
+ /* Free User Data */
+ g_free(user_data);
+}
+
+static void __bt_gatt_desc_method_call(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+
+ if (g_strcmp0(method_name, "ReadValue") == 0) {
+ struct hal_ev_gatt_server_read_req ev;
+
+ gchar *addr = NULL;
+ guint req_id = 0;
+ guint16 offset = 0;
+ struct gatt_client_info_t *conn_info = NULL;
+ struct gatt_req_info *req_info = NULL;
+ struct gatt_service_info *svc_info = NULL;
+ int desc_hdl = -1;
+
+ DBG("ReadValue");
+ DBG("Application path = %s", object_path);
+ DBG("Sender = %s", sender);
+
+ svc_info = __bt_gatt_find_gatt_service_from_desc(object_path, &desc_hdl);
+ if (svc_info == NULL) {
+ ERR("Coudn't find service for %s", object_path);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ g_variant_get(parameters, "(&suq)", &addr, &req_id, &offset);
+ DBG("Request id = %u, Offset = %u", req_id, offset);
+
+ /* Check if device is already in connected list */
+ conn_info = __bt_find_remote_gatt_client_info(addr);
+
+ if (conn_info == NULL) {
+ ERR("Coudn't find Connection info for %s", addr);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ if (!event_cb) {
+ ERR("GATT callback NOT registered");
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ /* Store requests information */
+ req_info = g_new0(struct gatt_req_info, 1);
+ req_info->attr_path = g_strdup(object_path);
+ req_info->svc_path = g_strdup(svc_info->serv_path);
+ req_info->request_id = req_id;
+ req_info->offset = offset;
+ req_info->context = invocation;
+
+ /* Append request info in list of requests for the particular connection */
+ conn_info->gatt_req_info_list = g_slist_append(conn_info->gatt_req_info_list, req_info);
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_info->connection_id;
+ ev.trans_id = req_id;
+ ev.att_handle = desc_hdl;
+ ev.offset = offset;
+ ev.is_long = false; /* TODO*/
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, addr);
+
+ event_cb(HAL_EV_GATT_READ_REQUESTED, (void *)&ev, sizeof(ev));
+ return;
+ } else if (g_strcmp0(method_name, "WriteValue") == 0) {
+
+ GVariant *var = NULL;
+ gchar *addr = NULL;
+ guint req_id = 0;
+ guint16 offset = 0;
+ gboolean response_needed = FALSE;
+ struct hal_ev_gatt_server_write_req ev;
+ int desc_hdl = -1;
+ int len;
+
+ struct gatt_service_info *svc_info = NULL;
+ struct gatt_client_info_t *conn_info = NULL;
+ struct gatt_req_info *req_info = NULL;
+
+ DBG("WriteValue");
+ DBG("Application path = %s", object_path);
+ DBG("Sender = %s", sender);
+
+ g_variant_get(parameters, "(&suqb@ay)",
+ &addr, &req_id, &offset, &response_needed, &var);
+ DBG("Request id = %u, Offset = %u", req_id, offset);
+
+ /* Check if device is already in connected list */
+ conn_info = __bt_find_remote_gatt_client_info(addr);
+
+ svc_info = __bt_gatt_find_gatt_service_from_desc(object_path, &desc_hdl);
+
+ if (conn_info == NULL || svc_info == NULL || event_cb == NULL) {
+ g_variant_unref(var);
+ if (response_needed)
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ else
+ g_object_unref(invocation);
+ return;
+ }
+
+ len = g_variant_get_size(var);
+ if (len > 0) {
+ char *data;
+ data = (char *)g_variant_get_data(var);
+ memcpy(ev.value, data, len);
+ ev.length = len;
+ }
+ if (response_needed) {
+ /* Store request information */
+ req_info = g_new0(struct gatt_req_info, 1);
+ req_info->attr_path = g_strdup(object_path);
+ req_info->svc_path = g_strdup(svc_info->serv_path);
+ req_info->request_id = req_id;
+ req_info->offset = offset;
+ req_info->context = invocation;
+
+ /* Append request info in list of requests for the particular connection */
+ conn_info->gatt_req_info_list = g_slist_append(conn_info->gatt_req_info_list, req_info);
+ } else {
+ g_object_unref(invocation);
+ }
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_info->connection_id;
+ ev.trans_id = req_id;
+ ev.att_handle = desc_hdl;
+ ev.offset = offset;
+ ev.need_rsp = response_needed;
+ ev.is_prep = 0;
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, addr);
+
+ event_cb(HAL_EV_GATT_WRITE_REQUESTED, (void *)&ev, sizeof(ev));
+
+ g_variant_unref(var);
+ return;
+ }
+}
+
+static void __bt_gatt_char_method_call(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ if (g_strcmp0(method_name, "ReadValue") == 0) {
+ gchar *addr = NULL;
+ guint req_id = 0;
+ guint16 offset = 0;
+ struct hal_ev_gatt_server_read_req ev;
+ int char_hdl = -1;
+
+ struct gatt_req_info *req_info = NULL;
+ struct gatt_client_info_t *conn_info = NULL;
+ struct gatt_service_info *svc_info = NULL;
+
+ DBG("Application path = %s", object_path);
+ DBG("Sender = %s", sender);
+
+ /* Check if device is already in connected list */
+ conn_info = __bt_find_remote_gatt_client_info(addr);
+
+ svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl);
+
+ if (svc_info == NULL || conn_info == NULL) {
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ if (!event_cb) {
+ ERR("GATT callback NOT registered");
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ g_variant_get(parameters, "(&suq)", &addr, &req_id, &offset);
+ DBG("Request id = %u, Offset = %u", req_id, offset);
+
+ /* Store requets information */
+ req_info = g_new0(struct gatt_req_info, 1);
+ req_info->attr_path = g_strdup(object_path);
+ req_info->svc_path = g_strdup(svc_info->serv_path);
+ req_info->request_id = req_id;
+ req_info->offset = offset;
+ req_info->context = invocation;
+
+ /* Append request info in list of requests for the particular connection */
+ conn_info->gatt_req_info_list = g_slist_append(conn_info->gatt_req_info_list, req_info);
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_info->connection_id;
+ ev.trans_id = req_id;
+ ev.att_handle = char_hdl;
+ ev.offset = offset;
+ ev.is_long = false; /* TODO*/
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, addr);
+
+ event_cb(HAL_EV_GATT_READ_REQUESTED, (void *)&ev, sizeof(ev));
+ return;
+ } else if (g_strcmp0(method_name, "WriteValue") == 0) {
+ GVariant *var = NULL;
+ gchar *addr = NULL;
+ guint req_id = 0;
+ guint16 offset = 0;
+ gboolean response_needed = FALSE;
+ struct hal_ev_gatt_server_write_req ev;
+ int char_hdl = -1;
+
+ struct gatt_service_info *svc_info = NULL;
+ struct gatt_req_info *req_info = NULL;
+ struct gatt_client_info_t *conn_info = NULL;
+
+ DBG("WriteValue");
+ DBG("Application path = %s", object_path);
+ DBG("Sender = %s", sender);
+
+ g_variant_get(parameters, "(&suqb@ay)",
+ &addr, &req_id, &offset, &response_needed, &var);
+ DBG("Request id = %u, Offset = %u", req_id, offset);
+
+ svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl);
+
+ /* Check if device is already in connected list */
+ conn_info = __bt_find_remote_gatt_client_info(addr);
+
+ if (svc_info == NULL || conn_info == NULL || event_cb == NULL) {
+ g_variant_unref(var);
+ if (response_needed)
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ else
+ g_object_unref(invocation);
+ return;
+ }
+
+ if (response_needed) {
+ /* Store requets information */
+ req_info = g_new0(struct gatt_req_info, 1);
+ req_info->attr_path = g_strdup(object_path);
+ req_info->svc_path = g_strdup(svc_info->serv_path);
+ req_info->request_id = req_id;
+ req_info->offset = offset;
+ req_info->context = invocation;
+
+ /* Append request info in list of requests for the particular connection */
+ conn_info->gatt_req_info_list = g_slist_append(conn_info->gatt_req_info_list, req_info);
+
+ } else {
+ g_object_unref(invocation);
+ }
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_info->connection_id;
+ ev.trans_id = req_id;
+ ev.att_handle = char_hdl;
+ ev.offset = offset;
+ ev.need_rsp = response_needed;
+ ev.is_prep = 0;
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, addr);
+
+ event_cb(HAL_EV_GATT_WRITE_REQUESTED, (void *)&ev, sizeof(ev));
+
+ g_variant_unref(var);
+ return;
+
+ } else if (g_strcmp0(method_name, "StartNotify") == 0) {
+ DBG("StartNotify");
+#ifdef TIZEN_BT_HAL
+ struct gatt_service_info *svc_info = NULL;
+ struct hal_ev_gatt_server_notifcation_change ev;
+ int char_hdl = -1;
+
+ svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl);
+ if (svc_info == NULL || event_cb == NULL) {
+ return;
+ }
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = -1; /*TODO Bluez does not provide remote GATT client address, so no conn_id */
+ ev.trans_id = -1; /*TODO Bluez does not provide request id or transacion ID */
+ ev.att_handle = char_hdl;
+ ev.notify = true;
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, "00:00:00:00:00"); /* TODO Bluez Does not provide address of GATT client */
+
+ event_cb(HAL_EV_GATT_NOTIFICATION_CHANGE, (void *)&ev, sizeof(ev));
+#endif
+
+ } else if (g_strcmp0(method_name, "StopNotify") == 0) {
+ DBG("StopNotify");
+#ifdef TIZEN_BT_HAL
+ struct gatt_service_info *svc_info = NULL;
+ struct hal_ev_gatt_server_notifcation_change ev;
+ int char_hdl = -1;
+
+ svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl);
+ if (svc_info == NULL || event_cb == NULL) {
+ return;
+ }
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = -1; /*TODO Bluez does not provide remote GATT client address, so no conn_id */
+ ev.trans_id = -1; /*TODO Bluez does not provide request id or transacion ID */
+ ev.att_handle = char_hdl;
+ ev.notify = false;
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, "00:00:00:00:00"); /* TODO Bluez DOes not provide address of GATT client */
+
+ event_cb(HAL_EV_GATT_NOTIFICATION_CHANGE, (void *)&ev, sizeof(ev));
+#endif
+
+ } else if (g_strcmp0(method_name, "IndicateConfirm") == 0) {
+ gchar *addr = NULL;
+ gboolean complete = FALSE;
+ int char_hdl = -1;
+
+ struct gatt_service_info *svc_info = NULL;
+ struct gatt_client_info_t *conn_info = NULL;
+
+ struct hal_ev_gatt_server_indicate_cfm ev;
+
+ DBG("IndicateConfirm");
+ DBG("Application path = %s", object_path);
+ DBG("Sender = %s", sender);
+
+ g_variant_get(parameters, "(&sb)", &addr, &complete);
+ DBG("Remote Device address number = %s", addr);
+ DBG("Is Indicate confirmation for last device [%d]", complete);
+
+ /* Check if device is already in connected list */
+ conn_info = __bt_find_remote_gatt_client_info(addr);
+
+ svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl);
+
+ if (svc_info == NULL || conn_info == NULL
+ || event_cb == NULL) {
+ return;
+ }
+
+ /* Send HAL event */
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_info->connection_id;
+ ev.trans_id = -1; /*TODO Bluez does not provide Transaction ID or request ID */
+ ev.att_handle = char_hdl;
+
+ /* Convert address to hex */
+ _bt_convert_addr_string_to_type(ev.bdaddr, addr);
+
+ event_cb(HAL_EV_GATT_INDICATE_CFM, (void *)&ev, sizeof(ev));
+ }
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+gboolean __bt_hal_gatt_emit_interface_removed(gchar *object_path, gchar *interface)
+{
+ gboolean ret;
+ GError *error = NULL;
+ GVariantBuilder *array_builder;
+
+ array_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_init(array_builder, G_VARIANT_TYPE("as"));
+ g_variant_builder_add(array_builder, "s", interface);
+
+ ret = g_dbus_connection_emit_signal(g_conn, NULL, "/",
+ "org.freedesktop.Dbus.Objectmanager",
+ "InterfacesRemoved",
+ g_variant_new("(oas)",
+ object_path, array_builder),
+ &error);
+
+ if (!ret) {
+ if (error != NULL) {
+ /* dbus gives error cause */
+ ERR("d-bus api failure: errcode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ }
+ g_variant_builder_unref(array_builder);
+
+ return ret;
+}
+
+static void __bt_hal_gatt_free_descriptor_info(struct gatt_desc_info *desc_info)
+{
+ int i;
+
+ if (!desc_info)
+ return;
+
+ g_free(desc_info->desc_path);
+ g_free(desc_info->desc_uuid);
+ g_free(desc_info->desc_value);
+
+ for (i = 0; i < desc_info->flags_length; i++)
+ g_free(desc_info->desc_flags[i]);
+
+ g_free(desc_info);
+}
+
+static void __bt_hal_gatt_free_characteristic_info(struct gatt_char_info *char_info)
+{
+ int i;
+
+ if (!char_info)
+ return;
+
+ g_free(char_info->char_path);
+ g_free(char_info->char_uuid);
+ g_free(char_info->char_value);
+
+ for (i = 0; i < char_info->flags_length; i++)
+ g_free(char_info->char_flags[i]);
+
+ g_free(char_info);
+}
+
+
+static void __bt_hal_gatt_free_service_info(struct gatt_service_info *svc_info)
+{
+ if (!svc_info)
+ return;
+
+ g_free(svc_info->serv_path);
+ g_free(svc_info->service_uuid);
+ g_free(svc_info);
+}
+
+static const GDBusInterfaceVTable desc_interface_vtable = {
+ __bt_gatt_desc_method_call,
+ NULL,
+ NULL,
+};
+
+static const GDBusInterfaceVTable char_interface_vtable = {
+ __bt_gatt_char_method_call,
+ NULL,
+ NULL,
+};
+
+static const GDBusInterfaceVTable serv_interface_vtable = {
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const GDBusInterfaceVTable manager_interface_vtable = {
+ __bt_gatt_manager_method_call,
+ NULL,
+ NULL
+};
+
+
+static GDBusNodeInfo *__bt_gatt_create_method_node_info(
+ const gchar *introspection_data)
+{
+ GError *err = NULL;
+ GDBusNodeInfo *node_info = NULL;
+
+ if (introspection_data == NULL)
+ return NULL;
+
+
+ DBG("Create new node info");
+ node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
+
+ if (err) {
+ ERR("Unable to create node: %s", err->message);
+ g_clear_error(&err);
+ return NULL;
+ }
+
+ return node_info;
+}
+
+/* To send stack event to hal-av handler */
+void _bt_hal_register_gatt_server_handler_cb(handle_stack_msg cb)
+{
+ event_cb = cb;
+}
+
+void _bt_hal_unregister_gatt_server_handler_cb(void)
+{
+ event_cb = NULL;
+}
+
+static gboolean __bt_hal_gatt_desc_added_cb(gpointer user_data)
+{
+ struct hal_ev_gatt_desc_added ev;
+ hal_gatt_desc_added *data = (hal_gatt_desc_added*) user_data;
+
+ /* Prepare to GATT characteristic added event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.server_instance = data->instance_data;
+ memcpy(ev.desc_uuid, data->uuid.uu, sizeof(data->uuid.uu));
+ ev.service_handle = data->srvc_hdl;
+ ev.desc_handle = data->desc_hdl;
+
+ if (!event_cb)
+ ERR("GATT Descriptor Added callback registered");
+ else {
+ DBG("GATT Descriptor Added: server if [%d] Service handle [%d] Descriptor Handle [%d]",
+ data->instance_data, data->srvc_hdl, data->desc_hdl);
+
+ event_cb(HAL_EV_GATT_DESC_ADDED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(data);
+ return FALSE;
+}
+
+static gboolean __bt_hal_gatt_char_added_cb(gpointer user_data)
+{
+ struct hal_ev_gatt_char_added ev;
+ hal_gatt_char_added *data = (hal_gatt_char_added*) user_data;
+
+ /* Prepare to GATT characteristic added event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.server_instance = data->instance_data;
+ memcpy(ev.char_uuid, data->uuid.uu, sizeof(data->uuid.uu));
+ ev.service_handle = data->srvc_hdl;
+ ev.char_handle = data->char_hdl;
+
+ if (!event_cb)
+ ERR("GATT Characteristic Added callback registered");
+ else {
+ DBG("GATT Characteristic Added: server if [%d] Service handle [%d] Characteristic handle [%d]",
+ data->instance_data, data->srvc_hdl, data->char_hdl);
+
+ event_cb(HAL_EV_GATT_CHAR_ADDED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(data);
+ return FALSE;
+}
+
+static gboolean __bt_hal_gatt_service_added_cb(gpointer user_data)
+{
+ struct hal_ev_gatt_service_added ev;
+ hal_gatt_service_added *data = (hal_gatt_service_added*) user_data;
+
+ /* Prepare to GATT Service added event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.server_instance = data->instance_data;
+ memcpy(ev.svc_uuid, data->uuid.uu, sizeof(data->uuid.uu));
+ ev.service_handle = data->srvc_hdl;
+ ev.is_primary = data->is_primary;
+
+ if (!event_cb)
+ ERR("GATT Service Added callback registered");
+ else {
+ DBG("GATT Service Added: server if [%d] Service handle [%d]",
+ data->instance_data, data->srvc_hdl);
+ event_cb(HAL_EV_GATT_SERVICE_ADDED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(data);
+ return FALSE;
+}
+
+static gboolean __bt_hal_gatt_service_started_cb(gpointer user_data)
+{
+ struct hal_ev_gatt_service_started ev;
+ hal_gatt_service_started *data = (hal_gatt_service_started*) user_data;
+
+ /* Prepare to GATT Service added event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.server_instance = data->instance_data;
+ ev.service_handle = data->srvc_hdl;
+
+ if (!event_cb)
+ ERR("GATT Service Started callback registered");
+ else {
+ DBG("GATT Service Started: server if [%d] Service handle [%d]",
+ data->instance_data, data->srvc_hdl);
+ event_cb(HAL_EV_GATT_SERVICE_STARTED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(data);
+ return FALSE;
+}
+
+static gboolean __bt_hal_gatt_service_deleted_cb(gpointer user_data)
+{
+ struct hal_ev_gatt_service_deleted ev;
+ hal_gatt_service_deleted *data = (hal_gatt_service_deleted*) user_data;
+
+ /* Prepare to GATT Service added event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.server_instance = data->instance_data;
+ ev.service_handle = data->srvc_hdl;
+
+ if (!event_cb)
+ ERR("GATT Service Deleted callback registered");
+ else {
+ DBG("GATT Service Deleted: server if [%d] Service handle [%d]",
+ data->instance_data, data->srvc_hdl);
+ event_cb(HAL_EV_GATT_SERVICE_DELETED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(data);
+ return FALSE;
+}
+
+static gboolean __bt_hal_register_slot_id_cb(gpointer user_data)
+{
+ struct hal_ev_server_instance_registered ev;
+ hal_register_server_data *data = (hal_register_server_data*) user_data;
+
+ /* Prepare to send AV connecting event */
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_STATUS_SUCCESS;
+ ev.server_instance = data->instance_data;
+ memcpy(ev.app_uuid, data->uuid.uu, sizeof(ev.app_uuid));
+
+ if (!event_cb)
+ ERR("GATT Register Server Instance Callback not registered");
+ else {
+ DBG("Server Instance is registered!! server if [%d]", data->instance_data);
+ event_cb(HAL_EV_SERVER_INSTANCE_INITIALIZED, (void *)&ev, sizeof(ev));
+ }
+
+ g_free(data);
+ return FALSE;
+}
+
+static bt_status_t gatt_server_register_app(bt_uuid_t *uuid)
+{
+ CHECK_BTGATT_INIT();
+ int status = BT_STATUS_FAIL;
+ int server_if;
+ DBG("Register server instance request");
+ hal_register_server_data *user_data = g_malloc0(sizeof(hal_register_server_data));
+
+ /* Check if slot available */
+ server_if = _bt_hal_get_available_adv_slot_id(uuid);
+
+ if (server_if == -1) {
+ ERR("Allocation of server instance failed");
+ g_free(user_data);
+ return status;
+ } else {
+ user_data->instance_data = server_if;
+ DBG("Allocated new Advertising slot with Stack [%d]", user_data->instance_data);
+ }
+
+ /*
+ * As we need to provide async callback to user from HAL, simply schedule a
+ * callback method which will carry actual result
+ */
+ memcpy(user_data->uuid.uu, uuid->uu, sizeof(bt_uuid_t));
+ g_idle_add(__bt_hal_register_slot_id_cb, (gpointer)user_data);
+
+ /* If available, then return success, else return error */
+ return BT_STATUS_SUCCESS;
+}
+
+void _bt_hal_remove_gatt_server_from_list(int server_if)
+{
+ GSList *l;
+ struct gatt_server_app *info = NULL;
+
+ for (l = gatt_server_apps; l != NULL;) {
+ info = (struct gatt_server_app*)l->data;
+ l = g_slist_next(l);
+ if (info == NULL)
+ continue;
+ if (info->slot == server_if) {
+ INFO("Found Matching GATT Server in List path[%s] slot [%d]",
+ info->app_path, info->slot);
+
+ /* Only if all services are deleted from the GATT Server, then only Unregister it.
+ Reason: it is possible, GATT Server app oly wants to disable multi advertising
+ In above case, only advertising block will be deallocated, Gatt Server will remain
+ unaffected */
+ if (info->services == NULL) {
+ gatt_server_apps = g_slist_remove(gatt_server_apps, (gpointer)info);
+ INFO("Total gatt server apps still existing after removing above is [%d]",
+ g_slist_length(gatt_server_apps));
+
+ /* DBUS Unregister only for current app */
+ __bt_hal_gatt_deinit(info->app_path);
+
+ g_free(info->app_path);
+ g_free(info);
+ return;
+ } else {
+ INFO("GATT Server still has services count[%d] in it..Can not remove it!!!",
+ g_slist_length(info->services));
+ }
+ }
+ }
+}
+
+static bt_status_t gatt_server_unregister_app(int server_if)
+{
+ CHECK_BTGATT_INIT();
+ DBG("Un-Register server instance request [%d]", server_if);
+
+ if (_bt_hal_is_advertising_in_slot(server_if) == FALSE)
+ _bt_hal_free_server_slot(server_if);
+
+ /* If server_if belongs to a GATT Server, then delete the GATT server from List */
+ _bt_hal_remove_gatt_server_from_list(server_if);
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t gatt_server_open(int server_if, const bt_bdaddr_t *bd_addr, bool is_direct)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t gatt_server_close(int server_if, const bt_bdaddr_t *bd_addr, int conn_id)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_SUCCESS;
+}
+
+static void __bt_gatt_close_gdbus_connection(void)
+{
+ GError *err = NULL;
+ DBG("+");
+
+ if (g_conn == NULL)
+ return;
+
+ if (!g_dbus_connection_flush_sync(g_conn, NULL, &err)) {
+ ERR("Fail to flush the connection: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ if (!g_dbus_connection_close_sync(g_conn, NULL, &err)) {
+ if (err) {
+ ERR("Fail to close the dbus connection: %s", err->message);
+ g_error_free(err);
+ }
+ }
+
+ g_object_unref(g_conn);
+ g_conn = NULL;
+ DBG("-");
+}
+
+static GDBusConnection *__bt_gatt_get_gdbus_connection(void)
+{
+ GDBusConnection *local_system_gconn = NULL;
+ char *address;
+ GError *err = NULL;
+
+ if (g_conn == NULL) {
+ address = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (address == NULL) {
+ if (err) {
+ ERR("Failed to get bus address: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+
+ g_conn = g_dbus_connection_new_for_address_sync(address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+ NULL, /* GDBusAuthObserver */
+ NULL,
+ &err);
+ if (!g_conn) {
+ if (err) {
+ ERR("Unable to connect to dbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+ } else if (g_dbus_connection_is_closed(g_conn)) {
+ address = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (address == NULL) {
+ if (err) {
+ ERR("Failed to get bus address: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+
+ local_system_gconn = g_dbus_connection_new_for_address_sync(address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+ NULL, /* GDBusAuthObserver */
+ NULL,
+ &err);
+
+ if (!local_system_gconn) {
+ ERR("Unable to connect to dbus: %s", err->message);
+ g_clear_error(&err);
+ }
+
+ g_conn = local_system_gconn;
+ }
+
+ return g_conn;
+}
+
+static char* __bt_hal_convert_uuid_to_string(bt_uuid_t *srvc_id)
+{
+ char uuid_buf[5];
+ const char *uuid;
+
+ uuid = btuuid2str(srvc_id->uu);
+ DBG("Original UUID [%s]", uuid);
+
+ if (_bt_hal_uuid_is_standard(srvc_id) == TRUE) {
+ /* Extract Standard UUID string */
+ memcpy(uuid_buf, &uuid[4], 4);
+ uuid_buf[4] = '\0';
+ DBG("Converted string [%s]", uuid_buf);
+ return g_strdup(uuid_buf);
+ } else
+ return strdup(uuid);
+}
+
+int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id_t *srvc_id)
+{
+ /* For GATT service specific */
+ GDBusNodeInfo *node_info;
+ guint object_id;
+ gchar *path = NULL;
+ struct gatt_service_info *serv_info = NULL;
+ GVariantBuilder *builder = NULL;
+ GVariantBuilder *builder1 = NULL;
+ GVariantBuilder *inner_builder = NULL;
+ gboolean svc_primary = TRUE;
+ GError *error = NULL;
+ hal_gatt_service_added *user_data = NULL;
+ DBG("Service add to DBUS slot [%d]", slot);
+
+ node_info = __bt_gatt_create_method_node_info(
+ service_introspection_xml);
+
+ if (node_info == NULL)
+ return BT_STATUS_FAIL;
+
+ DBG("Add new GATT Service: Current GATT Service handle [%d]", gatt_service_handle);
+ path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, ++gatt_service_handle);
+ DBG("gatt service path is [%s]", path);
+
+ object_id = g_dbus_connection_register_object(g_conn, path,
+ node_info->interfaces[0],
+ &serv_interface_vtable,
+ NULL, NULL, &error);
+
+ if (object_id == 0) {
+ ERR("failed to register: %s", error->message);
+ g_error_free(error);
+ g_free(path);
+ return BT_STATUS_FAIL;
+ }
+ /* Add object_id/gatt service information; it's required at the time of
+ * service unregister and Getmanagedobjects
+ */
+ serv_info = g_new0(struct gatt_service_info, 1);
+
+ serv_info->serv_path = g_strdup(path);
+ serv_info->serv_id = object_id;
+ serv_info->service_uuid = __bt_hal_convert_uuid_to_string(&srvc_id->id.uuid);//g_strdup(btuuid2str(srvc_id->id.uuid.uu));
+ serv_info->is_svc_registered = FALSE;
+ serv_info->is_svc_primary = svc_primary;
+ DBG("Service Handle to be added is [%d]", gatt_service_handle);
+ serv_info->service_handle = gatt_service_handle;
+
+ /* Update service in GATT Server service List */
+ gatt_services = g_slist_append(gatt_services, serv_info);
+
+ /* emit interfacesadded signal here for service path */
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(inner_builder, "{sv}",
+ "UUID", g_variant_new_string(btuuid2str(srvc_id->id.uuid.uu)));
+
+ g_variant_builder_add(inner_builder, "{sv}",
+ "Primary", g_variant_new_boolean(svc_primary));
+
+ builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
+
+ g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
+ g_variant_new("ao", builder1));
+
+ g_variant_builder_add(builder, "{sa{sv}}",
+ GATT_SERV_INTERFACE, inner_builder);
+
+ g_dbus_connection_emit_signal(g_conn, NULL, "/",
+ "org.freedesktop.Dbus.ObjectManager",
+ "InterfacesAdded",
+ g_variant_new("(oa{sa{sv}})",
+ path, builder),
+ &error);
+
+ /* Send Service handle to application */
+ user_data = g_malloc0(sizeof(hal_gatt_service_added));
+ user_data->srvc_hdl = serv_info->service_handle;
+ user_data->instance_data = slot;
+ memcpy(user_data->uuid.uu, srvc_id->id.uuid.uu, sizeof(srvc_id->id.uuid.uu));
+ g_idle_add(__bt_hal_gatt_service_added_cb, (gpointer)user_data);
+
+ /* Save newly created service in GATT Server's service list */
+ _bt_hal_update_gatt_service_in_gatt_server(slot, serv_info);
+
+ /* Free data */
+ g_free(path);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(builder);
+ g_variant_builder_unref(builder1);
+ return BT_STATUS_SUCCESS;
+}
+
+static void __bt_hal_unregister_application_cb(GObject *object, GAsyncResult *res,
+ gpointer user_data)
+{
+ char *app_path = (char*)user_data;
+ INFO("UnregisterApplication is completed app [%s]", app_path);
+ GError *error = NULL;
+ GVariant *result;
+
+ result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
+
+ if (result == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("Dbus-RPC is failed\n");
+
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]\n",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ } else {
+ g_variant_unref(result);
+ }
+ g_free(app_path);
+}
+
+static void __bt_hal_gatt_deinit(char *app_path)
+{
+ GDBusProxy *proxy = NULL;
+ char *data;
+ INFO("+");
+
+ /* Step1: Remove requested App */
+ proxy = __bt_gatt_gdbus_get_gatt_manager_proxy("org.bluez",
+ "/org/bluez/hci0", "org.bluez.GattManager1");
+
+ if (proxy == NULL)
+ return;
+
+ INFO("UnregisterApplication : path [%s]", app_path);
+
+ /* Async Call to Unregister Service */
+ data = g_strdup(app_path);
+ g_dbus_proxy_call(proxy,
+ "UnregisterApplication",
+ g_variant_new("(o)",
+ app_path),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL,
+ (GAsyncReadyCallback)__bt_hal_unregister_application_cb,
+ (gpointer)data);
+
+ /* If requested app is last GATT Server app, then clean all resources */
+ if (gatt_server_apps == NULL) {
+ INFO("All GATT servers are removed, clean all DBUS resources");
+ if (owner_id) {
+ /* unregister the exported interface for object manager
+ g_conn and manager_id are common for all GATT servers */
+ g_dbus_connection_unregister_object(g_conn,
+ manager_id);
+ manager_id = 0;
+ g_bus_unown_name(owner_id);
+ owner_id = 0;
+
+ g_object_unref(manager_gproxy);
+ manager_gproxy = NULL;
+
+ /* Close the GDBUS connection */
+ __bt_gatt_close_gdbus_connection();
+ }
+ }
+ INFO("-");
+}
+
+int __bt_hal_gatt_init(void)
+{
+ GDBusConnection *conn = NULL;
+ DBG("+");
+ /* Only once for ALL GATT Servers */
+ if (owner_id == 0) {
+ owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
+ BT_GATT_SERVICE_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL, NULL, NULL, NULL, NULL);
+ }
+ INFO("Owner ID [%d]", owner_id);
+
+ /* Only once for ALL GATT Servers conn = g_conn(global)*/
+ conn = __bt_gatt_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return BT_STATUS_FAIL;
+ }
+
+ /* Only once for ALL GATT Servers */
+ if (manager_node_info == NULL) {
+ /* Register ObjectManager interface */
+ manager_node_info = __bt_gatt_create_method_node_info(
+ manager_introspection_xml);
+
+ if (manager_node_info == NULL) {
+ ERR("failed to get node info");
+ return BT_STATUS_FAIL;
+ }
+ }
+
+ INFO("-");
+ return BT_STATUS_SUCCESS;
+}
+
+void _bt_hal_is_gatt_server_initialzed(int slot, char **app_path)
+{
+ GSList *l;
+
+ for (l = gatt_server_apps; l; l = g_slist_next(l)) {
+ struct gatt_server_app *app = (struct gatt_server_app *)l->data;
+ if (app->slot == slot) {
+ INFO("GATT Server app found app path [%s] instance [%d]",
+ app->app_path, app->slot);
+ *app_path = app->app_path;
+ return;
+ }
+ }
+ /* GATT Server not found */
+ *app_path = NULL;
+}
+
+void _bt_hal_update_gatt_server_path(int slot, char *app_path)
+{
+ if (app_path == NULL)
+ return;
+
+ struct gatt_server_app *app = g_malloc0(sizeof(struct gatt_server_app));
+ app->app_path = g_strdup(app_path);
+ app->slot = slot;
+ gatt_server_apps = g_slist_append(gatt_server_apps, app);
+ INFO("GATT Server: Path [%s] Slot [%d]-> Updated", app_path, slot);
+
+}
+
+
+static bt_status_t gatt_server_add_service(int server_if, btgatt_srvc_id_t *srvc_id,
+ int num_handles)
+{
+ CHECK_BTGATT_INIT();
+ char *app_path = NULL;
+ GError *error = NULL;
+ int *app_id = NULL;
+ guint manager_id;
+
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("GATT Server Add service request: Instance ID[%d] Is Primary [%d] UUID [%s]",
+ server_if, srvc_id->is_primary, btuuid2str(srvc_id->id.uuid.uu));
+
+ /* Check if this GATT server Application is already registered with DBUS */
+ _bt_hal_is_gatt_server_initialzed(server_if, &app_path);
+
+ if (app_path != NULL) {
+ DBG("GATT server path is already defined [%s]", app_path);
+ return __bt_hal_add_service_to_dbus(app_path, server_if, srvc_id);
+ } else {
+ DBG("GATT server application path for instance [%d] is not defined yet", server_if);
+ result = __bt_hal_gatt_init();
+ if (result != BT_STATUS_SUCCESS)
+ return result;
+
+ /* Only once for each GATT Server */
+ app_path = g_strdup_printf("/com/%d", server_if);
+
+ app_id = g_malloc0(sizeof(int));
+ *app_id = server_if;
+
+ manager_id = g_dbus_connection_register_object(g_conn, app_path,
+ manager_node_info->interfaces[0],
+ &manager_interface_vtable,
+ (gpointer)app_id, NULL, &error);
+
+ if (manager_id == 0) {
+ ERR("failed to register: %s", error->message);
+ g_error_free(error);
+ goto failed;
+ }
+
+ /* For current GATT Server, app_path is created, save it in Table */
+ _bt_hal_update_gatt_server_path(server_if, app_path);
+
+ /* Add GATT Service to DBUS */
+ if (__bt_hal_add_service_to_dbus(app_path, server_if, srvc_id) != BT_STATUS_SUCCESS)
+ goto failed;
+ }
+
+ INFO("Successfully added service");
+ return BT_STATUS_SUCCESS;
+failed:
+ if (app_id)
+ g_free(app_id);
+ if (app_path)
+ g_free(app_path);
+ INFO("Service addition failed!!");
+ return BT_STATUS_FAIL;
+}
+
+static bt_status_t gatt_server_add_included_service(int server_if, int service_handle,
+ int included_handle)
+{
+ CHECK_BTGATT_INIT();
+ return BT_STATUS_SUCCESS;
+}
+
+
+static gboolean __bt_is_service_last_in_server_list(int instance, int service_handle)
+{
+ GSList *l;
+ GSList *gatt_services = NULL;
+ int len;
+ struct gatt_service_info *info = NULL;
+
+ gatt_services = _bt_get_service_list_from_server(instance);
+
+ len = g_slist_length(gatt_services);
+ l = g_slist_nth(gatt_services, len -1);
+
+ info = l->data;
+
+ if (info->service_handle == service_handle)
+ return TRUE;
+ return FALSE;
+}
+
+static struct gatt_service_info *__bt_gatt_find_gatt_service_info(int instance,
+ int service_handle)
+{
+ GSList *l;
+ GSList *gatt_services = NULL;
+ INFO("Find Service: svc handle [%d] from GATT Server slot[%d]", service_handle, instance);
+
+ gatt_services = _bt_get_service_list_from_server(instance);
+
+ for (l = gatt_services; l != NULL; l = g_slist_next(l)) {
+ struct gatt_service_info *info = l->data;
+ INFO("Got one service with handle [%d]", info->service_handle);
+ if (info->service_handle == service_handle) {
+ return info;
+ }
+ }
+ ERR("Gatt service with handle [%d] not found", service_handle);
+ return NULL;
+}
+
+static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
+ bt_uuid_t *uuid, int properties,
+ int permissions)
+{
+ GError *error = NULL;
+ guint object_id;
+ GDBusNodeInfo *node_info;
+ gchar *path = NULL;
+ GVariantBuilder *builder = NULL;
+ GVariantBuilder *inner_builder = NULL;
+ struct gatt_service_info *serv_info = NULL;
+ struct gatt_char_info *char_info = NULL;
+ GVariantBuilder *builder2 = NULL;
+ GVariantBuilder *builder3 = NULL;
+ GVariant *flags_val = NULL;
+ int i = 0;
+ char *char_flags[NUMBER_OF_FLAGS];
+ int flag_count = 0;
+ hal_gatt_char_added *user_data = NULL;
+ int *app_id;
+
+ CHECK_BTGATT_INIT();
+ DBG("Add new characteristic to GATT Service handle [%d]", service_handle);
+ DBG("Properties of new charateristic [%d] Permission [%d]", properties, permissions);
+
+ serv_info = __bt_gatt_find_gatt_service_info(slot, service_handle);
+ if (serv_info == NULL)
+ return BT_STATUS_FAIL;
+
+ node_info = __bt_gatt_create_method_node_info(
+ characteristics_introspection_xml);
+
+ if (node_info == NULL)
+ return BT_STATUS_FAIL;
+
+ DBG("Add new GATT characteristic: Current GATT char handle [%d]", gatt_char_handle);
+ path = g_strdup_printf("%s/characteristic%d", serv_info->serv_path, ++gatt_char_handle);
+ DBG("gatt characteristic path is [%s]", path);
+
+ app_id = g_malloc0(sizeof(int));
+ *app_id = slot;
+
+ object_id = g_dbus_connection_register_object(g_conn, path,
+ node_info->interfaces[0],
+ &char_interface_vtable,
+ (gpointer)app_id, NULL, &error);
+
+ if (object_id == 0) {
+ ERR("failed to register: %s", error->message);
+ g_error_free(error);
+ g_free(path);
+
+ return BT_STATUS_FAIL;
+ }
+
+ if (permissions & BT_HAL_GATT_PERMISSION_ENCRYPT_READ)
+ properties |= BT_HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ;
+ if (permissions & BT_HAL_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ)
+ properties |= BT_HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ;
+ if (permissions & BT_HAL_GATT_PERMISSION_ENCRYPT_WRITE)
+ properties |= BT_HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE;
+ if (permissions & BT_HAL_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE)
+ properties |= BT_HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE;
+
+ flag_count = bt_hal_gatt_convert_prop2string(properties, char_flags);
+
+ char_info = g_new0(struct gatt_char_info, 1);
+
+ char_info->char_path = g_strdup(path);
+ char_info->char_id = object_id;
+ char_info->char_uuid = __bt_hal_convert_uuid_to_string(uuid);//g_strdup(btuuid2str(uuid->uu));
+ for (i = 0; i < flag_count; i++)
+ char_info->char_flags[i] = char_flags[i];
+
+
+ char_info->flags_length = flag_count;
+ char_info->char_handle = gatt_char_handle;
+
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(inner_builder, "{sv}", "UUID",
+ g_variant_new("s", char_info->char_uuid));
+ g_variant_builder_add(inner_builder, "{sv}", "Service",
+ g_variant_new("o", serv_info->serv_path));
+
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ for (i = 0; i < flag_count; i++)
+ g_variant_builder_add(builder2, "s", char_flags[i]);
+
+ flags_val = g_variant_new("as", builder2);
+ g_variant_builder_add(inner_builder, "{sv}", "Flags",
+ flags_val);
+
+ builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
+
+ g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
+ g_variant_new("ao", builder3));
+
+ g_variant_builder_add(builder, "{sa{sv}}",
+ GATT_CHAR_INTERFACE,
+ inner_builder);
+
+ g_dbus_connection_emit_signal(g_conn, NULL, "/",
+ "org.freedesktop.Dbus.ObjectManager",
+ "InterfacesAdded",
+ g_variant_new("(oa{sa{sv}})",
+ path, builder),
+ &error);
+
+ //*char_path = g_strdup(path);
+
+ //new_char = TRUE;
+
+
+ /* Send Service handle to application */
+ user_data = g_malloc0(sizeof(hal_gatt_char_added));
+ user_data->srvc_hdl = serv_info->service_handle;
+ user_data->char_hdl = gatt_char_handle;
+ user_data->instance_data = slot;
+ memcpy(user_data->uuid.uu, uuid->uu, sizeof(uuid->uu));
+ g_idle_add(__bt_hal_gatt_char_added_cb, (gpointer)user_data);
+
+ /* Save newly created charatcristic to GATT Server's service's characteristic list */
+ serv_info->char_data = g_slist_append(serv_info->char_data, char_info);
+
+ /* Free data */
+ g_free(path);
+
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(builder);
+ g_variant_builder_unref(builder2);
+ g_variant_builder_unref(builder3);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_uuid_t *uuid,
+ int permissions)
+{
+ CHECK_BTGATT_INIT();
+
+// static int desc_id = 1;
+ GError *error = NULL;
+ guint object_id;
+ GDBusNodeInfo *node_info;
+ gchar *path = NULL;
+ GVariantBuilder *builder = NULL;
+ GVariantBuilder *inner_builder = NULL;
+
+ struct gatt_char_info *char_info = NULL;
+ struct gatt_desc_info *desc_info = NULL;
+ struct gatt_service_info *serv_info = NULL;
+
+ gchar **line_argv = NULL;
+ char *serv_path;
+ char *char_path = NULL;
+ GSList *l;
+
+ GVariantBuilder *builder2 = NULL;
+ GVariant *flags_val = NULL;
+ int i = 0;
+ char *desc_flags[NUMBER_OF_FLAGS];
+ int flag_count = 0;
+ int *app_id;
+
+ hal_gatt_desc_added *user_data = NULL;
+#if 0
+ if (new_char) {
+ desc_id = 1;
+ new_char = FALSE;
+ }
+#endif
+ /* Fetch service data for the GATT server */
+ serv_info = __bt_gatt_find_gatt_service_info(slot, service_handle);
+ if (serv_info == NULL)
+ return BT_STATUS_FAIL;
+
+ /* Fetch list of characteristics from the service info */
+ l = serv_info->char_data;
+
+ /* Fetch last char info from the characteristic list */
+ char_info = g_slist_last(l)->data;
+ if (char_info == NULL) {
+ return BT_STATUS_FAIL;
+ }
+
+ /* Fetch characteristic path from char info */
+ char_path = char_info->char_path;
+
+ line_argv = g_strsplit_set(char_path, "/", 0);
+ serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
+
+
+ node_info = __bt_gatt_create_method_node_info(
+ descriptor_introspection_xml);
+
+ if (node_info == NULL) {
+ g_strfreev(line_argv);
+ g_free(serv_path);
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("Add new Descriptor: Current GATT desc handle [%d]", gatt_desc_handle);
+
+ path = g_strdup_printf("%s/descriptor%d", char_path, ++gatt_desc_handle);
+ DBG("gatt descriptor path is [%s]", path);
+
+ app_id = g_malloc0(sizeof(int));
+ *app_id = slot;
+
+ object_id = g_dbus_connection_register_object(g_conn, path,
+ node_info->interfaces[0],
+ &desc_interface_vtable,
+ (gpointer)app_id, NULL, &error);
+
+ if (object_id == 0) {
+ ERR("failed to register: %s", error->message);
+ g_error_free(error);
+ g_free(path);
+ g_strfreev(line_argv);
+ g_free(serv_path);
+
+ return BT_STATUS_FAIL;
+ }
+
+ flag_count = bt_hal_gatt_convert_perm2string(permissions, desc_flags);
-static handle_stack_msg event_cb = NULL;
+ desc_info = g_new0(struct gatt_desc_info, 1);
-typedef struct {
- uint32_t instance_data;
- bt_uuid_t uuid;
-} hal_register_server_data;
+ desc_info->desc_path = g_strdup(path);
+ desc_info->desc_id = object_id;
+ desc_info->desc_uuid = __bt_hal_convert_uuid_to_string(uuid);//g_strdup(btuuid2str(uuid->uu));
-#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\
-{\
- ERR("%s: BTGATT not initialized", __FUNCTION__);\
- return BT_STATUS_NOT_READY;\
-} else {\
- DBG("%s", __FUNCTION__);\
-}
+ for (i = 0; i < flag_count; i++)
+ desc_info->desc_flags[i] = desc_flags[i];
-/* To send stack event to hal-av handler */
-void _bt_hal_register_gatt_server_handler_cb(handle_stack_msg cb)
-{
- event_cb = cb;
-}
+ desc_info->flags_length = flag_count;
+ desc_info->desc_handle = gatt_desc_handle;
-void _bt_hal_unregister_gatt_server_handler_cb(void)
-{
- event_cb = NULL;
-}
-static gboolean __bt_hal_register_slot_id_cb(gpointer user_data)
-{
- struct hal_ev_server_instance_registered ev;
- hal_register_server_data *data = (hal_register_server_data*) user_data;
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
- /* Prepare to send AV connecting event */
- memset(&ev, 0, sizeof(ev));
- ev.status = BT_STATUS_SUCCESS;
- ev.server_instance = data->instance_data;
- memcpy(ev.app_uuid, data->uuid.uu, sizeof(ev.app_uuid));
+ g_variant_builder_add(inner_builder, "{sv}", "UUID",
+ g_variant_new("s", btuuid2str(uuid->uu)));
+ g_variant_builder_add(inner_builder, "{sv}", "Characteristic",
+ g_variant_new("o", char_path));
- if (!event_cb)
- ERR("GATT Register Server Instance Callback not registered");
- else {
- DBG("Server Instance is registered!! server if [%d]", data->instance_data);
- event_cb(HAL_EV_SERVER_INSTANCE_INITIALIZED, (void *)&ev, sizeof(ev));
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
- }
+ for (i = 0; i < flag_count; i++)
+ g_variant_builder_add(builder2, "s", desc_flags[i]);
- g_free(data);
- return FALSE;
-}
+ flags_val = g_variant_new("as", builder2);
+ g_variant_builder_add(inner_builder, "{sv}", "Flags",
+ flags_val);
-static bt_status_t gatt_server_register_app(bt_uuid_t *uuid)
-{
- CHECK_BTGATT_INIT();
- int status = BT_STATUS_FAIL;
- int server_if;
- DBG("Register server instance request");
- hal_register_server_data *user_data = g_malloc0(sizeof(hal_register_server_data));
+ g_variant_builder_add(builder, "{sa{sv}}",
+ GATT_DESC_INTERFACE,
+ inner_builder);
- /* Check if slot available */
- server_if = _bt_hal_get_available_adv_slot_id(uuid);
+ g_dbus_connection_emit_signal(g_conn, NULL, "/",
+ "org.freedesktop.Dbus.ObjectManager",
+ "InterfacesAdded",
+ g_variant_new("(oa{sa{sv}})",
+ path, builder),
+ &error);
- if (server_if == -1) {
- ERR("Allocation of server instance failed");
- g_free(user_data);
- return status;
- } else {
- user_data->instance_data = server_if;
- DBG("Allocated new Advertising slot with Stack [%d]", user_data->instance_data);
- }
+ //*desc_path = g_strdup(path);
- /*
- * As we need to provide async callback to user from HAL, simply schedule a
- * callback method which will carry actual result
- */
- memcpy(user_data->uuid.uu, uuid->uu, sizeof(bt_uuid_t));
- g_idle_add(__bt_hal_register_slot_id_cb, (gpointer)user_data);
+ /* Save newly created descriptor to GATT server's service's characteristic */
+ char_info->desc_data = g_slist_append(char_info->desc_data, desc_info);
- /* If available, then return success, else return error */
- return BT_STATUS_SUCCESS;
-}
+ /* Send descriptor handle to application */
+ user_data = g_malloc0(sizeof(hal_gatt_desc_added));
+ user_data->srvc_hdl = serv_info->service_handle;
+ user_data->desc_hdl = gatt_desc_handle;
+ user_data->instance_data = slot;
+ memcpy(user_data->uuid.uu, uuid->uu, sizeof(uuid->uu));
+ g_idle_add(__bt_hal_gatt_desc_added_cb, (gpointer)user_data);
-static bt_status_t gatt_server_unregister_app(int server_if)
-{
- CHECK_BTGATT_INIT();
- DBG("Un-Register server instance request [%d]", server_if);
- _bt_hal_free_server_slot(server_if);
+ /* Free data */
+ g_free(path);
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(builder);
return BT_STATUS_SUCCESS;
}
-static bt_status_t gatt_server_open(int server_if, const bt_bdaddr_t *bd_addr, bool is_direct)
+static void __bt_hal_register_application_cb(GObject *object, GAsyncResult *res, gpointer user_data)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
-}
+ GError *error = NULL;
+ GVariant *result;
+ char *data = (char*) user_data;
+ INFO("RegisterApplication is completed path [%s]", data);
-static bt_status_t gatt_server_close(int server_if, const bt_bdaddr_t *bd_addr, int conn_id)
-{
- CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
-}
+ result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
-static bt_status_t gatt_server_add_service(int server_if, btgatt_srvc_id_t *srvc_id,
- int num_handles)
-{
- CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+ if (result == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("Dbus-RPC is failed\n");
+
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]\n",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ } else {
+ g_variant_unref(result);
+ }
+ g_free(data);
}
-static bt_status_t gatt_server_add_included_service(int server_if, int service_handle,
- int included_handle)
+static GDBusProxy *__bt_hal_gatt_gdbus_init_manager_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+ GDBusProxy *proxy;
+ GError *err = NULL;
+
+ if (g_conn == NULL)
+ g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM,
+ NULL, &err);
+
+ if (!g_conn) {
+ if (err) {
+ ERR("Unable to connect to gdbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+
+ proxy = g_dbus_proxy_new_sync(g_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ service, path,
+ interface, NULL, &err);
+
+ if (!proxy) {
+ if (err) {
+ ERR("Unable to create proxy: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+ manager_gproxy = proxy;
+
+ return proxy;
}
-static bt_status_t gatt_server_add_characteristic(int server_if, int service_handle,
- bt_uuid_t *uuid, int properties,
- int permissions)
+static GDBusProxy *__bt_gatt_gdbus_get_gatt_manager_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+ return (manager_gproxy) ? manager_gproxy :
+ __bt_hal_gatt_gdbus_init_manager_proxy(service,
+ path, interface);
}
-static bt_status_t gatt_server_add_descriptor(int server_if, int service_handle, bt_uuid_t *uuid,
- int permissions)
+static void __bt_register_application_to_dbus(int slot)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+ GDBusProxy *proxy = NULL;
+ char *app_path = NULL;
+ char *data;
+ DBG("RegisterApplication slot [%d]", slot);
+
+ /* It is impossible that app path is still not initialized */
+ _bt_hal_is_gatt_server_initialzed(slot, &app_path);
+
+ proxy = __bt_gatt_gdbus_get_gatt_manager_proxy("org.bluez",
+ "/org/bluez/hci0", "org.bluez.GattManager1");
+
+ data = g_strdup(app_path);
+ g_dbus_proxy_call(proxy,
+ "RegisterApplication",
+ g_variant_new("(oa{sv})",
+ app_path, NULL),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL,
+ (GAsyncReadyCallback)__bt_hal_register_application_cb,
+ (gpointer)data);
+ INFO("GATT server started");
}
static bt_status_t gatt_server_start_service(int server_if, int service_handle, int transport)
{
CHECK_BTGATT_INIT();
+ struct gatt_service_info *serv_info = NULL;
+ hal_gatt_service_started *user_data = NULL;
+ DBG("Start GATT Service svc hdl [%d], slot [%d]", service_handle, server_if);
+
+ /* Fetch service data for the GATT server */
+ serv_info = __bt_gatt_find_gatt_service_info(server_if, service_handle);
+ if (serv_info == NULL)
+ return BT_STATUS_FAIL;
+
+ if (serv_info->is_svc_registered) {
+ DBG("service already registered \n");
+ }
+
+ serv_info->is_svc_registered = TRUE;
+
+ /* Send Service handle to application */
+ user_data = g_malloc0(sizeof(hal_gatt_service_started));
+ user_data->srvc_hdl = serv_info->service_handle;
+ user_data->instance_data = server_if;
+ g_idle_add(__bt_hal_gatt_service_started_cb, (gpointer)user_data);
+
+ /* If this is nth Service that is started, then register application at this point */
+ if (__bt_is_service_last_in_server_list(server_if, service_handle)) {
+ DBG("This is the last service started from the GATT Server's list of services handle [%d]",
+ service_handle);
+ __bt_register_application_to_dbus(server_if);
+ }
+
return BT_STATUS_SUCCESS;
}
static bt_status_t gatt_server_stop_service(int server_if, int service_handle)
{
CHECK_BTGATT_INIT();
+ INFO("Stop service successful");
return BT_STATUS_SUCCESS;
}
static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+ struct gatt_service_info *serv_info = NULL;
+ hal_gatt_service_deleted *user_data = NULL;
+ GSList *l = NULL;
+ GSList *l1 = NULL;
+ int err = BT_STATUS_SUCCESS;
+ int ret = BT_STATUS_SUCCESS;
+ INFO("Slot [%d] service handle [%d]", server_if, service_handle);
+
+ /* Fetch service data for the GATT server */
+ serv_info = __bt_gatt_find_gatt_service_info(server_if, service_handle);
+ if (serv_info == NULL) {
+ ERR("Could not find service info svc handle [%d] server slot [%d]",
+ service_handle, server_if);
+ return BT_STATUS_FAIL;
+ }
+
+ if (serv_info->is_svc_registered == FALSE) {
+ ERR("service Not registered path [%s] handle [%d]",
+ serv_info->serv_path, service_handle);
+ }
+
+ for (l = serv_info->char_data; l != NULL; l = g_slist_next(l)) {
+ struct gatt_char_info *char_info = l->data;
+
+ if (char_info == NULL)
+ break;
+
+ for (l1 = char_info->desc_data; l1 != NULL; l1 = g_slist_next(l1)) {
+ struct gatt_desc_info *desc_info = l1->data;
+
+ if (desc_info == NULL)
+ break;
+
+ ret = g_dbus_connection_unregister_object(g_conn,
+ desc_info->desc_id);
+ if (ret) {
+ __bt_hal_gatt_emit_interface_removed(
+ desc_info->desc_path,
+ GATT_DESC_INTERFACE);
+ } else {
+ err = BT_STATUS_FAIL;
+ }
+
+ /* list remove & free */
+ char_info->desc_data = g_slist_remove(char_info->desc_data, desc_info);
+ __bt_hal_gatt_free_descriptor_info(desc_info);
+ }
+
+ g_slist_free(char_info->desc_data);
+ char_info->desc_data = NULL;
+
+ ret = g_dbus_connection_unregister_object(g_conn,
+ char_info->char_id);
+ if (ret) {
+ __bt_hal_gatt_emit_interface_removed(char_info->char_path,
+ GATT_CHAR_INTERFACE);
+ } else {
+ INFO("Err");
+ err = BT_STATUS_FAIL;
+ }
+
+ /* list remove & free */
+ serv_info->char_data = g_slist_remove(serv_info->char_data, char_info);
+ __bt_hal_gatt_free_characteristic_info(char_info);
+ }
+
+ g_slist_free(serv_info->char_data);
+ serv_info->char_data = NULL;
+
+ ret = g_dbus_connection_unregister_object(g_conn, serv_info->serv_id);
+ if (ret) {
+ __bt_hal_gatt_emit_interface_removed(serv_info->serv_path,
+ GATT_SERV_INTERFACE);
+ } else {
+ INFO("Failed!!");
+ err = BT_STATUS_FAIL;
+ }
+
+ ret = g_dbus_connection_unregister_object(g_conn, serv_info->prop_id);
+ if (ret)
+ DBG("Unregistered the service on properties interface");
+
+ /* Remove from global list */
+ gatt_services = g_slist_remove(gatt_services, serv_info);
+ INFO("After removing from global list total service dount [%d]", g_slist_length(gatt_services));
+
+ /* Remove from GATT Server's list of services */
+ _bt_remote_service_from_gatt_server(server_if, service_handle);
+
+ if (gatt_services == NULL) {
+ INFO("All GATT Services of all GATT Servers are unregistered");
+ }
+
+ if (err == BT_STATUS_SUCCESS) {
+ INFO("Send GATT Service deleted Event");
+ /* Send Service handle to application */
+ user_data = g_malloc0(sizeof(hal_gatt_service_deleted));
+ user_data->srvc_hdl = serv_info->service_handle;
+ user_data->instance_data = server_if;
+ g_idle_add(__bt_hal_gatt_service_deleted_cb, (gpointer)user_data);
+ }
+
+ /* Free the service */
+ __bt_hal_gatt_free_service_info(serv_info);
+ return err;
+}
+
+static gboolean __bt_gatt_get_service_state(const char *service_path)
+{
+ struct gatt_service_info *svc_info = NULL;
+ GSList *l = NULL;
+
+ for (l= gatt_services; l; l = g_slist_next(l)) {
+
+ svc_info = (struct gatt_service_info *)l->data;
+ if (svc_info->serv_path == service_path) {
+ DBG("Return the state of the gatt service %d",
+ svc_info->is_svc_registered);
+ return svc_info->is_svc_registered;
+ }
+ }
+
+ DBG("gatt service info is NULL");
+ return FALSE;
}
static bt_status_t gatt_server_send_indication(int server_if, int attribute_handle, int conn_id,
int len, int confirm, char* p_value)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+
+ /* For Notifying */
+ GVariantBuilder *outer_builder;
+ GVariantBuilder *invalidated_builder;
+
+ /* For Value update via PropertyChange */
+ GVariantBuilder *outer_builder1;
+ GVariantBuilder *inner_builder1;
+ GVariantBuilder *invalidated_builder1;
+ GVariant *update_value = NULL;
+
+ /* Other variables */
+ struct gatt_client_info_t *conn_info = NULL;
+ gchar *serv_path = NULL;
+ char *char_path = NULL;
+ gchar **line_argv = NULL;
+ gboolean notify = TRUE;
+ gboolean ret = TRUE;
+ int err = BT_STATUS_SUCCESS;
+ char addr[20];
+ GError *error = NULL;
+ int i;
+
+ memset(addr, 0x00, sizeof(addr));
+
+ conn_info = __bt_find_remote_gatt_client_info_from_conn(conn_id);
+ if (conn_info == NULL) {
+ ERR("No Connection Inforamtion!!!");
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("Send Indication to GATT client addr [%s]", conn_info->addr);
+
+ char_path = __bt_gatt_find_char_path_from_handle(attribute_handle);
+ if (char_path == NULL)
+ return BT_STATUS_FAIL;
+
+ line_argv = g_strsplit_set(char_path, "/", 0);
+ serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
+
+ if (!__bt_gatt_get_service_state(serv_path)) {
+ DBG("service not registered for this characteristic \n");
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ return BT_STATUS_FAIL;
+ }
+
+ outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ g_variant_builder_add(outer_builder, "{sv}", "Notifying",
+ g_variant_new("b", notify));
+
+ _bt_convert_addr_type_to_string(addr, (unsigned char *)conn_info->addr);
+
+ g_variant_builder_add(outer_builder, "{sv}", "Unicast",
+ g_variant_new("s", addr));
+
+ DBG("Set characteristic Notification \n");
+ ret = g_dbus_connection_emit_signal(g_conn, NULL,
+ char_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new("(sa{sv}as)",
+ "org.bluez.GattCharacteristic1",
+ outer_builder, invalidated_builder),
+ &error);
+
+ if (!ret) {
+ if (error != NULL) {
+ ERR("D-Bus API failure: errCode[%x], \
+ message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ err = BT_STATUS_FAIL;
+ }
+
+ g_variant_builder_unref(outer_builder);
+ g_variant_builder_unref(invalidated_builder);
+
+
+ /* Notifying Done, now update Value to Bluez via PropertyChanged */
+ invalidated_builder1 = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ for (i = 0; i < len; i++)
+ g_variant_builder_add(inner_builder1, "y", p_value[i]);
+
+ update_value = g_variant_new("ay", inner_builder1);
+
+
+ outer_builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(outer_builder1, "{sv}", "Value",
+ update_value);
+
+ DBG("Updating characteristic value \n");
+ ret = g_dbus_connection_emit_signal(g_conn, NULL,
+ char_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new("(sa{sv}as)",
+ "org.bluez.GattCharacteristic1",
+ outer_builder1, invalidated_builder1),
+ &error);
+
+ if (!ret) {
+ if (error != NULL) {
+ ERR("D-Bus API failure: errCode[%x], \
+ message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ err = BT_STATUS_FAIL;
+ } else {
+ struct gatt_char_info *char_info = NULL;
+
+ char_info = __bt_gatt_find_char_info_from_handle(attribute_handle);
+ if (char_info == NULL) {
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ g_variant_builder_unref(inner_builder1);
+ g_variant_builder_unref(outer_builder1);
+ g_variant_builder_unref(invalidated_builder1);
+
+ return BT_STATUS_FAIL;
+ }
+
+ char_info->value_length = len;
+
+ char_info->char_value = (char *)realloc(char_info->char_value, len);
+ if (char_info->char_value) {
+ for (i = 0; i < len; i++)
+ char_info->char_value[i] = p_value[i];
+ }
+ }
+
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ g_variant_builder_unref(inner_builder1);
+ g_variant_builder_unref(outer_builder1);
+ g_variant_builder_unref(invalidated_builder1);
+
+ return err;
}
static bt_status_t gatt_server_send_response(int conn_id, int trans_id,
int status, btgatt_response_t *response)
{
CHECK_BTGATT_INIT();
+
+ struct gatt_req_info *req_info = NULL;
+ struct gatt_client_info_t *conn_info = NULL;
+ int i;
+
+ DBG("GATT Server Send Response Conn ID [%d]", conn_id);
+
+ conn_info = __bt_find_remote_gatt_client_info_from_conn(conn_id);
+ if (conn_info == NULL) {
+ ERR("No Connection Inforamtion!!!");
+ return BT_STATUS_FAIL;
+ }
+
+ req_info = __bt_find_remote_gatt_client_request_info(conn_id, trans_id);
+ if (req_info == NULL) {
+ ERR("No Request Inforamtion!!!");
+ return BT_STATUS_FAIL;
+ }
+
+ if (status != BT_STATUS_SUCCESS) {
+ ERR("resp_state is 0x%X", status);
+
+ g_dbus_method_invocation_return_dbus_error(req_info->context,
+ "org.bluez.Error.Failed", "Application Error");
+
+ conn_info->gatt_req_info_list = g_slist_remove(conn_info->gatt_req_info_list, req_info);
+
+ req_info->context = NULL;
+ if (req_info->attr_path)
+ g_free(req_info->attr_path);
+ if (req_info->svc_path)
+ g_free(req_info->svc_path);
+ g_free(req_info);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ DBG("Reponse Value length [%d]", response->attr_value.len);
+ /* DEBUG */
+ for(i=0; i < response->attr_value.len; i++) {
+ DBG("Resonse [%d] = [0x%x]", response->attr_value.value[i]);
+
+ }
+
+ if (req_info->request_type == BT_HAL_GATT_REQUEST_TYPE_READ) {
+ GVariantBuilder *inner_builder = NULL;
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+ if (response->attr_value.len > 0) {
+ for (i = 0; i < response->attr_value.len; i++)
+ g_variant_builder_add(inner_builder, "y", response->attr_value.value[i]);
+ }
+ g_dbus_method_invocation_return_value(req_info->context,
+ g_variant_new("(ay)", inner_builder));
+
+ g_variant_builder_unref(inner_builder);
+ } else {
+ g_dbus_method_invocation_return_value(req_info->context, NULL);
+ }
+ conn_info->gatt_req_info_list = g_slist_remove(conn_info->gatt_req_info_list, req_info);
+
+ req_info->context = NULL;
+ if (req_info->attr_path)
+ g_free(req_info->attr_path);
+ if (req_info->svc_path)
+ g_free(req_info->svc_path);
+ g_free(req_info);
+
return BT_STATUS_SUCCESS;
}
+static bt_status_t gatt_server_update_att_value(int server_if, int attribute_handle,
+ int value_length, char* att_value)
+{
+ CHECK_BTGATT_INIT();
+
+ /* Other variables */
+ char *char_path = NULL;
+ gboolean ret = TRUE;
+ GError *error = NULL;
+
+ GVariantBuilder *outer_builder;
+ GVariantBuilder *inner_builder;
+ GVariantBuilder *invalidated_builder;
+ GVariant *update_value = NULL;
+ int err = BT_STATUS_SUCCESS;
+ int i = 0;
+ gchar **line_argv = NULL;
+ gchar *serv_path = NULL;
+
+ char_path = __bt_gatt_find_char_path_from_handle(attribute_handle);
+ if (char_path == NULL)
+ return BT_STATUS_FAIL;
+
+ line_argv = g_strsplit_set(char_path, "/", 0);
+ serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
+
+ if (!__bt_gatt_get_service_state(serv_path)) {
+ DBG("service not registered for this characteristic \n");
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ return BT_STATUS_FAIL;
+ }
+
+ line_argv = g_strsplit_set(char_path, "/", 0);
+ serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
+
+ if (!__bt_gatt_get_service_state(serv_path)) {
+ DBG("service not registered for this characteristic \n");
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ return BT_STATUS_FAIL;
+ }
+
+ outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ for (i = 0; i < value_length; i++)
+ g_variant_builder_add(inner_builder, "y", att_value[i]);
+
+ update_value = g_variant_new("ay", inner_builder);
+
+ outer_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(outer_builder, "{sv}", "Value",
+ update_value);
+
+ DBG("Updating characteristic value \n");
+ ret = g_dbus_connection_emit_signal(g_conn, NULL,
+ char_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new("(sa{sv}as)",
+ "org.bluez.GattCharacteristic1",
+ outer_builder, invalidated_builder),
+ &error);
+
+ if (!ret) {
+ if (error != NULL) {
+ ERR("D-Bus API failure: errCode[%x], \
+ message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ err = BT_STATUS_FAIL;
+ } else {
+ struct gatt_char_info *char_info = NULL;
+
+ char_info = __bt_gatt_find_char_info_from_handle(attribute_handle);
+ if (char_info == NULL) {
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(outer_builder);
+ g_variant_builder_unref(invalidated_builder);
+
+ return BT_STATUS_FAIL;
+ }
+
+ char_info->value_length = value_length;
+
+ char_info->char_value = (char *)realloc(char_info->char_value, value_length);
+ if (char_info->char_value) {
+ for (i = 0; i < value_length; i++)
+ char_info->char_value[i] = att_value[i];
+ }
+ }
+
+ /* Free data */
+ g_free(serv_path);
+ g_strfreev(line_argv);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(outer_builder);
+ g_variant_builder_unref(invalidated_builder);
+
+ return err;
+}
+
static bt_status_t gatt_server_listen(int server_if, bool start)
{
CHECK_BTGATT_INIT();
static bt_status_t gatt_server_multi_adv_enable(int server_if)
{
CHECK_BTGATT_INIT();
- /* Send Data to LE Module */
+ /* Send Enable Advertising request to LE Module */
return _bt_hal_enable_advertising(server_if, TRUE, TRUE);
- return BT_STATUS_SUCCESS;
}
static bt_status_t gatt_server_multi_adv_update(int server_if, int min_interval,int max_interval,int adv_type,
static bt_status_t gatt_server_get_mtu_size(int conn_id, int *mtu_size)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_SUCCESS;
+ char *object_path = NULL;
+
+ GDBusProxy *device_proxy;
+ GError *error = NULL;
+ GVariant *value;
+ GVariant *tmp_value;
+ GDBusConnection *conn;
+ GVariant *result = NULL;
+ int ret = BT_STATUS_SUCCESS;
+ struct gatt_client_info_t *conn_info = NULL;
+ unsigned int mtu;
+
+ if (mtu_size == NULL)
+ return BT_STATUS_PARM_INVALID;
+
+ /* GDBUS Connection Info validate */
+ conn = _bt_get_system_gconn();
+ if (conn == NULL) {
+ ERR("Could not get System DBUS Connection");
+ return BT_STATUS_FAIL;
+ }
+
+ /* Connection Info validate */
+ conn_info = __bt_find_remote_gatt_client_info_from_conn(conn_id);
+ if (conn_info == NULL) {
+ ERR("No Connection Inforamtion!!!");
+ return BT_STATUS_FAIL;
+ }
+
+
+ object_path = _bt_get_device_object_path(conn_info->addr);
+ if (object_path == NULL)
+ return BT_STATUS_FAIL;
+
+ device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME, object_path,
+ BT_HAL_PROPERTIES_INTERFACE, NULL, NULL);
+
+ g_free(object_path);
+ if (device_proxy == NULL)
+ return BT_STATUS_FAIL;
+
+ result = g_dbus_proxy_call_sync(device_proxy, "GetAll",
+ g_variant_new("(s)", BT_HAL_DEVICE_INTERFACE),
+ 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(device_proxy);
+ return BT_STATUS_FAIL;
+ }
+
+ g_variant_get(result , "(@a{sv})", &value);
+ g_variant_unref(result);
+
+ tmp_value = g_variant_lookup_value(value, "AttMtu", G_VARIANT_TYPE_UINT16);
+ if (tmp_value == NULL) {
+ g_object_unref(device_proxy);
+ g_variant_unref(value);
+ return BT_STATUS_FAIL;
+ }
+
+ mtu = g_variant_get_uint16(tmp_value);
+
+ DBG("ATT MTU : [%d]", mtu);
+
+ g_variant_unref(tmp_value);
+ g_variant_unref(value);
+ g_object_unref(device_proxy);
+
+ *mtu_size = (int) mtu;
+
+ return ret;
}
const btgatt_server_interface_t btgatt_server_interface = {
gatt_server_delete_service,
gatt_server_send_indication,
gatt_server_send_response,
+ gatt_server_update_att_value,
gatt_server_listen,
gatt_server_set_adv_data,
gatt_server_multi_adv_enable,