Skip to contentSkip to conversation

LE Set CIG Parameters / Create CIS fixes

PATCH In review Pauli Virtanen 3 participants 7 messages Jun 1, 2023 – Jun 2, 2023

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover LE Set CIG Parameters / Create CIS fixes

This patchset fixes a few issues with emission of HCI Remove CIG, Set CIG Parameters, Create CIS when multiple ISO sockets in the same CIG are closed and reconnected rapidly.

v2: Dropped patches that added error checking in hci_le_set_cig_params,
TBD separately later. Returning errors there triggers some race condition in the emulator when it's cleaning up the connections, which needs some more looking.

Simplified the Set CIG Parameters event parsing.

The patches here now are enough to make the test suite pass, and enough to fix the race conditions encountered in BlueZ ISO ops.

Pauli Virtanen (4):
Bluetooth: ISO: use hci_sync for setting CIG parameters
Bluetooth: ISO: don't try to remove CIG if there are bound CIS left
Bluetooth: ISO: use correct CIS order in Set CIG Parameters event
Bluetooth: ISO: do not emit new LE Create CIS if previous is pending

 include/net/bluetooth/hci_core.h |   4 +-
 include/net/bluetooth/hci_sync.h |   2 +-
 net/bluetooth/hci_conn.c         | 123 ++++++++++++++++++-------------
 net/bluetooth/hci_event.c        |  72 +++++++++++++-----
 net/bluetooth/hci_sync.c         |  90 +++++++++++++++-------
 net/bluetooth/iso.c              |   2 +-
 6 files changed, 193 insertions(+), 100 deletions(-)
Signature · 1 line
2.40.1
#1 lore raw

PATCH v2 1/4 Bluetooth: ISO: use hci_sync for setting CIG parameters

When reconfiguring CIG after disconnection of the last CIS, LE Remove CIG shall be sent before LE Set CIG Parameters. Otherwise, it fails because CIG is in the inactive state and not configurable (Core v5.3 Vol 6 Part B Sec. 4.5.14.3). This ordering is currently wrong under suitable timing conditions, because LE Remove CIG is sent via the hci_sync queue and may be delayed, but Set CIG Parameters is via hci_send_cmd.

Make the ordering well-defined by sending also Set CIG Parameters via hci_sync.

Fixes 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections")

---

Notes:
v2: rebased, no changes

 net/bluetooth/hci_conn.c | 47 +++++++++++++++++++++++++++++++++-------
 1 file changed, 39 insertions(+), 8 deletions(-)
net/bluetooth/hci_conn.c +39 -8
index 795b2daa5bac..f45476deca82 100644
@@ -775,6 +775,11 @@ static void le_conn_timeout(struct work_struct *work)
 	hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
 }
 
+struct iso_cig_params {
+	struct hci_cp_le_set_cig_params cp;
+	struct hci_cis_params cis[0x1f];
+};
+
 struct iso_list_data {
 	union {
 		u8  cig;
@@ -786,10 +791,7 @@ struct iso_list_data {
 		u16 sync_handle;
 	};
 	int count;
-	struct {
-		struct hci_cp_le_set_cig_params cp;
-		struct hci_cis_params cis[0x11];
-	} pdu;
+	struct iso_cig_params pdu;
 	bool big_term;
 };
 
@@ -1783,10 +1785,33 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos)
 	return hci_send_cmd(hdev, HCI_OP_LE_CREATE_BIG, sizeof(cp), &cp);
 }
 
+static void set_cig_params_complete(struct hci_dev *hdev, void *data, int err)
+{
+	struct iso_cig_params *pdu = data;
+
+	bt_dev_dbg(hdev, "");
+
+	if (err)
+		bt_dev_err(hdev, "Unable to set CIG parameters: %d", err);
+
+	kfree(pdu);
+}
+
+static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+{
+	struct iso_cig_params *pdu = data;
+	u32 plen;
+
+	plen = sizeof(pdu->cp) + pdu->cp.num_cis * sizeof(pdu->cis[0]);
+	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_CIG_PARAMS, plen, pdu,
+				     HCI_CMD_TIMEOUT);
+}
+
 static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct iso_list_data data;
+	struct iso_cig_params *pdu;
 
 	memset(&data, 0, sizeof(data));
 
@@ -1856,12 +1881,18 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
 	if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET || !data.pdu.cp.num_cis)
 		return false;
 
-	if (hci_send_cmd(hdev, HCI_OP_LE_SET_CIG_PARAMS,
-			 sizeof(data.pdu.cp) +
-			 (data.pdu.cp.num_cis * sizeof(*data.pdu.cis)),
-			 &data.pdu) < 0)
+	pdu = kzalloc(sizeof(*pdu), GFP_KERNEL);
+	if (!pdu)
 		return false;
 
+	memcpy(pdu, &data.pdu, sizeof(*pdu));
+
+	if (hci_cmd_sync_queue(hdev, set_cig_params_sync, pdu,
+			       set_cig_params_complete) < 0) {
+		kfree(pdu);
+		return false;
+	}
+
 	return true;
 }
 
Signature · 1 line
2.40.1
#2 lore raw

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=752943

---Test result---

Test Summary:

CheckPatch                    PASS      3.68 seconds
GitLint                       PASS      1.00 seconds
SubjectPrefix                 PASS      0.28 seconds
BuildKernel                   PASS      38.01 seconds
CheckAllWarning               PASS      42.14 seconds
CheckSparse                   WARNING   47.48 seconds
CheckSmatch                   WARNING   129.23 seconds
BuildKernel32                 PASS      37.72 seconds
TestRunnerSetup               PASS      528.41 seconds
TestRunner_l2cap-tester       PASS      19.39 seconds
TestRunner_iso-tester         PASS      27.00 seconds
TestRunner_bnep-tester        PASS      6.56 seconds
TestRunner_mgmt-tester        PASS      132.55 seconds
TestRunner_rfcomm-tester      PASS      10.70 seconds
TestRunner_sco-tester         PASS      9.77 seconds
TestRunner_ioctl-tester       PASS      11.76 seconds
TestRunner_mesh-tester        PASS      8.46 seconds
TestRunner_smp-tester         PASS      9.57 seconds
TestRunner_userchan-tester    PASS      6.95 seconds
IncrementalBuild              PASS      81.16 seconds

Details
##############################
Test: CheckSparse - WARNING
Desc: Run sparse tool with linux kernel
Output:
net/bluetooth/hci_event.c: note: in included file (through include/net/bluetooth/hci_core.h):net/bluetooth/hci_event.c: note: in included file (through include/net/bluetooth/hci_core.h):
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
net/bluetooth/hci_event.c: note: in included file (through include/net/bluetooth/hci_core.h):net/bluetooth/hci_event.c: note: in included file (through include/net/bluetooth/hci_core.h):

---
Regards,
Linux Bluetooth

#3 lore raw

PATCH v2 2/4 Bluetooth: ISO: don't try to remove CIG if there are bound CIS left

In reply to Pauli Virtanen

Consider existing BOUND & CONNECT state CIS to block CIG removal. Otherwise, under suitable timing conditions we may attempt to remove CIG while Create CIS is pending, which fails.

Fixes 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections")

---

Notes:
v2: no changes

 net/bluetooth/hci_conn.c | 2 ++
 1 file changed, 2 insertions(+)
net/bluetooth/hci_conn.c +2 -0
index f45476deca82..15cba23ade52 100644
@@ -983,6 +983,8 @@ static void cis_cleanup(struct hci_conn *conn)
 	/* Check if ISO connection is a CIS and remove CIG if there are
 	 * no other connections using it.
 	 */
+	hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_BOUND, &d);
+	hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECT, &d);
 	hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d);
 	if (d.count)
 		return;
Signature · 1 line
2.40.1
#4 lore raw

PATCH v2 3/4 Bluetooth: ISO: use correct CIS order in Set CIG Parameters event

In reply to Pauli Virtanen

The order of CIS handle array in Set CIG Parameters response shall match the order of the CIS_ID array in the command (Core v5.3 Vol 4 Part E Sec 7.8.97). We send CIS_IDs mainly in the order of increasing CIS_ID (but with "last" CIS first if it has fixed CIG_ID). In handling of the reply, we currently assume this is also the same as the order of hci_conn in hdev->conn_hash, but that is not true.

Match the correct hci_conn to the correct handle by matching them based on the CIG+CIS combination. The CIG+CIS combination shall be unique for ISO_LINK hci_conn at state >= BT_BOUND, which we maintain in hci_le_set_cig_params.

Fixes 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections")

---

Notes:
v2: simplify and swap loops

 net/bluetooth/hci_event.c | 59 +++++++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 18 deletions(-)
net/bluetooth/hci_event.c +41 -18
index fe8177512a89..d0ccb8ebdcc9 100644
@@ -3804,44 +3804,67 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
 				   struct sk_buff *skb)
 {
 	struct hci_rp_le_set_cig_params *rp = data;
+	struct hci_cp_le_set_cig_params *cp;
 	struct hci_conn *conn;
-	int i = 0;
+	u8 status = rp->status;
+	int i;
 
 	bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
+	cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
+	if (!cp || rp->num_handles != cp->num_cis || rp->cig_id != cp->cig_id) {
+		bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
+		status = HCI_ERROR_UNSPECIFIED;
+	}
+
 	hci_dev_lock(hdev);
 
-	if (rp->status) {
+	if (status) {
 		while ((conn = hci_conn_hash_lookup_cig(hdev, rp->cig_id))) {
 			conn->state = BT_CLOSED;
-			hci_connect_cfm(conn, rp->status);
+			hci_connect_cfm(conn, status);
 			hci_conn_del(conn);
 		}
 		goto unlock;
 	}
 
+	/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E page 2553
+	 *
+	 * If the Status return parameter is zero, then the Controller shall
+	 * set the Connection_Handle arrayed return parameter to the connection
+	 * handle(s) corresponding to the CIS configurations specified in
+	 * the CIS_IDs command parameter, in the same order.
+	 */
+
 	rcu_read_lock();
 
-	list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
-		if (conn->type != ISO_LINK ||
-		    conn->iso_qos.ucast.cig != rp->cig_id ||
-		    conn->state == BT_CONNECTED)
-			continue;
+	for (i = 0; i < rp->num_handles; ++i) {
+		list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
+			if (conn->type != ISO_LINK ||
+			    !bacmp(&conn->dst, BDADDR_ANY))
+				continue;
+			if (conn->state != BT_BOUND &&
+			    conn->state != BT_CONNECT)
+				continue;
+			if (conn->iso_qos.ucast.cig != rp->cig_id ||
+			    conn->iso_qos.ucast.cis != cp->cis[i].cis_id)
+				continue;
 
-		conn->handle = __le16_to_cpu(rp->handle[i++]);
+			conn->handle = __le16_to_cpu(rp->handle[i]);
 
-		bt_dev_dbg(hdev, "%p handle 0x%4.4x parent %p", conn,
-			   conn->handle, conn->parent);
+			bt_dev_dbg(hdev, "%p handle 0x%4.4x parent %p",
+				   conn, conn->handle, conn->parent);
 
-		/* Create CIS if LE is already connected */
-		if (conn->parent && conn->parent->state == BT_CONNECTED) {
-			rcu_read_unlock();
-			hci_le_create_cis(conn);
-			rcu_read_lock();
-		}
+			/* Create CIS if LE is already connected */
+			if (conn->parent &&
+			    conn->parent->state == BT_CONNECTED) {
+				rcu_read_unlock();
+				hci_le_create_cis(conn);
+				rcu_read_lock();
+			}
 
-		if (i == rp->num_handles)
 			break;
+		}
 	}
 
 	rcu_read_unlock();
Signature · 1 line
2.40.1
#5 lore raw

PATCH v2 4/4 Bluetooth: ISO: do not emit new LE Create CIS if previous is pending

In reply to Pauli Virtanen

LE Create CIS command shall not be sent before all CIS Established events from its previous invocation have been processed. Currently it is sent via hci_sync but that only waits for the first event, but there can be multiple.

Make it wait for all events, and simplify the CIS creation as follows:

Add new flag HCI_CONN_CREATE_CIS, which is set if Create CIS has been sent for the connection but it is not yet completed.

Make BT_CONNECT state to mean the connection wants Create CIS.

On events after which new Create CIS may need to be sent, send it if possible and some connections need it. These events are:
hci_connect_cis, iso_connect_cfm, hci_cs_le_create_cis, hci_le_cis_estabilished_evt.

The Create CIS status/completion events shall queue new Create CIS only if at least one of the connections transitions away from BT_CONNECT, so that we don't loop if controller is sending bogus events.

This fixes sending multiple CIS Create for the same CIS in the "ISO AC 6(i) - Success" BlueZ test case:

< HCI Command: LE Create Co.. (0x08|0x0064) plen 9 #129 [hci0]
Number of CIS: 2
CIS Handle: 257
ACL Handle: 42
CIS Handle: 258
ACL Handle: 42

Quoted 1 line

HCI Event: Command Status (0x0f) plen 4 #130 [hci0]

      LE Create Connected Isochronous Stream (0x08|0x0064) ncmd 1
        Status: Success (0x00)
Quoted 1 line

HCI Event: LE Meta Event (0x3e) plen 29 #131 [hci0]

      LE Connected Isochronous Stream Established (0x19)
        Status: Success (0x00)
        Connection Handle: 257
        ...
< HCI Command: LE Setup Is.. (0x08|0x006e) plen 13  #132 [hci0]
        ...
Quoted 1 line

HCI Event: Command Complete (0x0e) plen 6 #133 [hci0]

      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        ...

< HCI Command: LE Create Co.. (0x08|0x0064) plen 5 #134 [hci0]
Number of CIS: 1
CIS Handle: 258
ACL Handle: 42

Quoted 1 line

HCI Event: Command Status (0x0f) plen 4 #135 [hci0]

      LE Create Connected Isochronous Stream (0x08|0x0064) ncmd 1
        Status: ACL Connection Already Exists (0x0b)
Quoted 1 line

HCI Event: LE Meta Event (0x3e) plen 29 #136 [hci0]

      LE Connected Isochronous Stream Established (0x19)
        Status: Success (0x00)
        Connection Handle: 258
        ...
Fixes c09b80be6ffc ("Bluetooth: hci_conn: Fix not waiting for HCI_EVT_LE_CIS_ESTABLISHED")

---

Notes:
v2: no changes

 include/net/bluetooth/hci_core.h |  4 +-
 include/net/bluetooth/hci_sync.h |  2 +-
 net/bluetooth/hci_conn.c         | 74 +++++++++++---------------
 net/bluetooth/hci_event.c        | 27 +++++++---
 net/bluetooth/hci_sync.c         | 90 ++++++++++++++++++++++----------
 net/bluetooth/iso.c              |  2 +-
 6 files changed, 118 insertions(+), 81 deletions(-)
include/net/bluetooth/hci_core.h +3 -1
index 74ec1f40ab6b..2a29ea8e808c 100644
@@ -976,6 +976,7 @@ enum {
 	HCI_CONN_AUTH_FAILURE,
 	HCI_CONN_PER_ADV,
 	HCI_CONN_BIG_CREATED,
+	HCI_CONN_CREATE_CIS,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -1351,7 +1352,8 @@ int hci_disconnect(struct hci_conn *conn, __u8 reason);
 bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
 void hci_sco_setup(struct hci_conn *conn, __u8 status);
 bool hci_iso_setup_path(struct hci_conn *conn);
-int hci_le_create_cis(struct hci_conn *conn);
+int hci_le_create_cis_pending(struct hci_dev *hdev);
+int hci_conn_check_create_cis(struct hci_conn *conn);
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
 			      u8 role);
include/net/bluetooth/hci_sync.h +1 -1
index 2495be4d8b82..b516a0f4a55b 100644
@@ -124,7 +124,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);
 
 int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);
 
-int hci_le_create_cis_sync(struct hci_dev *hdev, struct hci_conn *conn);
+int hci_le_create_cis_sync(struct hci_dev *hdev);
 
 int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle);
 
net/bluetooth/hci_conn.c +30 -44

100 lines not on this page · raw message

net/bluetooth/hci_event.c +20 -7
index d0ccb8ebdcc9..f48456863c27 100644
@@ -3807,6 +3807,7 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
 	struct hci_cp_le_set_cig_params *cp;
 	struct hci_conn *conn;
 	u8 status = rp->status;
+	bool pending = false;
 	int i;
 
 	bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
@@ -3855,13 +3856,8 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
 			bt_dev_dbg(hdev, "%p handle 0x%4.4x parent %p",
 				   conn, conn->handle, conn->parent);
 
-			/* Create CIS if LE is already connected */
-			if (conn->parent &&
-			    conn->parent->state == BT_CONNECTED) {
-				rcu_read_unlock();
-				hci_le_create_cis(conn);
-				rcu_read_lock();
-			}
+			if (conn->state == BT_CONNECT)
+				pending = true;
 
 			break;
 		}
@@ -3870,6 +3866,9 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
 	rcu_read_unlock();
 
 unlock:
+	if (pending)
+		hci_le_create_cis_pending(hdev);
+
 	hci_dev_unlock(hdev);
 
 	return rp->status;
@@ -4235,6 +4234,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
 static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
 {
 	struct hci_cp_le_create_cis *cp;
+	bool pending = false;
 	int i;
 
 	bt_dev_dbg(hdev, "status 0x%2.2x", status);
@@ -4257,12 +4257,18 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
 
 		conn = hci_conn_hash_lookup_handle(hdev, handle);
 		if (conn) {
+			if (test_and_clear_bit(HCI_CONN_CREATE_CIS,
+					       &conn->flags))
+				pending = true;
 			conn->state = BT_CLOSED;
 			hci_connect_cfm(conn, status);
 			hci_conn_del(conn);
 		}
 	}
 
+	if (pending)
+		hci_le_create_cis_pending(hdev);
+
 	hci_dev_unlock(hdev);
 }
 
@@ -6805,6 +6811,7 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
 {
 	struct hci_evt_le_cis_established *ev = data;
 	struct hci_conn *conn;
+	bool pending = false;
 	u16 handle = __le16_to_cpu(ev->handle);
 
 	bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
@@ -6826,6 +6833,8 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
 		goto unlock;
 	}
 
+	pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, &conn->flags);
+
 	if (conn->role == HCI_ROLE_SLAVE) {
 		__le32 interval;
 
@@ -6851,10 +6860,14 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
 		goto unlock;
 	}
 
+	conn->state = BT_CLOSED;
 	hci_connect_cfm(conn, ev->status);
 	hci_conn_del(conn);
 
 unlock:
+	if (pending)
+		hci_le_create_cis_pending(hdev);
+
 	hci_dev_unlock(hdev);
 }
 
net/bluetooth/hci_sync.c +63 -27

119 lines not on this page · raw message

net/bluetooth/iso.c +1 -1
index 485348fcc030..73ac9753728b 100644
@@ -1681,7 +1681,7 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
 		}
 
 		/* Create CIS if pending */
-		hci_le_create_cis(hcon);
+		hci_le_create_cis_pending(hcon->hdev);
 		return;
 	}
 
Signature · 1 line
2.40.1
#6 lore raw
In reply to Pauli Virtanen
This series was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:

Hello:

This series was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:

Quoted 10 lines · On Thu, 1 Jun 2023 09:34:42 +0300 you wrote:

This patchset fixes a few issues with emission of HCI Remove CIG, Set CIG Parameters, Create CIS when multiple ISO sockets in the same CIG are closed and reconnected rapidly.

v2: Dropped patches that added error checking in hci_le_set_cig_params,
TBD separately later. Returning errors there triggers some race condition in the emulator when it's cleaning up the connections, which needs some more looking.

[...]

Here is the summary with links:
- [v2,1/4] Bluetooth: ISO: use hci_sync for setting CIG parameters

    https://git.kernel.org/bluetooth/bluetooth-next/c/f0393238e391
  - [v2,2/4] Bluetooth: ISO: don't try to remove CIG if there are bound CIS left
    https://git.kernel.org/bluetooth/bluetooth-next/c/59b32ee40f50

- [v2,3/4] Bluetooth: ISO: use correct CIS order in Set CIG Parameters event (no matching commit)
- [v2,4/4] Bluetooth: ISO: do not emit new LE Create CIS if previous is pending (no matching commit)

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html