Fix gatt handle number limitation issue 70/281570/1
authorWootak Jung <wootak.jung@samsung.com>
Mon, 15 Mar 2021 04:41:41 +0000 (13:41 +0900)
committerWootak Jung <wootak.jung@samsung.com>
Tue, 20 Sep 2022 01:42:56 +0000 (10:42 +0900)
Change-Id: I69771df30f0f3b6aa9f4be2bd9dacbd392bcda92
Signed-off-by: Wootak Jung <wootak.jung@samsung.com>
bt-oal/bluez_hal/src/bt-hal-gatt-server.c

index 200075ff75a8ed0adb1ab5d194813790f8eda2af..e5ee461833730aa4b9d5e5cb70cd87d107fec0a1 100644 (file)
@@ -64,13 +64,19 @@ 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 */
-#define SERVICE_HANDLE_NUM 100
-#define CHAR_HANDLE_NUM 200
-#define DESC_HANDLE_NUM 300
-static int gatt_service_handle = SERVICE_HANDLE_NUM;
-static int gatt_char_handle = CHAR_HANDLE_NUM;
-static int gatt_desc_handle = DESC_HANDLE_NUM;
+#define GATT_HANDLE_MAX_NUM 100 /* Not defined in spec, implementation dependent */
+#define SERV_HANDLE_NUM (GATT_HANDLE_MAX_NUM)
+#define CHAR_HANDLE_NUM (SERV_HANDLE_NUM + GATT_HANDLE_MAX_NUM)
+#define DESC_HANDLE_NUM (CHAR_HANDLE_NUM + GATT_HANDLE_MAX_NUM)
+typedef enum {
+       BT_GATT_TYPE_SERV,
+       BT_GATT_TYPE_CHAR,
+       BT_GATT_TYPE_DESC,
+       BT_GATT_TYPE_MAX
+} bt_gatt_type_e;
+static int assigned_handle[BT_GATT_TYPE_MAX];
+static gboolean gatt_handle_used[BT_GATT_TYPE_MAX][GATT_HANDLE_MAX_NUM];
+static int gatt_handle_base[BT_GATT_TYPE_MAX] = {SERV_HANDLE_NUM, CHAR_HANDLE_NUM, DESC_HANDLE_NUM};
 
 struct gatt_service_info {
        gchar *serv_path;
@@ -366,6 +372,9 @@ void _bt_hal_gatt_server_init(void)
        assigned_id = 0;
        memset(instance_id_used, 0x00, sizeof(instance_id_used));
 
+       assigned_handle[BT_GATT_TYPE_SERV] = assigned_handle[BT_GATT_TYPE_CHAR] = assigned_handle[BT_GATT_TYPE_DESC] = -1;
+       memset(gatt_handle_used, 0x00, sizeof(gatt_handle_used));
+
        g_slist_free_full(gatt_server_apps, (GDestroyNotify)__bt_free_gatt_server_app);
        gatt_server_apps = NULL;
 
@@ -412,6 +421,52 @@ static void __bt_hal_gatt_delete_id(int instance_id)
        instance_id_used[instance_id] = FALSE;
 }
 
+static int __bt_hal_assign_gatt_handle(bt_gatt_type_e type)
+{
+       int index;
+
+       index = assigned_handle[type] + 1;
+
+       if (index >= GATT_HANDLE_MAX_NUM)
+               index = 0;
+
+       while (gatt_handle_used[type][index] == TRUE) {
+               if (index == assigned_handle[type]) {
+                       /* No available handle */
+                       ERR("All handle is used");
+                       return -1;
+               }
+
+               index++;
+
+               if (index >= GATT_HANDLE_MAX_NUM)
+                       index = 0;
+       }
+
+       assigned_handle[type] = index;
+       gatt_handle_used[type][index] = TRUE;
+
+       return assigned_handle[type] + gatt_handle_base[type];
+}
+
+static void __bt_hal_free_gatt_handle(bt_gatt_type_e type, int handle)
+{
+       int index;
+
+       if (type >= BT_GATT_TYPE_MAX) {
+               ERR("Invalid type");
+               return;
+       }
+
+       index = handle - gatt_handle_base[type];
+       if (index < 0 || index >= GATT_HANDLE_MAX_NUM) {
+               ERR("Invalid handle: %d(type: %d)", handle, type);
+               return;
+       }
+
+       gatt_handle_used[type][index] = FALSE;
+}
+
 static GSList *_bt_get_service_list_from_server(int instance)
 {
        GSList *l;
@@ -2146,20 +2201,23 @@ static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id
        gboolean svc_primary = TRUE;
        GError *error = NULL;
        hal_gatt_service_added *user_data = NULL;
+       int service_handle = 0;
        DBG("Service add to DBUS slot [%d]", slot);
 
-       DBG("Add new GATT Service: Current GATT Service handle [%d]", gatt_service_handle);
-       if (gatt_service_handle >= CHAR_HANDLE_NUM) {
-               ERR("Exceeded the number of service");
+       service_handle = __bt_hal_assign_gatt_handle(BT_GATT_TYPE_SERV);
+       if (service_handle == -1) {
+               ERR("Too many gatt service handles are created");
                return BT_STATUS_FAIL;
        }
-       path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, ++gatt_service_handle);
+
+       path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, service_handle);
        DBG("gatt service path is [%s]", path);
 
        node_info = __bt_gatt_create_method_node_info(
                        service_introspection_xml);
        if (node_info == NULL) {
                g_free(path);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_SERV, service_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2172,6 +2230,7 @@ static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id
                ERR("failed to register: %s", error->message);
                g_error_free(error);
                g_free(path);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_SERV, service_handle);
                return BT_STATUS_FAIL;
        }
        /* Add object_id/gatt service information; it's required at the time of
@@ -2184,8 +2243,8 @@ static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_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;
+       DBG("Service Handle to be added is [%d]", service_handle);
+       serv_info->service_handle = service_handle;
 
        /* Update service in GATT Server service List */
        gatt_services = g_slist_append(gatt_services, serv_info);
@@ -2519,6 +2578,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
        int flag_count = 0;
        hal_gatt_char_added *user_data = NULL;
        int *app_id;
+       int char_handle = 0;
 
        CHECK_BTGATT_INIT();
        DBG("Add new characteristic to GATT Service handle [%d]", service_handle);
@@ -2528,18 +2588,21 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
        if (serv_info == NULL)
                return BT_STATUS_FAIL;
 
-       DBG("Add new GATT characteristic: Current GATT char handle [%d]", gatt_char_handle);
-       if (gatt_char_handle >= DESC_HANDLE_NUM) {
-               ERR("Exceeded the number of characteristic");
+       char_handle = __bt_hal_assign_gatt_handle(BT_GATT_TYPE_CHAR);
+       if (char_handle == -1) {
+               ERR("Too many gatt char handles are created");
                return BT_STATUS_FAIL;
        }
-       path = g_strdup_printf("%s/characteristic%d", serv_info->serv_path, ++gatt_char_handle);
+
+       DBG("Add new GATT characteristic: Current GATT char handle [%d]", char_handle);
+       path = g_strdup_printf("%s/characteristic%d", serv_info->serv_path, char_handle);
        DBG("gatt characteristic path is [%s]", path);
 
        node_info = __bt_gatt_create_method_node_info(
                        characteristics_introspection_xml);
        if (node_info == NULL) {
                g_free(path);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_CHAR, char_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2556,6 +2619,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
                g_error_free(error);
                g_free(path);
                g_free(app_id);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_CHAR, char_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2580,7 +2644,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
 
 
        char_info->flags_length = flag_count;
-       char_info->char_handle = gatt_char_handle;
+       char_info->char_handle = char_handle;
 
 
        builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
@@ -2632,7 +2696,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
        /* 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->char_hdl = 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);
@@ -2680,6 +2744,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
        int flag_count = 0;
        int *app_id;
        hal_gatt_desc_added *user_data = NULL;
+       int desc_handle = 0;
 
        /* Fetch service data for the GATT server */
        serv_info = __bt_gatt_find_gatt_service_info(slot, service_handle);
@@ -2710,9 +2775,14 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
                return BT_STATUS_FAIL;
        }
 
-       DBG("Add new Descriptor: Current GATT desc handle [%d]", gatt_desc_handle);
+       desc_handle = __bt_hal_assign_gatt_handle(BT_GATT_TYPE_DESC);
+       if (desc_handle == -1) {
+               ERR("Too many gatt desc handles are created");
+               return BT_STATUS_FAIL;
+       }
 
-       path = g_strdup_printf("%s/descriptor%d", char_path, ++gatt_desc_handle);
+       DBG("Add new Descriptor: Current GATT desc handle [%d]", desc_handle);
+       path = g_strdup_printf("%s/descriptor%d", char_path, desc_handle);
        DBG("gatt descriptor path is [%s]", path);
 
        app_id = g_malloc0(sizeof(int));
@@ -2730,6 +2800,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
                g_strfreev(line_argv);
                g_free(serv_path);
                g_free(app_id);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_DESC, desc_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2745,7 +2816,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
                desc_info->desc_flags[i] = desc_flags[i];
 
        desc_info->flags_length = flag_count;
-       desc_info->desc_handle = gatt_desc_handle;
+       desc_info->desc_handle = desc_handle;
 
 
        builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
@@ -2789,7 +2860,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
        /* 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->desc_hdl = 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);
@@ -2993,6 +3064,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
 
                        /* list remove & free */
                        char_info->desc_data = g_slist_remove(char_info->desc_data, desc_info);
+                       __bt_hal_free_gatt_handle(BT_GATT_TYPE_DESC, desc_info->desc_handle);
                        __bt_hal_gatt_free_descriptor_info(desc_info);
                }
 
@@ -3011,6 +3083,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
 
                /* list remove & free */
                serv_info->char_data = g_slist_remove(serv_info->char_data, char_info);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_CHAR, char_info->char_handle);
                __bt_hal_gatt_free_characteristic_info(char_info);
        }
 
@@ -3032,6 +3105,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
 
        /* Remove from global list */
        gatt_services = g_slist_remove(gatt_services, serv_info);
+       __bt_hal_free_gatt_handle(BT_GATT_TYPE_SERV, serv_info->service_handle);
        INFO("After removing from global list total service dount [%d]", g_slist_length(gatt_services));
 
        /* Remove from GATT Server's list of services */