X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-oal%2Fbluez_hal%2Fsrc%2Fbt-hal-gatt-server.c;h=26d15c865bf1b28cd562cab1b68224f3f683aa48;hb=cd9e35acccf53453cf686a5b82e7ceac7707bea9;hp=12f672ab21a65990927f39cd5389bbadf56bdc76;hpb=139e5eb4d25f99975e443ccc89d7247a52f8f220;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-oal/bluez_hal/src/bt-hal-gatt-server.c b/bt-oal/bluez_hal/src/bt-hal-gatt-server.c index 12f672a..26d15c8 100644 --- a/bt-oal/bluez_hal/src/bt-hal-gatt-server.c +++ b/bt-oal/bluez_hal/src/bt-hal-gatt-server.c @@ -40,6 +40,7 @@ #include "bt-hal-utils.h" #include "bt-hal-dbus-common-utils.h" +#include "bt-hal-gatt.h" #include "bt-hal-adapter-le.h" #include "bt-hal-event-receiver.h" @@ -58,11 +59,10 @@ 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; +static guint owner_id; +static GDBusConnection *g_conn = NULL; +static GDBusNodeInfo *manager_node_info = NULL; +static guint manager_id; /* Global handles which needs to be incremented during each addition */ static int gatt_service_handle = 10; @@ -111,6 +111,8 @@ 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_HAL_GATT_REQUEST_TYPE_ACQUIRE_WRITE = 0x03, /* Exec Write Requested */ + BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_NOTIFY = 0x04, /* Exec Write Requested */ } bt_gatt_request_type_e; struct gatt_req_info { @@ -133,7 +135,7 @@ static GSList *gatt_server_apps = NULL; static GSList *gatt_services = NULL; -static int conn_id = 0; +extern int hal_gatt_conn_id; /* Linked List of connected Remote GATT clients */ static GSList *gatt_client_info_list = NULL; @@ -184,7 +186,25 @@ typedef struct { bt_uuid_t uuid; } hal_gatt_desc_added; -#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\ + +struct hal_gatts_server_register_info_t { + int server_if; + int adv_slot_id; + bt_uuid_t app_uuid; +}; + +static GSList * hal_gatts_server_register_list; + + +/* Should match the range with bt-service-gatt.c's MAX_APPS_SUPPORTED */ +/* TODO: Adjust MAX Server after modifying MAX app handle logic */ +#define BT_GATTS_MAX 11 + +static int assigned_id = 0; + +static gboolean instance_id_used[BT_GATTS_MAX]; + +#define CHECK_BTGATT_INIT() if (_bt_hal_gatt_interface_ready() == false)\ {\ ERR("%s: BTGATT not initialized", __FUNCTION__);\ return BT_STATUS_NOT_READY;\ @@ -205,6 +225,8 @@ static void __bt_hal_unregister_application_cb(GObject *object, GAsyncResult *re static GDBusProxy *__bt_gatt_gdbus_get_gatt_manager_proxy(const gchar *service, const gchar *path, const gchar *interface); +static int bt_hal_gatts_get_gatt_server_instance(); + /* Introspection data for the service we are exporting */ static const gchar service_introspection_xml[] = "" @@ -228,7 +250,7 @@ static const gchar characteristics_introspection_xml[] = " " " " " " -" " +" " " " " " " " @@ -239,6 +261,16 @@ static const gchar characteristics_introspection_xml[] = " " " " " " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " " " " " " " @@ -263,6 +295,10 @@ static const gchar characteristics_introspection_xml[] = " " " " " " +" " +" " +" " +" " " " ""; @@ -306,7 +342,74 @@ static const gchar manager_introspection_xml[] = " " ""; -GSList *_bt_get_service_list_from_server(int instance) +static void __bt_free_gatt_server_app(struct gatt_server_app *app) +{ + g_free(app->app_path); + g_free(app); +} + +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); +} + +void _bt_hal_gatt_server_init(void) +{ + assigned_id = 0; + memset(instance_id_used, 0x00, sizeof(instance_id_used)); + + g_slist_free_full(gatt_server_apps, (GDestroyNotify)__bt_free_gatt_server_app); + gatt_server_apps = NULL; + + g_slist_free_full(gatt_services, (GDestroyNotify)__bt_hal_gatt_free_service_info); + gatt_services = NULL; + + g_slist_free_full(hal_gatts_server_register_list, g_free); + hal_gatts_server_register_list = NULL; +} + +static int __bt_hal_gatt_assign_id(void) +{ + int index; + + index = assigned_id + 1; + + if (index >= BT_GATTS_MAX) + index = 1; + + while (instance_id_used[index] == TRUE) { + if (index == assigned_id) { + /* No available ID */ + ERR("All interface ID is used"); + return -1; + } + + index++; + + if (index >= BT_GATTS_MAX) + index = 1; + } + + assigned_id = index; + instance_id_used[index] = TRUE; + + return assigned_id; +} + +static void __bt_hal_gatt_delete_id(int instance_id) +{ + if (instance_id >= BT_GATTS_MAX || instance_id < 0) + return; + + instance_id_used[instance_id] = FALSE; +} + +static GSList *_bt_get_service_list_from_server(int instance) { GSList *l; INFO("Number of GATT Server apps [%d]", g_slist_length(gatt_server_apps)); @@ -324,7 +427,25 @@ GSList *_bt_get_service_list_from_server(int instance) return NULL; } -void _bt_remote_service_from_gatt_server(int instance, int service_handle) +static char *__bt_get_server_app_path_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, App path [%s]", + app->slot, app->app_path); + return app->app_path; + } + } + return NULL; +} + +static void _bt_remote_service_from_gatt_server(int instance, int service_handle) { GSList *l; GSList *l1; @@ -344,7 +465,7 @@ void _bt_remote_service_from_gatt_server(int instance, int service_handle) } } -void _bt_hal_update_gatt_service_in_gatt_server(int slot, struct gatt_service_info *serv_info) +static 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)) { @@ -358,7 +479,7 @@ void _bt_hal_update_gatt_service_in_gatt_server(int slot, struct gatt_service_in } } -static struct gatt_client_info_t *__bt_find_remote_gatt_client_info(char *address) +int _bt_get_remote_gatt_client_conn_id(char *address) { GSList *l; struct gatt_client_info_t *info = NULL; @@ -370,9 +491,25 @@ static struct gatt_client_info_t *__bt_find_remote_gatt_client_info(char *addres if (!g_strcmp0(info->addr, address)) { INFO("Remote GATT client found addr[%s]", info->addr); - return info; + return info->connection_id; } } + return 0; +} + +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)) + return info; + } return NULL; } @@ -386,10 +523,8 @@ static struct gatt_client_info_t *__bt_find_remote_gatt_client_info_from_conn(in if (info == NULL) continue; - if (info->connection_id == conn_id) { - INFO("Remote GATT client found addr[%s]", info->addr); + if (info->connection_id == conn_id) return info; - } } return NULL; } @@ -415,10 +550,8 @@ static struct gatt_req_info *__bt_find_remote_gatt_client_request_info(int conn_ if (info1 == NULL) continue; - if (info1->request_id == trans_id) { - INFO("Remote GATT client found addr[%s]", info->addr); + if (info1->request_id == trans_id) return info1; - } } } } @@ -429,16 +562,8 @@ 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_hal_convert_addr_string_to_type(ev.bdaddr, address); @@ -446,7 +571,6 @@ void _bt_hal_gatt_connected_state_event(gboolean is_connected, char *address) /* 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"); @@ -472,12 +596,26 @@ void _bt_hal_gatt_connected_state_event(gboolean is_connected, char *address) } /* If connected, and conn info NOT found, then add conn info */ } else { + int instance = -1; + + /* Find Server Instance */ + instance = bt_hal_gatts_get_gatt_server_instance(); + if (instance == -1) { + ERR("Not even a single GATT server is registered"); + ev.conn_id = ++hal_gatt_conn_id; + ev.server_instance = -1; + ev.connected = is_connected; + event_cb(HAL_EV_GATT_SERVER_CONNECTED, (void *)&ev, sizeof(ev)); + return; + } + DBG("server instance [%d]", instance); + 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; + DBG("Added GATT client addr[%s]", conn_info->addr); + conn_info->connection_id = ++hal_gatt_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)); @@ -493,6 +631,8 @@ void _bt_hal_gatt_connected_state_event(gboolean is_connected, char *address) event_cb(HAL_EV_GATT_SERVER_CONNECTED, (void *)&ev, sizeof(ev)); } + } else { + ERR("Abnormal case. conn_info should be NULL"); } } /* Send GATT connected or disconnected event */ @@ -519,7 +659,7 @@ static struct gatt_service_info *__bt_gatt_find_gatt_service_from_char(const cha return NULL; } -char *__bt_gatt_find_char_path_from_handle(int char_hdl) +static char *__bt_gatt_find_char_path_from_handle(int char_hdl) { GSList *l1, *l2; @@ -537,7 +677,7 @@ char *__bt_gatt_find_char_path_from_handle(int char_hdl) return NULL; } -struct gatt_char_info *__bt_gatt_find_char_info_from_handle(int char_hdl) +static struct gatt_char_info *__bt_gatt_find_char_info_from_handle(int char_hdl) { GSList *l1, *l2; @@ -599,6 +739,8 @@ static void __bt_gatt_manager_method_call(GDBusConnection *connection, GSList *gatt_services = NULL; int *instance; instance = (int*)user_data; + gboolean writeAcquired = FALSE; + gboolean notifyAcquired = FALSE; DBG("Getting values for service, chars and descriptors"); DBG("GATT Server App for which services are requested [%d]", *instance); @@ -613,6 +755,7 @@ static void __bt_gatt_manager_method_call(GDBusConnection *connection, if (g_slist_length(gatt_services) == 0) { ERR("No registered GATT services!!!!"); g_dbus_method_invocation_return_value(invocation, NULL); + g_variant_builder_unref(builder); return; } @@ -718,6 +861,16 @@ static void __bt_gatt_manager_method_call(GDBusConnection *connection, for (i = 0; i < char_info->flags_length; i++) { g_variant_builder_add(builder2, "s", char_info->char_flags[i]); + + if (strncmp(char_info->char_flags[i], "write-without-response", 16) == 0) { + DBG("setting WriteAcquired property"); + writeAcquired = TRUE; + } + + if (strncmp(char_info->char_flags[i], "notify", 4) == 0) { + DBG("setting NotifyAcquired property"); + notifyAcquired = TRUE; + } } flags_val = g_variant_new("as", builder2); @@ -728,6 +881,20 @@ static void __bt_gatt_manager_method_call(GDBusConnection *connection, g_variant_builder_add(inner_builder, "{sv}", "Notifying", g_variant_new("b", notify)); + /* WriteAcquired */ + if (writeAcquired == TRUE) { + DBG("adding WriteAcquired property"); + g_variant_builder_add(inner_builder, "{sv}", "WriteAcquired", + g_variant_new("b", writeAcquired)); + } + + /* NotifyAcquired */ + if (notifyAcquired == TRUE) { + DBG("adding NotifyAcquired property"); + g_variant_builder_add(inner_builder, "{sv}", "NotifyAcquired", + g_variant_new("b", notifyAcquired)); + } + /* Unicast */ unicast = g_strdup("00:00:00:00:00:00"); g_variant_builder_add(inner_builder, "{sv}", "Unicast", @@ -919,6 +1086,7 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection, 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->request_type = BT_HAL_GATT_REQUEST_TYPE_READ; req_info->offset = offset; req_info->context = invocation; @@ -990,6 +1158,7 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection, 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->request_type = BT_HAL_GATT_REQUEST_TYPE_WRITE; req_info->offset = offset; req_info->context = invocation; @@ -1037,8 +1206,10 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, 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); + g_variant_get(parameters, "(&suq)", + &addr, &req_id, &offset); + + DBG("ReadValue : req id %u, offset %u, path %s, sender %s, %s", req_id, offset, object_path, sender, addr); /* Check if device is already in connected list */ conn_info = __bt_find_remote_gatt_client_info(addr); @@ -1046,6 +1217,7 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl); if (svc_info == NULL || conn_info == NULL) { + ERR("Invalid information %p, %p", svc_info, conn_info); g_dbus_method_invocation_return_value(invocation, NULL); return; } @@ -1056,9 +1228,6 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, 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); @@ -1081,7 +1250,6 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, /* Convert address to hex */ _bt_hal_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) { @@ -1100,9 +1268,7 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, memset(&ev, 0, sizeof(ev)); - DBG("WriteValue"); - DBG("Application path = %s", object_path); - DBG("Sender = %s", sender); + DBG("WriteValue : Application path %s, sender %s", object_path, sender); g_variant_get(parameters, "(&suqb@ay)", &addr, &req_id, &offset, &response_needed, &var); @@ -1221,9 +1387,7 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, struct hal_ev_gatt_server_indicate_cfm ev; - DBG("IndicateConfirm"); - DBG("Application path = %s", object_path); - DBG("Sender = %s", sender); + DBG("IndicateConfirm : Application path %s, sender %s", object_path, sender); g_variant_get(parameters, "(&sb)", &addr, &complete); DBG("Remote Device address number = %s", addr); @@ -1249,12 +1413,144 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, _bt_hal_convert_addr_string_to_type(ev.bdaddr, addr); event_cb(HAL_EV_GATT_INDICATE_CFM, (void *)&ev, sizeof(ev)); + } else if (g_strcmp0(method_name, "AcquireWrite") == 0) { + + uint16_t mtu = 512; + int char_hdl = -1; + struct hal_ev_gatt_server_acquire_write_res ev; + struct gatt_service_info *svc_info = NULL; + struct gatt_req_info *req_info = NULL; + struct gatt_client_info_t *conn_info = NULL; + char *dev_path = NULL; + char *link = NULL; + char addr[BT_HAL_ADDRESS_STRING_SIZE]; + + DBG("AcquireWrite : Application path %s, sender %s", object_path, sender); + + GVariantIter* iter; + g_variant_get(parameters, "(a{sv})", &iter); + char *key = NULL; + GVariant *value = NULL; + while (g_variant_iter_loop(iter, "{sv}", &key, &value)) { + if (g_strcmp0(key, "MTU") == 0) + g_variant_get(value, "q", &mtu); + else if (g_strcmp0(key, "link") == 0) + g_variant_get(value, "s", &link); + else if (g_strcmp0(key, "device") == 0) + g_variant_get(value, "o", &dev_path); + } + + DBG(" path %s LINK = %s, MTU = %u", dev_path, link, mtu); + + svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl); + + _bt_hal_convert_device_path_to_address(dev_path, addr); + + DBG("remote address %s", addr); + g_free(link); + g_free(dev_path); + + /* Check if device is already in connected list */ + conn_info = __bt_find_remote_gatt_client_info(addr); + if (conn_info == NULL) { + ERR("Cleint info not found\n"); + g_variant_iter_free(iter); + goto done; + } + + if (svc_info == NULL) { + ERR("svc_info info not found\n"); + g_variant_iter_free(iter); + goto done; + } + + /* 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 = conn_info->connection_id; + req_info->request_type = BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_WRITE; + req_info->offset = mtu; + 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.char_handl = char_hdl; + ev.mtu = mtu; + ev.trans_id = conn_info->connection_id; + _bt_hal_convert_addr_string_to_type(ev.bdaddr, addr); + event_cb(HAL_EV_GATT_SERVER_ACQUIRE_WRITE_RES, (void *)&ev, sizeof(ev)); + g_variant_iter_free(iter); + return; + } else if (g_strcmp0(method_name, "AcquireNotify") == 0) { + + uint16_t mtu = 512; + int char_hdl = -1; + struct hal_ev_gatt_server_acquire_notify ev; + struct gatt_service_info *svc_info = NULL; + struct gatt_client_info_t *conn_info = NULL; + struct gatt_req_info *req_info = NULL; + + DBG("AcquireNotify : Application path %s, sender %s", object_path, sender); + + GVariantIter* iter; + g_variant_get(parameters, "(a{sv})", &iter); + char* key = NULL; + GVariant* value = NULL; + while (g_variant_iter_loop(iter, "{sv}", &key, &value)) { + if (g_strcmp0(key, "MTU") == 0) + g_variant_get(value, "q", &mtu); + } + + DBG("MTU = %u", mtu); + + svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl); + + if (svc_info == NULL) { + ERR("svc_info info not found\n"); + g_variant_iter_free(iter); + goto done; + } + + /* 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 = 33; + req_info->request_type = BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_NOTIFY; + req_info->offset = mtu; + req_info->context = invocation; + + conn_info = g_new0(struct gatt_client_info_t, 1); + conn_info->addr = g_strdup(object_path); + INFO("AcquireNotify : Added GATT client path[%s]", conn_info->addr); + conn_info->connection_id = 33; + conn_info->instance_id = 33; + /* 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); + gatt_client_info_list = g_slist_append(gatt_client_info_list, conn_info); + + /* Send HAL event */ + memset(&ev, 0, sizeof(ev)); + ev.conn_id = 33; + ev.char_handl = char_hdl; + ev.mtu = mtu; + ev.trans_id = 33; + + event_cb(HAL_EV_GATT_SERVER_ACQUIRE_NOTIFY_RES, (void *)&ev, sizeof(ev)); + g_variant_iter_free(iter); + return; } +done: g_dbus_method_invocation_return_value(invocation, NULL); } -gboolean __bt_hal_gatt_emit_interface_removed(gchar *object_path, gchar *interface) +static gboolean __bt_hal_gatt_emit_interface_removed(const char *app_path, gchar *object_path, gchar *interface) { gboolean ret; GError *error = NULL; @@ -1264,8 +1560,8 @@ gboolean __bt_hal_gatt_emit_interface_removed(gchar *object_path, gchar *interfa 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", + ret = g_dbus_connection_emit_signal(g_conn, NULL, app_path, + "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", g_variant_new("(oas)", object_path, array_builder), @@ -1318,17 +1614,6 @@ static void __bt_hal_gatt_free_characteristic_info(struct gatt_char_info *char_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, @@ -1532,180 +1817,298 @@ static gboolean __bt_hal_register_slot_id_cb(gpointer user_data) return FALSE; } -static bt_status_t gatt_server_register_app(bt_uuid_t *uuid) + +static int bt_hal_gatts_get_gatt_server_instance() { - 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)); + DBG("+"); - /* Check if slot available */ - server_if = _bt_hal_get_available_adv_slot_id(uuid); + GSList *l; + struct hal_gatts_server_register_info_t *info = NULL; - 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); - } + for (l = hal_gatts_server_register_list; l != NULL; l = g_slist_next(l)) { + info = (struct hal_gatts_server_register_info_t *)l->data; + if (info == NULL) { + continue; + } - /* - * 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); + return info->server_if; + } - /* If available, then return success, else return error */ - return BT_STATUS_SUCCESS; + return -1; } -void _bt_hal_remove_gatt_server_from_list(int server_if) +static struct hal_gatts_server_register_info_t * bt_hal_gatts_find_server_register_info_from_uuid(bt_uuid_t *app_uuid) { + DBG("+"); + GSList *l; - struct gatt_server_app *info = NULL; + struct hal_gatts_server_register_info_t *info = NULL; - for (l = gatt_server_apps; l != NULL;) { - info = (struct gatt_server_app*)l->data; - l = g_slist_next(l); - if (info == NULL) + for (l = hal_gatts_server_register_list; l != NULL; l = g_slist_next(l)) { + info = (struct hal_gatts_server_register_info_t *)l->data; + 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)); - } + if (memcmp(&info->app_uuid, app_uuid, sizeof(bt_uuid_t)) == 0) { + DBG("gatt server register found"); + return info; } } + + return NULL; } -static bt_status_t gatt_server_unregister_app(int server_if) +static struct hal_gatts_server_register_info_t * bt_hal_gatts_find_server_register_info(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); + GSList *l; + struct hal_gatts_server_register_info_t *info = NULL; - /* 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; -} + for (l = hal_gatts_server_register_list; l != NULL; l = g_slist_next(l)) { + info = (struct hal_gatts_server_register_info_t *)l->data; + if (info == NULL) { + continue; + } -static bt_status_t gatt_server_open(int server_if, const bt_bdaddr_t *bd_addr, bool is_direct) + if (info->server_if == server_if) { + return info; + } + } + + return NULL; +} + +static struct hal_gatts_server_register_info_t * bt_hal_gatts_find_server_register_info_by_slot_id(int adv_slot_id) +{ + DBG("+"); + + GSList *l; + struct hal_gatts_server_register_info_t *info = NULL; + + for (l = hal_gatts_server_register_list; l != NULL; l = g_slist_next(l)) { + info = (struct hal_gatts_server_register_info_t *)l->data; + if (info == NULL) { + continue; + } + + if (info->adv_slot_id == adv_slot_id) { + DBG("gatt server register found"); + return info; + } + } + + return NULL; +} + +static struct hal_gatts_server_register_info_t * bt_hal_gatts_add_server_app(bt_uuid_t *app_uuid) +{ + struct hal_gatts_server_register_info_t * server_register_info = NULL; + int instance_id = 0; + + server_register_info = bt_hal_gatts_find_server_register_info_from_uuid(app_uuid); + if (server_register_info != NULL) { + DBG("gatt server is already registered"); + return server_register_info; + } + + instance_id = __bt_hal_gatt_assign_id(); + if (instance_id == -1) { + ERR("Fail to allocate the server if"); + return NULL; + } + + server_register_info = g_malloc0(sizeof(struct hal_gatts_server_register_info_t)); + server_register_info->server_if = instance_id; + + DBG("Adding the gatt server app. server_if:[%d]", server_register_info->server_if); + + server_register_info->adv_slot_id = -1; + memcpy(&server_register_info->app_uuid, app_uuid, sizeof(bt_uuid_t)); + hal_gatts_server_register_list = g_slist_append(hal_gatts_server_register_list, server_register_info); + + return server_register_info; +} + +static bt_status_t gatt_server_register_app(bt_uuid_t *uuid) { CHECK_BTGATT_INIT(); + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + DBG("Register server instance request"); + server_register_info = bt_hal_gatts_add_server_app(uuid); + if (server_register_info == NULL) { + ERR("Fail to register the server app"); + return BT_STATUS_FAIL; + } + + hal_register_server_data *user_data = g_malloc0(sizeof(hal_register_server_data)); + user_data->instance_data = server_register_info->server_if; + + /* + * 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; } -static bt_status_t gatt_server_close(int server_if, const bt_bdaddr_t *bd_addr, int conn_id) +static 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); + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + DBG("gatt server is not registered"); + return BT_STATUS_SUCCESS; + } + + /* remove the gatt server register info from the register list */ + hal_gatts_server_register_list = g_slist_remove(hal_gatts_server_register_list, server_register_info); + g_free(server_register_info); + + __bt_hal_gatt_delete_id(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 void __bt_gatt_close_gdbus_connection(void) +static bt_status_t gatt_server_open(int server_if, const bt_bdaddr_t *bd_addr, bool is_direct) { - GError *err = NULL; - DBG("+"); + CHECK_BTGATT_INIT(); + return BT_STATUS_SUCCESS; +} - if (g_conn == NULL) - return; +static void __le_disconnection_req_cb(GDBusProxy *proxy, GAsyncResult *res, + gpointer user_data) +{ + GError *g_error = NULL; + GVariant *reply = NULL; - 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; - } + DBG("+"); - 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); + reply = g_dbus_proxy_call_finish(proxy, res, &g_error); + g_object_unref(proxy); + if (reply == NULL) { + ERR("Disconnect LE Dbus Call Error"); + if (g_error) { + ERR("Error: %s\n", g_error->message); + g_clear_error(&g_error); } } - - g_object_unref(g_conn); - g_conn = NULL; - DBG("-"); + g_variant_unref(reply); } -static GDBusConnection *__bt_gatt_get_gdbus_connection(void) + +static bt_status_t gatt_server_close(int server_if, const bt_bdaddr_t *bd_addr, int conn_id) { - GDBusConnection *local_system_gconn = NULL; - char *address; - GError *err = NULL; + CHECK_BTGATT_INIT(); + + char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 }; + gchar *device_path; + GDBusProxy *device_proxy; + GDBusConnection *g_conn; + struct gatt_client_info_t *conn_info = NULL; + + INFO("+"); + if (NULL == bd_addr) { + ERR("bd_addr is NULL"); + return BT_STATUS_PARM_INVALID; + } + + /* GDBUS Connection Info validate */ + g_conn = _bt_hal_get_system_gconn(); 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; - } + ERR("Could not get System DBUS Connection"); + return BT_STATUS_FAIL; + } - 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; - } + /* 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; + } - 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); + _bt_hal_convert_addr_type_to_string(device_address, + (unsigned char *)bd_addr->address); - if (!local_system_gconn) { - ERR("Unable to connect to dbus: %s", err->message); - g_clear_error(&err); - } + //check if connection has the same device address + if (g_strcmp0(conn_info->addr, device_address) != 0) { + ERR("device address [%s] does not match", device_address); + return BT_STATUS_FAIL; + } - g_conn = local_system_gconn; + device_path = _bt_hal_get_device_object_path(conn_info->addr); + if (device_path == NULL) { + ERR("device_path is NULL"); + return BT_STATUS_PARM_INVALID; } - return g_conn; + device_proxy = g_dbus_proxy_new_sync(g_conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_HAL_BLUEZ_NAME, + device_path, BT_HAL_DEVICE_INTERFACE, NULL, NULL); + + + g_free(device_path); + if (device_proxy == NULL) + return BT_STATUS_FAIL; + + INFO("Disconnect LE [%s]", device_address); + + g_dbus_proxy_call(device_proxy, "DisconnectLE", + NULL, + G_DBUS_CALL_FLAGS_NONE, + BT_HAL_MAX_DBUS_TIMEOUT, + NULL, + (GAsyncReadyCallback)__le_disconnection_req_cb, conn_info); + + INFO("-"); + return BT_STATUS_SUCCESS; } static char* __bt_hal_convert_uuid_to_string(bt_uuid_t *srvc_id) @@ -1726,7 +2129,7 @@ static char* __bt_hal_convert_uuid_to_string(bt_uuid_t *srvc_id) return strdup(uuid); } -int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id_t *srvc_id) +static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id_t *srvc_id) { gboolean ret; /* For GATT service specific */ @@ -1798,7 +2201,7 @@ int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id_t *srv GATT_SERV_INTERFACE, inner_builder); ret = g_dbus_connection_emit_signal(g_conn, NULL, "/", - "org.freedesktop.Dbus.ObjectManager", + "org.freedesktop.Dbus.ObjectManager", // TODO: need to check Dbus is working or not "InterfacesAdded", g_variant_new("(oa{sa{sv}})", path, builder), @@ -1887,43 +2290,47 @@ static void __bt_hal_gatt_deinit(char *app_path) 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); + /* unregister the exported interface for object manager */ + 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) +static 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); + GError *err = NULL; + gchar *name = NULL; - /* 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; + 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 BT_STATUS_FAIL; + } + + name = g_strdup_printf("%s.p%d", BT_GATT_SERVICE_NAME, getpid()); + INFO("well-known name: %s", name); + + owner_id = g_bus_own_name_on_connection(g_conn, name, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, NULL, NULL, NULL); + + g_free(name); } + INFO("Owner ID [%d]", owner_id); /* Only once for ALL GATT Servers */ if (manager_node_info == NULL) { @@ -1941,7 +2348,7 @@ int __bt_hal_gatt_init(void) return BT_STATUS_SUCCESS; } -void _bt_hal_is_gatt_server_initialzed(int slot, char **app_path) +static void _bt_hal_is_gatt_server_initialzed(int slot, char **app_path) { GSList *l; @@ -1958,7 +2365,7 @@ void _bt_hal_is_gatt_server_initialzed(int slot, char **app_path) *app_path = NULL; } -void _bt_hal_update_gatt_server_path(int slot, char *app_path) +static void _bt_hal_update_gatt_server_path(int slot, char *app_path) { if (app_path == NULL) return; @@ -1968,10 +2375,8 @@ void _bt_hal_update_gatt_server_path(int slot, char *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) { @@ -1979,7 +2384,6 @@ static bt_status_t gatt_server_add_service(int server_if, btgatt_srvc_id_t *srvc char *app_path = NULL; GError *error = NULL; int *app_id = NULL; - guint manager_id; int result = BT_STATUS_SUCCESS; @@ -2014,6 +2418,7 @@ static bt_status_t gatt_server_add_service(int server_if, btgatt_srvc_id_t *srvc g_error_free(error); goto failed; } + INFO("manager_id [%d]", manager_id); /* For current GATT Server, app_path is created, save it in Table */ _bt_hal_update_gatt_server_path(server_if, app_path); @@ -2261,14 +2666,8 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u 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) @@ -2363,6 +2762,11 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u g_variant_new("(oa{sa{sv}})", path, builder), &error); + if (error != NULL) { + ERR("g_dbus_connection_emit_signal failed: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } //*desc_path = g_strdup(path); @@ -2528,6 +2932,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle) GSList *l1 = NULL; int err = BT_STATUS_SUCCESS; int ret = BT_STATUS_SUCCESS; + char *app_path = NULL; INFO("Slot [%d] service handle [%d]", server_if, service_handle); /* Fetch service data for the GATT server */ @@ -2538,6 +2943,13 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle) return BT_STATUS_FAIL; } + app_path = __bt_get_server_app_path_from_server(server_if); + if (app_path == 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); @@ -2559,6 +2971,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle) desc_info->desc_id); if (ret) { __bt_hal_gatt_emit_interface_removed( + app_path, desc_info->desc_path, GATT_DESC_INTERFACE); } else { @@ -2576,7 +2989,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle) ret = g_dbus_connection_unregister_object(g_conn, char_info->char_id); if (ret) { - __bt_hal_gatt_emit_interface_removed(char_info->char_path, + __bt_hal_gatt_emit_interface_removed(app_path, char_info->char_path, GATT_CHAR_INTERFACE); } else { INFO("Err"); @@ -2593,7 +3006,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle) ret = g_dbus_connection_unregister_object(g_conn, serv_info->serv_id); if (ret) { - __bt_hal_gatt_emit_interface_removed(serv_info->serv_path, + __bt_hal_gatt_emit_interface_removed(app_path, serv_info->serv_path, GATT_SERV_INTERFACE); } else { INFO("Failed!!"); @@ -2632,15 +3045,12 @@ 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); + + if (!g_strcmp0(svc_info->serv_path, service_path)) return svc_info->is_svc_registered; - } } DBG("gatt service info is NULL"); @@ -2704,7 +3114,8 @@ static bt_status_t gatt_server_send_indication(int server_if, int attribute_hand g_variant_builder_add(outer_builder, "{sv}", "Notifying", g_variant_new("b", notify)); - _bt_hal_convert_addr_type_to_string(addr, (unsigned char *)conn_info->addr); + memcpy(addr, conn_info->addr, BT_HAL_ADDRESS_STRING_SIZE); + DBG("Send Indication to Unicast addr [%s]", addr); g_variant_builder_add(outer_builder, "{sv}", "Unicast", g_variant_new("s", addr)); @@ -2806,22 +3217,20 @@ static bt_status_t gatt_server_send_response(int conn_id, int trans_id, 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!!!"); + ERR("No Connection Inforamtion. conn_id %d", conn_id); 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!!!"); + ERR("No Request Inforamtion. conn_id %d", conn_id); return BT_STATUS_FAIL; } if (status != BT_STATUS_SUCCESS) { - ERR("resp_state is 0x%X", status); + ERR("resp_state is 0x%X, conn_id %d", status, conn_id); g_dbus_method_invocation_return_dbus_error(req_info->context, "org.bluez.Error.Failed", "Application Error"); @@ -2838,13 +3247,6 @@ static bt_status_t gatt_server_send_response(int conn_id, int trans_id, return BT_STATUS_SUCCESS; } - DBG("Reponse Value length [%d]", response->attr_value.len); - DBG("Request type: [%d]", req_info->request_type); - - /* 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")); @@ -2872,6 +3274,76 @@ static bt_status_t gatt_server_send_response(int conn_id, int trans_id, return BT_STATUS_SUCCESS; } + +static bt_status_t gatt_server_send_acquire_response(int conn_id, int trans_id, + int status, int fd, int mtu, void *fdlist) +{ + CHECK_BTGATT_INIT(); + + struct gatt_req_info *req_info = NULL; + struct gatt_client_info_t *conn_info = NULL; + + 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; + } + + + if (req_info->request_type == BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_WRITE) { + + INFO("GATT Server Send Response BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_WRITE to bluez %d\n", fd); + g_dbus_method_invocation_return_value_with_unix_fd_list( + req_info->context, g_variant_new("(hq)", 0, mtu), (GUnixFDList*)fdlist); + + } else if (req_info->request_type == BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_NOTIFY) { + + INFO("GATT Server Send Response BT_HAL_GATT_REQUEST_TYPE_ACQUIRE_NOTIFY to bluez %d\n", fd); + g_dbus_method_invocation_return_value_with_unix_fd_list( + req_info->context, g_variant_new("(hq)", 0, mtu), (GUnixFDList*)fdlist); + + } 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) { @@ -2906,6 +3378,8 @@ static bt_status_t gatt_server_update_att_value(int server_if, int attribute_han } g_free(serv_path); + g_strfreev(line_argv); + 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]); @@ -2925,7 +3399,6 @@ static bt_status_t gatt_server_update_att_value(int server_if, int attribute_han 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); @@ -2983,8 +3456,26 @@ static bt_status_t gatt_server_update_att_value(int server_if, int attribute_han static bt_status_t gatt_server_listen(int server_if, bool start) { CHECK_BTGATT_INIT(); + + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + DBG("server_if: [%d]", server_if); + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + DBG("gatt server is not registered"); + return BT_STATUS_FAIL; + } + + DBG("gatt server:[%d], adv_slot:[%d]", server_register_info->server_if, server_register_info->adv_slot_id); + + if (server_register_info->adv_slot_id < 0 ) { + DBG("adv_slot is not assigned to server:[%d] \n", server_if); + return BT_STATUS_FAIL; + } + /* Send Data to LE Module */ - return _bt_hal_enable_advertising(server_if, start, FALSE); + return _bt_hal_enable_advertising(server_if, server_register_info->adv_slot_id, start, FALSE); } static bt_status_t gatt_server_set_adv_data(int server_if, bool set_scan_rsp, bool include_name, @@ -2997,27 +3488,158 @@ static bt_status_t gatt_server_set_adv_data(int server_if, bool set_scan_rsp, bo return BT_STATUS_SUCCESS; } +static int bt_hal_gatts_allocate_adv_slot(struct hal_gatts_server_register_info_t *server_register_info) +{ + int adv_slot_id = -1; + + /* allocate adv slot for gatt server if not assigned */ + if (server_register_info->adv_slot_id < 0 ) { + adv_slot_id = _bt_hal_get_available_adv_slot_id(&server_register_info->app_uuid, FALSE); + if (adv_slot_id < 0) { + ERR("failed to get the adv_slot"); + return -1; + } + + server_register_info->adv_slot_id = adv_slot_id; + } + + DBG("gatt server:[%d] Assigned adv_slot [%d]", server_register_info->server_if, server_register_info->adv_slot_id); + + return 0; +} + +int bt_hal_gatts_allocate_adv_slot_by_server_if(int server_if) +{ + CHECK_BTGATT_INIT(); + + int ret = -1; + + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + DBG("server_if: [%d]", server_if); + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + DBG("gatt server is not registered"); + return -1; + } + + DBG("gatt server:[%d], adv_slot:[%d]", server_register_info->server_if, server_register_info->adv_slot_id); + + if (server_register_info->adv_slot_id < 0 ) { + DBG("adv_slot is not assigned to server:[%d] \n", server_if); + + ret = bt_hal_gatts_allocate_adv_slot(server_register_info); + if (ret < 0) { + DBG("failed to get adv_slot"); + return -1; + } + } + + return server_register_info->adv_slot_id; +} + +void bt_hal_gatts_release_adv_slot(int server_if) +{ + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + ERR("failed to get server_register_info"); + return; + } + + if (server_register_info->adv_slot_id < 0) { + ERR("adv_slot is not allocated"); + return; + } + + if(_bt_hal_is_advertising_in_slot(server_register_info->adv_slot_id) == FALSE) { + DBG("advertising is disabled"); + _bt_hal_free_server_slot(server_register_info->adv_slot_id); + server_register_info->adv_slot_id = -1; + } +} + +int bt_hal_gatts_get_adv_slot_id(int server_if) +{ + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + DBG("failed to get server_register_info"); + return -1; + } + + return server_register_info->adv_slot_id; +} + +int bt_hal_gatts_get_server_if(int slot_id) +{ + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + server_register_info = bt_hal_gatts_find_server_register_info_by_slot_id(slot_id); + if (server_register_info == NULL) { + DBG("failed to get server_register_info"); + return -1; + } + + return server_register_info->server_if; +} + static bt_status_t gatt_server_multi_adv_enable(int server_if) { CHECK_BTGATT_INIT(); + + int ret = -1; + + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + ERR("gatt server is not registered"); + return BT_STATUS_FAIL; + } + + DBG("gatt server:[%d], adv_slot:[%d]", server_register_info->server_if, server_register_info->adv_slot_id); + + if (server_register_info->adv_slot_id < 0 ) { + DBG("adv_slot is not assigned to server:[%d]", server_if); + + ret = bt_hal_gatts_allocate_adv_slot(server_register_info); + if (ret < 0) { + ERR("failed to get adv_slot"); + return BT_STATUS_FAIL; + } + } + /* Send Enable Advertising request to LE Module */ - return _bt_hal_enable_advertising(server_if, TRUE, TRUE); + return _bt_hal_enable_advertising(server_if, server_register_info->adv_slot_id, TRUE, TRUE); } static bt_status_t gatt_server_multi_adv_update(int server_if, int min_interval, int max_interval, int adv_type, int chnl_map, int tx_power, int timeout_s) { CHECK_BTGATT_INIT(); - DBG("+"); + /* Send Advertising parameters to LE Module */ return _bt_hal_set_advertising_params(server_if, min_interval, max_interval, adv_type, chnl_map, tx_power, timeout_s); } -static bt_status_t gatt_server_multi_adv_set_inst_data(btgatt_adv_param_setup_t adv_param_setup) +static bt_status_t gatt_server_set_filter_policy(int filter_policy) { CHECK_BTGATT_INIT(); DBG("+"); + /* Send the Filter policy parameter to LE Module */ + _bt_hal_set_filter_policy_param(filter_policy); + return BT_STATUS_SUCCESS; +} + +static bt_status_t gatt_server_multi_adv_set_inst_data(btgatt_adv_param_setup_t adv_param_setup) +{ + CHECK_BTGATT_INIT(); + /* Send Data to LE Module */ return _bt_hal_set_advertising_data(adv_param_setup); } @@ -3025,8 +3647,26 @@ static bt_status_t gatt_server_multi_adv_set_inst_data(btgatt_adv_param_setup_t static bt_status_t gatt_server_multi_adv_disable(int server_if) { CHECK_BTGATT_INIT(); + + struct hal_gatts_server_register_info_t *server_register_info = NULL; + + DBG("server_if: [%d]", server_if); + + server_register_info = bt_hal_gatts_find_server_register_info(server_if); + if (server_register_info == NULL) { + DBG("gatt server is not registered"); + return BT_STATUS_FAIL; + } + + DBG("gatt server:[%d], adv_slot:[%d]", server_register_info->server_if, server_register_info->adv_slot_id); + + if (server_register_info->adv_slot_id < 0 ) { + DBG("adv_slot is not assigned to server:[%d] \n", server_if); + return BT_STATUS_FAIL; + } + /* Send Data to LE Module */ - return _bt_hal_enable_advertising(server_if, FALSE, TRUE); + return _bt_hal_enable_advertising(server_if, server_register_info->adv_slot_id, FALSE, TRUE); } static bt_status_t gatt_server_get_mtu_size(int conn_id, int *mtu_size) @@ -3113,25 +3753,27 @@ static bt_status_t gatt_server_get_mtu_size(int conn_id, int *mtu_size) } const btgatt_server_interface_t btgatt_server_interface = { - gatt_server_register_app, - gatt_server_unregister_app, - gatt_server_open, - gatt_server_close, - gatt_server_add_service, - gatt_server_add_included_service, - gatt_server_add_characteristic, - gatt_server_add_descriptor, - gatt_server_start_service, - gatt_server_stop_service, - 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, - gatt_server_multi_adv_update, - gatt_server_multi_adv_set_inst_data, - gatt_server_multi_adv_disable, - gatt_server_get_mtu_size + .register_server = gatt_server_register_app, + .unregister_server = gatt_server_unregister_app, + .connect = gatt_server_open, + .disconnect = gatt_server_close, + .add_service = gatt_server_add_service, + .add_included_service = gatt_server_add_included_service, + .add_characteristic = gatt_server_add_characteristic, + .add_descriptor = gatt_server_add_descriptor, + .start_service = gatt_server_start_service, + .stop_service = gatt_server_stop_service, + .delete_service = gatt_server_delete_service, + .send_indication = gatt_server_send_indication, + .send_response = gatt_server_send_response, + .update_att_value = gatt_server_update_att_value, + .listen = gatt_server_listen, + .set_adv_data = gatt_server_set_adv_data, + .multi_adv_enable = gatt_server_multi_adv_enable, + .multi_adv_update = gatt_server_multi_adv_update, + .set_filter_policy = gatt_server_set_filter_policy, + .multi_adv_set_inst_data = gatt_server_multi_adv_set_inst_data, + .multi_adv_disable = gatt_server_multi_adv_disable, + .get_att_mtu = gatt_server_get_mtu_size, + .send_response_acquire = gatt_server_send_acquire_response };