[Bluetooth] Support concurrent connect requests
authorMarcel Holtmann <marcel@holtmann.org>
Sun, 15 Oct 2006 15:30:56 +0000 (17:30 +0200)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 16 Oct 2006 06:14:30 +0000 (23:14 -0700)
Most Bluetooth chips don't support concurrent connect requests, because
this would involve a multiple baseband page with only one radio. In the
case an upper layer like L2CAP requests a concurrent connect these chips
return the error "Command Disallowed" for the second request. If this
happens it the responsibility of the Bluetooth core to queue the request
and try again after the previous connect attempt has been completed.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci_core.h
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c

index df22efcfcc0b7deceb77ee1094a05d24f00c22d2..c0fc39620f3643c4393ba2b1d99c8181498b0da0 100644 (file)
@@ -153,6 +153,7 @@ struct hci_conn {
        __u8             mode;
        __u8             type;
        __u8             out;
+       __u8             attempt;
        __u8             dev_class[3];
        __u8             features[8];
        __u16            interval;
@@ -289,6 +290,22 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
        return NULL;
 }
 
+static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
+                                       __u8 type, __u16 state)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct list_head *p;
+       struct hci_conn  *c;
+
+       list_for_each(p, &h->list) {
+               c = list_entry(p, struct hci_conn, list);
+               if (c->type == type && c->state == state)
+                       return c;
+       }
+       return NULL;
+}
+
+void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
 
index 305a099b7477eb8fd0e4a7a7b487b7bd435e6677..a91fee4f27058f19f4301aae08ff0e3f20cd1e97 100644 (file)
@@ -48,7 +48,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.10"
+#define VERSION "2.11"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
index 90e3a285a17eaf9a4bde198879748d8a4da680a7..6cd5711fa28a59265403a81f608e6698e7f03dfa 100644 (file)
@@ -51,7 +51,7 @@
 #define BT_DBG(D...)
 #endif
 
-static void hci_acl_connect(struct hci_conn *conn)
+void hci_acl_connect(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
        struct inquiry_entry *ie;
@@ -63,6 +63,8 @@ static void hci_acl_connect(struct hci_conn *conn)
        conn->out   = 1;
        conn->link_mode = HCI_LM_MASTER;
 
+       conn->attempt++;
+
        memset(&cp, 0, sizeof(cp));
        bacpy(&cp.bdaddr, &conn->dst);
        cp.pscan_rep_mode = 0x02;
@@ -80,7 +82,7 @@ static void hci_acl_connect(struct hci_conn *conn)
                cp.role_switch  = 0x01;
        else
                cp.role_switch  = 0x00;
-               
+
        hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
 }
 
index d43d0c8909752564796b540a61cb58389cc8cb0d..65f094845719126013cfb9f3c1c19e11f4b2b566 100644 (file)
@@ -414,9 +414,12 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
-                       conn->state = BT_CLOSED;
-                       hci_proto_connect_cfm(conn, status);
-                       hci_conn_del(conn);
+                       if (status != 0x0c || conn->attempt > 2) {
+                               conn->state = BT_CLOSED;
+                               hci_proto_connect_cfm(conn, status);
+                               hci_conn_del(conn);
+                       } else
+                               conn->state = BT_CONNECT2;
                }
        } else {
                if (!conn) {
@@ -728,7 +731,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
-       struct hci_conn *conn;
+       struct hci_conn *conn, *pend;
 
        BT_DBG("%s", hdev->name);
 
@@ -801,6 +804,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (ev->status)
                hci_conn_del(conn);
 
+       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+       if (pend)
+               hci_acl_connect(pend);
+
        hci_dev_unlock(hdev);
 }