blob: 8944ef245390aad884c8e9bf2a2be8fdf1d18ede [file] [log] [blame]
From ce602a0a88297fe9272c865096540111933fad35 Mon Sep 17 00:00:00 2001
From: Alain Michaud <alainm@chromium.org>
Date: Fri, 9 Apr 2021 15:21:27 +0000
Subject: [PATCH] CHROMIUM: Use link policies to disallow role switches
Some peripherals will attempt to role switch the host device into a
peripheral role mode. When combined with other peripherals such as mice
and keyboards, this forces the controller to maintain a complicated
topology which results in audio glitches or mouse movement glitches.
The solution implemented by this patch is to leverage the link_policy to
attempt to disallow the peripheral from switching roles once the host
settles into the central role.
This is submitted as a chromium patch to gain some feedback on
improvement before proposing upstream.
Signed-off-by: Alain Michaud <alainm@chromium.org>
BUG=none
TEST=build
Signed-off-by: Zhengping Jiang <jiangzp@google.com>
---
net/bluetooth/hci_conn.c | 3 +--
net/bluetooth/hci_event.c | 19 +++++++++++++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 2909c00632041e0d1550404c33d3a15b7d2e8d42..802d13d3c31cc85af33193d662c5cf411ac8ee7c 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -210,8 +210,6 @@ static void hci_acl_create_connection(struct hci_conn *conn)
conn->attempt++;
- conn->link_policy = hdev->link_policy;
-
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
@@ -985,6 +983,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
conn->tx_power = HCI_TX_POWER_INVALID;
conn->max_tx_power = HCI_TX_POWER_INVALID;
conn->sync_handle = HCI_SYNC_HANDLE_INVALID;
+ conn->link_policy = hdev->link_policy;
set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0849e0dafa951c65918b51c77b621fc9dd531a3d..f05d322a7b4249651b59757c86a64aa3858c72b0 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3182,6 +3182,12 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
}
if (!status) {
+ int mask = hdev->link_mode;
+ __u8 flags = 0;
+
+ mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type,
+ &flags);
+
status = hci_conn_set_handle(conn, __le16_to_cpu(ev->handle));
if (status)
goto done;
@@ -3207,6 +3213,19 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
if (test_bit(HCI_ENCRYPT, &hdev->flags))
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
+ /* Attempt to remain in the central role if preferred */
+ if ((conn->mode == HCI_ROLE_MASTER && (mask & HCI_LM_MASTER)) &&
+ (conn->link_policy & HCI_LP_RSWITCH)) {
+ struct hci_cp_write_link_policy cp;
+
+ conn->link_policy &= ~HCI_LP_RSWITCH;
+
+ cp.handle = ev->handle;
+ cp.policy = conn->link_policy;
+ hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY,
+ sizeof(cp), &cp);
+ }
+
/* Get remote features */
if (conn->type == ACL_LINK) {
struct hci_cp_read_remote_features cp;
--
2.43.0.rc2.451.g8631bc7472-goog