Hi Shuai, On Thu, Jun 26, 2025 at 11:04 PM Shuai Zhang <quic_shuaz@xxxxxxxxxxx> wrote: > > 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; We have rx_queue for deferring packets, we may need to extend that to store requests to channels that require encryption. > 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. > + */ This should have been resolved by https://github.com/bluez/bluetooth-next/commit/c82b6357a5465a3222780ac5d3edcdfb02208cc3: /* If the key enc_size is already known, use it as conn->enc_key_size, * otherwise use hdev->min_enc_key_size so the likes of * l2cap_check_enc_key_size don't fail while waiting for * HCI_OP_READ_ENC_KEY_SIZE response. */ if (key_enc_size && *key_enc_size) conn->enc_key_size = *key_enc_size; else conn->enc_key_size = hdev->min_enc_key_size; This will use the hci_conn_key_enc_size, then on the command reply we do: /* Attempt to check if the key size is too small or if it has * been downgraded from the last time it was stored as part of * the link_key. */ if (conn->enc_key_size < hdev->min_enc_key_size || (key_enc_size && conn->enc_key_size < *key_enc_size)) { /* As slave role, the conn->state has been set to * BT_CONNECTED and l2cap conn req might not be received * yet, at this moment the l2cap layer almost does * nothing with the non-zero status. * So we also clear encrypt related bits, and then the * handler of l2cap conn req will get the right secure * state at a later time. */ status = HCI_ERROR_AUTH_FAILURE; clear_bit(HCI_CONN_ENCRYPT, &conn->flags); clear_bit(HCI_CONN_AES_CCM, &conn->flags); } > + 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 > > -- Luiz Augusto von Dentz