Skip to contentSkip to conversation

Enable use of L2CAP_MODE_EXT_FLOWCTL

PATCH Superseded Luiz Augusto von Dentz 2 participants 10 messages Mar 23, 2020 – Mar 24, 2020

Subsystems (2)
lore
Share & tools
lore

Luiz Augusto von Dentz

author maintainer
#0 lore raw

v5 cover Enable use of L2CAP_MODE_EXT_FLOWCTL

From: Luiz Augusto von Dentz <[email protected]>

This enables use of BT_MODE_EXT_FLOWCTL with BT_MODE socketopt, in addition to that add support for DEFER_SETUP to be used with client sockets so they can be grouped and sent together.

BT_MODE is not compatible with L2CAP_OPTIONS so attempting to use them both will cause an error to be returned to the applicatio.

This has been tested by introducing support for L2CAP_MODE_EXT_FLOWCTL into l2cap-tester which now produces the following trace:

Enable ecred PDUs:
#echo 1 > /sys/module/bluetooth/parameters/enable_ecred

#sudo tools/l2cap-tester -p "L2CAP Ext-Flowctl"
L2CAP Ext-Flowctl Client - Success - init
Read Index List callback

    Status: 0x00
  New hciemu instance created
  Index Added callback
    Index: 0x0000
  Read Info callback
    Status: 0x00
    Address: 00:AA:01:00:00:00
    Version: 0x09
    Manufacturer: 0x003f
    Supported settings: 0x0001be1b
    Current settings: 0x00000200
    Class: 0x000000
    Name:
    Short name:

L2CAP Ext-Flowctl Client - Success - setup
Powering on controller
Controller powered on
Client set connectable status 0x00
L2CAP Ext-Flowctl Client - Success - setup complete L2CAP Ext-Flowctl Client - Success - run
Connect in progress
Successfully connected
L2CAP Ext-Flowctl Client - Success - test passed L2CAP Ext-Flowctl Client - Success - teardown
Index Removed callback

    Index: 0x0000

L2CAP Ext-Flowctl Client - Success - teardown complete L2CAP Ext-Flowctl Client - Success - done

L2CAP Ext-Flowctl Client, Direct Advertising - Success - init
Read Index List callback

    Status: 0x00
  New hciemu instance created
  Index Added callback
    Index: 0x0000
  Read Info callback
    Status: 0x00
    Address: 00:AA:01:00:00:00
    Version: 0x09
    Manufacturer: 0x003f
    Supported settings: 0x0001be1b
    Current settings: 0x00000200
    Class: 0x000000
    Name:
    Short name:

L2CAP Ext-Flowctl Client, Direct Advertising - Success - setup
Powering on controller
Controller powered on
Client set connectable status 0x00
L2CAP Ext-Flowctl Client, Direct Advertising - Success - setup complete L2CAP Ext-Flowctl Client, Direct Advertising - Success - run
Connect in progress
Received advertising parameters HCI command
L2CAP Ext-Flowctl Client, Direct Advertising - Success - test passed L2CAP Ext-Flowctl Client, Direct Advertising - Success - teardown
Index Removed callback

    Index: 0x0000

L2CAP Ext-Flowctl Client, Direct Advertising - Success - teardown complete L2CAP Ext-Flowctl Client, Direct Advertising - Success - done

L2CAP Ext-Flowctl Client SMP - Success - init
Read Index List callback

    Status: 0x00
  New hciemu instance created
  Index Added callback
    Index: 0x0000
  Read Info callback
    Status: 0x00
    Address: 00:AA:01:00:00:00
    Version: 0x09
    Manufacturer: 0x003f
    Supported settings: 0x0001be1b
    Current settings: 0x00000200
    Class: 0x000000
    Name:
    Short name:

L2CAP Ext-Flowctl Client SMP - Success - setup
Powering on controller
Controller powered on
Client set connectable status 0x00
L2CAP Ext-Flowctl Client SMP - Success - setup complete L2CAP Ext-Flowctl Client SMP - Success - run
Connect in progress
Successfully connected
L2CAP Ext-Flowctl Client SMP - Success - test passed L2CAP Ext-Flowctl Client SMP - Success - teardown
Index Removed callback

    Index: 0x0000

L2CAP Ext-Flowctl Client SMP - Success - teardown complete L2CAP Ext-Flowctl Client SMP - Success - done

L2CAP Ext-Flowctl Client - Command Reject - init
Read Index List callback

    Status: 0x00
  New hciemu instance created
  Index Added callback
    Index: 0x0000
  Read Info callback
    Status: 0x00
    Address: 00:AA:01:00:00:00
    Version: 0x09
    Manufacturer: 0x003f
    Supported settings: 0x0001be1b
    Current settings: 0x00000200
    Class: 0x000000
    Name:
    Short name:

L2CAP Ext-Flowctl Client - Command Reject - setup
Powering on controller
Controller powered on
Client set connectable status 0x00
L2CAP Ext-Flowctl Client - Command Reject - setup complete L2CAP Ext-Flowctl Client - Command Reject - run
Connect in progress
New connection with handle 0x002a
Connect failed: Connection refused (111)
L2CAP Ext-Flowctl Client - Command Reject - test passed L2CAP Ext-Flowctl Client - Command Reject - teardown
Index Removed callback

    Index: 0x0000

L2CAP Ext-Flowctl Client - Command Reject - teardown complete L2CAP Ext-Flowctl Client - Command Reject - done

L2CAP Ext-Flowctl Client - Open two sockets - init
Read Index List callback

    Status: 0x00
  New hciemu instance created
  Index Added callback
    Index: 0x0000
  Read Info callback
    Status: 0x00
    Address: 00:AA:01:00:00:00
    Version: 0x09
    Manufacturer: 0x003f
    Supported settings: 0x0001be1b
    Current settings: 0x00000200
    Class: 0x000000
    Name:
    Short name:

L2CAP Ext-Flowctl Client - Open two sockets - setup
Powering on controller
Controller powered on
L2CAP Ext-Flowctl Client - Open two sockets - setup complete L2CAP Ext-Flowctl Client - Open two sockets - run
Connect in progress, sk = 19 (deferred)
HCI Command 0x200b length 7
HCI Command 0x200c length 2
Connect in progress, sk = 20
Client set connectable status 0x00
HCI Command 0x200c length 2
HCI Command 0x200d length 25
HCI Command 0x2016 length 2
Successfully connected
Successfully connected
L2CAP Ext-Flowctl Client - Open two sockets - test passed L2CAP Ext-Flowctl Client - Open two sockets - teardown
Index Removed callback

    Index: 0x0000

L2CAP Ext-Flowctl Client - Open two sockets - teardown complete L2CAP Ext-Flowctl Client - Open two sockets - done

L2CAP Ext-Flowctl Client - Open two sockets close one - init
Read Index List callback

    Status: 0x00
  New hciemu instance created
  Index Added callback
    Index: 0x0000
  Read Info callback
    Status: 0x00
    Address: 00:AA:01:00:00:00
    Version: 0x09
    Manufacturer: 0x003f
    Supported settings: 0x0001be1b
    Current settings: 0x00000200
    Class: 0x000000
    Name:
    Short name:

L2CAP Ext-Flowctl Client - Open two sockets close one - setup
Powering on controller
Controller powered on
L2CAP Ext-Flowctl Client - Open two sockets close one - setup complete L2CAP Ext-Flowctl Client - Open two sockets close one - run
Connect in progress, sk = 19 (deferred)
HCI Command 0x200b length 7
HCI Command 0x200c length 2
Connect in progress, sk = 20
Closing first socket! -1
Client set connectable status 0x00
HCI Command 0x200c length 2
HCI Command 0x200d length 25
HCI Command 0x2016 length 2
Successfully connected
L2CAP Ext-Flowctl Client - Open two sockets close one - test passed L2CAP Ext-Flowctl Client - Open two sockets close one - teardown
Index Removed callback

    Index: 0x0000

L2CAP Ext-Flowctl Client - Open two sockets close one - teardown complete L2CAP Ext-Flowctl Client - Open two sockets close one - done

Test Summary
------------
L2CAP Ext-Flowctl Client - Success Passed 0.068 seconds
L2CAP Ext-Flowctl Client, Direct Advertising - Success Passed 0.023 seconds

L2CAP Ext-Flowctl Client SMP - Success               Passed       0.027 seconds
L2CAP Ext-Flowctl Client - Command Reject            Passed       0.046 seconds
L2CAP Ext-Flowctl Client - Open two sockets          Passed       0.014 seconds

L2CAP Ext-Flowctl Client - Open two sockets close one Passed 0.066 seconds
Total: 6, Passed: 6 (100.0%), Failed: 0, Not Run: 0 Overall execution time: 0.247 seconds

Luiz Augusto von Dentz (3):
Bluetooth: L2CAP: Add get_peer_pid callback
Bluetooth: L2CAP: Use DEFER_SETUP to group ECRED connections
Bluetooth: Add BT_MODE socket option

 include/net/bluetooth/bluetooth.h |  11 +++
 include/net/bluetooth/l2cap.h     |   5 ++
 net/bluetooth/l2cap_core.c        | 136 +++++++++++++++++++++++++++---
 net/bluetooth/l2cap_sock.c        | 104 +++++++++++++++++++++++
 4 files changed, 246 insertions(+), 10 deletions(-)
Signature · 1 line
2.21.1
author maintainer
#1 lore raw

PATCH v5 1/3 Bluetooth: L2CAP: Add get_peer_pid callback

From: Luiz Augusto von Dentz <[email protected]>

This adds a callback to read the socket pid.

---
 include/net/bluetooth/l2cap.h | 1 +
 net/bluetooth/l2cap_sock.c    | 8 ++++++++
 2 files changed, 9 insertions(+)
include/net/bluetooth/l2cap.h +1 -0
index 537aaead259f..2d7d28474d34 100644
@@ -660,6 +660,7 @@ struct l2cap_ops {
 	void			(*suspend) (struct l2cap_chan *chan);
 	void			(*set_shutdown) (struct l2cap_chan *chan);
 	long			(*get_sndtimeo) (struct l2cap_chan *chan);
+	struct pid		*(*get_peer_pid) (struct l2cap_chan *chan);
 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
 					       unsigned long hdr_len,
 					       unsigned long len, int nb);
net/bluetooth/l2cap_sock.c +8 -0
index 40fb10b591bd..117ba20ea194 100644
@@ -1504,6 +1504,13 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan)
 	return sk->sk_sndtimeo;
 }
 
+static struct pid *l2cap_sock_get_peer_pid_cb(struct l2cap_chan *chan)
+{
+	struct sock *sk = chan->data;
+
+	return sk->sk_peer_pid;
+}
+
 static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
 {
 	struct sock *sk = chan->data;
@@ -1525,6 +1532,7 @@ static const struct l2cap_ops l2cap_chan_ops = {
 	.suspend		= l2cap_sock_suspend_cb,
 	.set_shutdown		= l2cap_sock_set_shutdown_cb,
 	.get_sndtimeo		= l2cap_sock_get_sndtimeo_cb,
+	.get_peer_pid		= l2cap_sock_get_peer_pid_cb,
 	.alloc_skb		= l2cap_sock_alloc_skb_cb,
 };
 
Signature · 1 line
2.21.1
maintainer
#2 lore raw

Re: [PATCH v5 1/3] Bluetooth: L2CAP: Add get_peer_pid callback

Hi Luiz,

Quoted 7 lines

This adds a callback to read the socket pid.

---
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/l2cap_sock.c | 8 ++++++++

2 files changed, 9 insertions(+)

patch has been applied to bluetooth-next tree.

Regards

Marcel

author maintainer
#3 lore raw

PATCH v5 2/3 Bluetooth: L2CAP: Use DEFER_SETUP to group ECRED connections

In reply to Luiz Augusto von Dentz

From: Luiz Augusto von Dentz <[email protected]>

This uses the DEFER_SETUP flag to group channels with L2CAP_CREDIT_BASED_CONNECTION_REQ.

---
 include/net/bluetooth/l2cap.h |   4 +
 net/bluetooth/l2cap_core.c    | 136 +++++++++++++++++++++++++++++++---
 2 files changed, 130 insertions(+), 10 deletions(-)
include/net/bluetooth/l2cap.h +4 -0
index 2d7d28474d34..dada14d0622c 100644
@@ -47,6 +47,7 @@
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
 #define L2CAP_BREDR_MAX_PAYLOAD		1019    /* 3-DH5 packet */
 #define L2CAP_LE_MIN_MTU		23
+#define L2CAP_ECRED_CONN_SCID_MAX	5
 
 #define L2CAP_DISC_TIMEOUT		msecs_to_jiffies(100)
 #define L2CAP_DISC_REJ_TIMEOUT		msecs_to_jiffies(5000)
@@ -984,6 +985,9 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan);
 int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data);
+void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+		     void *data);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
net/bluetooth/l2cap_core.c +126 -10

173 lines not on this page · raw message

Signature · 1 line
2.21.1
maintainer
#4 lore raw

Re: [PATCH v5 2/3] Bluetooth: L2CAP: Use DEFER_SETUP to group ECRED connections

Hi Luiz,

Quoted 191 lines

This uses the DEFER_SETUP flag to group channels with L2CAP_CREDIT_BASED_CONNECTION_REQ.

---
include/net/bluetooth/l2cap.h | 4 +
net/bluetooth/l2cap_core.c | 136 +++++++++++++++++++++++++++++++---

2 files changed, 130 insertions(+), 10 deletions(-)
include/net/bluetooth/l2cap.h +4 -0
index 2d7d28474d34..dada14d0622c 100644
@@ -47,6 +47,7 @@
 #define L2CAP_DEFAULT_ACC_LAT		0xFFFFFFFF
 #define L2CAP_BREDR_MAX_PAYLOAD		1019    /* 3-DH5 packet */
 #define L2CAP_LE_MIN_MTU		23
+#define L2CAP_ECRED_CONN_SCID_MAX	5
 
 #define L2CAP_DISC_TIMEOUT		msecs_to_jiffies(100)
 #define L2CAP_DISC_REJ_TIMEOUT		msecs_to_jiffies(5000)
@@ -984,6 +985,9 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan);
 int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data);
+void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+		     void *data);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
net/bluetooth/l2cap_core.c +110 -10
index 5e6e35ab44dd..9f699d09d973 100644
@@ -678,6 +678,29 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 }
 EXPORT_SYMBOL_GPL(l2cap_chan_del);
 
+static void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+			      void *data)
+{
+	struct l2cap_chan *chan;
+
+	list_for_each_entry(chan, &conn->chan_l, list) {
+		func(chan, data);
+	}
+}
+
+void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+		     void *data)
+{
+	if (!conn)
+		return;
+
+	mutex_lock(&conn->chan_lock);
+	__l2cap_chan_list(conn, func, data);
+	mutex_unlock(&conn->chan_lock);
+}
+
+EXPORT_SYMBOL_GPL(l2cap_chan_list);
+
 static void l2cap_conn_update_id_addr(struct work_struct *work)
 {
 	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
@@ -1356,29 +1379,79 @@ static void l2cap_le_connect(struct l2cap_chan *chan)
 		       sizeof(req), &req);
 }
 
-static void l2cap_ecred_connect(struct l2cap_chan *chan)
-{
-	struct l2cap_conn *conn = chan->conn;
+struct l2cap_ecred_conn_data {
 	struct {
 		struct l2cap_ecred_conn_req req;
-		__le16 scid;
+		__le16 scid[5];
 	} __packed pdu;
+	struct l2cap_chan *chan;
+	struct pid *pid;
+	int count;
+};
+
+static void l2cap_ecred_defer_connect(struct l2cap_chan *chan, void *data)
+{
+	struct l2cap_ecred_conn_data *conn = data;
+	struct pid *pid;
+
+	if (chan == conn->chan)
+		return;
+
+	if (!test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
+		return;
+
+	pid = chan->ops->get_peer_pid(chan);
+
+	/* Only add deferred channels with the same PID/PSM */
+	if (conn->pid != pid || chan->psm != conn->chan->psm || chan->ident ||
+	    chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
+		return;
+
+	if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
+		return;
+
+	l2cap_ecred_init(chan, 0);
+
+	/* Set the same ident so we can match on the rsp */
+	chan->ident = conn->chan->ident;
+
+	/* Include all channels deferred */
+	conn->pdu.scid[conn->count] = cpu_to_le16(chan->scid);
+
+	conn->count++;
+}
+
+static void l2cap_ecred_connect(struct l2cap_chan *chan)
+{
+	struct l2cap_conn *conn = chan->conn;
+	struct l2cap_ecred_conn_data data;
+
+	if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
+		return;
 
 	if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
 		return;
 
 	l2cap_ecred_init(chan, 0);
 
-	pdu.req.psm     = chan->psm;
-	pdu.req.mtu     = cpu_to_le16(chan->imtu);
-	pdu.req.mps     = cpu_to_le16(chan->mps);
-	pdu.req.credits = cpu_to_le16(chan->rx_credits);
-	pdu.scid        = cpu_to_le16(chan->scid);
+	data.pdu.req.psm     = chan->psm;
+	data.pdu.req.mtu     = cpu_to_le16(chan->imtu);
+	data.pdu.req.mps     = cpu_to_le16(chan->mps);
+	data.pdu.req.credits = cpu_to_le16(chan->rx_credits);
+	data.pdu.scid[0]     = cpu_to_le16(chan->scid);
 
 	chan->ident = l2cap_get_ident(conn);
+	data.pid = chan->ops->get_peer_pid(chan);
+
+	data.count = 1;
+	data.chan = chan;
+	data.pid = chan->ops->get_peer_pid(chan);
+
+	__l2cap_chan_list(conn, l2cap_ecred_defer_connect, &data);
 
 	l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_CONN_REQ,
-		       sizeof(pdu), &pdu);
+		       sizeof(data.pdu.req) + data.count * sizeof(__le16),
+		       &data.pdu);
 }
 
 static void l2cap_le_start(struct l2cap_chan *chan)
@@ -7694,6 +7767,33 @@ static bool is_valid_psm(u16 psm, u8 dst_type) {
 	return ((psm & 0x0101) == 0x0001);
 }
 
+struct l2cap_chan_data {
+	struct l2cap_chan *chan;
+	struct pid *pid;
+	int count;
+};
+
+static void l2cap_chan_by_pid(struct l2cap_chan *chan, void *data)
+{
+	struct l2cap_chan_data *d = data;
+	struct pid *pid;
+
+	if (chan == d->chan)
+		return;
+
+	if (!test_bit(FLAG_DEFER_SETUP, &chan->flags))
+		return;
+
+	pid = chan->ops->get_peer_pid(chan);
+
+	/* Only count deferred channels with the same PID/PSM */
+	if (d->pid != pid || chan->psm != d->chan->psm || chan->ident ||
+	    chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
+		return;
+
+	d->count++;
+}
+
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		       bdaddr_t *dst, u8 dst_type)
 {
@@ -7813,6 +7913,22 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		goto done;

net/bluetooth/l2cap_core.c int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, · line 7923

Quoted 10 lines
net/bluetooth/l2cap_core.c +8 -0
 	}
 
+	if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
+		struct l2cap_chan_data data;
+
+		data.chan = chan;
+		data.pid = chan->ops->get_peer_pid(chan);
+		data.count = 0;
+
+		l2cap_chan_list(conn, l2cap_chan_by_pid, &data);

Put an empty line after this. It gives emphasis to the comment.

net/bluetooth/l2cap_core.c int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, · line 7925

Quoted 2 lines
net/bluetooth/l2cap_core.c +2 -0
+		/* Check if there isn't too many channels being connected */
+		if (!(data.count < L2CAP_ECRED_CONN_SCID_MAX - 1)) {

If (data.count > L2CAP_ECRED_CONN_SCID_MIX) ???

net/bluetooth/l2cap_core.c int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, · line 7933

Quoted 8 lines
net/bluetooth/l2cap_core.c +6 -0
+			hci_conn_drop(hcon);
+			err = -EPROTO;
+			goto done;
+		}
+	}
+
 	mutex_lock(&conn->chan_lock);
 	l2cap_chan_lock(chan);

Regards

Marcel

author maintainer
#5 lore raw

Re: [PATCH v5 2/3] Bluetooth: L2CAP: Use DEFER_SETUP to group ECRED connections

Hi Marcel,

Quoted 207 lines · Marcel Holtmann

Hi Luiz,

Quoted 191 lines

This uses the DEFER_SETUP flag to group channels with L2CAP_CREDIT_BASED_CONNECTION_REQ.

---
include/net/bluetooth/l2cap.h | 4 +
net/bluetooth/l2cap_core.c | 136 +++++++++++++++++++++++++++++++---

2 files changed, 130 insertions(+), 10 deletions(-)
include/net/bluetooth/l2cap.h +4 -0
index 2d7d28474d34..dada14d0622c 100644
@@ -47,6 +47,7 @@
 #define L2CAP_DEFAULT_ACC_LAT         0xFFFFFFFF
 #define L2CAP_BREDR_MAX_PAYLOAD               1019    /* 3-DH5 packet */
 #define L2CAP_LE_MIN_MTU              23
+#define L2CAP_ECRED_CONN_SCID_MAX    5
 
 #define L2CAP_DISC_TIMEOUT            msecs_to_jiffies(100)
 #define L2CAP_DISC_REJ_TIMEOUT                msecs_to_jiffies(5000)
@@ -984,6 +985,9 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan);
 int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data);
+void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+                  void *data);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
net/bluetooth/l2cap_core.c +110 -10
index 5e6e35ab44dd..9f699d09d973 100644
@@ -678,6 +678,29 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 }
 EXPORT_SYMBOL_GPL(l2cap_chan_del);
 
+static void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+                           void *data)
+{
+     struct l2cap_chan *chan;
+
+     list_for_each_entry(chan, &conn->chan_l, list) {
+             func(chan, data);
+     }
+}
+
+void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
+                  void *data)
+{
+     if (!conn)
+             return;
+
+     mutex_lock(&conn->chan_lock);
+     __l2cap_chan_list(conn, func, data);
+     mutex_unlock(&conn->chan_lock);
+}
+
+EXPORT_SYMBOL_GPL(l2cap_chan_list);
+
 static void l2cap_conn_update_id_addr(struct work_struct *work)
 {
      struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
@@ -1356,29 +1379,79 @@ static void l2cap_le_connect(struct l2cap_chan *chan)
                     sizeof(req), &req);
 }
 
-static void l2cap_ecred_connect(struct l2cap_chan *chan)
-{
-     struct l2cap_conn *conn = chan->conn;
+struct l2cap_ecred_conn_data {
      struct {
              struct l2cap_ecred_conn_req req;
-             __le16 scid;
+             __le16 scid[5];
      } __packed pdu;
+     struct l2cap_chan *chan;
+     struct pid *pid;
+     int count;
+};
+
+static void l2cap_ecred_defer_connect(struct l2cap_chan *chan, void *data)
+{
+     struct l2cap_ecred_conn_data *conn = data;
+     struct pid *pid;
+
+     if (chan == conn->chan)
+             return;
+
+     if (!test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
+             return;
+
+     pid = chan->ops->get_peer_pid(chan);
+
+     /* Only add deferred channels with the same PID/PSM */
+     if (conn->pid != pid || chan->psm != conn->chan->psm || chan->ident ||
+         chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
+             return;
+
+     if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
+             return;
+
+     l2cap_ecred_init(chan, 0);
+
+     /* Set the same ident so we can match on the rsp */
+     chan->ident = conn->chan->ident;
+
+     /* Include all channels deferred */
+     conn->pdu.scid[conn->count] = cpu_to_le16(chan->scid);
+
+     conn->count++;
+}
+
+static void l2cap_ecred_connect(struct l2cap_chan *chan)
+{
+     struct l2cap_conn *conn = chan->conn;
+     struct l2cap_ecred_conn_data data;
+
+     if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
+             return;
 
      if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
              return;
 
      l2cap_ecred_init(chan, 0);
 
-     pdu.req.psm     = chan->psm;
-     pdu.req.mtu     = cpu_to_le16(chan->imtu);
-     pdu.req.mps     = cpu_to_le16(chan->mps);
-     pdu.req.credits = cpu_to_le16(chan->rx_credits);
-     pdu.scid        = cpu_to_le16(chan->scid);
+     data.pdu.req.psm     = chan->psm;
+     data.pdu.req.mtu     = cpu_to_le16(chan->imtu);
+     data.pdu.req.mps     = cpu_to_le16(chan->mps);
+     data.pdu.req.credits = cpu_to_le16(chan->rx_credits);
+     data.pdu.scid[0]     = cpu_to_le16(chan->scid);
 
      chan->ident = l2cap_get_ident(conn);
+     data.pid = chan->ops->get_peer_pid(chan);
+
+     data.count = 1;
+     data.chan = chan;
+     data.pid = chan->ops->get_peer_pid(chan);
+
+     __l2cap_chan_list(conn, l2cap_ecred_defer_connect, &data);
 
      l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_CONN_REQ,
-                    sizeof(pdu), &pdu);
+                    sizeof(data.pdu.req) + data.count * sizeof(__le16),
+                    &data.pdu);
 }
 
 static void l2cap_le_start(struct l2cap_chan *chan)
@@ -7694,6 +7767,33 @@ static bool is_valid_psm(u16 psm, u8 dst_type) {
      return ((psm & 0x0101) == 0x0001);
 }
 
+struct l2cap_chan_data {
+     struct l2cap_chan *chan;
+     struct pid *pid;
+     int count;
+};
+
+static void l2cap_chan_by_pid(struct l2cap_chan *chan, void *data)
+{
+     struct l2cap_chan_data *d = data;
+     struct pid *pid;
+
+     if (chan == d->chan)
+             return;
+
+     if (!test_bit(FLAG_DEFER_SETUP, &chan->flags))
+             return;
+
+     pid = chan->ops->get_peer_pid(chan);
+
+     /* Only count deferred channels with the same PID/PSM */
+     if (d->pid != pid || chan->psm != d->chan->psm || chan->ident ||
+         chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
+             return;
+
+     d->count++;
+}
+
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                     bdaddr_t *dst, u8 dst_type)
 {
@@ -7813,6 +7913,22 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
              goto done;

net/bluetooth/l2cap_core.c int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, · line 7923

Quoted 10 lines
net/bluetooth/l2cap_core.c +8 -0
      }
 
+     if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
+             struct l2cap_chan_data data;
+
+             data.chan = chan;
+             data.pid = chan->ops->get_peer_pid(chan);
+             data.count = 0;
+
+             l2cap_chan_list(conn, l2cap_chan_by_pid, &data);

Put an empty line after this. It gives emphasis to the comment.

Quoted 4 lines

net/bluetooth/l2cap_core.c int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, · line 7925

Quoted 2 lines
net/bluetooth/l2cap_core.c +2 -0
+             /* Check if there isn't too many channels being connected */
+             if (!(data.count < L2CAP_ECRED_CONN_SCID_MAX - 1)) {

If (data.count > L2CAP_ECRED_CONN_SCID_MIX) ???

We need to take into account the chan itself is not part of the list yet, so that means data.count + 1 or we initialize the it as 1 a couple lines before, I will change the logic to use > operation.

Quoted 13 lines

net/bluetooth/l2cap_core.c int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, · line 7933

Quoted 8 lines
net/bluetooth/l2cap_core.c +6 -0
+                     hci_conn_drop(hcon);
+                     err = -EPROTO;
+                     goto done;
+             }
+     }
+
      mutex_lock(&conn->chan_lock);
      l2cap_chan_lock(chan);

Regards

Marcel

Signature · 1 line
Luiz Augusto von Dentz
author maintainer
#6 lore raw

PATCH v5 3/3 Bluetooth: Add BT_MODE socket option

In reply to Luiz Augusto von Dentz

From: Luiz Augusto von Dentz <[email protected]>

This adds BT_MODE socket option which can be used to set L2CAP modes, including modes only supported over LE which were not supported using the L2CAP_OPTIONS.

---
 include/net/bluetooth/bluetooth.h |   8 ++
 include/net/bluetooth/l2cap.h     |   6 ++
 net/bluetooth/l2cap_sock.c        | 124 ++++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+)
include/net/bluetooth/bluetooth.h +8 -0
index 1576353a2773..3fa7b1e3c5d9 100644
@@ -139,6 +139,14 @@ struct bt_voice {
 #define BT_PHY_LE_CODED_TX	0x00002000
 #define BT_PHY_LE_CODED_RX	0x00004000
 
+#define BT_MODE			15
+
+#define BT_MODE_BASIC		0x00
+#define BT_MODE_ERTM		0x01
+#define BT_MODE_STREAMING	0x02
+#define BT_MODE_LE_FLOWCTL	0x03
+#define BT_MODE_EXT_FLOWCTL	0x04
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
include/net/bluetooth/l2cap.h +6 -0
index dada14d0622c..56f727ba23bd 100644
@@ -720,9 +720,15 @@ struct l2cap_user {
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
+#define L2CAP_PI_OPTION_UNSET		0x00
+#define L2CAP_PI_OPTION_LEGACY		0x01
+#define L2CAP_PI_OPTION_BT_MODE		0x02
+
 struct l2cap_pinfo {
 	struct bt_sock		bt;
 	struct l2cap_chan	*chan;
+	u8			option;
+	u8			bt_mode;
 	struct sk_buff		*rx_busy_skb;
 };
 
net/bluetooth/l2cap_sock.c +124 -0

160 lines not on this page · raw message

Signature · 1 line
2.21.1
maintainer
#7 lore raw

Re: [PATCH v5 3/3] Bluetooth: Add BT_MODE socket option

Hi Luiz,

Quoted 39 lines

This adds BT_MODE socket option which can be used to set L2CAP modes, including modes only supported over LE which were not supported using the L2CAP_OPTIONS.

---

include/net/bluetooth/bluetooth.h |   8 ++
include/net/bluetooth/l2cap.h     |   6 ++
net/bluetooth/l2cap_sock.c        | 124 ++++++++++++++++++++++++++++++
3 files changed, 138 insertions(+)
include/net/bluetooth/bluetooth.h +8 -0
index 1576353a2773..3fa7b1e3c5d9 100644
@@ -139,6 +139,14 @@ struct bt_voice {
 #define BT_PHY_LE_CODED_TX	0x00002000
 #define BT_PHY_LE_CODED_RX	0x00004000
 
+#define BT_MODE			15
+
+#define BT_MODE_BASIC		0x00
+#define BT_MODE_ERTM		0x01
+#define BT_MODE_STREAMING	0x02
+#define BT_MODE_LE_FLOWCTL	0x03
+#define BT_MODE_EXT_FLOWCTL	0x04
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
include/net/bluetooth/l2cap.h +1 -0
index dada14d0622c..56f727ba23bd 100644
@@ -720,9 +720,15 @@ struct l2cap_user {
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
+#define L2CAP_PI_OPTION_UNSET		0x00

include/net/bluetooth/l2cap.h struct l2cap_user { · line 733

Quoted 10 lines
include/net/bluetooth/l2cap.h +5 -0
+#define L2CAP_PI_OPTION_LEGACY		0x01
+#define L2CAP_PI_OPTION_BT_MODE		0x02
+
 struct l2cap_pinfo {
 	struct bt_sock		bt;
 	struct l2cap_chan	*chan;
+	u8			option;
+	u8			bt_mode;
 	struct sk_buff		*rx_busy_skb;
 };

why do you want to store bt_mode here. Whatever we have in l2cap_chan should be plenty.

I also looked at l2cap_sock_setsockopt_old and if you use L2CAP_OPTIONS and want to read BT_MODE, then everything should be fine. Same as setting BT_MODE (except EXT_FLOWCTL) and then reading L2CAP_OPTIONS is fine as well. We can all translate this properly and with have EINVAL return errors for not supported / disabled modes.

So the only time L2CAP_OPTIONS read should fail is if you use BT_MODE with EXT_FLOWCTL as mode. So you can just check the mode set in l2cap_chan. And we start using our new mode definition there and then convert it for L2CAP_OPTIONS.

Regards

Marcel

author maintainer
#8 lore raw

Re: [PATCH v5 3/3] Bluetooth: Add BT_MODE socket option

Hi Marcel,

Quoted 41 lines · Marcel Holtmann

Hi Luiz,

Quoted 38 lines

This adds BT_MODE socket option which can be used to set L2CAP modes, including modes only supported over LE which were not supported using the L2CAP_OPTIONS.

---

include/net/bluetooth/bluetooth.h |   8 ++
include/net/bluetooth/l2cap.h     |   6 ++
net/bluetooth/l2cap_sock.c        | 124 ++++++++++++++++++++++++++++++
3 files changed, 138 insertions(+)
include/net/bluetooth/bluetooth.h +8 -0
index 1576353a2773..3fa7b1e3c5d9 100644
@@ -139,6 +139,14 @@ struct bt_voice {
 #define BT_PHY_LE_CODED_TX    0x00002000
 #define BT_PHY_LE_CODED_RX    0x00004000
 
+#define BT_MODE                      15
+
+#define BT_MODE_BASIC                0x00
+#define BT_MODE_ERTM         0x01
+#define BT_MODE_STREAMING    0x02
+#define BT_MODE_LE_FLOWCTL   0x03
+#define BT_MODE_EXT_FLOWCTL  0x04
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
include/net/bluetooth/l2cap.h +0 -0
index dada14d0622c..56f727ba23bd 100644
@@ -720,9 +720,15 @@ struct l2cap_user {
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
Quoted 13 lines

include/net/bluetooth/l2cap.h struct l2cap_user { · line 733

Quoted 11 lines
include/net/bluetooth/l2cap.h +6 -0
+#define L2CAP_PI_OPTION_UNSET                0x00
+#define L2CAP_PI_OPTION_LEGACY               0x01
+#define L2CAP_PI_OPTION_BT_MODE              0x02
+
 struct l2cap_pinfo {
      struct bt_sock          bt;
      struct l2cap_chan       *chan;
+     u8                      option;
+     u8                      bt_mode;
      struct sk_buff          *rx_busy_skb;
 };

why do you want to store bt_mode here. Whatever we have in l2cap_chan should be plenty.

Ive thought it would be cleaner to mess with types that comes from the spec itself so l2cap_chan would continue to use them.

Quoted 3 lines

I also looked at l2cap_sock_setsockopt_old and if you use L2CAP_OPTIONS and want to read BT_MODE, then everything should be fine. Same as setting BT_MODE (except EXT_FLOWCTL) and then reading L2CAP_OPTIONS is fine as well. We can all translate this properly and with have EINVAL return errors for not supported / disabled modes.

So the only time L2CAP_OPTIONS read should fail is if you use BT_MODE with EXT_FLOWCTL as mode. So you can just check the mode set in l2cap_chan. And we start using our new mode definition there and then convert it for L2CAP_OPTIONS.

Sure, I thought it would be more efficient to not have conversions back and forth but Im fine either way.

Quoted 4 lines

Regards

Marcel

Signature · 1 line
Luiz Augusto von Dentz
maintainer
#9 lore raw

Re: [PATCH v5 3/3] Bluetooth: Add BT_MODE socket option

Hi Luiz,

Quoted 52 lines
Quoted 38 lines
Quoted 38 lines

This adds BT_MODE socket option which can be used to set L2CAP modes, including modes only supported over LE which were not supported using the L2CAP_OPTIONS.

---

include/net/bluetooth/bluetooth.h |   8 ++
include/net/bluetooth/l2cap.h     |   6 ++
net/bluetooth/l2cap_sock.c        | 124 ++++++++++++++++++++++++++++++
3 files changed, 138 insertions(+)
include/net/bluetooth/bluetooth.h +8 -0
index 1576353a2773..3fa7b1e3c5d9 100644
@@ -139,6 +139,14 @@ struct bt_voice {
 #define BT_PHY_LE_CODED_TX    0x00002000
 #define BT_PHY_LE_CODED_RX    0x00004000
 
+#define BT_MODE                      15
+
+#define BT_MODE_BASIC                0x00
+#define BT_MODE_ERTM         0x01
+#define BT_MODE_STREAMING    0x02
+#define BT_MODE_LE_FLOWCTL   0x03
+#define BT_MODE_EXT_FLOWCTL  0x04
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
include/net/bluetooth/l2cap.h +0 -0
index dada14d0622c..56f727ba23bd 100644
@@ -720,9 +720,15 @@ struct l2cap_user {
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
Quoted 13 lines

include/net/bluetooth/l2cap.h struct l2cap_user { · line 733

Quoted 11 lines
include/net/bluetooth/l2cap.h +6 -0
+#define L2CAP_PI_OPTION_UNSET                0x00
+#define L2CAP_PI_OPTION_LEGACY               0x01
+#define L2CAP_PI_OPTION_BT_MODE              0x02
+
 struct l2cap_pinfo {
     struct bt_sock          bt;
     struct l2cap_chan       *chan;
+     u8                      option;
+     u8                      bt_mode;
     struct sk_buff          *rx_busy_skb;
 };

why do you want to store bt_mode here. Whatever we have in l2cap_chan should be plenty.

Quoted 2 lines

Ive thought it would be cleaner to mess with types that comes from the spec itself so l2cap_chan would continue to use them.

Actually the LE_FLOWCTL and EXT_FLOWCTL are not spec values either. Frankly I don’t care which ones we store right now. I am fine keeping the spec one for now and just translate it to BT_MODE.

Quoted 6 lines
Quoted 3 lines

I also looked at l2cap_sock_setsockopt_old and if you use L2CAP_OPTIONS and want to read BT_MODE, then everything should be fine. Same as setting BT_MODE (except EXT_FLOWCTL) and then reading L2CAP_OPTIONS is fine as well. We can all translate this properly and with have EINVAL return errors for not supported / disabled modes.

So the only time L2CAP_OPTIONS read should fail is if you use BT_MODE with EXT_FLOWCTL as mode. So you can just check the mode set in l2cap_chan. And we start using our new mode definition there and then convert it for L2CAP_OPTIONS.

Sure, I thought it would be more efficient to not have conversions back and forth but Im fine either way.

In the end it makes the code simpler to just do the conversion. And once we add a kernel option to disable setsockopt_old, we have less code.

Regards

Marcel