]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: L2CAP: Fix result of L2CAP_ECRED_CONN_RSP when MTU is too short
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 5 Feb 2026 20:11:34 +0000 (15:11 -0500)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 23 Feb 2026 20:28:56 +0000 (15:28 -0500)
Test L2CAP/ECFC/BV-26-C expect the response to L2CAP_ECRED_CONN_REQ with
and MTU value < L2CAP_ECRED_MIN_MTU (64) to be L2CAP_CR_LE_INVALID_PARAMS
rather than L2CAP_CR_LE_UNACCEPT_PARAMS.

Also fix not including the correct number of CIDs in the response since
the spec requires all CIDs being rejected to be included in the
response.

Link: https://github.com/bluez/bluez/issues/1868
Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/l2cap.h
net/bluetooth/l2cap_core.c

index 6f9cf7a05986260a73462d9fff3fc17ecdef263b..010f1a8fd15f827eac649211f88e2a8c5ad3cd19 100644 (file)
@@ -284,9 +284,9 @@ struct l2cap_conn_rsp {
 #define L2CAP_CR_LE_BAD_KEY_SIZE       0x0007
 #define L2CAP_CR_LE_ENCRYPTION         0x0008
 #define L2CAP_CR_LE_INVALID_SCID       0x0009
-#define L2CAP_CR_LE_SCID_IN_USE                0X000A
-#define L2CAP_CR_LE_UNACCEPT_PARAMS    0X000B
-#define L2CAP_CR_LE_INVALID_PARAMS     0X000C
+#define L2CAP_CR_LE_SCID_IN_USE                0x000A
+#define L2CAP_CR_LE_UNACCEPT_PARAMS    0x000B
+#define L2CAP_CR_LE_INVALID_PARAMS     0x000C
 
 /* connect/create channel status */
 #define L2CAP_CS_NO_INFO       0x0000
index 81038458be0cc37173cdae5e7c197dc392bcdf58..390d25909104702e96d8861b30ddde1222f19cfe 100644 (file)
@@ -5051,13 +5051,15 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
        struct l2cap_chan *chan, *pchan;
        u16 mtu, mps;
        __le16 psm;
-       u8 result, len = 0;
+       u8 result, rsp_len = 0;
        int i, num_scid;
        bool defer = false;
 
        if (!enable_ecred)
                return -EINVAL;
 
+       memset(pdu, 0, sizeof(*pdu));
+
        if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) {
                result = L2CAP_CR_LE_INVALID_PARAMS;
                goto response;
@@ -5066,6 +5068,9 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
        cmd_len -= sizeof(*req);
        num_scid = cmd_len / sizeof(u16);
 
+       /* Always respond with the same number of scids as in the request */
+       rsp_len = cmd_len;
+
        if (num_scid > L2CAP_ECRED_MAX_CID) {
                result = L2CAP_CR_LE_INVALID_PARAMS;
                goto response;
@@ -5075,7 +5080,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
        mps  = __le16_to_cpu(req->mps);
 
        if (mtu < L2CAP_ECRED_MIN_MTU || mps < L2CAP_ECRED_MIN_MPS) {
-               result = L2CAP_CR_LE_UNACCEPT_PARAMS;
+               result = L2CAP_CR_LE_INVALID_PARAMS;
                goto response;
        }
 
@@ -5095,8 +5100,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
 
        BT_DBG("psm 0x%2.2x mtu %u mps %u", __le16_to_cpu(psm), mtu, mps);
 
-       memset(pdu, 0, sizeof(*pdu));
-
        /* Check if we have socket listening on psm */
        pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
                                         &conn->hcon->dst, LE_LINK);
@@ -5121,7 +5124,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
                BT_DBG("scid[%d] 0x%4.4x", i, scid);
 
                pdu->dcid[i] = 0x0000;
-               len += sizeof(*pdu->dcid);
 
                /* Check for valid dynamic CID range */
                if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
@@ -5188,7 +5190,7 @@ response:
                return 0;
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_ECRED_CONN_RSP,
-                      sizeof(*pdu) + len, pdu);
+                      sizeof(*pdu) + rsp_len, pdu);
 
        return 0;
 }