| From 9faaa506a4dff388c7100c6c2a62744789dc1f85 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. |
| |
| BUG=b:181843241 |
| TEST=update_kernel on hatch. Observed the role switch 3 seconds after |
| the connection using a Bose headset and observe the connection remains |
| in central role after the kernel is updated. |
| |
| Signed-off-by: Alain Michaud <alainm@chromium.org> |
| Change-Id: I67136706ba39a9f09b3285017b62a13a920bfffd |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2818461 |
| Reviewed-by: Miao-chen Chou <mcchou@chromium.org> |
| --- |
| 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 fe803bee419a..754b92e4d19e 100644 |
| --- a/net/bluetooth/hci_conn.c |
| +++ b/net/bluetooth/hci_conn.c |
| @@ -226,8 +226,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; |
| @@ -704,6 +702,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, |
| conn->rssi = HCI_RSSI_INVALID; |
| conn->tx_power = HCI_TX_POWER_INVALID; |
| conn->max_tx_power = HCI_TX_POWER_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 5ef357b63c68..19725446366e 100644 |
| --- a/net/bluetooth/hci_event.c |
| +++ b/net/bluetooth/hci_event.c |
| @@ -3125,6 +3125,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); |
| + |
| conn->handle = __le16_to_cpu(ev->handle); |
| if (conn->handle > HCI_CONN_HANDLE_MAX) { |
| bt_dev_err(hdev, "Invalid handle: 0x%4.4x > 0x%4.4x", |
| @@ -3154,6 +3160,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.36.0.512.ge40c2bad7a-goog |
| |