aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2006-09-26 03:43:48 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-28 21:01:33 -0400
commit6ac59344ef25d5f0ebadb5663cf700d25d2a3886 (patch)
treeb4dbdf1589e0a7b6d3ed04d38fb7615a54f0d7af
parent1143e5a6d4d69cd36d44e0184769aa2b17041a10 (diff)
[Bluetooth] Support create connection cancel command
In case of non-blocking connects it is possible that the last user of an ACL link quits before the connection has been fully established. This will lead to a race condition where the internal state of a connection is closed, but the actual link has been established and is active. In case of Bluetooth 1.2 and later devices it is possible to call create connection cancel to abort the connect. For older devices the disconnect timer will be used to trigger the needed disconnect. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci.h6
-rw-r--r--include/net/bluetooth/hci_core.h9
-rw-r--r--net/bluetooth/hci_conn.c31
-rw-r--r--net/bluetooth/hci_event.c4
4 files changed, 43 insertions, 7 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 5f04181b8109..10a3eec191fd 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -297,6 +297,7 @@ struct hci_cp_host_buffer_size {
297 297
298/* Link Control */ 298/* Link Control */
299#define OGF_LINK_CTL 0x01 299#define OGF_LINK_CTL 0x01
300
300#define OCF_CREATE_CONN 0x0005 301#define OCF_CREATE_CONN 0x0005
301struct hci_cp_create_conn { 302struct hci_cp_create_conn {
302 bdaddr_t bdaddr; 303 bdaddr_t bdaddr;
@@ -307,6 +308,11 @@ struct hci_cp_create_conn {
307 __u8 role_switch; 308 __u8 role_switch;
308} __attribute__ ((packed)); 309} __attribute__ ((packed));
309 310
311#define OCF_CREATE_CONN_CANCEL 0x0008
312struct hci_cp_create_conn_cancel {
313 bdaddr_t bdaddr;
314} __attribute__ ((packed));
315
310#define OCF_ACCEPT_CONN_REQ 0x0009 316#define OCF_ACCEPT_CONN_REQ 0x0009
311struct hci_cp_accept_conn_req { 317struct hci_cp_accept_conn_req {
312 bdaddr_t bdaddr; 318 bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7451a9c92d9d..df22efcfcc0b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -316,10 +316,13 @@ static inline void hci_conn_put(struct hci_conn *conn)
316 if (atomic_dec_and_test(&conn->refcnt)) { 316 if (atomic_dec_and_test(&conn->refcnt)) {
317 unsigned long timeo; 317 unsigned long timeo;
318 if (conn->type == ACL_LINK) { 318 if (conn->type == ACL_LINK) {
319 timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
320 if (!conn->out)
321 timeo *= 2;
322 del_timer(&conn->idle_timer); 319 del_timer(&conn->idle_timer);
320 if (conn->state == BT_CONNECTED) {
321 timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
322 if (!conn->out)
323 timeo *= 2;
324 } else
325 timeo = msecs_to_jiffies(10);
323 } else 326 } else
324 timeo = msecs_to_jiffies(10); 327 timeo = msecs_to_jiffies(10);
325 mod_timer(&conn->disc_timer, jiffies + timeo); 328 mod_timer(&conn->disc_timer, jiffies + timeo);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7e9515b41cc0..90e3a285a17e 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -84,6 +84,20 @@ static void hci_acl_connect(struct hci_conn *conn)
84 hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp); 84 hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
85} 85}
86 86
87static void hci_acl_connect_cancel(struct hci_conn *conn)
88{
89 struct hci_cp_create_conn_cancel cp;
90
91 BT_DBG("%p", conn);
92
93 if (conn->hdev->hci_ver < 2)
94 return;
95
96 bacpy(&cp.bdaddr, &conn->dst);
97 hci_send_cmd(conn->hdev, OGF_LINK_CTL,
98 OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
99}
100
87void hci_acl_disconn(struct hci_conn *conn, __u8 reason) 101void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
88{ 102{
89 struct hci_cp_disconnect cp; 103 struct hci_cp_disconnect cp;
@@ -94,7 +108,8 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
94 108
95 cp.handle = __cpu_to_le16(conn->handle); 109 cp.handle = __cpu_to_le16(conn->handle);
96 cp.reason = reason; 110 cp.reason = reason;
97 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, sizeof(cp), &cp); 111 hci_send_cmd(conn->hdev, OGF_LINK_CTL,
112 OCF_DISCONNECT, sizeof(cp), &cp);
98} 113}
99 114
100void hci_add_sco(struct hci_conn *conn, __u16 handle) 115void hci_add_sco(struct hci_conn *conn, __u16 handle)
@@ -124,12 +139,20 @@ static void hci_conn_timeout(unsigned long arg)
124 return; 139 return;
125 140
126 hci_dev_lock(hdev); 141 hci_dev_lock(hdev);
127 if (conn->state == BT_CONNECTED) 142
143 switch (conn->state) {
144 case BT_CONNECT:
145 hci_acl_connect_cancel(conn);
146 break;
147 case BT_CONNECTED:
128 hci_acl_disconn(conn, 0x13); 148 hci_acl_disconn(conn, 0x13);
129 else 149 break;
150 default:
130 conn->state = BT_CLOSED; 151 conn->state = BT_CLOSED;
152 break;
153 }
154
131 hci_dev_unlock(hdev); 155 hci_dev_unlock(hdev);
132 return;
133} 156}
134 157
135static void hci_conn_idle(unsigned long arg) 158static void hci_conn_idle(unsigned long arg)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 7518bdbf34cd..bb25484b8747 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -750,6 +750,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
750 if (test_bit(HCI_ENCRYPT, &hdev->flags)) 750 if (test_bit(HCI_ENCRYPT, &hdev->flags))
751 conn->link_mode |= HCI_LM_ENCRYPT; 751 conn->link_mode |= HCI_LM_ENCRYPT;
752 752
753 hci_conn_hold(conn);
754
753 /* Get remote features */ 755 /* Get remote features */
754 if (conn->type == ACL_LINK) { 756 if (conn->type == ACL_LINK) {
755 struct hci_cp_read_remote_features cp; 757 struct hci_cp_read_remote_features cp;
@@ -778,6 +780,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
778 hci_send_cmd(hdev, OGF_LINK_CTL, 780 hci_send_cmd(hdev, OGF_LINK_CTL,
779 OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); 781 OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
780 } 782 }
783
784 hci_conn_put(conn);
781 } else 785 } else
782 conn->state = BT_CLOSED; 786 conn->state = BT_CLOSED;
783 787