gatt: Enable EATT bearer support
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 26 Dec 2019 22:01:06 +0000 (14:01 -0800)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:48 +0000 (14:30 +0530)
This adds support for EATT connections.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/device.c
src/gatt-client.c
src/gatt-database.c

index f683a6d..5ff3bef 100644 (file)
@@ -7349,6 +7349,17 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                return false;
        }
 
+       if (dev->att) {
+               if (!bt_att_attach_fd(dev->att, g_io_channel_unix_get_fd(io))) {
+                       DBG("EATT channel connected");
+                       g_io_channel_set_close_on_unref(io, FALSE);
+                       return true;
+               }
+
+               error("Failed to attach EATT channel");
+               return false;
+       }
+
 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
        if (sec_level == BT_IO_SEC_LOW && dev->le_state.paired) {
                DBG("Elevating security level since LTK is available");
index a96be57..6dd7868 100644 (file)
 #include "lib/uuid.h"
 
 #include "gdbus/gdbus.h"
+#include "btio/btio.h"
 
 #include "log.h"
 #include "error.h"
+#include "hcid.h"
 #include "adapter.h"
 #include "device.h"
 #include "src/shared/io.h"
 #define GATT_CHARACTERISTIC_IFACE      "org.bluez.GattCharacteristic1"
 #define GATT_DESCRIPTOR_IFACE          "org.bluez.GattDescriptor1"
 
+#define EATT_MAX_BEARERS 2
+
 struct btd_gatt_client {
        struct btd_device *device;
+       uint8_t features;
        bool ready;
        char devaddr[18];
        struct gatt_db *db;
@@ -2531,6 +2536,55 @@ static void register_notify(void *data, void *user_data)
        notify_client_free(notify_client);
 }
 
+static void eatt_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
+{
+       struct btd_gatt_client *client = user_data;
+
+       if (gerr)
+               return;
+
+       device_attach_att(client->device, io);
+}
+
+static void eatt_connect(struct btd_gatt_client *client)
+{
+       struct btd_device *dev = client->device;
+       struct btd_adapter *adapter = device_get_adapter(dev);
+       GIOChannel *io;
+       GError *gerr = NULL;
+       char addr[18];
+       int i;
+
+       ba2str(device_get_address(dev), addr);
+
+       DBG("Connection attempt to: %s", addr);
+
+       for (i = 0; i < EATT_MAX_BEARERS; i++) {
+               /* Fallback to regular LE mode */
+               io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR,
+                                       btd_adapter_get_address(adapter),
+                                       BT_IO_OPT_SOURCE_TYPE,
+                                       btd_adapter_get_address_type(adapter),
+                                       BT_IO_OPT_DEST_BDADDR,
+                                       device_get_address(dev),
+                                       BT_IO_OPT_DEST_TYPE,
+                                       device_get_le_address_type(dev),
+                                       BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_MTU, main_opts.gatt_mtu,
+                                       BT_IO_OPT_INVALID);
+               if (!io) {
+                       error("EATT bt_io_connect(%s): %s", addr,
+                                                       gerr->message);
+                       g_error_free(gerr);
+                       return;
+               }
+
+               g_io_channel_unref(io);
+       }
+}
+
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
 static void check_chrcs_ready(void *data, void *user_data)
 {
@@ -2604,6 +2658,16 @@ void btd_gatt_client_ready(struct btd_gatt_client *client)
        DBG("GATT client ready");
 
        create_services(client);
+
+       DBG("Features 0x%02x", client->features);
+
+       if (!client->features) {
+               client->features = bt_gatt_client_get_features(client->gatt);
+               DBG("Update Features 0x%02x", client->features);
+               if (client->features & BT_GATT_CHRC_CLI_FEAT_EATT)
+                       eatt_connect(client);
+       }
+
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        /*
         * In case of more number of services and services having
@@ -2648,6 +2712,11 @@ void btd_gatt_client_connected(struct btd_gatt_client *client)
         * for any pre-registered notification sessions.
         */
        queue_foreach(client->all_notify_clients, register_notify, client);
+
+       if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT))
+               return;
+
+       eatt_connect(client);
 }
 
 void btd_gatt_client_service_added(struct btd_gatt_client *client,
index 21345de..bd51f50 100644 (file)
 #include "profile.h"
 #include "service.h"
 
-#ifndef ATT_CID
-#define ATT_CID 4
-#endif
-
-#ifndef ATT_PSM
-#define ATT_PSM 31
-#endif
-
 #define GATT_MANAGER_IFACE     "org.bluez.GattManager1"
 #define GATT_PROFILE_IFACE     "org.bluez.GattProfile1"
 #define GATT_SERVICE_IFACE     "org.bluez.GattService1"
@@ -80,7 +72,8 @@ struct btd_gatt_database {
        struct gatt_db *db;
        unsigned int db_id;
        GIOChannel *le_io;
-       GIOChannel *l2cap_io;
+       GIOChannel *eatt_io;
+       GIOChannel *bredr_io;
        struct queue *records;
        struct queue *device_states;
        struct queue *ccc_callbacks;
@@ -88,6 +81,7 @@ struct btd_gatt_database {
        struct gatt_db_attribute *svc_chngd_ccc;
        struct gatt_db_attribute *cli_feat;
        struct gatt_db_attribute *db_hash;
+       struct gatt_db_attribute *eatt;
        struct queue *apps;
        struct queue *profiles;
 };
@@ -662,9 +656,14 @@ static void gatt_database_free(void *data)
                g_io_channel_unref(database->le_io);
        }
 
-       if (database->l2cap_io) {
-               g_io_channel_shutdown(database->l2cap_io, FALSE, NULL);
-               g_io_channel_unref(database->l2cap_io);
+       if (database->eatt_io) {
+               g_io_channel_shutdown(database->eatt_io, FALSE, NULL);
+               g_io_channel_unref(database->eatt_io);
+       }
+
+       if (database->bredr_io) {
+               g_io_channel_shutdown(database->bredr_io, FALSE, NULL);
+               g_io_channel_unref(database->bredr_io);
        }
 
        /* TODO: Persistently store CCC states before freeing them */
@@ -848,7 +847,7 @@ static sdp_record_t *record_new(uuid_t *uuid, uint16_t start, uint16_t end)
        uuid_t root_uuid, proto_uuid, l2cap;
        sdp_record_t *record;
        sdp_data_t *psm, *sh, *eh;
-       uint16_t lp = ATT_PSM;
+       uint16_t lp = BT_ATT_PSM;
 
        if (uuid == NULL)
                return NULL;
@@ -1309,7 +1308,10 @@ static void cli_feat_write_cb(struct gatt_db_attribute *attrib,
 {
        struct btd_gatt_database *database = user_data;
        struct device_state *state;
+       uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
+                               BT_GATT_CHRC_CLI_FEAT_EATT };
        uint8_t ecode = 0;
+       unsigned int i;
 
        DBG("Client Features write");
 
@@ -1324,13 +1326,12 @@ static void cli_feat_write_cb(struct gatt_db_attribute *attrib,
                goto done;
        }
 
-       /* A client shall never clear a bit it has set.
-        * TODO: make it generic to any bits.
-        */
-       if (state->cli_feat[0] & BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING &&
-                       !(value[0] & BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING)) {
-               ecode = BT_ATT_ERROR_VALUE_NOT_ALLOWED;
-               goto done;
+       for (i = 0; i < sizeof(bits); i++) {
+               /* A client shall never clear a bit it has set */
+               if (state->cli_feat[0] & (1 << i) && !(value[0] & (1 << i))) {
+                       ecode = BT_ATT_ERROR_VALUE_NOT_ALLOWED;
+                       goto done;
+               }
        }
 
        /* Shall we reallocate the feat array if bigger? */
@@ -1340,7 +1341,7 @@ static void cli_feat_write_cb(struct gatt_db_attribute *attrib,
                len--;
        }
 
-       state->cli_feat[0] &= BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING;
+       state->cli_feat[0] &= ((1 << sizeof(bits)) - 1);
        state->change_aware = true;
 
 done:
@@ -1380,6 +1381,28 @@ static void db_hash_read_cb(struct gatt_db_attribute *attrib,
                state->change_aware = true;
 }
 
+static void server_feat_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       struct device_state *state;
+       uint8_t ecode = 0;
+       uint8_t value = 0;
+
+       state = get_device_state(database, att);
+       if (!state) {
+               ecode = BT_ATT_ERROR_UNLIKELY;
+               goto done;
+       }
+
+       value |= BT_GATT_CHRC_SERVER_FEAT_EATT;
+
+done:
+       gatt_db_attribute_read_result(attrib, id, ecode, &value, sizeof(value));
+}
+
 static void populate_gatt_service(struct btd_gatt_database *database)
 {
        bt_uuid_t uuid;
@@ -1387,7 +1410,7 @@ static void populate_gatt_service(struct btd_gatt_database *database)
 
        /* Add the GATT service */
        bt_uuid16_create(&uuid, UUID_GATT);
-       service = gatt_db_add_service(database->db, &uuid, true, 8);
+       service = gatt_db_add_service(database->db, &uuid, true, 10);
 
        bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
        database->svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
@@ -1410,6 +1433,11 @@ static void populate_gatt_service(struct btd_gatt_database *database)
                                &uuid, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
                                db_hash_read_cb, NULL, database);
 
+       bt_uuid16_create(&uuid, GATT_CHARAC_SERVER_FEAT);
+       database->eatt = gatt_db_service_add_characteristic(service,
+                               &uuid, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                               server_feat_read_cb, NULL, database);
+
        gatt_db_service_set_active(service, true);
 
        database_add_record(database, service);
@@ -4183,7 +4211,7 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
                                        BT_IO_OPT_SOURCE_BDADDR, addr,
                                        BT_IO_OPT_SOURCE_TYPE,
                                        btd_adapter_get_address_type(adapter),
-                                       BT_IO_OPT_CID, ATT_CID,
+                                       BT_IO_OPT_CID, BT_ATT_CID,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
        if (!database->le_io) {
@@ -4192,14 +4220,29 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
                goto fail;
        }
 
+       /* EATT socket */
+       database->eatt_io = bt_io_listen(connect_cb, NULL, NULL, NULL,
+                                       &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, addr,
+                                       BT_IO_OPT_SOURCE_TYPE,
+                                       btd_adapter_get_address_type(adapter),
+                                       BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_MTU, main_opts.gatt_mtu,
+                                       BT_IO_OPT_INVALID);
+       if (!database->eatt_io) {
+               g_error_free(gerr);
+               goto fail;
+       }
+
        /* BR/EDR socket */
-       database->l2cap_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
+       database->bredr_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
                                        BT_IO_OPT_SOURCE_BDADDR, addr,
-                                       BT_IO_OPT_PSM, ATT_PSM,
+                                       BT_IO_OPT_PSM, BT_ATT_PSM,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                        BT_IO_OPT_MTU, main_opts.gatt_mtu,
                                        BT_IO_OPT_INVALID);
-       if (database->l2cap_io == NULL) {
+       if (database->bredr_io == NULL) {
                error("Failed to start listening: %s", gerr->message);
                g_error_free(gerr);
                goto fail;