[RFC] Bluetooth: Add support for using controller white list filtering

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

 



The Bluetooth controller can use a white list filter when scanning
to avoid waking up the host for devices that are of no interest.

Devices marked as reporting, direct connection (incoming) or general
connection are now added to the controller white list. The update of
the white list happens just before enabling passive scanning.

In case the white list is full and can not hold all devices, the
white list is not used and the filter policy set to accept all
advertisements.

Signed-off-by: Marcel Holtmann <marcel@xxxxxxxxxxxx>
---
 net/bluetooth/hci_core.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d8f91d5b0e56..543a8e35f702 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3636,6 +3636,13 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
 	if (params->auto_connect == auto_connect)
 		return 0;
 
+	/* Update setting for auto_connect so that when updating
+	 * the white list, the correct values are available. Any
+	 * changes to the controller white list will happen just
+	 * before enabling passive scanning.
+	 */
+	params->auto_connect = auto_connect;
+
 	list_del_init(&params->action);
 
 	switch (auto_connect) {
@@ -3656,8 +3663,6 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
 		break;
 	}
 
-	params->auto_connect = auto_connect;
-
 	BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
 	       auto_connect);
 
@@ -5406,12 +5411,84 @@ void hci_req_add_le_scan_disable(struct hci_request *req)
 	hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 }
 
+static u8 update_white_list(struct hci_request *req)
+{
+	struct hci_dev *hdev = req->hdev;
+	struct hci_conn_params *params;
+	struct bdaddr_list *b;
+	uint8_t white_list_entries = 0;
+
+	/* Go through the current white list programmed into the
+	 * controller one by one and check if that address is still
+	 * in the list of devices. If not present then queue the
+	 * command to remove it from the controller.
+	 */
+	list_for_each_entry(b, &hdev->le_white_list, list) {
+		struct hci_cp_le_del_from_white_list cp;
+
+		params = hci_conn_params_lookup(hdev, &b->bdaddr,
+						b->bdaddr_type);
+		if (params) {
+			if (params->auto_connect == HCI_AUTO_CONN_REPORT ||
+			    params->auto_connect == HCI_AUTO_CONN_DIRECT ||
+			    params->auto_connect == HCI_AUTO_CONN_ALWAYS) {
+				white_list_entries++;
+				continue;
+			}
+		}
+
+		cp.bdaddr_type = b->bdaddr_type;
+		bacpy(&cp.bdaddr, &b->bdaddr);
+
+		hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST,
+			    sizeof(cp), &cp);
+	}
+
+	/* Since all no longer valid white list entries have been
+	 * removed, walk through the list of devices and ensure
+	 * that any new device gets programmed into the controller.
+	 *
+	 * If the list of the devices is larger than the list of
+	 * available white list entries in the controller, then
+	 * just abort and return filer policy value to not use the
+	 * white list.
+	 */
+	list_for_each_entry(params, &hdev->le_conn_params, list) {
+		struct hci_cp_le_add_to_white_list cp;
+
+		if (params->auto_connect != HCI_AUTO_CONN_REPORT &&
+		    params->auto_connect != HCI_AUTO_CONN_DIRECT &&
+		    params->auto_connect != HCI_AUTO_CONN_ALWAYS)
+			continue;
+
+		if (hci_bdaddr_list_lookup(&hdev->le_white_list,
+					   &params->addr, params->addr_type))
+			continue;
+
+		if (white_list_entries >= hdev->le_white_list_size) {
+			/* Select filter policy to accept all advertising */
+			return 0x00;
+		}
+
+		white_list_entries++;
+
+		cp.bdaddr_type = params->addr_type;
+		bacpy(&cp.bdaddr, &params->addr);
+
+		hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp);
+	}
+
+	/* Select filter policy to use white list */
+	return 0x01;
+}
+
 void hci_req_add_le_passive_scan(struct hci_request *req)
 {
 	struct hci_cp_le_set_scan_param param_cp;
 	struct hci_cp_le_set_scan_enable enable_cp;
 	struct hci_dev *hdev = req->hdev;
 	u8 own_addr_type;
+	u8 filter_policy;
 
 	/* Set require_privacy to false since no SCAN_REQ are send
 	 * during passive scanning. Not using an unresolvable address
@@ -5422,11 +5499,18 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
 	if (hci_update_random_address(req, false, &own_addr_type))
 		return;
 
+	/* Adding or removing entries from the white list must
+	 * happen before enabling scanning. The controller does
+	 * not allow white list modification while scanning.
+	 */
+	filter_policy = update_white_list(req);
+
 	memset(&param_cp, 0, sizeof(param_cp));
 	param_cp.type = LE_SCAN_PASSIVE;
 	param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
 	param_cp.window = cpu_to_le16(hdev->le_scan_window);
 	param_cp.own_address_type = own_addr_type;
+	param_cp.filter_policy = filter_policy;
 	hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
 		    &param_cp);
 
-- 
1.9.3

--
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