Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[Bluetooth] Support concurrent connect requests

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>

authored by

Marcel Holtmann and committed by
David S. Miller
4c67bc74 e9c4bec6

+33 -7
+17
include/net/bluetooth/hci_core.h
··· 153 153 __u8 mode; 154 154 __u8 type; 155 155 __u8 out; 156 + __u8 attempt; 156 157 __u8 dev_class[3]; 157 158 __u8 features[8]; 158 159 __u16 interval; ··· 290 289 return NULL; 291 290 } 292 291 292 + static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, 293 + __u8 type, __u16 state) 294 + { 295 + struct hci_conn_hash *h = &hdev->conn_hash; 296 + struct list_head *p; 297 + struct hci_conn *c; 298 + 299 + list_for_each(p, &h->list) { 300 + c = list_entry(p, struct hci_conn, list); 301 + if (c->type == type && c->state == state) 302 + return c; 303 + } 304 + return NULL; 305 + } 306 + 307 + void hci_acl_connect(struct hci_conn *conn); 293 308 void hci_acl_disconn(struct hci_conn *conn, __u8 reason); 294 309 void hci_add_sco(struct hci_conn *conn, __u16 handle); 295 310
+1 -1
net/bluetooth/af_bluetooth.c
··· 48 48 #define BT_DBG(D...) 49 49 #endif 50 50 51 - #define VERSION "2.10" 51 + #define VERSION "2.11" 52 52 53 53 /* Bluetooth sockets */ 54 54 #define BT_MAX_PROTO 8
+4 -2
net/bluetooth/hci_conn.c
··· 51 51 #define BT_DBG(D...) 52 52 #endif 53 53 54 - static void hci_acl_connect(struct hci_conn *conn) 54 + void hci_acl_connect(struct hci_conn *conn) 55 55 { 56 56 struct hci_dev *hdev = conn->hdev; 57 57 struct inquiry_entry *ie; ··· 62 62 conn->state = BT_CONNECT; 63 63 conn->out = 1; 64 64 conn->link_mode = HCI_LM_MASTER; 65 + 66 + conn->attempt++; 65 67 66 68 memset(&cp, 0, sizeof(cp)); 67 69 bacpy(&cp.bdaddr, &conn->dst); ··· 82 80 cp.role_switch = 0x01; 83 81 else 84 82 cp.role_switch = 0x00; 85 - 83 + 86 84 hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp); 87 85 } 88 86
+11 -4
net/bluetooth/hci_event.c
··· 414 414 415 415 if (status) { 416 416 if (conn && conn->state == BT_CONNECT) { 417 - conn->state = BT_CLOSED; 418 - hci_proto_connect_cfm(conn, status); 419 - hci_conn_del(conn); 417 + if (status != 0x0c || conn->attempt > 2) { 418 + conn->state = BT_CLOSED; 419 + hci_proto_connect_cfm(conn, status); 420 + hci_conn_del(conn); 421 + } else 422 + conn->state = BT_CONNECT2; 420 423 } 421 424 } else { 422 425 if (!conn) { ··· 731 728 static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) 732 729 { 733 730 struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; 734 - struct hci_conn *conn; 731 + struct hci_conn *conn, *pend; 735 732 736 733 BT_DBG("%s", hdev->name); 737 734 ··· 803 800 hci_proto_connect_cfm(conn, ev->status); 804 801 if (ev->status) 805 802 hci_conn_del(conn); 803 + 804 + pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); 805 + if (pend) 806 + hci_acl_connect(pend); 806 807 807 808 hci_dev_unlock(hdev); 808 809 }