Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

+51 -22
+2
include/net/bluetooth/l2cap.h
··· 493 493 #define L2CAP_RECONF_SUCCESS 0x0000 494 494 #define L2CAP_RECONF_INVALID_MTU 0x0001 495 495 #define L2CAP_RECONF_INVALID_MPS 0x0002 496 + #define L2CAP_RECONF_INVALID_CID 0x0003 497 + #define L2CAP_RECONF_INVALID_PARAMS 0x0004 496 498 497 499 struct l2cap_ecred_reconf_rsp { 498 500 __le16 result;
+49 -22
net/bluetooth/l2cap_core.c
··· 5310 5310 struct l2cap_ecred_reconf_req *req = (void *) data; 5311 5311 struct l2cap_ecred_reconf_rsp rsp; 5312 5312 u16 mtu, mps, result; 5313 - struct l2cap_chan *chan; 5313 + struct l2cap_chan *chan[L2CAP_ECRED_MAX_CID] = {}; 5314 5314 int i, num_scid; 5315 5315 5316 5316 if (!enable_ecred) 5317 5317 return -EINVAL; 5318 5318 5319 - if (cmd_len < sizeof(*req) || cmd_len - sizeof(*req) % sizeof(u16)) { 5320 - result = L2CAP_CR_LE_INVALID_PARAMS; 5319 + if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) { 5320 + result = L2CAP_RECONF_INVALID_CID; 5321 5321 goto respond; 5322 5322 } 5323 5323 ··· 5327 5327 BT_DBG("mtu %u mps %u", mtu, mps); 5328 5328 5329 5329 if (mtu < L2CAP_ECRED_MIN_MTU) { 5330 - result = L2CAP_RECONF_INVALID_MTU; 5330 + result = L2CAP_RECONF_INVALID_PARAMS; 5331 5331 goto respond; 5332 5332 } 5333 5333 5334 5334 if (mps < L2CAP_ECRED_MIN_MPS) { 5335 - result = L2CAP_RECONF_INVALID_MPS; 5335 + result = L2CAP_RECONF_INVALID_PARAMS; 5336 5336 goto respond; 5337 5337 } 5338 5338 5339 5339 cmd_len -= sizeof(*req); 5340 5340 num_scid = cmd_len / sizeof(u16); 5341 + 5342 + if (num_scid > L2CAP_ECRED_MAX_CID) { 5343 + result = L2CAP_RECONF_INVALID_PARAMS; 5344 + goto respond; 5345 + } 5346 + 5341 5347 result = L2CAP_RECONF_SUCCESS; 5342 5348 5349 + /* Check if each SCID, MTU and MPS are valid */ 5343 5350 for (i = 0; i < num_scid; i++) { 5344 5351 u16 scid; 5345 5352 5346 5353 scid = __le16_to_cpu(req->scid[i]); 5347 - if (!scid) 5348 - return -EPROTO; 5349 - 5350 - chan = __l2cap_get_chan_by_dcid(conn, scid); 5351 - if (!chan) 5352 - continue; 5353 - 5354 - /* If the MTU value is decreased for any of the included 5355 - * channels, then the receiver shall disconnect all 5356 - * included channels. 5357 - */ 5358 - if (chan->omtu > mtu) { 5359 - BT_ERR("chan %p decreased MTU %u -> %u", chan, 5360 - chan->omtu, mtu); 5361 - result = L2CAP_RECONF_INVALID_MTU; 5354 + if (!scid) { 5355 + result = L2CAP_RECONF_INVALID_CID; 5356 + goto respond; 5362 5357 } 5363 5358 5364 - chan->omtu = mtu; 5365 - chan->remote_mps = mps; 5359 + chan[i] = __l2cap_get_chan_by_dcid(conn, scid); 5360 + if (!chan[i]) { 5361 + result = L2CAP_RECONF_INVALID_CID; 5362 + goto respond; 5363 + } 5364 + 5365 + /* The MTU field shall be greater than or equal to the greatest 5366 + * current MTU size of these channels. 5367 + */ 5368 + if (chan[i]->omtu > mtu) { 5369 + BT_ERR("chan %p decreased MTU %u -> %u", chan[i], 5370 + chan[i]->omtu, mtu); 5371 + result = L2CAP_RECONF_INVALID_MTU; 5372 + goto respond; 5373 + } 5374 + 5375 + /* If more than one channel is being configured, the MPS field 5376 + * shall be greater than or equal to the current MPS size of 5377 + * each of these channels. If only one channel is being 5378 + * configured, the MPS field may be less than the current MPS 5379 + * of that channel. 5380 + */ 5381 + if (chan[i]->remote_mps >= mps && i) { 5382 + BT_ERR("chan %p decreased MPS %u -> %u", chan[i], 5383 + chan[i]->remote_mps, mps); 5384 + result = L2CAP_RECONF_INVALID_MPS; 5385 + goto respond; 5386 + } 5387 + } 5388 + 5389 + /* Commit the new MTU and MPS values after checking they are valid */ 5390 + for (i = 0; i < num_scid; i++) { 5391 + chan[i]->omtu = mtu; 5392 + chan[i]->remote_mps = mps; 5366 5393 } 5367 5394 5368 5395 respond: