aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-09-13 01:58:18 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-13 19:08:32 -0400
commit230352711ef9d819bff5ccc18d407bfd5f51ef81 (patch)
treee3df22deb5f09f9e79f7c90aacef8aeb382d514f /net
parentddc650c1b220e15a831ebc1624504a590ee0e8d9 (diff)
Bluetooth: Fix rfkill functionality during the HCI setup stage
commit bf5430360ebe4b2d0c51d91f782e649107b502eb upstream. We need to let the setup stage complete cleanly even when the HCI device is rfkilled. Otherwise the HCI device will stay in an undefined state and never get notified to user space through mgmt (even when it gets unblocked through rfkill). This patch makes sure that hci_dev_open() can be called in the HCI_SETUP stage, that blocking the device doesn't abort the setup stage, and that the device gets proper powered down as soon as the setup stage completes in case it was blocked meanwhile. The bug that this patch fixed can be very easily reproduced using e.g. the rfkill command line too. By running "rfkill block all" before inserting a Bluetooth dongle the resulting HCI device goes into a state where it is never announced over mgmt, not even when "rfkill unblock all" is run. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/hci_core.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 45c91b27d9d1..7c88f5f83598 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1123,7 +1123,11 @@ int hci_dev_open(__u16 dev)
1123 goto done; 1123 goto done;
1124 } 1124 }
1125 1125
1126 if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) { 1126 /* Check for rfkill but allow the HCI setup stage to proceed
1127 * (which in itself doesn't cause any RF activity).
1128 */
1129 if (test_bit(HCI_RFKILLED, &hdev->dev_flags) &&
1130 !test_bit(HCI_SETUP, &hdev->dev_flags)) {
1127 ret = -ERFKILL; 1131 ret = -ERFKILL;
1128 goto done; 1132 goto done;
1129 } 1133 }
@@ -1547,7 +1551,8 @@ static int hci_rfkill_set_block(void *data, bool blocked)
1547 1551
1548 if (blocked) { 1552 if (blocked) {
1549 set_bit(HCI_RFKILLED, &hdev->dev_flags); 1553 set_bit(HCI_RFKILLED, &hdev->dev_flags);
1550 hci_dev_do_close(hdev); 1554 if (!test_bit(HCI_SETUP, &hdev->dev_flags))
1555 hci_dev_do_close(hdev);
1551 } else { 1556 } else {
1552 clear_bit(HCI_RFKILLED, &hdev->dev_flags); 1557 clear_bit(HCI_RFKILLED, &hdev->dev_flags);
1553} 1558}
@@ -1572,9 +1577,13 @@ static void hci_power_on(struct work_struct *work)
1572 return; 1577 return;
1573 } 1578 }
1574 1579
1575 if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) 1580 if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) {
1581 clear_bit(HCI_AUTO_OFF, &hdev->dev_flags);
1582 hci_dev_do_close(hdev);
1583 } else if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
1576 queue_delayed_work(hdev->req_workqueue, &hdev->power_off, 1584 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1577 HCI_AUTO_OFF_TIMEOUT); 1585 HCI_AUTO_OFF_TIMEOUT);
1586 }
1578 1587
1579 if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) 1588 if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
1580 mgmt_index_added(hdev); 1589 mgmt_index_added(hdev);