Implement the set mtu for LE device
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / gatt / bt-service-gatt.c
index 4ba0750..5365660 100644 (file)
@@ -54,6 +54,7 @@
 #define BT_UUID_STRING_MAX 64
 #define BT_SENDER_MAX_LENGTH 50
 #define MAX_APPS_SUPPORTED 11 /* Slot 0 is not used */
+#define BT_DEFAULT_ATT_MTU 23
 
 #ifdef TIZEN_GATT_CLIENT
 #define NUM_UUID 20
@@ -251,15 +252,27 @@ static void __bt_handle_client_characteristic_read_data(event_gattc_read_data *e
 static void __bt_handle_client_descriptor_read_data(event_gattc_read_data *event_data);
 static void __bt_handle_client_characteristic_write_data(event_gattc_write_data *event_data);
 static void __bt_handle_client_descriptor_write_data(event_gattc_write_data *event_data);
-static int __bt_do_unregister_gatt_instance(int instance_id);
 static void __bt_hanlde_le_device_disconnection(event_dev_conn_status_t *event_data);
 static void __bt_handle_client_notification_registered(event_gattc_regdereg_notify_t *event_data,
                gboolean is_registered);
 static void __bt_handle_client_notification_data(event_gattc_notify_data *event_data);
+static void __bt_handle_client_mtu_exchange_completed(event_gattc_mtu_configured_t *event_data);
 
 #endif
+static int __bt_unregister_gatt_server_instance(int server_instance);
 
-static int __bt_do_unregister_server_instance(int server_instance);
+/*mtu device list*/
+struct gatt_mtu_info_t {
+       char *addr;               /* Remote GATT Server address */
+       int att_mtu;
+};
+
+static GSList *gatt_mtu_info_list = NULL;
+
+static struct gatt_mtu_info_t *__bt_find_mtu_gatt_device(char *address);
+static void __bt_remove_mtu_gatt_device(char *address);
+static void __bt_add_mtu_gatt_device(char *address);
+static void __bt_update_mtu_gatt_device(char *address, int mtu);
 
 /* Linked List of GATT requests from Remote GATT Clients */
 static GSList *gatt_server_requests = NULL;
@@ -319,7 +332,7 @@ void _bt_check_adv_app_termination(const char *name)
                if (apps[k] == 1) {
                        BT_INFO("Unregister app[%d]", k);
                        /* Unregister server instance */
-                       __bt_do_unregister_server_instance(k);
+                       __bt_unregister_gatt_server_instance(k);
                }
        }
 }
@@ -596,58 +609,7 @@ void _bt_get_previous_scan_rsp_data(bluetooth_scan_resp_data_t *scan, int *len,
        }
 }
 
-#ifdef TIZEN_GATT_CLIENT
-static int __bt_do_unregister_gatt_instance(int instance_id)
-{
-       int ret = OAL_STATUS_SUCCESS;
-       int k;
-
-       BT_INFO("DeAllocate server or client instance ID [%d]", instance_id);
-
-       /* Reset data: instance_id parameter could be either for GATT Server or for GATT client  */
-       for (k = 1; k < MAX_APPS_SUPPORTED; k++) {
-               if (numapps[k].instance_id == instance_id) {
-                       BT_INFO("This is a GATT server app, unregister: Slot [%d] vacant", k);
-                       numapps[k].is_initialized = FALSE;
-                       numapps[k].instance_id = -1;
-                       numapps[k].adv_handle = 0;
-                       numapps[k].adv_instance = -1;
-                       memset(numapps[k].sender, 0x00, sizeof(numapps[k].sender));
-                       memset(numapps[k].uuid, 0x00, sizeof(numapps[k].uuid));
-                       memset(numapps[k].adv_data.data, 0x00, BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX);
-                       memset(numapps[k].scan_rsp.data, 0x00, BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX);
-                       numapps[k].adv_data_len = 0;
-                       numapps[k].scan_rsp_len = 0;
-
-                       /* Its a GATT Server Instance */
-                       ret = gatts_unregister(instance_id);
-                       if (ret != OAL_STATUS_SUCCESS) {
-                               BT_ERR("DeAllocate server instance with stack Fail ret: %d", ret);
-                               return BLUETOOTH_ERROR_INTERNAL;
-                       }
-                       break;
-               } else if (numapps[k].client_id == instance_id) {
-                       BT_INFO("This is a GATT client app, unregister: Slot [%d] vacant", k);
-                       numapps[k].client_id = -1;
-                       numapps[k].is_initialized = FALSE;
-                       memset(numapps[k].sender, 0x00, sizeof(numapps[k].sender));
-                       memset(numapps[k].uuid, 0x00, sizeof(numapps[k].uuid));
-                       memset(&numapps[k].address.addr, 0x00, sizeof(bluetooth_device_address_t));
-
-                       /* Its a GATT Client Instance */
-                       ret = gattc_deregister(instance_id);
-                       if (ret != OAL_STATUS_SUCCESS) {
-                               BT_ERR("DeAllocate GATT Client instance with stack Fail ret: %d", ret);
-                               return BLUETOOTH_ERROR_INTERNAL;
-                       }
-                       break;
-               }
-       }
-       return BLUETOOTH_ERROR_NONE;
-}
-#endif
-
-static int __bt_do_unregister_server_instance(int server_instance)
+static int __bt_unregister_gatt_server_instance(int server_instance)
 {
        int ret = OAL_STATUS_SUCCESS;
        int k;
@@ -758,7 +720,7 @@ int _bt_unregister_server_instance(const char *sender, int adv_handle)
                if (!numapps[server_instance].service_handles) {
                        BT_INFO("There are no Service handles with this app, safe to unregister");
                        /* Unregister server instance only if this sender does not have any gatt services in it */
-                       result = __bt_do_unregister_server_instance(server_instance);
+                       result = __bt_unregister_gatt_server_instance(server_instance);
                } else {
                        numapps[server_instance].adv_handle = 0;
                        memset(numapps[server_instance].adv_data.data, 0x00, BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX);
@@ -774,7 +736,7 @@ int _bt_unregister_server_instance(const char *sender, int adv_handle)
                if (apps[k] == 1) {
                        BT_INFO("Unregister app[%d]", k);
                        /* Unregister server instance */
-                       __bt_do_unregister_server_instance(k);
+                       __bt_unregister_gatt_server_instance(k);
                }
        }
 
@@ -842,8 +804,9 @@ static void __bt_gatt_handle_pending_request_info(int result,
        ret_if(data == NULL);
        BT_DBG("+");
 
-       for (l = _bt_get_invocation_list(); l != NULL; l = g_slist_next(l)) {
+       for (l = _bt_get_invocation_list(); l != NULL; ) {
                req_info = l->data;
+               l = g_slist_next(l);
                if (req_info == NULL || req_info->service_function != service_function)
                        continue;
 
@@ -1097,6 +1060,25 @@ static void __bt_gatt_handle_pending_request_info(int result,
                        g_free(addr);
                        break;
                }
+               case BT_REQ_ATT_MTU: {
+                       char *addr = (char*)req_info->user_data;
+                       bluetooth_device_address_t address;
+
+                       if (!g_strcmp0(addr, (char*)data)) {
+                               BT_INFO("GATT Client BT_REQ_ATT_MTU call pending for app [%s] addr [%s]",
+                                               req_info->sender, addr);
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               _bt_convert_addr_string_to_type(address.addr, addr);
+
+                               g_array_append_vals(out_param, (bluetooth_device_address_t*)&address,
+                                               sizeof(bluetooth_device_address_t));
+                               _bt_service_method_return(req_info->context, out_param, result);
+
+                               g_free(req_info->user_data);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_array_free(out_param, TRUE);
+                       }
+               }
 #endif
                default:
                        break;
@@ -1489,6 +1471,8 @@ static void __bt_handle_gatt_server_connection_state(event_gatts_conn_t *event)
                BT_INFO("Total num of connected Remote GATT Clients [%d]", g_slist_length(gatt_client_info_list));
        }
 
+       __bt_add_mtu_gatt_device(address);
+
        g_free(address);
 }
 
@@ -1545,6 +1529,8 @@ static void __bt_handle_gatt_server_disconnection_state(event_gatts_conn_t *even
                g_free(conn_info->addr);
                g_free(conn_info);
        }
+
+       __bt_remove_mtu_gatt_device(address);
 }
 #else
 
@@ -1967,6 +1953,8 @@ static void __bt_handle_gatt_mtu_changed_event(event_gatts_mtu_changed_t *event)
        BT_INFO("Got connection Info GATT client [%s] MTU Size [%d]",
                        conn_info->addr, event->mtu_size);
 
+       __bt_update_mtu_gatt_device(conn_info->addr, event->mtu_size);
+
        param = g_variant_new("(isqy)",
                        result,
                        conn_info->addr,
@@ -2138,7 +2126,12 @@ static void __bt_gatt_event_handler(int event_type, gpointer event_data)
        case OAL_EVENT_GATTC_NOTIFY_DATA: {
                BT_INFO("OAL Event: GATT Client Notification Data");
                __bt_handle_client_notification_data((event_gattc_notify_data *) event_data);
-
+               break;
+       }
+       case OAL_EVENT_GATTC_MTU_EXCHANGE_COMPLETED: {
+               BT_INFO("OAL Event: GATT Client MTU Exchange Complete");
+               __bt_handle_client_mtu_exchange_completed((event_gattc_mtu_configured_t *) event_data);
+               break;
        }
 #endif
        default:
@@ -2461,6 +2454,38 @@ int _bt_gatt_server_update_attribute_value(char *sender, int instance_id,
        return BLUETOOTH_ERROR_NONE;
 }
 
+int _bt_request_att_mtu(bluetooth_device_address_t *device_address,
+               unsigned int mtu)
+{
+       struct gatt_server_info_t *conn_info = NULL;
+       char *addr = NULL;
+       int ret = OAL_STATUS_SUCCESS;
+
+       addr = g_malloc0(sizeof(char) * BT_ADDRESS_STRING_SIZE);
+       _bt_convert_addr_type_to_string(addr, device_address->addr);
+
+       /* Check if remote GATT Server is connected or not */
+       conn_info = __bt_find_remote_gatt_server_info(addr);
+       if (conn_info) {
+               BT_INFO("GATT Server [%s] is connected, conn Id [%d]",
+                               conn_info->addr, conn_info->connection_id);
+       } else {
+               BT_ERR("GATT Server is not yet connected..");
+               g_free(addr);
+               return BLUETOOTH_ERROR_NOT_CONNECTED;
+       }
+
+       ret = gattc_configure_mtu(conn_info->connection_id, mtu);
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               g_free(addr);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       g_free(addr);
+       return BLUETOOTH_ERROR_NONE;
+}
+
 int _bt_get_att_mtu(bluetooth_device_address_t *address,
                unsigned int *mtu)
 {
@@ -2489,8 +2514,15 @@ int _bt_get_att_mtu(bluetooth_device_address_t *address,
                BT_ERR("ret: %d", ret);
                return BLUETOOTH_ERROR_INTERNAL;
        }
+
        BT_INFO("ATT MTU received from OAL [%d]", stack_mtu);
        *mtu = (unsigned int)stack_mtu;
+
+       if (*mtu == 0) {
+               BT_ERR("MTU value is zero, GATT Client [%s] is not yet connected..", addr);
+               return BLUETOOTH_ERROR_NOT_CONNECTED;
+       }
+
        return BLUETOOTH_ERROR_NONE;
 }
 
@@ -3057,6 +3089,8 @@ static void __bt_handle_client_connected(event_gattc_conn_t *event_data)
 #endif
                } else
                        BT_ERR("Local GATT Client connected event for addr[%s], but device is in connected list already", address);
+
+               __bt_add_mtu_gatt_device(address);
        } else
                BT_ERR("GATT Client Connection failed!!");
 
@@ -3126,6 +3160,8 @@ static void __bt_handle_client_disconnected(event_gattc_conn_t *event_data)
        } else
                BT_INFO("Can not find conn info, already removed!");
 
+       __bt_remove_mtu_gatt_device(address);
+
        /* If outgoing connection Info is present, then remove it */
        out_conn_info = __bt_find_gatt_outgoing_conn_info(address);
        if (out_conn_info) {
@@ -4034,8 +4070,22 @@ gboolean _bt_is_remote_gatt_device_connected(bluetooth_device_address_t *address
        if (conn_info) {
                BT_INFO("Remote GATT Server device [%s] is Connected", conn_info->addr);
                connected = TRUE;
-       } else
+       } else {
+               struct gatt_client_info_t *client_info = NULL;
+
                BT_INFO("Remote GATT Server Device [%s] is not Connected", addr);
+
+               /* Check if device is already in connected list */
+               client_info = __bt_find_remote_gatt_client_info(addr);
+
+               if (client_info) {
+                       BT_INFO("Remote Client device [%s] is Connected", client_info->addr);
+                       connected = TRUE;
+               } else {
+                       BT_INFO("Remote GATT Client Device [%s] is not Connected", addr);
+               }
+       }
+
        g_free(addr);
        return connected;
 }
@@ -4798,29 +4848,154 @@ int _bt_gatt_watch_service_changed_indication(const char *sender,
 
 int _bt_unregister_gatt_client_instance(const char *sender, int client_id)
 {
-       BT_INFO("Unregister Allocated GATT CLient instance [%s] Client ID [%d]",
-                       sender, client_id);
-       int result = BLUETOOTH_ERROR_NONE;
-       int k;
+       bt_service_app_info_t *info = NULL;
+       int k, ret;
+
+       BT_INFO("Unregister Allocated GATT Client instance [%s] Client ID [%d]", sender, client_id);
 
        /* Unregister CLient instance associated with address X. It is possible that another app still
           has client_id valid for same remote address */
-       bt_service_app_info_t *info = NULL;
-
        for (k = 1; k < MAX_APPS_SUPPORTED; k++) {
                info = &numapps[k];
 
                /* Exact matching of sender */
                if (!g_strcmp0(info->sender, sender) && info->client_id == client_id) {  /* Check for only valid GATT client Instance */
                        BT_INFO("Unregister GATT client instance [%d]", info->client_id);
-                       result = __bt_do_unregister_gatt_instance(info->client_id);
-                       if (result != BLUETOOTH_ERROR_NONE)
-                               BT_ERR("Error in unregistering GATT Client Interface");
+                       numapps[k].client_id = -1;
+                       numapps[k].is_initialized = FALSE;
+                       memset(numapps[k].sender, 0x00, sizeof(numapps[k].sender));
+                       memset(numapps[k].uuid, 0x00, sizeof(numapps[k].uuid));
+                       memset(&numapps[k].address.addr, 0x00, sizeof(bluetooth_device_address_t));
 
-                       break;
+                       /* Its a GATT Client Instance */
+                       ret = gattc_deregister(client_id);
+                       if (ret != OAL_STATUS_SUCCESS) {
+                               BT_ERR("DeAllocate GATT Client instance with stack Fail ret: %d", ret);
+                               return BLUETOOTH_ERROR_INTERNAL;
+                       } else {
+                               return BLUETOOTH_ERROR_NONE;
+                       }
                }
        }
-       return result;
+
+       return BLUETOOTH_ERROR_NOT_FOUND;
+}
+
+static void __bt_handle_client_mtu_exchange_completed(event_gattc_mtu_configured_t *event_data)
+{
+       int result = BLUETOOTH_ERROR_NONE;
+       struct gatt_server_info_t *conn_info = NULL;
+       GVariant *param = NULL;
+       guint16 mtu = 0;
+       guint8 status = 0;
+
+       conn_info = __bt_find_remote_gatt_server_info_from_conn_id(event_data->conn_id);
+       if (conn_info == NULL) {
+               BT_ERR("Cant find connection Information");
+               return;
+       }
+
+       BT_INFO("GATT Client: MTU Configured from addr [%s] status [%d] MTU size [%d]",
+                       conn_info->addr, event_data->status, event_data->mtu);
+
+       if (event_data->status != OAL_STATUS_SUCCESS)
+               result = BLUETOOTH_ERROR_INTERNAL;
+
+       BT_INFO("reply BT_REQ_ATT_MTU ");
+
+       /* DBUS Return fo BT_REQ_ATT_MTU for all the apps */
+       __bt_gatt_handle_pending_request_info(result, BT_REQ_ATT_MTU, conn_info->addr,
+                       BT_ADDRESS_STRING_SIZE);
+
+       if (result == BLUETOOTH_ERROR_NONE) {
+               BT_INFO("sending mtu event");
+
+               mtu = event_data->mtu;
+               param = g_variant_new("(isqy)",
+                               result,
+                               conn_info->addr,
+                               mtu,
+                               status);
+
+               /* Send event to BT-API */
+               _bt_send_event(BT_DEVICE_EVENT,
+                               BLUETOOTH_EVENT_GATT_ATT_MTU_CHANGED,
+                               param);
+
+               /* Update the MTU for current connection */
+               BT_INFO("Updating the MTU for current connection");
+               __bt_update_mtu_gatt_device(conn_info->addr, event_data->mtu);
+       }
+}
+
+static struct gatt_mtu_info_t *__bt_find_mtu_gatt_device(char *address)
+{
+       GSList *l = NULL;
+       struct gatt_mtu_info_t *info = NULL;
+
+       BT_INFO("+");
+
+       for (l = gatt_mtu_info_list; l != NULL; l = g_slist_next(l)) {
+               info = (struct gatt_mtu_info_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!g_strcmp0(info->addr, address)) {
+                       BT_INFO("Remote GATT device found addr[%s]", info->addr);
+                       return info;
+               }
+       }
+
+       BT_INFO("Not found Remote GATT device addr[%s]", address);
+       return NULL;
 }
 
+static void __bt_remove_mtu_gatt_device(char *address)
+{
+       struct gatt_mtu_info_t *dev_info = NULL;
+
+       BT_INFO("+");
+
+       dev_info = __bt_find_mtu_gatt_device(address);
+
+       if (dev_info) {
+               BT_INFO("removing the gatt device from mtu list");
+               gatt_mtu_info_list = g_slist_remove(gatt_mtu_info_list, dev_info);
+               g_free(dev_info->addr);
+               g_free(dev_info);
+       }
+}
+
+static void __bt_add_mtu_gatt_device(char *address)
+{
+       struct gatt_mtu_info_t *dev_info = NULL;
+
+       BT_INFO("+");
+
+       dev_info = __bt_find_mtu_gatt_device(address);
+
+       if (!dev_info) {
+               BT_INFO("adding the gatt device in mtu list");
+               dev_info = g_new0(struct gatt_mtu_info_t, 1);
+               dev_info->addr = g_strdup(address);
+               dev_info->att_mtu = BT_DEFAULT_ATT_MTU;
+               gatt_mtu_info_list = g_slist_append(gatt_mtu_info_list, dev_info);
+       }
+}
+
+static void __bt_update_mtu_gatt_device(char *address, int mtu)
+{
+       struct gatt_mtu_info_t *dev_info = NULL;
+
+       BT_INFO("+");
+
+       dev_info = __bt_find_mtu_gatt_device(address);
+
+       if (dev_info) {
+               BT_INFO("Udating the mtu");
+               dev_info->att_mtu = mtu;
+       }
+}
+
+
 #endif