Skip to content

Commit 1348659

Browse files
author
Paolo Abeni
committed
Merge tag 'for-net-2026-02-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - purge error queues in socket destructors - hci_sync: Fix CIS host feature condition - L2CAP: Fix invalid response to L2CAP_ECRED_RECONF_REQ - L2CAP: Fix result of L2CAP_ECRED_CONN_RSP when MTU is too short - L2CAP: Fix response to L2CAP_ECRED_CONN_REQ - L2CAP: Fix not checking output MTU is acceptable on L2CAP_ECRED_CONN_REQ - L2CAP: Fix missing key size check for L2CAP_LE_CONN_REQ - hci_qca: Cleanup on all setup failures * tag 'for-net-2026-02-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: L2CAP: Fix missing key size check for L2CAP_LE_CONN_REQ Bluetooth: L2CAP: Fix not checking output MTU is acceptable on L2CAP_ECRED_CONN_REQ Bluetooth: Fix CIS host feature condition Bluetooth: L2CAP: Fix response to L2CAP_ECRED_CONN_REQ Bluetooth: hci_qca: Cleanup on all setup failures Bluetooth: purge error queues in socket destructors Bluetooth: L2CAP: Fix result of L2CAP_ECRED_CONN_RSP when MTU is too short Bluetooth: L2CAP: Fix invalid response to L2CAP_ECRED_RECONF_REQ ==================== Link: https://patch.msgid.link/20260223211634.3800315-1-luiz.dentz@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents fb73d0e + 138d7ec commit 1348659

8 files changed

Lines changed: 105 additions & 43 deletions

File tree

drivers/bluetooth/hci_qca.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,19 +2046,23 @@ static int qca_setup(struct hci_uart *hu)
20462046
}
20472047

20482048
out:
2049-
if (ret && retries < MAX_INIT_RETRIES) {
2050-
bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
2049+
if (ret) {
20512050
qca_power_shutdown(hu);
2052-
if (hu->serdev) {
2053-
serdev_device_close(hu->serdev);
2054-
ret = serdev_device_open(hu->serdev);
2055-
if (ret) {
2056-
bt_dev_err(hdev, "failed to open port");
2057-
return ret;
2051+
2052+
if (retries < MAX_INIT_RETRIES) {
2053+
bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
2054+
if (hu->serdev) {
2055+
serdev_device_close(hu->serdev);
2056+
ret = serdev_device_open(hu->serdev);
2057+
if (ret) {
2058+
bt_dev_err(hdev, "failed to open port");
2059+
return ret;
2060+
}
20582061
}
2062+
retries++;
2063+
goto retry;
20592064
}
2060-
retries++;
2061-
goto retry;
2065+
return ret;
20622066
}
20632067

20642068
/* Setup bdaddr */

include/net/bluetooth/l2cap.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,9 @@ struct l2cap_conn_rsp {
284284
#define L2CAP_CR_LE_BAD_KEY_SIZE 0x0007
285285
#define L2CAP_CR_LE_ENCRYPTION 0x0008
286286
#define L2CAP_CR_LE_INVALID_SCID 0x0009
287-
#define L2CAP_CR_LE_SCID_IN_USE 0X000A
288-
#define L2CAP_CR_LE_UNACCEPT_PARAMS 0X000B
289-
#define L2CAP_CR_LE_INVALID_PARAMS 0X000C
287+
#define L2CAP_CR_LE_SCID_IN_USE 0x000A
288+
#define L2CAP_CR_LE_UNACCEPT_PARAMS 0x000B
289+
#define L2CAP_CR_LE_INVALID_PARAMS 0x000C
290290

291291
/* connect/create channel status */
292292
#define L2CAP_CS_NO_INFO 0x0000
@@ -493,6 +493,8 @@ struct l2cap_ecred_reconf_req {
493493
#define L2CAP_RECONF_SUCCESS 0x0000
494494
#define L2CAP_RECONF_INVALID_MTU 0x0001
495495
#define L2CAP_RECONF_INVALID_MPS 0x0002
496+
#define L2CAP_RECONF_INVALID_CID 0x0003
497+
#define L2CAP_RECONF_INVALID_PARAMS 0x0004
496498

497499
struct l2cap_ecred_reconf_rsp {
498500
__le16 result;

net/bluetooth/hci_sock.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,7 @@ static void hci_sock_destruct(struct sock *sk)
21662166
mgmt_cleanup(sk);
21672167
skb_queue_purge(&sk->sk_receive_queue);
21682168
skb_queue_purge(&sk->sk_write_queue);
2169+
skb_queue_purge(&sk->sk_error_queue);
21692170
}
21702171

21712172
static const struct proto_ops hci_sock_ops = {

net/bluetooth/hci_sync.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4592,7 +4592,7 @@ static int hci_le_set_host_features_sync(struct hci_dev *hdev)
45924592
{
45934593
int err;
45944594

4595-
if (iso_capable(hdev)) {
4595+
if (cis_capable(hdev)) {
45964596
/* Connected Isochronous Channels (Host Support) */
45974597
err = hci_le_set_host_feature_sync(hdev, 32,
45984598
(iso_enabled(hdev) ? 0x01 :

net/bluetooth/iso.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ static void iso_sock_destruct(struct sock *sk)
746746

747747
skb_queue_purge(&sk->sk_receive_queue);
748748
skb_queue_purge(&sk->sk_write_queue);
749+
skb_queue_purge(&sk->sk_error_queue);
749750
}
750751

751752
static void iso_sock_cleanup_listen(struct sock *parent)

net/bluetooth/l2cap_core.c

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4916,6 +4916,13 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
49164916
goto response_unlock;
49174917
}
49184918

4919+
/* Check if Key Size is sufficient for the security level */
4920+
if (!l2cap_check_enc_key_size(conn->hcon, pchan)) {
4921+
result = L2CAP_CR_LE_BAD_KEY_SIZE;
4922+
chan = NULL;
4923+
goto response_unlock;
4924+
}
4925+
49194926
/* Check for valid dynamic CID range */
49204927
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
49214928
result = L2CAP_CR_LE_INVALID_SCID;
@@ -5051,13 +5058,15 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50515058
struct l2cap_chan *chan, *pchan;
50525059
u16 mtu, mps;
50535060
__le16 psm;
5054-
u8 result, len = 0;
5061+
u8 result, rsp_len = 0;
50555062
int i, num_scid;
50565063
bool defer = false;
50575064

50585065
if (!enable_ecred)
50595066
return -EINVAL;
50605067

5068+
memset(pdu, 0, sizeof(*pdu));
5069+
50615070
if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) {
50625071
result = L2CAP_CR_LE_INVALID_PARAMS;
50635072
goto response;
@@ -5066,6 +5075,9 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50665075
cmd_len -= sizeof(*req);
50675076
num_scid = cmd_len / sizeof(u16);
50685077

5078+
/* Always respond with the same number of scids as in the request */
5079+
rsp_len = cmd_len;
5080+
50695081
if (num_scid > L2CAP_ECRED_MAX_CID) {
50705082
result = L2CAP_CR_LE_INVALID_PARAMS;
50715083
goto response;
@@ -5075,7 +5087,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50755087
mps = __le16_to_cpu(req->mps);
50765088

50775089
if (mtu < L2CAP_ECRED_MIN_MTU || mps < L2CAP_ECRED_MIN_MPS) {
5078-
result = L2CAP_CR_LE_UNACCEPT_PARAMS;
5090+
result = L2CAP_CR_LE_INVALID_PARAMS;
50795091
goto response;
50805092
}
50815093

@@ -5095,8 +5107,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
50955107

50965108
BT_DBG("psm 0x%2.2x mtu %u mps %u", __le16_to_cpu(psm), mtu, mps);
50975109

5098-
memset(pdu, 0, sizeof(*pdu));
5099-
51005110
/* Check if we have socket listening on psm */
51015111
pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
51025112
&conn->hcon->dst, LE_LINK);
@@ -5109,7 +5119,16 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
51095119

51105120
if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
51115121
SMP_ALLOW_STK)) {
5112-
result = L2CAP_CR_LE_AUTHENTICATION;
5122+
result = pchan->sec_level == BT_SECURITY_MEDIUM ?
5123+
L2CAP_CR_LE_ENCRYPTION : L2CAP_CR_LE_AUTHENTICATION;
5124+
goto unlock;
5125+
}
5126+
5127+
/* Check if the listening channel has set an output MTU then the
5128+
* requested MTU shall be less than or equal to that value.
5129+
*/
5130+
if (pchan->omtu && mtu < pchan->omtu) {
5131+
result = L2CAP_CR_LE_UNACCEPT_PARAMS;
51135132
goto unlock;
51145133
}
51155134

@@ -5121,7 +5140,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
51215140
BT_DBG("scid[%d] 0x%4.4x", i, scid);
51225141

51235142
pdu->dcid[i] = 0x0000;
5124-
len += sizeof(*pdu->dcid);
51255143

51265144
/* Check for valid dynamic CID range */
51275145
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
@@ -5188,7 +5206,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
51885206
return 0;
51895207

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

51935211
return 0;
51945212
}
@@ -5310,14 +5328,14 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
53105328
struct l2cap_ecred_reconf_req *req = (void *) data;
53115329
struct l2cap_ecred_reconf_rsp rsp;
53125330
u16 mtu, mps, result;
5313-
struct l2cap_chan *chan;
5331+
struct l2cap_chan *chan[L2CAP_ECRED_MAX_CID] = {};
53145332
int i, num_scid;
53155333

53165334
if (!enable_ecred)
53175335
return -EINVAL;
53185336

5319-
if (cmd_len < sizeof(*req) || cmd_len - sizeof(*req) % sizeof(u16)) {
5320-
result = L2CAP_CR_LE_INVALID_PARAMS;
5337+
if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) {
5338+
result = L2CAP_RECONF_INVALID_CID;
53215339
goto respond;
53225340
}
53235341

@@ -5327,42 +5345,69 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
53275345
BT_DBG("mtu %u mps %u", mtu, mps);
53285346

53295347
if (mtu < L2CAP_ECRED_MIN_MTU) {
5330-
result = L2CAP_RECONF_INVALID_MTU;
5348+
result = L2CAP_RECONF_INVALID_PARAMS;
53315349
goto respond;
53325350
}
53335351

53345352
if (mps < L2CAP_ECRED_MIN_MPS) {
5335-
result = L2CAP_RECONF_INVALID_MPS;
5353+
result = L2CAP_RECONF_INVALID_PARAMS;
53365354
goto respond;
53375355
}
53385356

53395357
cmd_len -= sizeof(*req);
53405358
num_scid = cmd_len / sizeof(u16);
5359+
5360+
if (num_scid > L2CAP_ECRED_MAX_CID) {
5361+
result = L2CAP_RECONF_INVALID_PARAMS;
5362+
goto respond;
5363+
}
5364+
53415365
result = L2CAP_RECONF_SUCCESS;
53425366

5367+
/* Check if each SCID, MTU and MPS are valid */
53435368
for (i = 0; i < num_scid; i++) {
53445369
u16 scid;
53455370

53465371
scid = __le16_to_cpu(req->scid[i]);
5347-
if (!scid)
5348-
return -EPROTO;
5372+
if (!scid) {
5373+
result = L2CAP_RECONF_INVALID_CID;
5374+
goto respond;
5375+
}
53495376

5350-
chan = __l2cap_get_chan_by_dcid(conn, scid);
5351-
if (!chan)
5352-
continue;
5377+
chan[i] = __l2cap_get_chan_by_dcid(conn, scid);
5378+
if (!chan[i]) {
5379+
result = L2CAP_RECONF_INVALID_CID;
5380+
goto respond;
5381+
}
53535382

5354-
/* If the MTU value is decreased for any of the included
5355-
* channels, then the receiver shall disconnect all
5356-
* included channels.
5383+
/* The MTU field shall be greater than or equal to the greatest
5384+
* current MTU size of these channels.
53575385
*/
5358-
if (chan->omtu > mtu) {
5359-
BT_ERR("chan %p decreased MTU %u -> %u", chan,
5360-
chan->omtu, mtu);
5386+
if (chan[i]->omtu > mtu) {
5387+
BT_ERR("chan %p decreased MTU %u -> %u", chan[i],
5388+
chan[i]->omtu, mtu);
53615389
result = L2CAP_RECONF_INVALID_MTU;
5390+
goto respond;
53625391
}
53635392

5364-
chan->omtu = mtu;
5365-
chan->remote_mps = mps;
5393+
/* If more than one channel is being configured, the MPS field
5394+
* shall be greater than or equal to the current MPS size of
5395+
* each of these channels. If only one channel is being
5396+
* configured, the MPS field may be less than the current MPS
5397+
* of that channel.
5398+
*/
5399+
if (chan[i]->remote_mps >= mps && i) {
5400+
BT_ERR("chan %p decreased MPS %u -> %u", chan[i],
5401+
chan[i]->remote_mps, mps);
5402+
result = L2CAP_RECONF_INVALID_MPS;
5403+
goto respond;
5404+
}
5405+
}
5406+
5407+
/* Commit the new MTU and MPS values after checking they are valid */
5408+
for (i = 0; i < num_scid; i++) {
5409+
chan[i]->omtu = mtu;
5410+
chan[i]->remote_mps = mps;
53665411
}
53675412

53685413
respond:

net/bluetooth/l2cap_sock.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,10 +1029,17 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
10291029
break;
10301030
}
10311031

1032-
/* Setting is not supported as it's the remote side that
1033-
* decides this.
1034-
*/
1035-
err = -EPERM;
1032+
/* Only allow setting output MTU when not connected */
1033+
if (sk->sk_state == BT_CONNECTED) {
1034+
err = -EISCONN;
1035+
break;
1036+
}
1037+
1038+
err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
1039+
if (err)
1040+
break;
1041+
1042+
chan->omtu = mtu;
10361043
break;
10371044

10381045
case BT_RCVMTU:
@@ -1817,6 +1824,7 @@ static void l2cap_sock_destruct(struct sock *sk)
18171824

18181825
skb_queue_purge(&sk->sk_receive_queue);
18191826
skb_queue_purge(&sk->sk_write_queue);
1827+
skb_queue_purge(&sk->sk_error_queue);
18201828
}
18211829

18221830
static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name,

net/bluetooth/sco.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ static void sco_sock_destruct(struct sock *sk)
470470

471471
skb_queue_purge(&sk->sk_receive_queue);
472472
skb_queue_purge(&sk->sk_write_queue);
473+
skb_queue_purge(&sk->sk_error_queue);
473474
}
474475

475476
static void sco_sock_cleanup_listen(struct sock *parent)

0 commit comments

Comments
 (0)