Commit 037c97b2 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-2022-08-25' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

 - Fix handling of duplicate connection handle
 - Fix handling of HCI vendor opcode
 - Fix suspend performance regression
 - Fix build errors
 - Fix not handling shutdown condition on ISO sockets
 - Fix double free issue

* tag 'for-net-2022-08-25' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: hci_sync: hold hdev->lock when cleanup hci_conn
  Bluetooth: move from strlcpy with unused retval to strscpy
  Bluetooth: hci_event: Fix checking conn for le_conn_complete_evt
  Bluetooth: ISO: Fix not handling shutdown condition
  Bluetooth: hci_sync: fix double mgmt_pending_free() in remove_adv_monitor()
  Bluetooth: MGMT: Fix Get Device Flags
  Bluetooth: L2CAP: Fix build errors in some archs
  Bluetooth: hci_sync: Fix suspend performance regression
  Bluetooth: hci_event: Fix vendor (unknown) opcode status handling
====================

Link: https://lore.kernel.org/r/20220825234559.1837409-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 2e085ec0 2da8eb83
......@@ -4179,6 +4179,17 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
}
}
if (i == ARRAY_SIZE(hci_cc_table)) {
/* Unknown opcode, assume byte 0 contains the status, so
* that e.g. __hci_cmd_sync() properly returns errors
* for vendor specific commands send by HCI drivers.
* If a vendor doesn't actually follow this convention we may
* need to introduce a vendor CC table in order to properly set
* the status.
*/
*status = skb->data[0];
}
handle_cmd_cnt_and_timer(hdev, ev->ncmd);
hci_req_cmd_complete(hdev, *opcode, *status, req_complete,
......@@ -5790,7 +5801,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
*/
hci_dev_clear_flag(hdev, HCI_LE_ADV);
conn = hci_lookup_le_connect(hdev);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
if (!conn) {
/* In case of error status and there is no connection pending
* just unlock as there is nothing to cleanup.
......
......@@ -4773,9 +4773,11 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
/* Cleanup hci_conn object if it cannot be cancelled as it
* likelly means the controller and host stack are out of sync.
*/
if (err)
if (err) {
hci_dev_lock(hdev);
hci_conn_failed(conn, err);
hci_dev_unlock(hdev);
}
return err;
case BT_CONNECT2:
return hci_reject_conn_sync(hdev, conn, reason);
......@@ -5288,17 +5290,21 @@ int hci_suspend_sync(struct hci_dev *hdev)
/* Prevent disconnects from causing scanning to be re-enabled */
hci_pause_scan_sync(hdev);
/* Soft disconnect everything (power off) */
err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
if (err) {
/* Set state to BT_RUNNING so resume doesn't notify */
hdev->suspend_state = BT_RUNNING;
hci_resume_sync(hdev);
return err;
}
if (hci_conn_count(hdev)) {
/* Soft disconnect everything (power off) */
err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
if (err) {
/* Set state to BT_RUNNING so resume doesn't notify */
hdev->suspend_state = BT_RUNNING;
hci_resume_sync(hdev);
return err;
}
/* Update event mask so only the allowed event can wakeup the host */
hci_set_event_mask_sync(hdev);
/* Update event mask so only the allowed event can wakeup the
* host.
*/
hci_set_event_mask_sync(hdev);
}
/* Only configure accept list if disconnect succeeded and wake
* isn't being prevented.
......
......@@ -83,14 +83,14 @@ static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo
ci->product = session->input->id.product;
ci->version = session->input->id.version;
if (session->input->name)
strlcpy(ci->name, session->input->name, 128);
strscpy(ci->name, session->input->name, 128);
else
strlcpy(ci->name, "HID Boot Device", 128);
strscpy(ci->name, "HID Boot Device", 128);
} else if (session->hid) {
ci->vendor = session->hid->vendor;
ci->product = session->hid->product;
ci->version = session->hid->version;
strlcpy(ci->name, session->hid->name, 128);
strscpy(ci->name, session->hid->name, 128);
}
}
......
......@@ -1309,7 +1309,7 @@ static int iso_sock_shutdown(struct socket *sock, int how)
struct sock *sk = sock->sk;
int err = 0;
BT_DBG("sock %p, sk %p", sock, sk);
BT_DBG("sock %p, sk %p, how %d", sock, sk, how);
if (!sk)
return 0;
......@@ -1317,17 +1317,32 @@ static int iso_sock_shutdown(struct socket *sock, int how)
sock_hold(sk);
lock_sock(sk);
if (!sk->sk_shutdown) {
sk->sk_shutdown = SHUTDOWN_MASK;
iso_sock_clear_timer(sk);
__iso_sock_close(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
!(current->flags & PF_EXITING))
err = bt_sock_wait_state(sk, BT_CLOSED,
sk->sk_lingertime);
switch (how) {
case SHUT_RD:
if (sk->sk_shutdown & RCV_SHUTDOWN)
goto unlock;
sk->sk_shutdown |= RCV_SHUTDOWN;
break;
case SHUT_WR:
if (sk->sk_shutdown & SEND_SHUTDOWN)
goto unlock;
sk->sk_shutdown |= SEND_SHUTDOWN;
break;
case SHUT_RDWR:
if (sk->sk_shutdown & SHUTDOWN_MASK)
goto unlock;
sk->sk_shutdown |= SHUTDOWN_MASK;
break;
}
iso_sock_clear_timer(sk);
__iso_sock_close(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
!(current->flags & PF_EXITING))
err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
unlock:
release_sock(sk);
sock_put(sk);
......
......@@ -1992,11 +1992,11 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
src_match = !bacmp(&c->src, src);
dst_match = !bacmp(&c->dst, dst);
if (src_match && dst_match) {
c = l2cap_chan_hold_unless_zero(c);
if (c) {
read_unlock(&chan_list_lock);
return c;
}
if (!l2cap_chan_hold_unless_zero(c))
continue;
read_unlock(&chan_list_lock);
return c;
}
/* Closest match */
......
......@@ -4547,6 +4547,22 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
MGMT_STATUS_NOT_SUPPORTED);
}
static u32 get_params_flags(struct hci_dev *hdev,
struct hci_conn_params *params)
{
u32 flags = hdev->conn_flags;
/* Devices using RPAs can only be programmed in the acceptlist if
* LL Privacy has been enable otherwise they cannot mark
* HCI_CONN_FLAG_REMOTE_WAKEUP.
*/
if ((flags & HCI_CONN_FLAG_REMOTE_WAKEUP) && !use_ll_privacy(hdev) &&
hci_find_irk_by_addr(hdev, &params->addr, params->addr_type))
flags &= ~HCI_CONN_FLAG_REMOTE_WAKEUP;
return flags;
}
static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
......@@ -4578,10 +4594,10 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
} else {
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (!params)
goto done;
supported_flags = get_params_flags(hdev, params);
current_flags = params->flags;
}
......@@ -4649,38 +4665,35 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
&cp->addr.bdaddr, cp->addr.type);
}
} else {
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (params) {
/* Devices using RPAs can only be programmed in the
* acceptlist LL Privacy has been enable otherwise they
* cannot mark HCI_CONN_FLAG_REMOTE_WAKEUP.
*/
if ((current_flags & HCI_CONN_FLAG_REMOTE_WAKEUP) &&
!use_ll_privacy(hdev) &&
hci_find_irk_by_addr(hdev, &params->addr,
params->addr_type)) {
bt_dev_warn(hdev,
"Cannot set wakeable for RPA");
goto unlock;
}
params->flags = current_flags;
status = MGMT_STATUS_SUCCESS;
goto unlock;
}
/* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
* has been set.
*/
if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
hci_update_passive_scan(hdev);
} else {
bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
&cp->addr.bdaddr,
le_addr_type(cp->addr.type));
}
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (!params) {
bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
&cp->addr.bdaddr, le_addr_type(cp->addr.type));
goto unlock;
}
supported_flags = get_params_flags(hdev, params);
if ((supported_flags | current_flags) != supported_flags) {
bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
current_flags, supported_flags);
goto unlock;
}
params->flags = current_flags;
status = MGMT_STATUS_SUCCESS;
/* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
* has been set.
*/
if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
hci_update_passive_scan(hdev);
unlock:
hci_dev_unlock(hdev);
......@@ -5054,7 +5067,6 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
else
status = MGMT_STATUS_FAILED;
mgmt_pending_remove(cmd);
goto unlock;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment