Re: [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]

 



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





[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