Bluetooth: Add timeout for LE connection attempts
authorJohan Hedberg <johan.hedberg@intel.com>
Fri, 28 Feb 2014 15:45:46 +0000 (17:45 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 28 Feb 2014 15:56:42 +0000 (07:56 -0800)
LE connection attempts do not have a controller side timeout in the same
way as BR/EDR has (in form of the page timeout). Since we always do
scanning before initiating connections the attempts are always expected
to succeed in some reasonable time.

This patch adds a timer which forces a cancellation of the connection
attempt within 20 seconds if it has not been successful by then. This
way we e.g. ensure that mgmt_pair_device times out eventually and gives
an error response.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c

index 439b4ebf96446927de5f0683e645b44a62cb09fa..0409f0119d2bb65703e7a4dd950436844ceee8fd 100644 (file)
@@ -183,6 +183,7 @@ enum {
 #define HCI_ACL_TX_TIMEOUT     msecs_to_jiffies(45000) /* 45 seconds */
 #define HCI_AUTO_OFF_TIMEOUT   msecs_to_jiffies(2000)  /* 2 seconds */
 #define HCI_POWER_OFF_TIMEOUT  msecs_to_jiffies(5000)  /* 5 seconds */
+#define HCI_LE_CONN_TIMEOUT    msecs_to_jiffies(20000) /* 20 seconds */
 
 /* HCI data types */
 #define HCI_COMMAND_PKT                0x01
index edf194679b7d928791ec73fdb4a3b50388d7d99d..dbb788e4f265f4b820a3375c71b65520d2cbcfaf 100644 (file)
@@ -375,6 +375,7 @@ struct hci_conn {
        struct delayed_work disc_work;
        struct delayed_work auto_accept_work;
        struct delayed_work idle_work;
+       struct delayed_work le_conn_timeout;
 
        struct device   dev;
 
index 818330c1b2a21ac1d3636d7becd814ca02aeeafb..7e47e4240c95be6b20d0d9a5848c79fe67840634 100644 (file)
@@ -363,6 +363,16 @@ static void hci_conn_auto_accept(struct work_struct *work)
                     &conn->dst);
 }
 
+static void le_conn_timeout(struct work_struct *work)
+{
+       struct hci_conn *conn = container_of(work, struct hci_conn,
+                                            le_conn_timeout.work);
+
+       BT_DBG("");
+
+       hci_le_create_connection_cancel(conn);
+}
+
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 {
        struct hci_conn *conn;
@@ -410,6 +420,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
        INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept);
        INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle);
+       INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout);
 
        atomic_set(&conn->refcnt, 0);
 
@@ -442,6 +453,8 @@ int hci_conn_del(struct hci_conn *conn)
                /* Unacked frames */
                hdev->acl_cnt += conn->sent;
        } else if (conn->type == LE_LINK) {
+               cancel_delayed_work_sync(&conn->le_conn_timeout);
+
                if (hdev->le_pkts)
                        hdev->le_cnt += conn->sent;
                else
index 3ae8ae1a029c720162a7732b0e93d559983c27f9..a1075c713a9d817c162a876cd165cfb9e6069e6a 100644 (file)
@@ -1678,6 +1678,16 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
        conn->resp_addr_type = cp->peer_addr_type;
        bacpy(&conn->resp_addr, &cp->peer_addr);
 
+       /* We don't want the connection attempt to stick around
+        * indefinitely since LE doesn't have a page timeout concept
+        * like BR/EDR. Set a timer for any connection that doesn't use
+        * the white list for connecting.
+        */
+       if (cp->filter_policy == HCI_LE_USE_PEER_ADDR)
+               queue_delayed_work(conn->hdev->workqueue,
+                                  &conn->le_conn_timeout,
+                                  HCI_LE_CONN_TIMEOUT);
+
 unlock:
        hci_dev_unlock(hdev);
 }
@@ -3794,6 +3804,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                        conn->init_addr_type = ev->bdaddr_type;
                        bacpy(&conn->init_addr, &ev->bdaddr);
                }
+       } else {
+               cancel_delayed_work(&conn->le_conn_timeout);
        }
 
        /* Ensure that the hci_conn contains the identity address type