@@ -310,7 +310,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;
@@ -3964,7 +3964,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)
@@ -3984,7 +3984,7 @@ static void device_add_gatt_services(struct btd_device *device)
static void device_accept_gatt_profiles(struct btd_device *device)
{
GSList *l;
- bool initiator = get_initiator(device);
+ bool initiator = btd_device_is_initiator(device);
DBG("initiator %s", initiator ? "true" : "false");
@@ -67,6 +67,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);
@@ -632,7 +632,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);
@@ -642,7 +641,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);
@@ -657,21 +655,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);
}
@@ -3802,6 +3788,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;
@@ -3838,14 +3888,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) {
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> 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 | 6 ++-- src/device.h | 1 + src/gatt-database.c | 88 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 73 insertions(+), 22 deletions(-)