| 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 |
| |