Bluetooth: Add different pairing timeout for Legacy Pairing
The Bluetooth stack uses a reference counting for all established ACL links and if no user (L2CAP connection) is present, the link will be terminated to save power. The problem part is the dedicated pairing when using Legacy Pairing (Bluetooth 2.0 and before). At that point no user is present and pairing attempts will be disconnected within 10 seconds or less. In previous kernel version this was not a problem since the disconnect timeout wasn't triggered on incoming connections for the first time. However this caused issues with broken host stacks that kept the connections around after dedicated pairing. When the support for Simple Pairing got added, the link establishment procedure needed to be changed and now causes issues when using Legacy Pairing When using Simple Pairing it is possible to do a proper reference counting of ACL link users. With Legacy Pairing this is not possible since the specification is unclear in some areas and too many broken Bluetooth devices have already been deployed. So instead of trying to deal with all the broken devices, a special pairing timeout will be introduced that increases the timeout to 60 seconds when pairing is triggered. If a broken devices now puts the stack into an unforeseen state, the worst that happens is the disconnect timeout triggers after 120 seconds instead of 4 seconds. This allows successful pairings with legacy and broken devices now. Based on a report by Johan Hedberg <johan.hedberg@nokia.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
f3784d834c
commit
052b30b0a8
4 changed files with 40 additions and 3 deletions
|
@ -101,6 +101,7 @@ enum {
|
|||
/* HCI timeouts */
|
||||
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
|
||||
#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
|
||||
#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
|
||||
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
|
||||
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ struct hci_conn {
|
|||
__u8 auth_type;
|
||||
__u8 sec_level;
|
||||
__u8 power_save;
|
||||
__u16 disc_timeout;
|
||||
unsigned long pend;
|
||||
|
||||
unsigned int sent;
|
||||
|
@ -349,9 +350,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
|
|||
if (conn->type == ACL_LINK) {
|
||||
del_timer(&conn->idle_timer);
|
||||
if (conn->state == BT_CONNECTED) {
|
||||
timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
|
||||
timeo = msecs_to_jiffies(conn->disc_timeout);
|
||||
if (!conn->out)
|
||||
timeo *= 5;
|
||||
timeo *= 2;
|
||||
} else
|
||||
timeo = msecs_to_jiffies(10);
|
||||
} else
|
||||
|
|
|
@ -215,6 +215,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
|||
conn->state = BT_OPEN;
|
||||
|
||||
conn->power_save = 1;
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
|
||||
switch (type) {
|
||||
case ACL_LINK:
|
||||
|
|
|
@ -883,6 +883,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||
if (conn->type == ACL_LINK) {
|
||||
conn->state = BT_CONFIG;
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
} else
|
||||
conn->state = BT_CONNECTED;
|
||||
|
||||
|
@ -1063,9 +1064,14 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||
hci_proto_connect_cfm(conn, ev->status);
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
hci_auth_cfm(conn, ev->status);
|
||||
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
|
||||
if (!ev->status) {
|
||||
struct hci_cp_set_conn_encrypt cp;
|
||||
|
@ -1479,7 +1485,21 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
|
|||
|
||||
static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_pin_code_req *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn) {
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
@ -1489,7 +1509,21 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
|
|||
|
||||
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_link_key_notify *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn) {
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
|
Loading…
Reference in a new issue