[PATCH v1] net: bluetooth: add callback to exe l2cap when read_security uncompleted

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When the DUT receives a remote L2CAP Connection Request during the Read
Encryption Key Size procedure, if it fails to complete reading the
Encryption Key Size while processing the request, it will respond with
a Connection Response – Refused (security block), resulting in the
disconnection of the remote device.

Use HCI_CONN_ENC_KEY_READY to determine whether
l2cap_connect_request is pending.

When l2cap_connect occurs before the read_enc_key_size event, it will
be pending because HCI_CONN_ENC_KEY_READY has not yet been set.
The connection request will be processed once the read_enc_key_size
event completes.

Signed-off-by: Shuai Zhang <quic_shuaz@xxxxxxxxxxx>
---
 include/net/bluetooth/hci_core.h |  3 +++
 include/net/bluetooth/l2cap.h    | 10 +++++++++-
 net/bluetooth/hci_event.c        | 16 ++++++++++++++++
 net/bluetooth/l2cap_core.c       | 30 ++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b47c74080..db329abbf 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -767,6 +767,8 @@ struct hci_conn {
 
 	struct bt_codec codec;
 
+	struct l2cap_pending_connect *pending_connect;
+
 	void (*connect_cfm_cb)	(struct hci_conn *conn, u8 status);
 	void (*security_cfm_cb)	(struct hci_conn *conn, u8 status);
 	void (*disconn_cfm_cb)	(struct hci_conn *conn, u8 reason);
@@ -970,6 +972,7 @@ enum {
 	HCI_CONN_CREATE_PA_SYNC,
 	HCI_CONN_PA_SYNC,
 	HCI_CONN_PA_SYNC_FAILED,
+	HCI_CONN_ENC_KEY_READY,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 4bb0eaedd..b1ccd56bd 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -679,6 +679,13 @@ struct l2cap_user {
 	void (*remove) (struct l2cap_conn *conn, struct l2cap_user *user);
 };
 
+struct l2cap_pending_connect {
+	struct l2cap_conn *conn;
+	struct l2cap_cmd_hdr cmd;
+	u8 data[sizeof(struct l2cap_conn_req)];
+	u8 rsp_code;
+};
+
 #define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
 #define L2CAP_INFO_FEAT_MASK_REQ_SENT	0x04
 #define L2CAP_INFO_FEAT_MASK_REQ_DONE	0x08
@@ -976,5 +983,6 @@ void l2cap_conn_put(struct l2cap_conn *conn);
 
 int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
 void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
-
+void l2cap_process_pending_connect(struct l2cap_conn *conn,
+				   struct l2cap_cmd_hdr *cmd, u8 *data, u8 rsp_code);
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c4b87bfb4..6c992f83e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -32,6 +32,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/mgmt.h>
+#include <net/bluetooth/l2cap.h>
 
 #include "hci_debugfs.h"
 #include "hci_codec.h"
@@ -766,10 +767,23 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
 		/* Update the key encryption size with the connection one */
 		if (key_enc_size && *key_enc_size != conn->enc_key_size)
 			*key_enc_size = conn->enc_key_size;
+		set_bit(HCI_CONN_ENC_KEY_READY, &conn->flags);
 	}
 
 	hci_encrypt_cfm(conn, status);
 
+	/*Defer l2cap_connect here if it's triggered before key size is read.*/
+	if (conn->pending_connect) {
+		struct l2cap_pending_connect *pc = conn->pending_connect;
+
+		conn->pending_connect = NULL;
+
+		bt_dev_dbg(hdev, "Defer l2cap_connect");
+		l2cap_process_pending_connect(pc->conn, &pc->cmd, pc->data, pc->rsp_code);
+
+		kfree(pc);
+	}
+
 done:
 	hci_dev_unlock(hdev);
 
@@ -3396,6 +3410,8 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
 	if (!conn)
 		goto unlock;
 
+	clear_bit(HCI_CONN_ENC_KEY_READY, &conn->flags);
+
 	if (ev->status) {
 		mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
 				       conn->dst_type, ev->status);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 40daa3827..c4cb60e65 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3982,6 +3982,30 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
 	struct l2cap_chan *chan = NULL, *pchan = NULL;
 	int result, status = L2CAP_CS_NO_INFO;
 
+	/* If encryption is requested, but the key size is not ready yet,
+	 * we need to wait for the key size to be ready before we can
+	 * proceed with the connection. We do this by deferring the
+	 * connection request until the key size is ready. This is done
+	 * by storing the connection request in the hcon->pending_connect
+	 * field. The connection request will be retried when the key size
+	 * is ready.
+	 */
+	if (test_bit(HCI_CONN_ENCRYPT, &conn->hcon->flags) &&
+	    !test_bit(HCI_CONN_ENC_KEY_READY, &conn->hcon->flags)) {
+		struct l2cap_pending_connect *pc;
+
+		pc = kzalloc(sizeof(*pc), GFP_KERNEL);
+		if (!pc)
+			return;
+		pc->conn = conn;
+		memcpy(&pc->cmd, cmd, sizeof(*cmd));
+		memcpy(pc->data, data, sizeof(struct l2cap_conn_req));
+		pc->rsp_code = rsp_code;
+		BT_DBG("store request and retried when keysize is ready");
+		conn->hcon->pending_connect = pc;
+		return;
+	}
+
 	u16 dcid = 0, scid = __le16_to_cpu(req->scid);
 	__le16 psm = req->psm;
 
@@ -4105,6 +4129,12 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
 	l2cap_chan_put(pchan);
 }
 
+void l2cap_process_pending_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
+				   u8 *data, u8 rsp_code)
+{
+	l2cap_connect(conn, cmd, data, rsp_code);
+}
+
 static int l2cap_connect_req(struct l2cap_conn *conn,
 			     struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
 {
-- 
2.34.1





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux