From 6064c3948e440d98adf17bea6d7ce52d8b4aed08 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 9 Mar 2023 14:20:17 -0800 Subject: [PATCH] gatt: Use DEFER_SETUP for EATT channels This makes use of DEFER_SETUP mechanism to do the following checks before accepting the connection: - Checks a valid device object exits - Checks if initiator/central as if the peripheral start connecting it may cause collisions. - Checks if the limit of allowed connections has been reached. --- src/device.c | 8 ++--- src/device.h | 1 + src/gatt-client.c | 3 +- src/gatt-database.c | 88 +++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/device.c b/src/device.c index 72b6686..58fb3e0 100644 --- a/src/device.c +++ b/src/device.c @@ -456,7 +456,7 @@ static struct bearer_state *get_state(struct btd_device *dev, return &dev->le_state; } -static bool get_initiator(struct btd_device *dev) +bool btd_device_is_initiator(struct btd_device *dev) { if (dev->le_state.connected) return dev->le_state.initiator; @@ -6273,7 +6273,7 @@ done: } /* Notify driver about the new connection */ - service_accept(service, get_initiator(device)); + service_accept(service, btd_device_is_initiator(device)); } static void device_add_gatt_services(struct btd_device *device) @@ -6305,7 +6305,7 @@ static void accept_gatt_service(struct gatt_db_attribute *attr, void *user_data) if (!l) return; - service_accept(l->data, get_initiator(device)); + service_accept(l->data, btd_device_is_initiator(device)); } #endif @@ -6313,7 +6313,7 @@ static void device_accept_gatt_profiles(struct btd_device *device) { #ifndef TIZEN_FEATURE_BLUEZ_MODIFY GSList *l; - bool initiator = get_initiator(device); + bool initiator = btd_device_is_initiator(device); DBG("initiator %s", initiator ? "true" : "false"); diff --git a/src/device.h b/src/device.h index 2d28070..74e3c98 100644 --- a/src/device.h +++ b/src/device.h @@ -88,6 +88,7 @@ GSList *btd_device_get_primaries(struct btd_device *device); struct gatt_db *btd_device_get_gatt_db(struct btd_device *device); struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device); struct bt_gatt_server *btd_device_get_gatt_server(struct btd_device *device); +bool btd_device_is_initiator(struct btd_device *device); void *btd_device_get_attrib(struct btd_device *device); void btd_device_gatt_set_service_changed(struct btd_device *device, uint16_t start, uint16_t end); diff --git a/src/gatt-client.c b/src/gatt-client.c index 0759b09..5d3f0dd 100644 --- a/src/gatt-client.c +++ b/src/gatt-client.c @@ -2700,7 +2700,8 @@ void btd_gatt_client_eatt_connect(struct btd_gatt_client *client) char addr[18]; int i; - if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT)) + if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT) || + !btd_device_is_initiator(dev)) return; if (bt_att_get_channels(att) == btd_opts.gatt_channels) return; diff --git a/src/gatt-database.c b/src/gatt-database.c index 068e11b..d02e1c5 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -700,7 +700,6 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) struct btd_device *device; uint8_t dst_type; bdaddr_t src, dst; - uint16_t cid; if (gerr) { error("%s", gerr->message); @@ -710,7 +709,6 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST_TYPE, &dst_type, - BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID); if (gerr) { error("bt_io_get: %s", gerr->message); @@ -725,21 +723,9 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) if (!adapter) return; - /* Check cid before attempting to create device, if the device is using - * an RPA it could be that the MGMT event has not been processed yet - * which would lead to create a second copy of the same device using its - * identity address. - */ - if (cid == BT_ATT_CID) - device = btd_adapter_get_device(adapter, &dst, dst_type); - else - device = btd_adapter_find_device(adapter, &dst, dst_type); - - if (!device) { - error("Unable to find device, dropping connection attempt"); - g_io_channel_shutdown(io, FALSE, NULL); + device = btd_adapter_get_device(adapter, &dst, dst_type); + if (!device) return; - } device_attach_att(device, io); @@ -4541,6 +4527,70 @@ static uint8_t server_authorize(struct bt_att *att, uint8_t opcode, return BT_ATT_ERROR_DB_OUT_OF_SYNC; } +static void eatt_confirm_cb(GIOChannel *io, gpointer data) +{ + char address[18]; + uint8_t dst_type; + bdaddr_t src, dst; + GError *gerr = NULL; + struct btd_device *device; + struct bt_gatt_server *server; + struct bt_att *att; + + bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, + BT_IO_OPT_DEST_BDADDR, &dst, + BT_IO_OPT_DEST_TYPE, &dst_type, + BT_IO_OPT_DEST, address, + BT_IO_OPT_INVALID); + if (gerr) { + error("bt_io_get: %s", gerr->message); + g_error_free(gerr); + goto drop; + } + + DBG("New incoming EATT connection"); + + /* Confirm the device exists before accepting the connection, if the + * device is using an RPA it could be that the MGMT event has not been + * processed yet which would lead to create a second copy of the same + * device using its identity address. + */ + device = btd_adapter_find_device(adapter_find(&src), &dst, dst_type); + if (!device) { + error("Unable to find device: %s", address); + goto drop; + } + + /* Only allow EATT connection from central */ + if (btd_device_is_initiator(device)) { + warn("EATT connection from peripheral may cause collisions"); + goto drop; + } + + server = btd_device_get_gatt_server(device); + if (!server) { + error("Unable to resolve bt_server"); + goto drop; + } + + att = bt_gatt_server_get_att(server); + if (bt_att_get_channels(att) == btd_opts.gatt_channels) { + DBG("EATT channel limit reached"); + goto drop; + } + + if (!bt_io_accept(io, connect_cb, NULL, NULL, &gerr)) { + error("bt_io_accept: %s", gerr->message); + g_error_free(gerr); + goto drop; + } + + return; + +drop: + g_io_channel_shutdown(io, TRUE, NULL); +} + struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) { struct btd_gatt_database *database; @@ -4577,14 +4627,14 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) if (btd_opts.gatt_channels == 1) goto bredr; - /* EATT socket */ - database->eatt_io = bt_io_listen(connect_cb, NULL, NULL, NULL, + /* EATT socket, encryption is required */ + database->eatt_io = bt_io_listen(NULL, eatt_confirm_cb, 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_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MTU, btd_opts.gatt_mtu, BT_IO_OPT_INVALID); if (!database->eatt_io) { -- 2.7.4