From 4fe45c54895f44cd734332ad3df3c9701c6f84fd Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 3 Sep 2025 16:23:53 -0400 Subject: [PATCH] device: Add initial support for setting DEVICE_FLAG_PAST This introduces device_set_past_support which can be used by drivers to indicate that DEVICE_FLAG_PAST shall be changed. --- src/adapter.c | 31 +++++++++++++++++++++++-------- src/adapter.h | 2 +- src/device.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/device.h | 3 +++ 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/adapter.c b/src/adapter.c index 1ee2f3a08..445203463 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -5640,6 +5640,8 @@ static void add_device_complete(uint8_t status, uint16_t length, struct btd_adapter *adapter = user_data; struct btd_device *dev; char addr[18]; + uint32_t flags; + if (length < sizeof(*rp)) { btd_error(adapter->dev_id, @@ -5669,8 +5671,7 @@ static void add_device_complete(uint8_t status, uint16_t length, DBG("%s (%u) added to kernel connect list", addr, rp->addr.type); if (btd_opts.device_privacy) { - uint32_t flags = btd_device_get_current_flags(dev); - + flags = btd_device_get_current_flags(dev); /* Set Device Privacy Mode if it has not set the flag yet. */ if (!(flags & DEVICE_FLAG_DEVICE_PRIVACY)) { /* Include the pending flags, or they may get @@ -5682,8 +5683,18 @@ static void add_device_complete(uint8_t status, uint16_t length, DEVICE_FLAG_DEVICE_PRIVACY, set_device_privacy_complete, dev); + return; } } + + /* Check if any flag was marked as pending before ADD_DEVICE + * complete then set it now + */ + flags = btd_device_get_pending_flags(dev); + if (flags) + adapter_set_device_flags(adapter, dev, flags, + set_device_privacy_complete, + dev); } void adapter_auto_connect_add(struct btd_adapter *adapter, @@ -5725,7 +5736,7 @@ void adapter_auto_connect_add(struct btd_adapter *adapter, adapter->connect_list = g_slist_append(adapter->connect_list, device); } -void adapter_set_device_flags(struct btd_adapter *adapter, +int adapter_set_device_flags(struct btd_adapter *adapter, struct btd_device *device, uint32_t flags, mgmt_request_func_t func, void *user_data) { @@ -5737,14 +5748,15 @@ void adapter_set_device_flags(struct btd_adapter *adapter, uint8_t bdaddr_type; bool ll_privacy = btd_adapter_has_settings(adapter, MGMT_SETTING_LL_PRIVACY); + unsigned int id; if (!btd_has_kernel_features(KERNEL_CONN_CONTROL) || - (supported | flags) != supported) - return; + (supported && (supported | flags) != supported)) + return -EINVAL; /* Check if changing flags are pending */ if ((current ^ flags) == (flags & pending)) - return; + return -EINPROGRESS; /* Set Device Privacy Mode if it has not set the flag yet. */ if (btd_opts.device_privacy && !(flags & DEVICE_FLAG_DEVICE_PRIVACY)) @@ -5764,9 +5776,12 @@ void adapter_set_device_flags(struct btd_adapter *adapter, cp.addr.type = bdaddr_type; cp.current_flags = cpu_to_le32(flags); - if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id, - sizeof(cp), &cp, func, user_data, NULL)) + id = mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id, + sizeof(cp), &cp, func, user_data, NULL); + if (id != 0) btd_device_set_pending_flags(device, flags); + + return id == 0 ? -EBUSY : 0; } static void device_flags_changed_callback(uint16_t index, uint16_t length, diff --git a/src/adapter.h b/src/adapter.h index ad81a10b1..dd0c90d9c 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -237,7 +237,7 @@ void adapter_connect_list_remove(struct btd_adapter *adapter, typedef void (*adapter_set_device_flags_func_t)(uint8_t status, uint16_t length, const void *param, void *user_data); -void adapter_set_device_flags(struct btd_adapter *adapter, +int adapter_set_device_flags(struct btd_adapter *adapter, struct btd_device *device, uint32_t flags, adapter_set_device_flags_func_t func, void *user_data); diff --git a/src/device.c b/src/device.c index 8d74ae0ea..91b6cc0c6 100644 --- a/src/device.c +++ b/src/device.c @@ -1733,6 +1733,56 @@ void device_set_wake_allowed(struct btd_device *device, bool wake_allowed, set_wake_allowed_complete, device); } +static void set_past_complete(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + const struct mgmt_rp_set_device_flags *rp = param; + struct btd_device *dev = user_data; + + if (status != MGMT_STATUS_SUCCESS) { + error("Set device flags return status: %s", + mgmt_errstr(status)); + return; + } + + if (length < sizeof(*rp)) { + error("Too small Set Device Flags complete event: %d", length); + return; + } + + btd_device_flags_changed(dev, dev->supported_flags, dev->pending_flags); +} + +void device_set_past_support(struct btd_device *device, bool value) +{ + uint32_t flags; + int err; + + if (!device) + return; + + if (btd_device_flags_enabled(device, DEVICE_FLAG_PAST) == value) + return; + + DBG("value %s", value ? "true" : "false"); + + flags = device->current_flags; + + /* Include the pending flags, or they may get overwritten. */ + flags |= device->pending_flags; + + if (value) + flags |= DEVICE_FLAG_PAST; + else + flags &= ~DEVICE_FLAG_PAST; + + err = adapter_set_device_flags(device->adapter, device, flags, + set_past_complete, device); + + if (err) + error("Failed to set past support: %s", strerror(-err)); +} + static gboolean dev_property_get_wake_allowed(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) diff --git a/src/device.h b/src/device.h index 9ff9cdfef..6ed8affa0 100644 --- a/src/device.h +++ b/src/device.h @@ -158,6 +158,9 @@ void device_set_wake_support(struct btd_device *device, bool wake_support); void device_set_wake_override(struct btd_device *device, bool wake_override); void device_set_wake_allowed(struct btd_device *device, bool wake_allowed, guint32 id); + +void device_set_past_support(struct btd_device *device, bool value); + void device_set_refresh_discovery(struct btd_device *dev, bool refresh); typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal, -- 2.47.3