* [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests
@ 2025-11-29 16:40 Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 2/4] btdev: implement Sync Conn Accept/Reject flow Pauli Virtanen
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Pauli Virtanen @ 2025-11-29 16:40 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Add tests for connect timeout behavior and kernel corner cases:
eSCO CVSD - Timeout
eSCO CVSD - Close
---
Notes:
Resend.
tools/sco-tester.c | 77 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 70 insertions(+), 7 deletions(-)
diff --git a/tools/sco-tester.c b/tools/sco-tester.c
index d2ab51b35..660f36e07 100644
--- a/tools/sco-tester.c
+++ b/tools/sco-tester.c
@@ -56,9 +56,15 @@ struct sco_client_data {
const uint8_t *send_data;
uint16_t data_len;
+ /* Connect timeout */
+ unsigned int connect_timeout_us;
+
/* Shutdown socket after connect */
bool shutdown;
+ /* Close socket after connect */
+ bool close_after_connect;
+
/* Enable SO_TIMESTAMPING with these flags */
uint32_t so_timestamping;
@@ -247,7 +253,7 @@ static void test_data_free(void *test_data)
}
#define test_sco_full(name, data, setup, func, _disable_esco, _enable_codecs, \
- _disable_sco_flowctl) \
+ _disable_sco_flowctl, _timeout) \
do { \
struct test_data *user; \
user = malloc(sizeof(struct test_data)); \
@@ -264,28 +270,39 @@ static void test_data_free(void *test_data)
user->disable_sco_flowctl = _disable_sco_flowctl; \
tester_add_full(name, data, \
test_pre_setup, setup, func, NULL, \
- test_post_teardown, 2, user, test_data_free); \
+ test_post_teardown, _timeout, user, \
+ test_data_free); \
} while (0)
#define test_sco(name, data, setup, func) \
- test_sco_full(name, data, setup, func, false, false, false)
+ test_sco_full(name, data, setup, func, false, false, false, 2)
#define test_sco_no_flowctl(name, data, setup, func) \
- test_sco_full(name, data, setup, func, false, false, true)
+ test_sco_full(name, data, setup, func, false, false, true, 2)
#define test_sco_11(name, data, setup, func) \
- test_sco_full(name, data, setup, func, true, false, false)
+ test_sco_full(name, data, setup, func, true, false, false, 2)
#define test_sco_11_no_flowctl(name, data, setup, func) \
- test_sco_full(name, data, setup, func, true, false, true)
+ test_sco_full(name, data, setup, func, true, false, true, 2)
#define test_offload_sco(name, data, setup, func) \
- test_sco_full(name, data, setup, func, false, true, false)
+ test_sco_full(name, data, setup, func, false, true, false, 2)
static const struct sco_client_data connect_success = {
.expect_err = 0
};
+static const struct sco_client_data connect_timeout = {
+ .expect_err = ETIMEDOUT,
+ .connect_timeout_us = 1,
+};
+
+/* Check timeout handling if closed before connect finishes */
+static const struct sco_client_data connect_close = {
+ .close_after_connect = true,
+};
+
static const struct sco_client_data disconnect_success = {
.expect_err = 0,
.shutdown = true,
@@ -684,6 +701,7 @@ end:
static int create_sco_sock(struct test_data *data)
{
+ const struct sco_client_data *scodata = data->test_data;
const uint8_t *central_bdaddr;
struct sockaddr_sco addr;
int sk, err;
@@ -697,6 +715,19 @@ static int create_sco_sock(struct test_data *data)
return err;
}
+ if (scodata->connect_timeout_us) {
+ struct timeval timeout = {
+ .tv_sec = scodata->connect_timeout_us / 1000000,
+ .tv_usec = scodata->connect_timeout_us % 1000000
+ };
+
+ if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO,
+ (void *)&timeout, sizeof(timeout))) {
+ tester_warn("failed to set timeout: %m");
+ return -EINVAL;
+ }
+ }
+
central_bdaddr = hciemu_get_central_bdaddr(data->hciemu);
if (!central_bdaddr) {
tester_warn("No central bdaddr");
@@ -923,6 +954,7 @@ static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
static void test_connect(const void *test_data)
{
struct test_data *data = tester_get_data();
+ const struct sco_client_data *scodata = data->test_data;
GIOChannel *io;
int sk;
@@ -938,6 +970,12 @@ static void test_connect(const void *test_data)
return;
}
+ if (scodata->close_after_connect) {
+ close(sk);
+ tester_test_passed();
+ return;
+ }
+
data->sk = sk;
io = g_io_channel_unix_new(sk);
@@ -1036,6 +1074,25 @@ end:
close(sk);
}
+static bool hook_delay_evt(const void *msg, uint16_t len, void *user_data)
+{
+ tester_print("Delaying emulator response...");
+ g_usleep(500000);
+ tester_print("Delaying emulator response... Done.");
+ return true;
+}
+
+static void test_connect_delayed(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+ BT_HCI_EVT_SYNC_CONN_COMPLETE,
+ hook_delay_evt, NULL);
+
+ test_connect(test_data);
+}
+
static bool hook_setup_sync_evt(const void *buf, uint16_t len, void *user_data)
{
struct test_data *data = tester_get_data();
@@ -1201,6 +1258,12 @@ int main(int argc, char *argv[])
test_sco("eSCO CVSD - Success", &connect_success, setup_powered,
test_connect);
+ test_sco_full("eSCO CVSD - Timeout", &connect_timeout, setup_powered,
+ test_connect_delayed, false, false, false, 8);
+
+ test_sco("eSCO CVSD - Close", &connect_close, setup_powered,
+ test_connect_delayed);
+
test_sco("eSCO mSBC - Success", &connect_success, setup_powered,
test_connect_transp);
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH BlueZ 2/4] btdev: implement Sync Conn Accept/Reject flow
2025-11-29 16:40 [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests Pauli Virtanen
@ 2025-11-29 16:41 ` Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 3/4] bthost: add bthost_setup_sco() and accept incoming eSCO Pauli Virtanen
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Pauli Virtanen @ 2025-11-29 16:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Send HCI Connection Request properly for Setup Synchronous Connection,
instead of proceeding to Connection Complete immediately.
See Core v6.1 Vol 2 Part F Sec 5
---
emulator/btdev.c | 294 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 230 insertions(+), 64 deletions(-)
diff --git a/emulator/btdev.c b/emulator/btdev.c
index 7019037c7..c84bcf783 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -59,6 +59,10 @@
#define SYNC_HANDLE 1
#define INV_HANDLE 0xffff
+#define SCO_AIRMODE_MASK 0x0003
+#define SCO_AIRMODE_CVSD 0x0000
+#define SCO_AIRMODE_TRANSP 0x0003
+
struct hook {
btdev_hook_func handler;
void *user_data;
@@ -136,6 +140,11 @@ struct le_cig {
bool activated;
} __attribute__ ((packed));
+struct pending_conn {
+ struct btdev *dev;
+ uint8_t link_type;
+};
+
struct btdev {
enum btdev_type type;
uint16_t id;
@@ -251,7 +260,7 @@ struct btdev {
uint8_t le_rl_enable;
uint16_t le_rl_timeout;
- struct btdev *pending_conn[MAX_PENDING_CONN];
+ struct pending_conn pending_conn[MAX_PENDING_CONN];
uint8_t le_local_sk256[32];
@@ -1283,29 +1292,49 @@ static struct btdev_conn *conn_link_bis(struct btdev *dev, struct btdev *remote,
return conn;
}
-static void pending_conn_add(struct btdev *btdev, struct btdev *remote)
+static void pending_conn_add(struct btdev *btdev, struct btdev *remote,
+ uint8_t link_type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(btdev->pending_conn); ++i) {
- if (!btdev->pending_conn[i]) {
- btdev->pending_conn[i] = remote;
+ if (!btdev->pending_conn[i].dev) {
+ btdev->pending_conn[i].dev = remote;
+ btdev->pending_conn[i].link_type = link_type;
return;
}
}
}
-static bool pending_conn_del(struct btdev *btdev, struct btdev *remote)
+static int pending_conn_del(struct btdev *btdev, struct btdev *remote)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(btdev->pending_conn); ++i) {
- if (btdev->pending_conn[i] == remote) {
- btdev->pending_conn[i] = NULL;
- return true;
+ if (btdev->pending_conn[i].dev == remote) {
+ btdev->pending_conn[i].dev = NULL;
+ return btdev->pending_conn[i].link_type;
}
}
- return false;
+ return -ENOENT;
+}
+
+static void sync_conn_init_complete(struct btdev_conn *conn,
+ uint8_t link_type, struct bt_hci_evt_sync_conn_complete *cc)
+{
+ struct bt_hci_cmd_enhanced_setup_sync_conn *cmd = conn->data;
+
+ memset(cc, 0, sizeof(*cc));
+
+ cc->status = 0x00;
+ memcpy(cc->bdaddr, conn->link->dev->bdaddr, 6);
+ cc->link_type = link_type;
+ cc->tx_interval = 0x0c;
+ cc->retrans_window = 0x06;
+ cc->rx_pkt_len = cpu_to_le16(60);
+ cc->tx_pkt_len = cpu_to_le16(60);
+ cc->air_mode = cmd->tx_coding_format[0];
+ cc->handle = cpu_to_le16(conn->handle);
}
static void conn_complete(struct btdev *btdev,
@@ -1313,16 +1342,39 @@ static void conn_complete(struct btdev *btdev,
{
struct bt_hci_evt_conn_complete cc;
struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+ int link_type;
if (!remote)
return;
+ link_type = pending_conn_del(btdev, remote);
+ switch (link_type) {
+ case 0x00:
+ case 0x01:
+ break;
+ default:
+ if (!status)
+ status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ link_type = 0x01;
+ break;
+ }
+
+ cc.link_type = link_type;
+
if (!status) {
+ struct bt_hci_evt_sync_conn_complete scc;
struct btdev_conn *conn;
- conn = conn_add_acl(btdev, bdaddr, BDADDR_BREDR);
- if (!conn)
- return;
+ if (link_type == 0x01) {
+ conn = conn_add_acl(btdev, bdaddr, BDADDR_BREDR);
+ if (!conn)
+ return;
+ } else {
+ conn = queue_find(btdev->conns, match_handle,
+ UINT_TO_PTR(SCO_HANDLE));
+ if (!conn)
+ return;
+ }
pending_conn_del(conn->link->dev, btdev);
@@ -1331,20 +1383,23 @@ static void conn_complete(struct btdev *btdev,
cc.encr_mode = 0x00;
cc.handle = cpu_to_le16(conn->link->handle);
- cc.link_type = 0x01;
send_event(conn->link->dev, BT_HCI_EVT_CONN_COMPLETE, &cc,
sizeof(cc));
+ if (link_type != 0x01) {
+ /* Initiating controller gets Sync Conn Complete */
+ sync_conn_init_complete(conn, link_type, &scc);
+ send_event(btdev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &scc,
+ sizeof(scc));
+ return;
+ }
+
cc.handle = cpu_to_le16(conn->handle);
- cc.link_type = 0x01;
} else {
cc.handle = cpu_to_le16(0x0000);
- cc.link_type = 0x01;
}
- pending_conn_del(btdev, remote);
-
cc.status = status;
memcpy(cc.bdaddr, bdaddr, 6);
cc.encr_mode = 0x00;
@@ -1352,6 +1407,57 @@ static void conn_complete(struct btdev *btdev,
send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
}
+static void sync_conn_complete(struct btdev *btdev,
+ const uint8_t *bdaddr, uint8_t status)
+{
+ struct bt_hci_evt_sync_conn_complete cc;
+ struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+ struct btdev_conn *conn;
+ int link_type;
+
+ if (!remote)
+ return;
+
+ link_type = pending_conn_del(btdev, remote);
+
+ switch (link_type) {
+ case 0x00: /* SCO */
+ case 0x02: /* eSCO */
+ break;
+ default:
+ status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
+
+ conn = queue_find(btdev->conns, match_handle, UINT_TO_PTR(SCO_HANDLE));
+ if (!conn) {
+ status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
+
+ if (!status) {
+ pending_conn_del(conn->link->dev, btdev);
+
+ sync_conn_init_complete(conn->link, link_type, &cc);
+ send_event(conn->link->dev, BT_HCI_EVT_SYNC_CONN_COMPLETE,
+ &cc, sizeof(cc));
+
+ sync_conn_init_complete(conn, link_type, &cc);
+ } else {
+ conn_remove(conn);
+
+ memset(&cc, 0, sizeof(cc));
+ cc.handle = cpu_to_le16(0x0000);
+ cc.link_type = 0x02;
+ }
+
+done:
+ cc.status = status;
+ memcpy(cc.bdaddr, bdaddr, 6);
+
+ send_event(btdev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
struct page_timeout_data {
struct btdev *btdev;
uint8_t bdaddr[6];
@@ -1387,7 +1493,7 @@ static int cmd_create_conn_complete(struct btdev *dev, const void *data,
memcpy(cr.dev_class, dev->dev_class, 3);
cr.link_type = 0x01;
- pending_conn_add(dev, remote);
+ pending_conn_add(dev, remote, cr.link_type);
send_event(remote, BT_HCI_EVT_CONN_REQUEST, &cr, sizeof(cr));
} else {
@@ -1413,6 +1519,7 @@ static int cmd_add_sco_conn(struct btdev *dev, const void *data, uint8_t len)
const struct bt_hci_cmd_add_sco_conn *cmd = data;
struct bt_hci_evt_conn_complete cc;
struct btdev_conn *conn;
+ struct bt_hci_cmd_enhanced_setup_sync_conn enh = { 0 };
memset(&cc, 0, sizeof(cc));
@@ -1429,6 +1536,8 @@ static int cmd_add_sco_conn(struct btdev *dev, const void *data, uint8_t len)
goto done;
}
+ conn->data = util_memdup(&enh, sizeof(enh));
+
cc.status = BT_HCI_ERR_SUCCESS;
memcpy(cc.bdaddr, conn->link->dev->bdaddr, 6);
cc.handle = cpu_to_le16(conn->handle);
@@ -1478,7 +1587,7 @@ static int cmd_create_conn_cancel_complete(struct btdev *dev, const void *data,
* Controller shall return an HCI_Command_Complete event with the error
* code Unknown Connection Identifier (0x02).
*/
- if (pending_conn_del(dev, remote)) {
+ if (pending_conn_del(dev, remote) >= 0) {
rp.status = BT_HCI_ERR_SUCCESS;
} else {
conn = queue_find(dev->conns, match_bdaddr, cmd->bdaddr);
@@ -1517,7 +1626,7 @@ static int cmd_accept_conn_complete(struct btdev *dev, const void *data,
if (dev->auth_enable || remote->auth_enable)
send_event(remote, BT_HCI_EVT_LINK_KEY_REQUEST, dev->bdaddr, 6);
else
- conn_complete(dev, cmd->bdaddr, BT_HCI_ERR_SUCCESS);
+ conn_complete(remote, dev->bdaddr, BT_HCI_ERR_SUCCESS);
return 0;
}
@@ -1533,8 +1642,12 @@ static int cmd_reject_conn_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_reject_conn_request *cmd = data;
+ struct btdev *remote = find_btdev_by_bdaddr(cmd->bdaddr);
- conn_complete(dev, cmd->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+ if (!remote)
+ return 0;
+
+ conn_complete(remote, dev->bdaddr, cmd->reason);
return 0;
}
@@ -2821,43 +2934,38 @@ static int cmd_enhanced_setup_sync_conn_complete(struct btdev *dev,
{
const struct bt_hci_cmd_enhanced_setup_sync_conn *cmd = data;
struct bt_hci_evt_sync_conn_complete cc;
+ struct bt_hci_evt_conn_request cr;
struct btdev_conn *conn;
memset(&cc, 0, sizeof(cc));
conn = queue_find(dev->conns, match_handle,
UINT_TO_PTR(le16_to_cpu(cmd->handle)));
- if (!conn) {
+ if (!conn || conn->type != HCI_ACLDATA_PKT) {
cc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- goto done;
+ goto fail;
}
conn = conn_add_sco(conn);
if (!conn) {
cc.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
- goto done;
+ goto fail;
}
- /* TODO: HCI_Connection_Request connection flow */
+ conn->data = util_memdup(cmd, sizeof(*cmd));
+ conn->link->data = util_memdup(cmd, sizeof(*cmd));
- cc.status = BT_HCI_ERR_SUCCESS;
- memcpy(cc.bdaddr, conn->link->dev->bdaddr, 6);
+ memcpy(cr.bdaddr, dev->bdaddr, 6);
+ memcpy(cr.dev_class, dev->dev_class, 3);
+ cr.link_type = 0x02;
- cc.handle = cpu_to_le16(conn->handle);
- cc.link_type = 0x02;
- cc.tx_interval = 0x000c;
- cc.retrans_window = 0x06;
- cc.rx_pkt_len = 60;
- cc.tx_pkt_len = 60;
- cc.air_mode = cmd->tx_coding_format[0];
+ pending_conn_add(dev, conn->link->dev, cr.link_type);
-done:
+ send_event(conn->link->dev, BT_HCI_EVT_CONN_REQUEST, &cr, sizeof(cr));
+ return 0;
+
+fail:
send_event(dev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &cc, sizeof(cc));
-
- if (conn)
- send_event(conn->link->dev, BT_HCI_EVT_SYNC_CONN_COMPLETE,
- &cc, sizeof(cc));
-
return 0;
}
@@ -2872,42 +2980,94 @@ static int cmd_setup_sync_conn_complete(struct btdev *dev, const void *data,
uint8_t len)
{
const struct bt_hci_cmd_setup_sync_conn *cmd = data;
- struct bt_hci_evt_sync_conn_complete cc;
+ struct bt_hci_cmd_enhanced_setup_sync_conn enh;
struct btdev_conn *conn;
- memset(&cc, 0, sizeof(cc));
-
conn = queue_find(dev->conns, match_handle,
UINT_TO_PTR(le16_to_cpu(cmd->handle)));
- if (!conn) {
- cc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- goto done;
+ if (conn && conn->type == HCI_SCODATA_PKT) {
+ struct bt_hci_evt_sync_conn_changed cc;
+
+ /* TODO: actually modify connection parameters */
+ memset(&cc, 0, sizeof(cc));
+ cc.status = BT_HCI_ERR_UNSUPPORTED_FEATURE;
+ send_event(dev, BT_HCI_EVT_SYNC_CONN_CHANGED, &cc, sizeof(cc));
+ return 0;
}
- conn = conn_add_sco(conn);
- if (!conn) {
- cc.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
- goto done;
+ memset(&enh, 0, sizeof(enh));
+
+ enh.handle = cmd->handle;
+
+ /* TODO: emulate also this properly? */
+ enh.tx_bandwidth = cmd->tx_bandwidth;
+ enh.rx_bandwidth = cmd->rx_bandwidth;
+ enh.max_latency = cmd->max_latency;
+ enh.retrans_effort = cmd->retrans_effort;
+ enh.pkt_type = cmd->pkt_type;
+
+ switch (le16_to_cpu(cmd->voice_setting) & SCO_AIRMODE_MASK) {
+ case SCO_AIRMODE_TRANSP:
+ enh.tx_coding_format[0] = 0x03;
+ break;
+ case SCO_AIRMODE_CVSD:
+ default:
+ enh.tx_coding_format[0] = 0x02;
+ break;
}
- cc.status = BT_HCI_ERR_SUCCESS;
- memcpy(cc.bdaddr, conn->link->dev->bdaddr, 6);
+ return cmd_enhanced_setup_sync_conn_complete(dev, &enh, sizeof(enh));
+}
- cc.handle = cpu_to_le16(conn->handle);
- cc.link_type = 0x02;
- cc.tx_interval = 0x000c;
- cc.retrans_window = 0x06;
- cc.rx_pkt_len = 60;
- cc.tx_pkt_len = 60;
- cc.air_mode = (cmd->voice_setting == 0x0060) ? 0x02 : 0x03;
+static int cmd_accept_sync_conn_request(struct btdev *dev, const void *data,
+ uint8_t len)
+{
+ const struct bt_hci_cmd_accept_sync_conn_request *cmd = data;
-done:
- send_event(dev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &cc, sizeof(cc));
+ if (!find_btdev_by_bdaddr(cmd->bdaddr))
+ return -EPERM;
- if (conn)
- send_event(conn->link->dev, BT_HCI_EVT_SYNC_CONN_COMPLETE,
- &cc, sizeof(cc));
+ cmd_status(dev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_ACCEPT_SYNC_CONN_REQUEST);
+ return 0;
+}
+static int cmd_accept_sync_conn_request_complete(struct btdev *dev,
+ const void *data, uint8_t len)
+{
+ const struct bt_hci_cmd_accept_sync_conn_request *cmd = data;
+ struct btdev *remote = find_btdev_by_bdaddr(cmd->bdaddr);
+
+ if (!remote)
+ return 0;
+
+ sync_conn_complete(remote, dev->bdaddr, BT_HCI_ERR_SUCCESS);
+ return 0;
+}
+
+static int cmd_reject_sync_conn_request(struct btdev *dev, const void *data,
+ uint8_t len)
+{
+ const struct bt_hci_cmd_accept_sync_conn_request *cmd = data;
+
+ if (!find_btdev_by_bdaddr(cmd->bdaddr))
+ return -EPERM;
+
+ cmd_status(dev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_REJECT_SYNC_CONN_REQUEST);
+ return 0;
+}
+
+static int cmd_reject_sync_conn_request_complete(struct btdev *dev,
+ const void *data, uint8_t len)
+{
+ const struct bt_hci_cmd_reject_sync_conn_request *cmd = data;
+ struct btdev *remote = find_btdev_by_bdaddr(cmd->bdaddr);
+
+ if (!remote)
+ return 0;
+
+ sync_conn_complete(remote, dev->bdaddr, cmd->reason);
return 0;
}
@@ -3235,6 +3395,10 @@ static int cmd_get_mws_transport_config(struct btdev *dev, const void *data,
#define CMD_BREDR \
CMD(BT_HCI_CMD_SETUP_SYNC_CONN, cmd_setup_sync_conn, \
cmd_setup_sync_conn_complete), \
+ CMD(BT_HCI_CMD_ACCEPT_SYNC_CONN_REQUEST, cmd_accept_sync_conn_request, \
+ cmd_accept_sync_conn_request_complete), \
+ CMD(BT_HCI_CMD_REJECT_SYNC_CONN_REQUEST, cmd_reject_sync_conn_request, \
+ cmd_reject_sync_conn_request_complete), \
CMD(BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE, cmd_read_ext_inquiry, NULL), \
CMD(BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE, cmd_write_ext_inquiry, \
NULL), \
@@ -3379,6 +3543,8 @@ static void set_bredr_commands(struct btdev *btdev)
set_common_commands_bredr20(btdev);
btdev->commands[16] |= 0x08; /* Setup Synchronous Connection */
+ btdev->commands[16] |= 0x10; /* Accept Synchronous Connection Req */
+ btdev->commands[16] |= 0x20; /* Reject Synchronous Connection Req */
btdev->commands[17] |= 0x01; /* Read Extended Inquiry Response */
btdev->commands[17] |= 0x02; /* Write Extended Inquiry Response */
btdev->commands[17] |= 0x20; /* Read Simple Pairing Mode */
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH BlueZ 3/4] bthost: add bthost_setup_sco() and accept incoming eSCO
2025-11-29 16:40 [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 2/4] btdev: implement Sync Conn Accept/Reject flow Pauli Virtanen
@ 2025-11-29 16:41 ` Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 4/4] sco-tester: add socket listen tests Pauli Virtanen
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Pauli Virtanen @ 2025-11-29 16:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Add support for bthost initiating SCO connections and accepting eSCO
ones with BT_HCI_CMD_ACCEPT_SYNC_CONN_REQUEST.
---
emulator/bthost.c | 63 ++++++++++++++++++++++++++++++++++++++++++++---
emulator/bthost.h | 3 +++
2 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 9f9538d0d..935b4ba60 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <endian.h>
+#include <errno.h>
#include <stdbool.h>
#include "bluetooth/bluetooth.h"
@@ -1317,11 +1318,29 @@ static void evt_conn_request(struct bthost *bthost, const void *data,
if (len < sizeof(*ev))
return;
- memset(&cmd, 0, sizeof(cmd));
- memcpy(cmd.bdaddr, ev->bdaddr, sizeof(ev->bdaddr));
+ if (ev->link_type == 0x01 || ev->link_type == 0x00) {
+ memset(&cmd, 0, sizeof(cmd));
+ memcpy(cmd.bdaddr, ev->bdaddr, sizeof(ev->bdaddr));
- send_command(bthost, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd,
+ send_command(bthost, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd,
sizeof(cmd));
+ } else if (ev->link_type == 0x02) {
+ struct bt_hci_cmd_accept_sync_conn_request cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memcpy(cmd.bdaddr, ev->bdaddr, sizeof(ev->bdaddr));
+
+ /* TODO: emulate these properly? */
+ cmd.tx_bandwidth = cpu_to_le32(0x00001f40);
+ cmd.rx_bandwidth = cpu_to_le32(0x00001f40);
+ cmd.max_latency = cpu_to_le16(0xffff);
+ cmd.voice_setting = 0x00;
+ cmd.retrans_effort = 0x02;
+ cmd.pkt_type = 0xff;
+
+ send_command(bthost, BT_HCI_CMD_ACCEPT_SYNC_CONN_REQUEST, &cmd,
+ sizeof(cmd));
+ }
}
static void init_conn(struct bthost *bthost, uint16_t handle,
@@ -3538,6 +3557,44 @@ void bthost_hci_disconnect(struct bthost *bthost, uint16_t handle,
send_command(bthost, BT_HCI_CMD_DISCONNECT, &disc, sizeof(disc));
}
+int bthost_setup_sco(struct bthost *bthost, uint16_t acl_handle,
+ uint16_t setting)
+{
+ static const struct bt_hci_cmd_setup_sync_conn settings[] = {
+ {
+ .tx_bandwidth = cpu_to_le32(0x00001f40),
+ .rx_bandwidth = cpu_to_le32(0x00001f40),
+ .max_latency = cpu_to_le16(0x000a),
+ .retrans_effort = 0x01,
+ .voice_setting = cpu_to_le16(BT_VOICE_CVSD_16BIT),
+ },
+ {
+ .tx_bandwidth = cpu_to_le32(0x00001f40),
+ .rx_bandwidth = cpu_to_le32(0x00001f40),
+ .max_latency = cpu_to_le16(0x000d),
+ .retrans_effort = 0x02,
+ .voice_setting = cpu_to_le16(BT_VOICE_TRANSPARENT),
+ }
+ };
+ struct bt_hci_cmd_setup_sync_conn cmd;
+ unsigned int i;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ for (i = 0; i < ARRAY_SIZE(settings); ++i) {
+ if (settings[i].voice_setting == cpu_to_le16(setting)) {
+ memcpy(&cmd, &settings[i], sizeof(cmd));
+ break;
+ }
+ }
+ if (!cmd.voice_setting)
+ return -EINVAL;
+
+ cmd.handle = cpu_to_le16(acl_handle);
+ send_command(bthost, BT_HCI_CMD_SETUP_SYNC_CONN, &cmd, sizeof(cmd));
+ return 0;
+}
+
void bthost_write_scan_enable(struct bthost *bthost, uint8_t scan)
{
send_command(bthost, BT_HCI_CMD_WRITE_SCAN_ENABLE, &scan, 1);
diff --git a/emulator/bthost.h b/emulator/bthost.h
index ce6bd820f..c88ea0329 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -69,6 +69,9 @@ void bthost_hci_ext_connect(struct bthost *bthost, const uint8_t *bdaddr,
void bthost_hci_disconnect(struct bthost *bthost, uint16_t handle,
uint8_t reason);
+int bthost_setup_sco(struct bthost *bthost, uint16_t acl_handle,
+ uint16_t setting);
+
typedef void (*bthost_cid_hook_func_t)(const void *data, uint16_t len,
void *user_data);
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH BlueZ 4/4] sco-tester: add socket listen tests
2025-11-29 16:40 [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 2/4] btdev: implement Sync Conn Accept/Reject flow Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 3/4] bthost: add bthost_setup_sco() and accept incoming eSCO Pauli Virtanen
@ 2025-11-29 16:41 ` Pauli Virtanen
2025-11-29 17:36 ` [BlueZ,1/4] sco-tester: add timeout / close during connection tests bluez.test.bot
2025-12-02 14:30 ` [PATCH BlueZ 1/4] " patchwork-bot+bluetooth
4 siblings, 0 replies; 6+ messages in thread
From: Pauli Virtanen @ 2025-11-29 16:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Add basic SCO server tests:
SCO CVSD Listen - Success
SCO CVSD Listen Defer - Success
SCO CVSD Listen Recv - Success
SCO CVSD Listen Send - Success
---
Notes:
These catch
WARNING: possible circular locking dependency detected
BUG: sleeping function called from invalid context at net/core/sock.c:3756
in sco_conn_ready()
tools/sco-tester.c | 269 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 261 insertions(+), 8 deletions(-)
diff --git a/tools/sco-tester.c b/tools/sco-tester.c
index 660f36e07..3d6b59092 100644
--- a/tools/sco-tester.c
+++ b/tools/sco-tester.c
@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
+#include <poll.h>
#include <stdbool.h>
#include <glib.h>
@@ -46,6 +47,7 @@ struct test_data {
bool enable_codecs;
bool disable_sco_flowctl;
int step;
+ uint16_t acl_handle;
uint16_t handle;
struct tx_tstamp_data tx_ts;
};
@@ -70,6 +72,12 @@ struct sco_client_data {
/* Number of additional packets to send. */
unsigned int repeat_send;
+
+ /* Listen on SCO socket */
+ bool server;
+
+ /* Defer setup when accepting SCO connections */
+ bool defer;
};
static void print_debug(const char *str, void *user_data)
@@ -360,15 +368,45 @@ static const struct sco_client_data connect_send_no_flowctl_tx_timestamping = {
.repeat_send = 2,
};
+static const struct sco_client_data listen_success = {
+ .server = true,
+ .expect_err = 0,
+};
+
+static const struct sco_client_data listen_defer_success = {
+ .server = true,
+ .defer = true,
+ .expect_err = 0,
+};
+
+static const struct sco_client_data listen_recv_success = {
+ .server = true,
+ .expect_err = 0,
+ .data_len = sizeof(data),
+ .recv_data = data,
+};
+
+static const struct sco_client_data listen_send_success = {
+ .server = true,
+ .expect_err = 0,
+ .data_len = sizeof(data),
+ .send_data = data,
+};
+
static void client_connectable_complete(uint16_t opcode, uint8_t status,
const void *param, uint8_t len,
void *user_data)
{
+ struct test_data *data = user_data;
+
if (opcode != BT_HCI_CMD_WRITE_SCAN_ENABLE)
return;
tester_print("Client set connectable status 0x%02x", status);
+ if (--data->step)
+ return;
+
if (status)
tester_setup_failed();
else
@@ -401,10 +439,26 @@ static void bthost_sco_disconnected(void *user_data)
data->handle = 0x0000;
}
+static void acl_new_conn(uint16_t handle, void *user_data)
+{
+ struct test_data *data = user_data;
+
+ tester_print("New ACL connection with handle 0x%04x", handle);
+
+ data->acl_handle = handle;
+
+ if (--data->step)
+ return;
+
+ tester_setup_complete();
+}
+
static void sco_new_conn(uint16_t handle, void *user_data)
{
struct test_data *data = user_data;
+ const struct sco_client_data *scodata = data->test_data;
struct bthost *host;
+ struct iovec iov = { (void *)scodata->recv_data, scodata->data_len };
tester_print("New client connection with handle 0x%04x", handle);
@@ -413,6 +467,9 @@ static void sco_new_conn(uint16_t handle, void *user_data)
host = hciemu_client_get_host(data->hciemu);
bthost_add_sco_hook(host, data->handle, bthost_recv_data, data,
bthost_sco_disconnected);
+
+ if (scodata->recv_data)
+ bthost_send_sco(host, data->handle, 0x00, &iov, 1);
}
static void setup_powered_callback(uint8_t status, uint16_t length,
@@ -421,6 +478,7 @@ static void setup_powered_callback(uint8_t status, uint16_t length,
struct test_data *data = tester_get_data();
const struct sco_client_data *scodata = data->test_data;
struct bthost *bthost;
+ const uint8_t *bdaddr;
if (status != MGMT_STATUS_SUCCESS) {
tester_setup_failed();
@@ -432,9 +490,20 @@ static void setup_powered_callback(uint8_t status, uint16_t length,
bthost = hciemu_client_get_host(data->hciemu);
bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
bthost_write_scan_enable(bthost, 0x03);
+ data->step++;
- if (scodata && (scodata->send_data || scodata->recv_data))
+ if (!scodata)
+ return;
+
+ if (scodata->send_data || scodata->recv_data || scodata->server)
bthost_set_sco_cb(bthost, sco_new_conn, data);
+
+ if (scodata->server) {
+ bdaddr = hciemu_get_central_bdaddr(data->hciemu);
+ bthost_set_connect_cb(bthost, acl_new_conn, data);
+ bthost_hci_connect(bthost, bdaddr, BDADDR_BREDR);
+ data->step++;
+ }
}
static void setup_powered(const void *test_data)
@@ -871,8 +940,6 @@ static gboolean sock_received_data(GIOChannel *io, GIOCondition cond,
static void sco_recv_data(struct test_data *data, GIOChannel *io)
{
const struct sco_client_data *scodata = data->test_data;
- struct iovec iov = { (void *)scodata->recv_data, scodata->data_len };
- struct bthost *bthost;
data->step = 0;
@@ -880,14 +947,12 @@ static void sco_recv_data(struct test_data *data, GIOChannel *io)
scodata->so_timestamping))
return;
- bthost = hciemu_client_get_host(data->hciemu);
g_io_add_watch(io, G_IO_IN, sock_received_data, NULL);
- bthost_send_sco(bthost, data->handle, 0x00, &iov, 1);
++data->step;
}
-static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
+static gboolean sco_connect(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
struct test_data *data = tester_get_data();
@@ -895,8 +960,6 @@ static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
int err, sk_err, sk;
socklen_t len = sizeof(sk_err);
- data->io_id = 0;
-
sk = g_io_channel_unix_get_fd(io);
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
@@ -951,6 +1014,16 @@ static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
+static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ data->io_id = 0;
+ sco_connect(io, cond, user_data);
+ return FALSE;
+}
+
static void test_connect(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -1239,6 +1312,174 @@ static void test_sco_ethtool_get_ts_info(const void *test_data)
!data->disable_sco_flowctl);
}
+static int listen_sco_sock(struct test_data *data)
+{
+ const struct sco_client_data *scodata = data->test_data;
+ struct sockaddr_sco addr;
+ const uint8_t *src;
+ int sk, err;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_SCO);
+ if (sk < 0) {
+ err = -errno;
+ tester_warn("Can't create socket: %s (%d)", strerror(errno),
+ errno);
+ return err;
+ }
+
+ src = hciemu_get_central_bdaddr(data->hciemu);
+ if (!src) {
+ tester_warn("No source bdaddr");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, (void *) src);
+
+ err = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0) {
+ err = -errno;
+ tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+ errno);
+ goto fail;
+ }
+
+ if (scodata->defer) {
+ int opt = 1;
+
+ if (setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &opt,
+ sizeof(opt)) < 0) {
+ tester_print("Can't enable deferred setup: %s (%d)",
+ strerror(errno), errno);
+ goto fail;
+ }
+ }
+
+ if (listen(sk, 10)) {
+ err = -errno;
+ tester_warn("Can't listen socket: %s (%d)", strerror(errno),
+ errno);
+ goto fail;
+ }
+
+ return sk;
+
+fail:
+ close(sk);
+ return err;
+}
+
+static bool sco_defer_accept(struct test_data *data, GIOChannel *io)
+{
+ int sk;
+ char c;
+ struct pollfd pfd;
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sk;
+ pfd.events = POLLOUT;
+
+ if (poll(&pfd, 1, 0) < 0) {
+ tester_warn("poll: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+
+ if (!(pfd.revents & POLLOUT)) {
+ if (read(sk, &c, 1) < 0) {
+ tester_warn("read: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+ }
+
+ tester_print("Accept deferred setup");
+
+ return true;
+}
+
+static gboolean sco_accept_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct sco_client_data *scodata = data->test_data;
+ int sk, new_sk;
+ gboolean ret;
+ GIOChannel *new_io;
+
+ tester_debug("New connection");
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ new_sk = accept(sk, NULL, NULL);
+ if (new_sk < 0) {
+ tester_test_failed();
+ return false;
+ }
+
+ new_io = g_io_channel_unix_new(new_sk);
+ g_io_channel_set_close_on_unref(new_io, TRUE);
+
+ if (scodata->defer) {
+ if (scodata->expect_err < 0) {
+ g_io_channel_unref(new_io);
+ tester_test_passed();
+ return false;
+ }
+
+ if (!sco_defer_accept(data, new_io)) {
+ tester_warn("Unable to accept deferred setup");
+ tester_test_failed();
+ return false;
+ }
+ }
+
+ ret = sco_connect(new_io, cond, user_data);
+
+ g_io_channel_unref(new_io);
+ return ret;
+}
+
+static void setup_listen(struct test_data *data, GIOFunc func)
+{
+ struct hciemu_client *client;
+ struct bthost *host;
+ int sk;
+ GIOChannel *io;
+
+ sk = listen_sco_sock(data);
+ if (sk < 0) {
+ if (sk == -EPROTONOSUPPORT)
+ tester_test_abort();
+ else
+ tester_test_failed();
+ return;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ data->io_id = g_io_add_watch(io, G_IO_IN, func, NULL);
+ g_io_channel_unref(io);
+
+ tester_print("Listen in progress");
+
+ client = hciemu_get_client(data->hciemu, 0);
+ host = hciemu_client_host(client);
+
+ bthost_setup_sco(host, data->acl_handle, BT_VOICE_CVSD_16BIT);
+}
+
+static void test_listen(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ setup_listen(data, sco_accept_cb);
+}
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
@@ -1325,5 +1566,17 @@ int main(int argc, char *argv[])
test_sco_no_flowctl("SCO Ethtool Get Ts Info No Flowctl - Success",
NULL, setup_powered, test_sco_ethtool_get_ts_info);
+ test_sco("SCO CVSD Listen - Success", &listen_success,
+ setup_powered, test_listen);
+
+ test_sco("SCO CVSD Listen Defer - Success", &listen_defer_success,
+ setup_powered, test_listen);
+
+ test_sco("SCO CVSD Listen Recv - Success", &listen_recv_success,
+ setup_powered, test_listen);
+
+ test_sco("SCO CVSD Listen Send - Success", &listen_send_success,
+ setup_powered, test_listen);
+
return tester_run();
}
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* RE: [BlueZ,1/4] sco-tester: add timeout / close during connection tests
2025-11-29 16:40 [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests Pauli Virtanen
` (2 preceding siblings ...)
2025-11-29 16:41 ` [PATCH BlueZ 4/4] sco-tester: add socket listen tests Pauli Virtanen
@ 2025-11-29 17:36 ` bluez.test.bot
2025-12-02 14:30 ` [PATCH BlueZ 1/4] " patchwork-bot+bluetooth
4 siblings, 0 replies; 6+ messages in thread
From: bluez.test.bot @ 2025-11-29 17:36 UTC (permalink / raw)
To: linux-bluetooth, pav
[-- Attachment #1: Type: text/plain, Size: 2130 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1028907
---Test result---
Test Summary:
CheckPatch PENDING 0.24 seconds
GitLint PENDING 0.23 seconds
BuildEll PASS 20.05 seconds
BluezMake PASS 631.48 seconds
MakeCheck PASS 21.83 seconds
MakeDistcheck PASS 239.56 seconds
CheckValgrind PASS 296.39 seconds
CheckSmatch WARNING 344.60 seconds
bluezmakeextell PASS 188.61 seconds
IncrementalBuild PENDING 0.23 seconds
ScanBuild PASS 970.87 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
tools/sco-tester.c: note: in included file:./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structuresemulator/btdev.c:470:29: warning: Variable length array is used.emulator/bthost.c:700:28: warning: Variable length array is used.emulator/bthost.c:701:32: warning: Variable length array is used.emulator/bthost.c:918:28: warning: Variable length array is used.emulator/bthost.c:952:28: warning: Variable length array is used.emulator/bthost.c:953:32: warning: Variable length array is used.tools/sco-tester.c: note: in included file:./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structures
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests
2025-11-29 16:40 [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests Pauli Virtanen
` (3 preceding siblings ...)
2025-11-29 17:36 ` [BlueZ,1/4] sco-tester: add timeout / close during connection tests bluez.test.bot
@ 2025-12-02 14:30 ` patchwork-bot+bluetooth
4 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+bluetooth @ 2025-12-02 14:30 UTC (permalink / raw)
To: Pauli Virtanen; +Cc: linux-bluetooth
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Sat, 29 Nov 2025 18:40:59 +0200 you wrote:
> Add tests for connect timeout behavior and kernel corner cases:
>
> eSCO CVSD - Timeout
> eSCO CVSD - Close
> ---
>
> Notes:
> Resend.
>
> [...]
Here is the summary with links:
- [BlueZ,1/4] sco-tester: add timeout / close during connection tests
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1d0655882d26
- [BlueZ,2/4] btdev: implement Sync Conn Accept/Reject flow
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=2769a919ebd4
- [BlueZ,3/4] bthost: add bthost_setup_sco() and accept incoming eSCO
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=85888a8357ea
- [BlueZ,4/4] sco-tester: add socket listen tests
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=9a97ad574642
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-12-02 14:33 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-29 16:40 [PATCH BlueZ 1/4] sco-tester: add timeout / close during connection tests Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 2/4] btdev: implement Sync Conn Accept/Reject flow Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 3/4] bthost: add bthost_setup_sco() and accept incoming eSCO Pauli Virtanen
2025-11-29 16:41 ` [PATCH BlueZ 4/4] sco-tester: add socket listen tests Pauli Virtanen
2025-11-29 17:36 ` [BlueZ,1/4] sco-tester: add timeout / close during connection tests bluez.test.bot
2025-12-02 14:30 ` [PATCH BlueZ 1/4] " patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox