mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Bluetooth: L2CAP: Fix invalid response to L2CAP_ECRED_RECONF_REQ
This fixes responding with an invalid result caused by checking the
wrong size of CID which should have been (cmd_len - sizeof(*req)) and
on top of it the wrong result was use L2CAP_CR_LE_INVALID_PARAMS which
is invalid/reserved for reconf when running test like L2CAP/ECFC/BI-03-C:
> ACL Data RX: Handle 64 flags 0x02 dlen 14
LE L2CAP: Enhanced Credit Reconfigure Request (0x19) ident 2 len 6
MTU: 64
MPS: 64
Source CID: 64
< ACL Data TX: Handle 64 flags 0x00 dlen 10
LE L2CAP: Enhanced Credit Reconfigure Respond (0x1a) ident 2 len 2
! Result: Reserved (0x000c)
Result: Reconfiguration failed - one or more Destination CIDs invalid (0x0003)
Fiix L2CAP/ECFC/BI-04-C which expects L2CAP_RECONF_INVALID_MPS (0x0002)
when more than one channel gets its MPS reduced:
> ACL Data RX: Handle 64 flags 0x02 dlen 16
LE L2CAP: Enhanced Credit Reconfigure Request (0x19) ident 2 len 8
MTU: 264
MPS: 99
Source CID: 64
! Source CID: 65
< ACL Data TX: Handle 64 flags 0x00 dlen 10
LE L2CAP: Enhanced Credit Reconfigure Respond (0x1a) ident 2 len 2
! Result: Reconfiguration successful (0x0000)
Result: Reconfiguration failed - reduction in size of MPS not allowed for more than one channel at a time (0x0002)
Fix L2CAP/ECFC/BI-05-C when SCID is invalid (85 unconnected):
> ACL Data RX: Handle 64 flags 0x02 dlen 14
LE L2CAP: Enhanced Credit Reconfigure Request (0x19) ident 2 len 6
MTU: 65
MPS: 64
! Source CID: 85
< ACL Data TX: Handle 64 flags 0x00 dlen 10
LE L2CAP: Enhanced Credit Reconfigure Respond (0x1a) ident 2 len 2
! Result: Reconfiguration successful (0x0000)
Result: Reconfiguration failed - one or more Destination CIDs invalid (0x0003)
Fix L2CAP/ECFC/BI-06-C when MPS < L2CAP_ECRED_MIN_MPS (64):
> ACL Data RX: Handle 64 flags 0x02 dlen 14
LE L2CAP: Enhanced Credit Reconfigure Request (0x19) ident 2 len 6
MTU: 672
! MPS: 63
Source CID: 64
< ACL Data TX: Handle 64 flags 0x00 dlen 10
LE L2CAP: Enhanced Credit Reconfigure Respond (0x1a) ident 2 len 2
! Result: Reconfiguration failed - reduction in size of MPS not allowed for more than one channel at a time (0x0002)
Result: Reconfiguration failed - other unacceptable parameters (0x0004)
Fix L2CAP/ECFC/BI-07-C when MPS reduced for more than one channel:
> ACL Data RX: Handle 64 flags 0x02 dlen 16
LE L2CAP: Enhanced Credit Reconfigure Request (0x19) ident 3 len 8
MTU: 84
! MPS: 71
Source CID: 64
! Source CID: 65
< ACL Data TX: Handle 64 flags 0x00 dlen 10
LE L2CAP: Enhanced Credit Reconfigure Respond (0x1a) ident 2 len 2
! Result: Reconfiguration successful (0x0000)
Result: Reconfiguration failed - reduction in size of MPS not allowed for more than one channel at a time (0x0002)
Link: https://github.com/bluez/bluez/issues/1865
Fixes: 15f02b9105 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
d4f687fbbc
commit
7accb1c432
|
|
@ -493,6 +493,8 @@ struct l2cap_ecred_reconf_req {
|
|||
#define L2CAP_RECONF_SUCCESS 0x0000
|
||||
#define L2CAP_RECONF_INVALID_MTU 0x0001
|
||||
#define L2CAP_RECONF_INVALID_MPS 0x0002
|
||||
#define L2CAP_RECONF_INVALID_CID 0x0003
|
||||
#define L2CAP_RECONF_INVALID_PARAMS 0x0004
|
||||
|
||||
struct l2cap_ecred_reconf_rsp {
|
||||
__le16 result;
|
||||
|
|
|
|||
|
|
@ -5310,14 +5310,14 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
|
|||
struct l2cap_ecred_reconf_req *req = (void *) data;
|
||||
struct l2cap_ecred_reconf_rsp rsp;
|
||||
u16 mtu, mps, result;
|
||||
struct l2cap_chan *chan;
|
||||
struct l2cap_chan *chan[L2CAP_ECRED_MAX_CID] = {};
|
||||
int i, num_scid;
|
||||
|
||||
if (!enable_ecred)
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd_len < sizeof(*req) || cmd_len - sizeof(*req) % sizeof(u16)) {
|
||||
result = L2CAP_CR_LE_INVALID_PARAMS;
|
||||
if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) {
|
||||
result = L2CAP_RECONF_INVALID_CID;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
|
|
@ -5327,42 +5327,69 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
|
|||
BT_DBG("mtu %u mps %u", mtu, mps);
|
||||
|
||||
if (mtu < L2CAP_ECRED_MIN_MTU) {
|
||||
result = L2CAP_RECONF_INVALID_MTU;
|
||||
result = L2CAP_RECONF_INVALID_PARAMS;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if (mps < L2CAP_ECRED_MIN_MPS) {
|
||||
result = L2CAP_RECONF_INVALID_MPS;
|
||||
result = L2CAP_RECONF_INVALID_PARAMS;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
cmd_len -= sizeof(*req);
|
||||
num_scid = cmd_len / sizeof(u16);
|
||||
|
||||
if (num_scid > L2CAP_ECRED_MAX_CID) {
|
||||
result = L2CAP_RECONF_INVALID_PARAMS;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
result = L2CAP_RECONF_SUCCESS;
|
||||
|
||||
/* Check if each SCID, MTU and MPS are valid */
|
||||
for (i = 0; i < num_scid; i++) {
|
||||
u16 scid;
|
||||
|
||||
scid = __le16_to_cpu(req->scid[i]);
|
||||
if (!scid)
|
||||
return -EPROTO;
|
||||
|
||||
chan = __l2cap_get_chan_by_dcid(conn, scid);
|
||||
if (!chan)
|
||||
continue;
|
||||
|
||||
/* If the MTU value is decreased for any of the included
|
||||
* channels, then the receiver shall disconnect all
|
||||
* included channels.
|
||||
*/
|
||||
if (chan->omtu > mtu) {
|
||||
BT_ERR("chan %p decreased MTU %u -> %u", chan,
|
||||
chan->omtu, mtu);
|
||||
result = L2CAP_RECONF_INVALID_MTU;
|
||||
if (!scid) {
|
||||
result = L2CAP_RECONF_INVALID_CID;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
chan->omtu = mtu;
|
||||
chan->remote_mps = mps;
|
||||
chan[i] = __l2cap_get_chan_by_dcid(conn, scid);
|
||||
if (!chan[i]) {
|
||||
result = L2CAP_RECONF_INVALID_CID;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
/* The MTU field shall be greater than or equal to the greatest
|
||||
* current MTU size of these channels.
|
||||
*/
|
||||
if (chan[i]->omtu > mtu) {
|
||||
BT_ERR("chan %p decreased MTU %u -> %u", chan[i],
|
||||
chan[i]->omtu, mtu);
|
||||
result = L2CAP_RECONF_INVALID_MTU;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
/* If more than one channel is being configured, the MPS field
|
||||
* shall be greater than or equal to the current MPS size of
|
||||
* each of these channels. If only one channel is being
|
||||
* configured, the MPS field may be less than the current MPS
|
||||
* of that channel.
|
||||
*/
|
||||
if (chan[i]->remote_mps >= mps && i) {
|
||||
BT_ERR("chan %p decreased MPS %u -> %u", chan[i],
|
||||
chan[i]->remote_mps, mps);
|
||||
result = L2CAP_RECONF_INVALID_MPS;
|
||||
goto respond;
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit the new MTU and MPS values after checking they are valid */
|
||||
for (i = 0; i < num_scid; i++) {
|
||||
chan[i]->omtu = mtu;
|
||||
chan[i]->remote_mps = mps;
|
||||
}
|
||||
|
||||
respond:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user