[RFC 06/16] Bluetooth: Fix stop_discovery()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



According to the Bluetooth spec, the inquiry cancel command should
only be issued after the inquiry command has been issued, a command
status event has been received for the inquiry command, and before
the inquiry complete event occurs.

As HCI_INQUIRY flag is only set just after an inquiry command status
event occurs and it is cleared just after an inquiry complete event
occurs, the inquiry cancel command should be issued only if HCI_INQUIRY
flag is set.

This spec constraint raises two possible race condition we must handle.

1. A MGMT_OP_STOP_DISCOVERY command is issued just after a
   MGMT_OP_START_DISCOVERY. The controller haven't sent the inquiry
   command status yet so the HCI_INQUIRY flag is not set.

2. While the MGMT_OP_STOP_DISCOVERY is being processed the controller
   sends the inquiry complete event and the HCI_INQUIRY flag is
   cleared.

Signed-off-by: Andre Guedes <andre.guedes@xxxxxxxxxxxxx>
---
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/hci_event.c        |   15 +++++++++++++--
 net/bluetooth/mgmt.c             |   14 ++++++++++++--
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index bfa5f0b..9bfcbb5 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -830,6 +830,7 @@ int mgmt_start_discovery_complete(u16 index);
 int mgmt_start_discovery_failed(u16 index);
 int mgmt_stop_discovery_complete(u16 index);
 int mgmt_stop_discovery_failed(u16 index);
+int mgmt_has_pending_stop_discov(u16 index);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0f8126d..540beb7 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -882,7 +882,10 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 
 	set_bit(HCI_INQUIRY, &hdev->flags);
 
-	mgmt_discovering(hdev->id, 1);
+	if (mgmt_has_pending_stop_discov(hdev->id))
+		hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+	else
+		mgmt_discovering(hdev->id, 1);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1269,8 +1272,16 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
+	hci_dev_lock(hdev);
+
 	mgmt_discovering(hdev->id, 0);
-	mgmt_start_discovery_complete(hdev->id);
+
+	if (mgmt_has_pending_stop_discov(hdev->id))
+		mgmt_stop_discovery_complete(hdev->id);
+	else
+		mgmt_start_discovery_complete(hdev->id);
+
+	hci_dev_unlock(hdev);
 }
 
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 70c7c77..12b7fcb 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1645,7 +1645,7 @@ static int stop_discovery(struct sock *sk, u16 index)
 {
 	struct hci_dev *hdev;
 	struct pending_cmd *cmd;
-	int err;
+	int err = 0;
 
 	BT_DBG("hci%u", index);
 
@@ -1672,7 +1672,9 @@ static int stop_discovery(struct sock *sk, u16 index)
 		goto failed;
 	}
 
-	err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+	if (test_bit(HCI_INQUIRY, &hdev->flags))
+		err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 
@@ -2271,3 +2273,11 @@ int mgmt_stop_discovery_failed(u16 index)
 
 	return err;
 }
+
+int mgmt_has_pending_stop_discov(u16 index)
+{
+	if (mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index))
+		return 1;
+
+	return 0;
+}
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux