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 -----BEGIN PGP SIGNATURE----- iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmmcw1EZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKUTyD/4jtQwDrveC19zamF5n7lFY Oils6eftANcLFzLwTrMqGO7IxESga4qdNOf2vc/UgVSUfNqsPIUJ5El+LzpXZXAa sYBP/KudEX53CfU3fEVyPTUaWkZ4CdMRZeiCmgXqW7GxYbGw92SFuaSIHAP6Ep4s Z7Ryd1H0xhX9QPMc4g4IgoMiBiKzNs4GtlLSbDJcivAtbC/34nkMOxK9g+1DbU0F qzW+oPfYCpPzXTf20I1QIAMt5smnSM3Tuvo9u2pZRuEGpKjENxeY4hdAejfjeKA6 RLWXm6JvMP2lUBT68plMQQdYyQ8DxG75sVjgSoQYIu2YTVnsX76t/kD2hhiHXH/Y nQoy4dtA1/5V7Ka0cfMhcvino4Rb9Gh3dsFKJOuWRT+aTY+gNhpyr56SuJh24Y3C 7tUeEDI4fBkJGaRAbreVbaI5vw4kbSfi7IDOM/ccWDSLaG8HGaLOtn0IU8q4AgMa IkYzB5zwtiyM/zaSTO1k0HkpjR0wwftnTd+Fj2mUWdTwSeek64R9enmKYmg5UJrv 14yhfLHFsbAQo+o1B3ZslnCdYQJpgFmyAInV6Jpunc78IE9+g/YA55K22JbDDSzI t9Zy25OWLyYZyuD1PzDkMlYU5OARNYeyRXbJ3w037LrpqRoEuFsK0qTmgi+kR9C7 VR9IpCqgf4SJbL7ge83H8g== =JBaa -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
1348659dc9
|
|
@ -2046,19 +2046,23 @@ retry:
|
|||
}
|
||||
|
||||
out:
|
||||
if (ret && retries < MAX_INIT_RETRIES) {
|
||||
bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
|
||||
if (ret) {
|
||||
qca_power_shutdown(hu);
|
||||
if (hu->serdev) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hdev, "failed to open port");
|
||||
return ret;
|
||||
|
||||
if (retries < MAX_INIT_RETRIES) {
|
||||
bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
|
||||
if (hu->serdev) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hdev, "failed to open port");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
retries++;
|
||||
goto retry;
|
||||
}
|
||||
retries++;
|
||||
goto retry;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup bdaddr */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2166,6 +2166,7 @@ static void hci_sock_destruct(struct sock *sk)
|
|||
mgmt_cleanup(sk);
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
skb_queue_purge(&sk->sk_write_queue);
|
||||
skb_queue_purge(&sk->sk_error_queue);
|
||||
}
|
||||
|
||||
static const struct proto_ops hci_sock_ops = {
|
||||
|
|
|
|||
|
|
@ -4592,7 +4592,7 @@ static int hci_le_set_host_features_sync(struct hci_dev *hdev)
|
|||
{
|
||||
int err;
|
||||
|
||||
if (iso_capable(hdev)) {
|
||||
if (cis_capable(hdev)) {
|
||||
/* Connected Isochronous Channels (Host Support) */
|
||||
err = hci_le_set_host_feature_sync(hdev, 32,
|
||||
(iso_enabled(hdev) ? 0x01 :
|
||||
|
|
|
|||
|
|
@ -746,6 +746,7 @@ static void iso_sock_destruct(struct sock *sk)
|
|||
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
skb_queue_purge(&sk->sk_write_queue);
|
||||
skb_queue_purge(&sk->sk_error_queue);
|
||||
}
|
||||
|
||||
static void iso_sock_cleanup_listen(struct sock *parent)
|
||||
|
|
|
|||
|
|
@ -4916,6 +4916,13 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
|||
goto response_unlock;
|
||||
}
|
||||
|
||||
/* Check if Key Size is sufficient for the security level */
|
||||
if (!l2cap_check_enc_key_size(conn->hcon, pchan)) {
|
||||
result = L2CAP_CR_LE_BAD_KEY_SIZE;
|
||||
chan = NULL;
|
||||
goto response_unlock;
|
||||
}
|
||||
|
||||
/* Check for valid dynamic CID range */
|
||||
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
|
||||
result = L2CAP_CR_LE_INVALID_SCID;
|
||||
|
|
@ -5051,13 +5058,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 +5075,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 +5087,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 +5107,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);
|
||||
|
|
@ -5109,7 +5119,16 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
|||
|
||||
if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
|
||||
SMP_ALLOW_STK)) {
|
||||
result = L2CAP_CR_LE_AUTHENTICATION;
|
||||
result = pchan->sec_level == BT_SECURITY_MEDIUM ?
|
||||
L2CAP_CR_LE_ENCRYPTION : L2CAP_CR_LE_AUTHENTICATION;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Check if the listening channel has set an output MTU then the
|
||||
* requested MTU shall be less than or equal to that value.
|
||||
*/
|
||||
if (pchan->omtu && mtu < pchan->omtu) {
|
||||
result = L2CAP_CR_LE_UNACCEPT_PARAMS;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
|
@ -5121,7 +5140,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 +5206,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;
|
||||
}
|
||||
|
|
@ -5310,14 +5328,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 +5345,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:
|
||||
|
|
|
|||
|
|
@ -1029,10 +1029,17 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Setting is not supported as it's the remote side that
|
||||
* decides this.
|
||||
*/
|
||||
err = -EPERM;
|
||||
/* Only allow setting output MTU when not connected */
|
||||
if (sk->sk_state == BT_CONNECTED) {
|
||||
err = -EISCONN;
|
||||
break;
|
||||
}
|
||||
|
||||
err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
chan->omtu = mtu;
|
||||
break;
|
||||
|
||||
case BT_RCVMTU:
|
||||
|
|
@ -1817,6 +1824,7 @@ static void l2cap_sock_destruct(struct sock *sk)
|
|||
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
skb_queue_purge(&sk->sk_write_queue);
|
||||
skb_queue_purge(&sk->sk_error_queue);
|
||||
}
|
||||
|
||||
static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name,
|
||||
|
|
|
|||
|
|
@ -470,6 +470,7 @@ static void sco_sock_destruct(struct sock *sk)
|
|||
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
skb_queue_purge(&sk->sk_write_queue);
|
||||
skb_queue_purge(&sk->sk_error_queue);
|
||||
}
|
||||
|
||||
static void sco_sock_cleanup_listen(struct sock *parent)
|
||||
|
|
|
|||
Loading…
Reference in New Issue