Commit 23bb57633df97ede067ea26f3cdc8a7ba2cd8109
Committed by
Gustavo F. Padovan
1 parent
c71e97bfaa
Exists in
master
and in
7 other branches
Bluetooth: Fix __hci_request synchronization for hci_open_dev
The initialization function used by hci_open_dev (hci_init_req) sends many different HCI commands. The __hci_request function should only return when all of these commands have completed (or a timeout occurs). Several of these commands cause hci_req_complete to be called which causes __hci_request to return prematurely. This patch fixes the issue by adding a new hdev->req_last_cmd variable which is set during the initialization procedure. The hci_req_complete function will no longer mark the request as complete until the command matching hdev->req_last_cmd completes. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Showing 3 changed files with 37 additions and 14 deletions Side-by-side Diff
include/net/bluetooth/hci_core.h
... | ... | @@ -129,6 +129,7 @@ |
129 | 129 | wait_queue_head_t req_wait_q; |
130 | 130 | __u32 req_status; |
131 | 131 | __u32 req_result; |
132 | + __u16 req_last_cmd; | |
132 | 133 | |
133 | 134 | struct inquiry_cache inq_cache; |
134 | 135 | struct hci_conn_hash conn_hash; |
... | ... | @@ -693,7 +694,7 @@ |
693 | 694 | #define hci_req_lock(d) mutex_lock(&d->req_lock) |
694 | 695 | #define hci_req_unlock(d) mutex_unlock(&d->req_lock) |
695 | 696 | |
696 | -void hci_req_complete(struct hci_dev *hdev, int result); | |
697 | +void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result); | |
697 | 698 | |
698 | 699 | #endif /* __HCI_CORE_H */ |
net/bluetooth/hci_core.c
... | ... | @@ -91,10 +91,17 @@ |
91 | 91 | |
92 | 92 | /* ---- HCI requests ---- */ |
93 | 93 | |
94 | -void hci_req_complete(struct hci_dev *hdev, int result) | |
94 | +void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) | |
95 | 95 | { |
96 | - BT_DBG("%s result 0x%2.2x", hdev->name, result); | |
96 | + BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result); | |
97 | 97 | |
98 | + /* If the request has set req_last_cmd (typical for multi-HCI | |
99 | + * command requests) check if the completed command matches | |
100 | + * this, and if not just return. Single HCI command requests | |
101 | + * typically leave req_last_cmd as 0 */ | |
102 | + if (hdev->req_last_cmd && cmd != hdev->req_last_cmd) | |
103 | + return; | |
104 | + | |
98 | 105 | if (hdev->req_status == HCI_REQ_PEND) { |
99 | 106 | hdev->req_result = result; |
100 | 107 | hdev->req_status = HCI_REQ_DONE; |
... | ... | @@ -149,7 +156,7 @@ |
149 | 156 | break; |
150 | 157 | } |
151 | 158 | |
152 | - hdev->req_status = hdev->req_result = 0; | |
159 | + hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0; | |
153 | 160 | |
154 | 161 | BT_DBG("%s end: err %d", hdev->name, err); |
155 | 162 | |
... | ... | @@ -252,6 +259,8 @@ |
252 | 259 | /* Connection accept timeout ~20 secs */ |
253 | 260 | param = cpu_to_le16(0x7d00); |
254 | 261 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); |
262 | + | |
263 | + hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT; | |
255 | 264 | } |
256 | 265 | |
257 | 266 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) |
net/bluetooth/hci_event.c
... | ... | @@ -58,7 +58,7 @@ |
58 | 58 | |
59 | 59 | clear_bit(HCI_INQUIRY, &hdev->flags); |
60 | 60 | |
61 | - hci_req_complete(hdev, status); | |
61 | + hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); | |
62 | 62 | |
63 | 63 | hci_conn_check_pending(hdev); |
64 | 64 | } |
... | ... | @@ -174,7 +174,7 @@ |
174 | 174 | if (!status) |
175 | 175 | hdev->link_policy = get_unaligned_le16(sent); |
176 | 176 | |
177 | - hci_req_complete(hdev, status); | |
177 | + hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status); | |
178 | 178 | } |
179 | 179 | |
180 | 180 | static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) |
... | ... | @@ -183,7 +183,7 @@ |
183 | 183 | |
184 | 184 | BT_DBG("%s status 0x%x", hdev->name, status); |
185 | 185 | |
186 | - hci_req_complete(hdev, status); | |
186 | + hci_req_complete(hdev, HCI_OP_RESET, status); | |
187 | 187 | } |
188 | 188 | |
189 | 189 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) |
... | ... | @@ -235,7 +235,7 @@ |
235 | 235 | clear_bit(HCI_AUTH, &hdev->flags); |
236 | 236 | } |
237 | 237 | |
238 | - hci_req_complete(hdev, status); | |
238 | + hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status); | |
239 | 239 | } |
240 | 240 | |
241 | 241 | static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) |
... | ... | @@ -258,7 +258,7 @@ |
258 | 258 | clear_bit(HCI_ENCRYPT, &hdev->flags); |
259 | 259 | } |
260 | 260 | |
261 | - hci_req_complete(hdev, status); | |
261 | + hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status); | |
262 | 262 | } |
263 | 263 | |
264 | 264 | static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) |
... | ... | @@ -285,7 +285,7 @@ |
285 | 285 | set_bit(HCI_PSCAN, &hdev->flags); |
286 | 286 | } |
287 | 287 | |
288 | - hci_req_complete(hdev, status); | |
288 | + hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status); | |
289 | 289 | } |
290 | 290 | |
291 | 291 | static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) |
... | ... | @@ -383,7 +383,7 @@ |
383 | 383 | |
384 | 384 | BT_DBG("%s status 0x%x", hdev->name, status); |
385 | 385 | |
386 | - hci_req_complete(hdev, status); | |
386 | + hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status); | |
387 | 387 | } |
388 | 388 | |
389 | 389 | static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) |
390 | 390 | |
391 | 391 | |
... | ... | @@ -536,15 +536,24 @@ |
536 | 536 | if (!rp->status) |
537 | 537 | bacpy(&hdev->bdaddr, &rp->bdaddr); |
538 | 538 | |
539 | - hci_req_complete(hdev, rp->status); | |
539 | + hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status); | |
540 | 540 | } |
541 | 541 | |
542 | +static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb) | |
543 | +{ | |
544 | + __u8 status = *((__u8 *) skb->data); | |
545 | + | |
546 | + BT_DBG("%s status 0x%x", hdev->name, status); | |
547 | + | |
548 | + hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status); | |
549 | +} | |
550 | + | |
542 | 551 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
543 | 552 | { |
544 | 553 | BT_DBG("%s status 0x%x", hdev->name, status); |
545 | 554 | |
546 | 555 | if (status) { |
547 | - hci_req_complete(hdev, status); | |
556 | + hci_req_complete(hdev, HCI_OP_INQUIRY, status); | |
548 | 557 | |
549 | 558 | hci_conn_check_pending(hdev); |
550 | 559 | } else |
... | ... | @@ -871,7 +880,7 @@ |
871 | 880 | |
872 | 881 | clear_bit(HCI_INQUIRY, &hdev->flags); |
873 | 882 | |
874 | - hci_req_complete(hdev, status); | |
883 | + hci_req_complete(hdev, HCI_OP_INQUIRY, status); | |
875 | 884 | |
876 | 885 | hci_conn_check_pending(hdev); |
877 | 886 | } |
... | ... | @@ -1377,6 +1386,10 @@ |
1377 | 1386 | |
1378 | 1387 | case HCI_OP_READ_BD_ADDR: |
1379 | 1388 | hci_cc_read_bd_addr(hdev, skb); |
1389 | + break; | |
1390 | + | |
1391 | + case HCI_OP_WRITE_CA_TIMEOUT: | |
1392 | + hci_cc_write_ca_timeout(hdev, skb); | |
1380 | 1393 | break; |
1381 | 1394 | |
1382 | 1395 | default: |