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, ...@@ -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); handle_cmd_cnt_and_timer(hdev, ev->ncmd);
hci_req_cmd_complete(hdev, *opcode, *status, req_complete, 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, ...@@ -5790,7 +5801,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
*/ */
hci_dev_clear_flag(hdev, HCI_LE_ADV); 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) { if (!conn) {
/* In case of error status and there is no connection pending /* In case of error status and there is no connection pending
* just unlock as there is nothing to cleanup. * 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) ...@@ -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 /* Cleanup hci_conn object if it cannot be cancelled as it
* likelly means the controller and host stack are out of sync. * 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_conn_failed(conn, err);
hci_dev_unlock(hdev);
}
return err; return err;
case BT_CONNECT2: case BT_CONNECT2:
return hci_reject_conn_sync(hdev, conn, reason); return hci_reject_conn_sync(hdev, conn, reason);
...@@ -5288,6 +5290,7 @@ int hci_suspend_sync(struct hci_dev *hdev) ...@@ -5288,6 +5290,7 @@ int hci_suspend_sync(struct hci_dev *hdev)
/* Prevent disconnects from causing scanning to be re-enabled */ /* Prevent disconnects from causing scanning to be re-enabled */
hci_pause_scan_sync(hdev); hci_pause_scan_sync(hdev);
if (hci_conn_count(hdev)) {
/* Soft disconnect everything (power off) */ /* Soft disconnect everything (power off) */
err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF); err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
if (err) { if (err) {
...@@ -5297,8 +5300,11 @@ int hci_suspend_sync(struct hci_dev *hdev) ...@@ -5297,8 +5300,11 @@ int hci_suspend_sync(struct hci_dev *hdev)
return err; return err;
} }
/* Update event mask so only the allowed event can wakeup the host */ /* Update event mask so only the allowed event can wakeup the
* host.
*/
hci_set_event_mask_sync(hdev); hci_set_event_mask_sync(hdev);
}
/* Only configure accept list if disconnect succeeded and wake /* Only configure accept list if disconnect succeeded and wake
* isn't being prevented. * isn't being prevented.
......
...@@ -83,14 +83,14 @@ static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo ...@@ -83,14 +83,14 @@ static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo
ci->product = session->input->id.product; ci->product = session->input->id.product;
ci->version = session->input->id.version; ci->version = session->input->id.version;
if (session->input->name) if (session->input->name)
strlcpy(ci->name, session->input->name, 128); strscpy(ci->name, session->input->name, 128);
else else
strlcpy(ci->name, "HID Boot Device", 128); strscpy(ci->name, "HID Boot Device", 128);
} else if (session->hid) { } else if (session->hid) {
ci->vendor = session->hid->vendor; ci->vendor = session->hid->vendor;
ci->product = session->hid->product; ci->product = session->hid->product;
ci->version = session->hid->version; 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) ...@@ -1309,7 +1309,7 @@ static int iso_sock_shutdown(struct socket *sock, int how)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p, how %d", sock, sk, how);
if (!sk) if (!sk)
return 0; return 0;
...@@ -1317,17 +1317,32 @@ static int iso_sock_shutdown(struct socket *sock, int how) ...@@ -1317,17 +1317,32 @@ static int iso_sock_shutdown(struct socket *sock, int how)
sock_hold(sk); sock_hold(sk);
lock_sock(sk); lock_sock(sk);
if (!sk->sk_shutdown) { switch (how) {
sk->sk_shutdown = SHUTDOWN_MASK; 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_clear_timer(sk);
__iso_sock_close(sk); __iso_sock_close(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
!(current->flags & PF_EXITING)) !(current->flags & PF_EXITING))
err = bt_sock_wait_state(sk, BT_CLOSED, err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
sk->sk_lingertime);
}
unlock:
release_sock(sk); release_sock(sk);
sock_put(sk); sock_put(sk);
......
...@@ -1992,12 +1992,12 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, ...@@ -1992,12 +1992,12 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
src_match = !bacmp(&c->src, src); src_match = !bacmp(&c->src, src);
dst_match = !bacmp(&c->dst, dst); dst_match = !bacmp(&c->dst, dst);
if (src_match && dst_match) { if (src_match && dst_match) {
c = l2cap_chan_hold_unless_zero(c); if (!l2cap_chan_hold_unless_zero(c))
if (c) { continue;
read_unlock(&chan_list_lock); read_unlock(&chan_list_lock);
return c; return c;
} }
}
/* Closest match */ /* Closest match */
src_any = !bacmp(&c->src, BDADDR_ANY); src_any = !bacmp(&c->src, BDADDR_ANY);
......
...@@ -4547,6 +4547,22 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, ...@@ -4547,6 +4547,22 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
MGMT_STATUS_NOT_SUPPORTED); 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, static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len) u16 data_len)
{ {
...@@ -4578,10 +4594,10 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -4578,10 +4594,10 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
} else { } else {
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type)); le_addr_type(cp->addr.type));
if (!params) if (!params)
goto done; goto done;
supported_flags = get_params_flags(hdev, params);
current_flags = params->flags; current_flags = params->flags;
} }
...@@ -4649,20 +4665,23 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -4649,20 +4665,23 @@ 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)", bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
&cp->addr.bdaddr, cp->addr.type); &cp->addr.bdaddr, cp->addr.type);
} }
} else {
goto unlock;
}
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type)); le_addr_type(cp->addr.type));
if (params) { if (!params) {
/* Devices using RPAs can only be programmed in the bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
* acceptlist LL Privacy has been enable otherwise they &cp->addr.bdaddr, le_addr_type(cp->addr.type));
* cannot mark HCI_CONN_FLAG_REMOTE_WAKEUP. goto unlock;
*/ }
if ((current_flags & HCI_CONN_FLAG_REMOTE_WAKEUP) &&
!use_ll_privacy(hdev) && supported_flags = get_params_flags(hdev, params);
hci_find_irk_by_addr(hdev, &params->addr,
params->addr_type)) { if ((supported_flags | current_flags) != supported_flags) {
bt_dev_warn(hdev, bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
"Cannot set wakeable for RPA"); current_flags, supported_flags);
goto unlock; goto unlock;
} }
...@@ -4674,12 +4693,6 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -4674,12 +4693,6 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
*/ */
if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY) if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
hci_update_passive_scan(hdev); 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));
}
}
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -5054,7 +5067,6 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, ...@@ -5054,7 +5067,6 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
else else
status = MGMT_STATUS_FAILED; status = MGMT_STATUS_FAILED;
mgmt_pending_remove(cmd);
goto unlock; 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