Bluetooth: close HCI device when user channel socket gets closed
authorSimon Fels <simon.fels@canonical.com>
Wed, 2 Sep 2015 10:10:12 +0000 (12:10 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 17 Sep 2015 11:20:02 +0000 (13:20 +0200)
With 9380f9eacfbbee701daa416edd6625efcd3e29e1 the order of unsetting
the HCI_USER_CHANNEL flag of the HCI device was reverted to ensure
the device is first closed before making it available again.

Due to hci_dev_close checking for HCI_USER_CHANNEL being set on the
device it was never really closed and was kept opened. We're now
calling hci_dev_do_close directly to make sure the device is correctly
closed and we keep the correct order to unset the flag on our device
object.

Signed-off-by: Simon Fels <simon.fels@canonical.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c
net/bluetooth/hci_sock.c

index 9e1a59e01fa2f6316ae950833974aa628761cf51..256e6734c1fbf93f025a3ebbb1ced9fae4002550 100644 (file)
@@ -987,6 +987,7 @@ int hci_resume_dev(struct hci_dev *hdev);
 int hci_reset_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
 int hci_dev_close(__u16 dev);
+int hci_dev_do_close(struct hci_dev *hdev);
 int hci_dev_reset(__u16 dev);
 int hci_dev_reset_stat(__u16 dev);
 int hci_dev_cmd(unsigned int cmd, void __user *arg);
index 5a3602046a8bc6b14bf19cf5227db640e690b906..a7cdd99ec3f1688b62ccca001bf9522daff2b273 100644 (file)
@@ -1549,7 +1549,7 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev)
        BT_DBG("All LE pending actions cleared");
 }
 
-static int hci_dev_do_close(struct hci_dev *hdev)
+int hci_dev_do_close(struct hci_dev *hdev)
 {
        BT_DBG("%s %p", hdev->name, hdev);
 
index f2d30d1156c92ed7cb8c05dfbe737f1615ad50a7..150556345263357a04a6bf2eb53382894a374349 100644 (file)
@@ -503,7 +503,16 @@ static int hci_sock_release(struct socket *sock)
 
        if (hdev) {
                if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
-                       hci_dev_close(hdev->id);
+                       /* When releasing an user channel exclusive access,
+                        * call hci_dev_do_close directly instead of calling
+                        * hci_dev_close to ensure the exclusive access will
+                        * be released and the controller brought back down.
+                        *
+                        * The checking of HCI_AUTO_OFF is not needed in this
+                        * case since it will have been cleared already when
+                        * opening the user channel.
+                        */
+                       hci_dev_do_close(hdev);
                        hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
                        mgmt_index_added(hdev);
                }