aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Tervo <ville.tervo@nokia.com>2011-02-16 09:32:41 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-16 14:33:26 -0500
commit6bd32326cdaa9b14794416150c88e4832fb7e592 (patch)
tree4c48387761df0207bb50952dda7fd5c980893351
parent7f4b2b04c88377af30c022f36c060190182850fb (diff)
Bluetooth: Use proper timer for hci command timout
Use proper timer instead of hci command flow control to timeout failed hci commands. Otherwise stack ends up sending commands when flow control is used to block new commands. 2010-09-01 18:29:41.592132 < HCI Command: Remote Name Request (0x01|0x0019) plen 10 bdaddr 00:16:CF:E1:C7:D7 mode 2 clkoffset 0x0000 2010-09-01 18:29:41.592681 > HCI Event: Command Status (0x0f) plen 4 Remote Name Request (0x01|0x0019) status 0x00 ncmd 0 2010-09-01 18:29:51.022033 < HCI Command: Remote Name Request Cancel (0x01|0x001a) plen 6 bdaddr 00:16:CF:E1:C7:D7 Signed-off-by: Ville Tervo <ville.tervo@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r--include/net/bluetooth/hci.h3
-rw-r--r--include/net/bluetooth/hci_core.h2
-rw-r--r--net/bluetooth/hci_core.c22
-rw-r--r--net/bluetooth/hci_event.c6
4 files changed, 26 insertions, 7 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index e756f82a29e5..6d4e11624fef 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -119,6 +119,7 @@ enum {
119#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ 119#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
120#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ 120#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
121#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ 121#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
122#define HCI_CMD_TIMEOUT (1000) /* 1 seconds */
122 123
123/* HCI data types */ 124/* HCI data types */
124#define HCI_COMMAND_PKT 0x01 125#define HCI_COMMAND_PKT 0x01
@@ -244,6 +245,8 @@ enum {
244#define HCI_AT_GENERAL_BONDING_MITM 0x05 245#define HCI_AT_GENERAL_BONDING_MITM 0x05
245 246
246/* ----- HCI Commands ---- */ 247/* ----- HCI Commands ---- */
248#define HCI_OP_NOP 0x0000
249
247#define HCI_OP_INQUIRY 0x0401 250#define HCI_OP_INQUIRY 0x0401
248struct hci_cp_inquiry { 251struct hci_cp_inquiry {
249 __u8 lap[3]; 252 __u8 lap[3];
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d30b93c82fd4..ecd2acf24420 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -132,7 +132,6 @@ struct hci_dev {
132 unsigned int sco_pkts; 132 unsigned int sco_pkts;
133 unsigned int le_pkts; 133 unsigned int le_pkts;
134 134
135 unsigned long cmd_last_tx;
136 unsigned long acl_last_tx; 135 unsigned long acl_last_tx;
137 unsigned long sco_last_tx; 136 unsigned long sco_last_tx;
138 unsigned long le_last_tx; 137 unsigned long le_last_tx;
@@ -143,6 +142,7 @@ struct hci_dev {
143 struct work_struct power_off; 142 struct work_struct power_off;
144 struct timer_list off_timer; 143 struct timer_list off_timer;
145 144
145 struct timer_list cmd_timer;
146 struct tasklet_struct cmd_task; 146 struct tasklet_struct cmd_task;
147 struct tasklet_struct rx_task; 147 struct tasklet_struct rx_task;
148 struct tasklet_struct tx_task; 148 struct tasklet_struct tx_task;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c01415bc8946..702d5651c656 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -41,6 +41,7 @@
41#include <linux/interrupt.h> 41#include <linux/interrupt.h>
42#include <linux/notifier.h> 42#include <linux/notifier.h>
43#include <linux/rfkill.h> 43#include <linux/rfkill.h>
44#include <linux/timer.h>
44#include <net/sock.h> 45#include <net/sock.h>
45 46
46#include <asm/system.h> 47#include <asm/system.h>
@@ -623,6 +624,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
623 624
624 /* Drop last sent command */ 625 /* Drop last sent command */
625 if (hdev->sent_cmd) { 626 if (hdev->sent_cmd) {
627 del_timer_sync(&hdev->cmd_timer);
626 kfree_skb(hdev->sent_cmd); 628 kfree_skb(hdev->sent_cmd);
627 hdev->sent_cmd = NULL; 629 hdev->sent_cmd = NULL;
628 } 630 }
@@ -1066,6 +1068,16 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
1066 return 0; 1068 return 0;
1067} 1069}
1068 1070
1071/* HCI command timer function */
1072static void hci_cmd_timer(unsigned long arg)
1073{
1074 struct hci_dev *hdev = (void *) arg;
1075
1076 BT_ERR("%s command tx timeout", hdev->name);
1077 atomic_set(&hdev->cmd_cnt, 1);
1078 tasklet_schedule(&hdev->cmd_task);
1079}
1080
1069/* Register HCI device */ 1081/* Register HCI device */
1070int hci_register_dev(struct hci_dev *hdev) 1082int hci_register_dev(struct hci_dev *hdev)
1071{ 1083{
@@ -1112,6 +1124,8 @@ int hci_register_dev(struct hci_dev *hdev)
1112 skb_queue_head_init(&hdev->cmd_q); 1124 skb_queue_head_init(&hdev->cmd_q);
1113 skb_queue_head_init(&hdev->raw_q); 1125 skb_queue_head_init(&hdev->raw_q);
1114 1126
1127 setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
1128
1115 for (i = 0; i < NUM_REASSEMBLY; i++) 1129 for (i = 0; i < NUM_REASSEMBLY; i++)
1116 hdev->reassembly[i] = NULL; 1130 hdev->reassembly[i] = NULL;
1117 1131
@@ -2004,11 +2018,6 @@ static void hci_cmd_task(unsigned long arg)
2004 2018
2005 BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); 2019 BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
2006 2020
2007 if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
2008 BT_ERR("%s command tx timeout", hdev->name);
2009 atomic_set(&hdev->cmd_cnt, 1);
2010 }
2011
2012 /* Send queued commands */ 2021 /* Send queued commands */
2013 if (atomic_read(&hdev->cmd_cnt)) { 2022 if (atomic_read(&hdev->cmd_cnt)) {
2014 skb = skb_dequeue(&hdev->cmd_q); 2023 skb = skb_dequeue(&hdev->cmd_q);
@@ -2021,7 +2030,8 @@ static void hci_cmd_task(unsigned long arg)
2021 if (hdev->sent_cmd) { 2030 if (hdev->sent_cmd) {
2022 atomic_dec(&hdev->cmd_cnt); 2031 atomic_dec(&hdev->cmd_cnt);
2023 hci_send_frame(skb); 2032 hci_send_frame(skb);
2024 hdev->cmd_last_tx = jiffies; 2033 mod_timer(&hdev->cmd_timer,
2034 jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
2025 } else { 2035 } else {
2026 skb_queue_head(&hdev->cmd_q, skb); 2036 skb_queue_head(&hdev->cmd_q, skb);
2027 tasklet_schedule(&hdev->cmd_task); 2037 tasklet_schedule(&hdev->cmd_task);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 74f04a27734d..09cb29e8713a 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1732,6 +1732,9 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
1732 break; 1732 break;
1733 } 1733 }
1734 1734
1735 if (ev->opcode != HCI_OP_NOP)
1736 del_timer(&hdev->cmd_timer);
1737
1735 if (ev->ncmd) { 1738 if (ev->ncmd) {
1736 atomic_set(&hdev->cmd_cnt, 1); 1739 atomic_set(&hdev->cmd_cnt, 1);
1737 if (!skb_queue_empty(&hdev->cmd_q)) 1740 if (!skb_queue_empty(&hdev->cmd_q))
@@ -1807,6 +1810,9 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
1807 break; 1810 break;
1808 } 1811 }
1809 1812
1813 if (ev->opcode != HCI_OP_NOP)
1814 del_timer(&hdev->cmd_timer);
1815
1810 if (ev->ncmd) { 1816 if (ev->ncmd) {
1811 atomic_set(&hdev->cmd_cnt, 1); 1817 atomic_set(&hdev->cmd_cnt, 1);
1812 if (!skb_queue_empty(&hdev->cmd_q)) 1818 if (!skb_queue_empty(&hdev->cmd_q))