Commit f7915cad authored by Olivier Crête's avatar Olivier Crête
Browse files

Bluetooth: Avoid calling device_add() on duplicated HCI conn event

The BCM20702A1 device in the ThinkPad x230 seems to send the HCI
Connection Complete event twice for the same connection, for which the
stack seems to recover, except for the core device_add() function
which is not meant to be called twice for the same device. So let's
just avoid calling it in that case.


Signed-off-by: Olivier Crête's avatarOlivier Crête <>
parent e0f14b8c
...@@ -449,6 +449,9 @@ struct hci_dev { ...@@ -449,6 +449,9 @@ struct hci_dev {
#define HCI_PHY_HANDLE(handle) (handle & 0xff) #define HCI_PHY_HANDLE(handle) (handle & 0xff)
/* Valid HCI handles are in the 0x0000-0x0EFF range per spec */
struct hci_conn { struct hci_conn {
struct list_head list; struct list_head list;
...@@ -516,6 +516,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, ...@@ -516,6 +516,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
conn->rssi = HCI_RSSI_INVALID; conn->rssi = HCI_RSSI_INVALID;
conn->tx_power = HCI_TX_POWER_INVALID; conn->tx_power = HCI_TX_POWER_INVALID;
conn->max_tx_power = HCI_TX_POWER_INVALID; conn->max_tx_power = HCI_TX_POWER_INVALID;
conn->handle = HCI_INVALID_HANDLE;
set_bit(HCI_CONN_POWER_SAVE, &conn->flags); set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
conn->disc_timeout = HCI_DISCONN_TIMEOUT; conn->disc_timeout = HCI_DISCONN_TIMEOUT;
...@@ -2493,6 +2493,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2493,6 +2493,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
} }
if (!ev->status) { if (!ev->status) {
int first_connection = (conn->handle == HCI_INVALID_HANDLE);
conn->handle = __le16_to_cpu(ev->handle); conn->handle = __le16_to_cpu(ev->handle);
if (conn->type == ACL_LINK) { if (conn->type == ACL_LINK) {
...@@ -2507,8 +2509,10 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2507,8 +2509,10 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
} else } else
conn->state = BT_CONNECTED; conn->state = BT_CONNECTED;
hci_debugfs_create_conn(conn); if (first_connection) {
hci_conn_add_sysfs(conn); hci_debugfs_create_conn(conn);
if (test_bit(HCI_AUTH, &hdev->flags)) if (test_bit(HCI_AUTH, &hdev->flags))
set_bit(HCI_CONN_AUTH, &conn->flags); set_bit(HCI_CONN_AUTH, &conn->flags);
  • Can't you just use conn->state being already BT_CONNECTED|BT_CONFIG, instead of poisoning the handler?

    old_state = conn->state; ... if (old_state != BT_CONNECTED && old_state != BT_CONFIG) { hci_conn_add_sysfs() }

    seems simpler.

  • The fix make sense and looks good. Not sure if gitlab is playing stupid, but the signoff line is mangled with the bugzilla line.

    Remember to cc since you are signing-off with your work email.

  • @krisman Using the state, but it gets reset by another event, so it's useless.

  • The fixes makes sense to me, I just wonder if there is a better way to check that. @ocrete when you say the state gets reset is that because of the duplicated event? Is it possible to check it before the reset?

    A trace with btmon would help understand what is happening too.

  • From what I can see from the attached log from the kernel, it seems that the controller decides to send a connection request event again with the same connection handle (which resets the ->state member BT_CONNECT), then it sends a new connection complete (which is where this code is called). Obviously, now that I try to make a log with btmon with more info, I can't reproduce the problem (with either kernel).

    Edited by Olivier Crête
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