Commit c28d2bff authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz
Browse files

Bluetooth: L2CAP: Fix result of L2CAP_ECRED_CONN_RSP when MTU is too short

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: 15f02b91 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 7accb1c4
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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
+8 −6
Original line number Diff line number Diff line
@@ -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 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
		return 0;

	l2cap_send_cmd(conn, cmd->ident, L2CAP_ECRED_CONN_RSP,
		       sizeof(*pdu) + len, pdu);
		       sizeof(*pdu) + rsp_len, pdu);

	return 0;
}