Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8bb6b97 authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann
Browse files

Bluetooth: Fix advertising and active scanning co-existence



Many controllers allow simultaneous active scanning and advertising
(e.g. Intel and Broadcom) but some do not (e.g. CSR). It's therefore
safest to implement mutual exclusion of these states in the kernel.

This patch ensures that the two states are never entered simultaneously.
Extra precaution needs to be taken for outgoing connection attempts in
slave role (i.e. through directed advertising) in which case the
operation that came first has precedence and the one that comes after
gets a rejection.

Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 376f54c1
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -772,6 +772,16 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,


	/* If requested to connect as slave use directed advertising */
	/* If requested to connect as slave use directed advertising */
	if (!master) {
	if (!master) {
		/* If we're active scanning most controllers are unable
		 * to initiate advertising. Simply reject the attempt.
		 */
		if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
		    hdev->le_scan_type == LE_SCAN_ACTIVE) {
			skb_queue_purge(&req.cmd_q);
			hci_conn_del(conn);
			return ERR_PTR(-EBUSY);
		}

		hci_req_directed_advertising(&req, conn);
		hci_req_directed_advertising(&req, conn);
		goto create_conn;
		goto create_conn;
	}
	}
+9 −1
Original line number Original line Diff line number Diff line
@@ -1176,13 +1176,21 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
		cancel_delayed_work(&hdev->le_scan_disable);
		cancel_delayed_work(&hdev->le_scan_disable);


		clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
		clear_bit(HCI_LE_SCAN, &hdev->dev_flags);

		/* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
		/* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
		 * interrupted scanning due to a connect request. Mark
		 * interrupted scanning due to a connect request. Mark
		 * therefore discovery as stopped.
		 * therefore discovery as stopped. If this was not
		 * because of a connect request advertising might have
		 * been disabled because of active scanning, so
		 * re-enable it again if necessary.
		 */
		 */
		if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED,
		if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED,
				       &hdev->dev_flags))
				       &hdev->dev_flags))
			hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
			hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
		else if (!test_bit(HCI_LE_ADV, &hdev->dev_flags) &&
			 hdev->discovery.state != DISCOVERY_STARTING)
			mgmt_reenable_advertising(hdev);

		break;
		break;


	default:
	default:
+18 −6
Original line number Original line Diff line number Diff line
@@ -3726,13 +3726,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
			goto failed;
			goto failed;
		}
		}


		if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
		if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) {
			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
			/* Don't let discovery abort an outgoing
			 * connection attempt that's using directed
			 * advertising.
			 */
			if (hci_conn_hash_lookup_state(hdev, LE_LINK,
						       BT_CONNECT)) {
				err = cmd_status(sk, hdev->id,
						 MGMT_OP_START_DISCOVERY,
						 MGMT_STATUS_REJECTED);
						 MGMT_STATUS_REJECTED);
				mgmt_pending_remove(cmd);
				mgmt_pending_remove(cmd);
				goto failed;
				goto failed;
			}
			}


			disable_advertising(&req);
		}

		/* If controller is scanning, it means the background scanning
		/* If controller is scanning, it means the background scanning
		 * is running. Thus, we should temporarily stop it in order to
		 * is running. Thus, we should temporarily stop it in order to
		 * set the discovery scanning parameters.
		 * set the discovery scanning parameters.
@@ -4078,7 +4088,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
	 * necessary).
	 * necessary).
	 */
	 */
	if (!hdev_is_powered(hdev) || val == enabled ||
	if (!hdev_is_powered(hdev) || val == enabled ||
	    hci_conn_num(hdev, LE_LINK) > 0) {
	    hci_conn_num(hdev, LE_LINK) > 0 ||
	    (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
	     hdev->le_scan_type == LE_SCAN_ACTIVE)) {
		bool changed = false;
		bool changed = false;


		if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
		if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {