Commit 037c97b2 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
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.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 2e085ec0 2da8eb83
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -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.
+18 −12
Original line number Diff line number Diff line
@@ -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,6 +5290,7 @@ int hci_suspend_sync(struct hci_dev *hdev)
	/* Prevent disconnects from causing scanning to be re-enabled */
	hci_pause_scan_sync(hdev);

	if (hci_conn_count(hdev)) {
		/* Soft disconnect everything (power off) */
		err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
		if (err) {
@@ -5297,8 +5300,11 @@ int hci_suspend_sync(struct hci_dev *hdev)
			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);
	}

	/* Only configure accept list if disconnect succeeded and wake
	 * isn't being prevented.
+3 −3
Original line number Diff line number Diff line
@@ -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);
	}
}

+25 −10
Original line number Diff line number Diff line
@@ -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;
	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);
	}
		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);

unlock:
	release_sock(sk);
	sock_put(sk);

+5 −5
Original line number Diff line number Diff line
@@ -1992,12 +1992,12 @@ 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) {
				if (!l2cap_chan_hold_unless_zero(c))
					continue;

				read_unlock(&chan_list_lock);
				return c;
			}
			}

			/* Closest match */
			src_any = !bacmp(&c->src, BDADDR_ANY);
Loading