* [PATCH BlueZ v2 2/4] adapter: Implement SetFilterPolicy AutoConnect filter
2025-05-23 14:25 [PATCH BlueZ v2 1/4] org.bluez.Adapter: Add AutoConnect to SetDiscoveryFilter Luiz Augusto von Dentz
@ 2025-05-23 14:25 ` Luiz Augusto von Dentz
2025-05-23 14:25 ` [PATCH BlueZ v2 3/4] client: Add scan.auto-connect command Luiz Augusto von Dentz
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2025-05-23 14:25 UTC (permalink / raw)
To: linux-bluetooth
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 --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)
{
--
2.49.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH BlueZ v2 3/4] client: Add scan.auto-connect command
2025-05-23 14:25 [PATCH BlueZ v2 1/4] org.bluez.Adapter: Add AutoConnect to SetDiscoveryFilter Luiz Augusto von Dentz
2025-05-23 14:25 ` [PATCH BlueZ v2 2/4] adapter: Implement SetFilterPolicy AutoConnect filter Luiz Augusto von Dentz
@ 2025-05-23 14:25 ` Luiz Augusto von Dentz
2025-05-23 14:25 ` [PATCH BlueZ v2 4/4] bluetoothctl-scan: Add documentation for auto-connect command Luiz Augusto von Dentz
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2025-05-23 14:25 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
[bluetoothctl]> scan.auto-connect --help
Set/Get auto-connect filter
Usage:
auto-connect [on/off]
---
client/main.c | 40 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/client/main.c b/client/main.c
index 5d53a7be11e4..46687c6dd944 100644
--- a/client/main.c
+++ b/client/main.c
@@ -161,6 +161,7 @@ static struct set_discovery_filter_args {
size_t uuids_len;
dbus_bool_t duplicate;
dbus_bool_t discoverable;
+ dbus_bool_t auto_connect;
bool set;
bool active;
unsigned int timeout;
@@ -1253,9 +1254,14 @@ static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
DBUS_TYPE_BOOLEAN,
&args->discoverable);
- if (args->pattern != NULL)
+ if (args->pattern != NULL) {
g_dbus_dict_append_entry(&dict, "Pattern", DBUS_TYPE_STRING,
&args->pattern);
+ if (args->auto_connect)
+ g_dbus_dict_append_entry(&dict, "AutoConnect",
+ DBUS_TYPE_BOOLEAN,
+ &args->auto_connect);
+ }
dbus_message_iter_close_container(iter, &dict);
}
@@ -1492,6 +1498,29 @@ static void cmd_scan_filter_pattern(int argc, char *argv[])
set_discovery_filter(false);
}
+static void cmd_scan_filter_auto_connect(int argc, char *argv[])
+{
+ if (argc < 2 || !strlen(argv[1])) {
+ bt_shell_printf("AutoConnect: %s\n",
+ filter.auto_connect ? "on" : "off");
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+ }
+
+ if (!strcmp(argv[1], "on"))
+ filter.auto_connect = true;
+ else if (!strcmp(argv[1], "off"))
+ filter.auto_connect = false;
+ else {
+ bt_shell_printf("Invalid option: %s\n", argv[1]);
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
+ filter.set = false;
+
+ if (filter.active)
+ set_discovery_filter(false);
+}
+
static void filter_clear_uuids(void)
{
g_strfreev(filter.uuids);
@@ -1531,6 +1560,11 @@ static void filter_clear_pattern(void)
filter.pattern = NULL;
}
+static void filter_auto_connect(void)
+{
+ filter.auto_connect = false;
+}
+
struct clear_entry {
const char *name;
void (*clear) (void);
@@ -1544,6 +1578,7 @@ static const struct clear_entry filter_clear[] = {
{ "duplicate-data", filter_clear_duplicate },
{ "discoverable", filter_clear_discoverable },
{ "pattern", filter_clear_pattern },
+ { "auto-connect", filter_auto_connect },
{}
};
@@ -3219,6 +3254,9 @@ static const struct bt_shell_menu scan_menu = {
{ "pattern", "[value]", cmd_scan_filter_pattern,
"Set/Get pattern filter",
NULL },
+ { "auto-connect", "[on/off]", cmd_scan_filter_auto_connect,
+ "Set/Get auto-connect filter",
+ NULL },
{ "clear",
"[uuids/rssi/pathloss/transport/duplicate-data/discoverable/pattern]",
cmd_scan_filter_clear,
--
2.49.0
^ permalink raw reply related [flat|nested] 6+ messages in thread