diff mbox series

[BlueZ,v2,2/4] adapter: Implement SetFilterPolicy AutoConnect filter

Message ID 20250523142505.3476436-2-luiz.dentz@gmail.com
State New
Headers show
Series None | expand

Commit Message

Luiz Augusto von Dentz May 23, 2025, 2:25 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This implements AutoConnect filter option in SetFilterPolicy method
according to its documentation.
---
 src/adapter.c |  55 +++++++++++++++++++++----
 src/device.c  | 111 +++++++++++++++++++++++++++-----------------------
 2 files changed, 107 insertions(+), 59 deletions(-)
diff mbox series

Patch

diff --git a/src/adapter.c b/src/adapter.c
index fd425e6d2fe4..6f0699302257 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -214,6 +214,7 @@  struct discovery_filter {
 	GSList *uuids;
 	bool duplicate;
 	bool discoverable;
+	bool auto_connect;
 };
 
 struct discovery_client {
@@ -2697,6 +2698,21 @@  static bool parse_pattern(DBusMessageIter *value,
 	return true;
 }
 
+static bool parse_auto_connect(DBusMessageIter *value,
+					struct discovery_filter *filter)
+{
+	dbus_bool_t connect;
+
+	if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
+		return false;
+
+	dbus_message_iter_get_basic(value, &connect);
+
+	filter->auto_connect = connect;
+
+	return true;
+}
+
 struct filter_parser {
 	const char *name;
 	bool (*func)(DBusMessageIter *iter, struct discovery_filter *filter);
@@ -2708,6 +2724,7 @@  struct filter_parser {
 	{ "DuplicateData", parse_duplicate_data },
 	{ "Discoverable", parse_discoverable },
 	{ "Pattern", parse_pattern },
+	{ "AutoConnect", parse_auto_connect },
 	{ }
 };
 
@@ -2748,6 +2765,7 @@  static bool parse_discovery_filter_dict(struct btd_adapter *adapter,
 	(*filter)->type = get_scan_type(adapter);
 	(*filter)->duplicate = false;
 	(*filter)->discoverable = false;
+	(*filter)->auto_connect = false;
 	(*filter)->pattern = NULL;
 
 	dbus_message_iter_init(msg, &iter);
@@ -2794,11 +2812,12 @@  static bool parse_discovery_filter_dict(struct btd_adapter *adapter,
 		goto invalid_args;
 
 	DBG("filtered discovery params: transport: %d rssi: %d pathloss: %d "
-		" duplicate data: %s discoverable %s pattern %s",
+		" duplicate data: %s discoverable %s pattern %s auto-connect %s",
 		(*filter)->type, (*filter)->rssi, (*filter)->pathloss,
 		(*filter)->duplicate ? "true" : "false",
 		(*filter)->discoverable ? "true" : "false",
-		(*filter)->pattern);
+		(*filter)->pattern,
+		(*filter)->auto_connect ? "true" : "false");
 
 	return true;
 
@@ -7212,7 +7231,7 @@  static void filter_duplicate_data(void *data, void *user_data)
 
 static bool device_is_discoverable(struct btd_adapter *adapter,
 					struct eir_data *eir, const char *addr,
-					uint8_t bdaddr_type)
+					uint8_t bdaddr_type, bool *auto_connect)
 {
 	GSList *l;
 	bool discoverable;
@@ -7242,15 +7261,21 @@  static bool device_is_discoverable(struct btd_adapter *adapter,
 		discoverable = false;
 
 		pattern_len = strlen(filter->pattern);
-		if (!pattern_len)
+		if (!pattern_len) {
+			*auto_connect = filter->auto_connect;
 			return true;
+		}
 
-		if (!strncmp(filter->pattern, addr, pattern_len))
+		if (!strncmp(filter->pattern, addr, pattern_len)) {
+			*auto_connect = filter->auto_connect;
 			return true;
+		}
 
 		if (eir->name && !strncmp(filter->pattern, eir->name,
-							pattern_len))
+							pattern_len)) {
+			*auto_connect = filter->auto_connect;
 			return true;
+		}
 	}
 
 	return discoverable;
@@ -7274,6 +7299,7 @@  void btd_adapter_device_found(struct btd_adapter *adapter,
 	bool name_resolve_failed;
 	bool scan_rsp;
 	bool duplicate = false;
+	bool auto_connect = false;
 	struct queue *matched_monitors = NULL;
 
 	confirm = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
@@ -7310,7 +7336,7 @@  void btd_adapter_device_found(struct btd_adapter *adapter,
 	ba2str(bdaddr, addr);
 
 	discoverable = device_is_discoverable(adapter, &eir_data, addr,
-							bdaddr_type);
+						bdaddr_type, &auto_connect);
 
 	dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);
 	if (!dev) {
@@ -7330,7 +7356,14 @@  void btd_adapter_device_found(struct btd_adapter *adapter,
 				MGMT_SETTING_ISO_SYNC_RECEIVER))
 			monitoring = true;
 
-		if (!discoverable && !monitoring && not_connectable) {
+		/* Monitor Devices advertising RSI since those can be
+		 * coordinated sets not marked as visible but their object are
+		 * needed.
+		 */
+		if (eir_data.rsi)
+			monitoring = true;
+
+		if (!discoverable && !monitoring) {
 			eir_data_free(&eir_data);
 			return;
 		}
@@ -7468,6 +7501,12 @@  void btd_adapter_device_found(struct btd_adapter *adapter,
 	adapter->discovery_found = g_slist_prepend(adapter->discovery_found,
 									dev);
 
+	/* If device has a pattern match and it also set auto-connect then
+	 * attempt to connect.
+	 */
+	if (!btd_device_is_connected(dev) && auto_connect)
+		btd_device_connect_services(dev, NULL);
+
 	return;
 
 connect_le:
diff --git a/src/device.c b/src/device.c
index 56583f71a78b..60fdc2ef2779 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2569,9 +2569,61 @@  static GSList *create_pending_list(struct btd_device *dev, const char *uuid)
 	return dev->pending;
 }
 
+#define NVAL_TIME ((time_t) -1)
+#define SEEN_TRESHHOLD 300
+
+static uint8_t select_conn_bearer(struct btd_device *dev)
+{
+	time_t bredr_last = NVAL_TIME, le_last = NVAL_TIME;
+	time_t current = time(NULL);
+
+	/* Use preferred bearer or bonded bearer in case only one is bonded */
+	if (dev->bredr_state.prefer ||
+			(dev->bredr_state.bonded && !dev->le_state.bonded))
+		return BDADDR_BREDR;
+	else if (dev->le_state.prefer ||
+			(!dev->bredr_state.bonded && dev->le_state.bonded))
+		return dev->bdaddr_type;
+
+	/* If the address is random it can only be connected over LE */
+	if (dev->bdaddr_type == BDADDR_LE_RANDOM)
+		return dev->bdaddr_type;
+
+	if (dev->bredr_state.connectable && dev->bredr_state.last_seen) {
+		bredr_last = current - dev->bredr_state.last_seen;
+		if (bredr_last > SEEN_TRESHHOLD)
+			bredr_last = NVAL_TIME;
+	}
+
+	if (dev->le_state.connectable && dev->le_state.last_seen) {
+		le_last = current - dev->le_state.last_seen;
+		if (le_last > SEEN_TRESHHOLD)
+			le_last = NVAL_TIME;
+	}
+
+	if (le_last == NVAL_TIME && bredr_last == NVAL_TIME)
+		return dev->bdaddr_type;
+
+	if (dev->bredr && (!dev->le || le_last == NVAL_TIME))
+		return BDADDR_BREDR;
+
+	if (dev->le && (!dev->bredr || bredr_last == NVAL_TIME))
+		return dev->bdaddr_type;
+
+	/*
+	 * Prefer BR/EDR if time is the same since it might be from an
+	 * advertisement with BR/EDR flag set.
+	 */
+	if (bredr_last <= le_last && btd_adapter_get_bredr(dev->adapter))
+		return BDADDR_BREDR;
+
+	return dev->bdaddr_type;
+}
+
 int btd_device_connect_services(struct btd_device *dev, GSList *services)
 {
 	GSList *l;
+	uint8_t bdaddr_type;
 
 	if (dev->pending || dev->connect || dev->browse)
 		return -EBUSY;
@@ -2579,6 +2631,14 @@  int btd_device_connect_services(struct btd_device *dev, GSList *services)
 	if (!btd_adapter_get_powered(dev->adapter))
 		return -ENETDOWN;
 
+	bdaddr_type = select_conn_bearer(dev);
+	if (bdaddr_type != BDADDR_BREDR) {
+		if (dev->le_state.connected)
+			return -EALREADY;
+
+		return device_connect_le(dev);
+	}
+
 	if (!dev->bredr_state.svc_resolved)
 		return -ENOENT;
 
@@ -2661,57 +2721,6 @@  resolve_services:
 	return NULL;
 }
 
-#define NVAL_TIME ((time_t) -1)
-#define SEEN_TRESHHOLD 300
-
-static uint8_t select_conn_bearer(struct btd_device *dev)
-{
-	time_t bredr_last = NVAL_TIME, le_last = NVAL_TIME;
-	time_t current = time(NULL);
-
-	/* Use preferred bearer or bonded bearer in case only one is bonded */
-	if (dev->bredr_state.prefer ||
-			(dev->bredr_state.bonded && !dev->le_state.bonded))
-		return BDADDR_BREDR;
-	else if (dev->le_state.prefer ||
-			(!dev->bredr_state.bonded && dev->le_state.bonded))
-		return dev->bdaddr_type;
-
-	/* If the address is random it can only be connected over LE */
-	if (dev->bdaddr_type == BDADDR_LE_RANDOM)
-		return dev->bdaddr_type;
-
-	if (dev->bredr_state.connectable && dev->bredr_state.last_seen) {
-		bredr_last = current - dev->bredr_state.last_seen;
-		if (bredr_last > SEEN_TRESHHOLD)
-			bredr_last = NVAL_TIME;
-	}
-
-	if (dev->le_state.connectable && dev->le_state.last_seen) {
-		le_last = current - dev->le_state.last_seen;
-		if (le_last > SEEN_TRESHHOLD)
-			le_last = NVAL_TIME;
-	}
-
-	if (le_last == NVAL_TIME && bredr_last == NVAL_TIME)
-		return dev->bdaddr_type;
-
-	if (dev->bredr && (!dev->le || le_last == NVAL_TIME))
-		return BDADDR_BREDR;
-
-	if (dev->le && (!dev->bredr || bredr_last == NVAL_TIME))
-		return dev->bdaddr_type;
-
-	/*
-	 * Prefer BR/EDR if time is the same since it might be from an
-	 * advertisement with BR/EDR flag set.
-	 */
-	if (bredr_last <= le_last && btd_adapter_get_bredr(dev->adapter))
-		return BDADDR_BREDR;
-
-	return dev->bdaddr_type;
-}
-
 static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
 							void *user_data)
 {