aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-09-13 01:58:18 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2013-09-18 13:39:23 -0400
commitbf5430360ebe4b2d0c51d91f782e649107b502eb (patch)
tree676531272b9aca18360c87395d062a12dddabf8f /net
parent5e130367d43ff22836bbae380d197d600fe8ddbb (diff)
Bluetooth: Fix rfkill functionality during the HCI setup stage
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> Cc: stable@vger.kernel.org Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
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 0d5bc246b607..1b66547a3ca6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1146,7 +1146,11 @@ int hci_dev_open(__u16 dev)
1146 goto done; 1146 goto done;
1147 } 1147 }
1148 1148
1149 if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) { 1149 /* Check for rfkill but allow the HCI setup stage to proceed
1150 * (which in itself doesn't cause any RF activity).
1151 */
1152 if (test_bit(HCI_RFKILLED, &hdev->dev_flags) &&
1153 !test_bit(HCI_SETUP, &hdev->dev_flags)) {
1150 ret = -ERFKILL; 1154 ret = -ERFKILL;
1151 goto done; 1155 goto done;
1152 } 1156 }
@@ -1568,7 +1572,8 @@ static int hci_rfkill_set_block(void *data, bool blocked)
1568 1572
1569 if (blocked) { 1573 if (blocked) {
1570 set_bit(HCI_RFKILLED, &hdev->dev_flags); 1574 set_bit(HCI_RFKILLED, &hdev->dev_flags);
1571 hci_dev_do_close(hdev); 1575 if (!test_bit(HCI_SETUP, &hdev->dev_flags))
1576 hci_dev_do_close(hdev);
1572 } else { 1577 } else {
1573 clear_bit(HCI_RFKILLED, &hdev->dev_flags); 1578 clear_bit(HCI_RFKILLED, &hdev->dev_flags);
1574} 1579}
@@ -1593,9 +1598,13 @@ static void hci_power_on(struct work_struct *work)
1593 return; 1598 return;
1594 } 1599 }
1595 1600
1596 if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) 1601 if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) {
1602 clear_bit(HCI_AUTO_OFF, &hdev->dev_flags);
1603 hci_dev_do_close(hdev);
1604 } else if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
1597 queue_delayed_work(hdev->req_workqueue, &hdev->power_off, 1605 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1598 HCI_AUTO_OFF_TIMEOUT); 1606 HCI_AUTO_OFF_TIMEOUT);
1607 }
1599 1608
1600 if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) 1609 if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
1601 mgmt_index_added(hdev); 1610 mgmt_index_added(hdev);