diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2023-03-09 14:20:17 -0800 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2023-03-09 16:33:02 -0800 |
commit | 1033a462377d9374e9240878357620a8ad368bbf (patch) | |
tree | fc5e8757a0947d60883080b82d142dc4bdf55a26 /src | |
parent | ab3ff0d2cd5aab8bde5a99cf76e4771eefa7f7a0 (diff) | |
download | bluez-1033a462377d9374e9240878357620a8ad368bbf.tar.gz |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/device.c | 6 | ||||
-rw-r--r-- | src/device.h | 1 | ||||
-rw-r--r-- | src/gatt-client.c | 3 | ||||
-rw-r--r-- | src/gatt-database.c | 88 |
4 files changed, 75 insertions, 23 deletions
diff --git a/src/device.c b/src/device.c index 2b8e06c91..326a4d46a 100644 --- a/src/device.c +++ b/src/device.c @@ -294,7 +294,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; @@ -3711,7 +3711,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) @@ -3731,7 +3731,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"); diff --git a/src/device.h b/src/device.h index 9e81fda9e..26d6b7fb4 100644 --- a/src/device.h +++ b/src/device.h @@ -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); diff --git a/src/gatt-client.c b/src/gatt-client.c index b2fc16b90..a54d65e30 100644 --- a/src/gatt-client.c +++ b/src/gatt-client.c @@ -2255,7 +2255,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) diff --git a/src/gatt-database.c b/src/gatt-database.c index 3b53bf2a3..01dd84e8e 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -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) { |