[PATCH BlueZ v1] device: Fix overwritting current_flags

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

 



From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>

MGMT Set Device Flags overwrites the current_flags so only the last
flags set this way would remain active which can be seem in the
following sequence when LL Privacy is enabled:

@ MGMT Command: Set Device Flags (0x0050) plen 11
        LE Address: CF:AC:A6:79:3D:B9 (Static)
        Current Flags: 0x00000001
          Remote Wakeup
@ MGMT Event: Command Complete (0x0001) plen 10
      Set Device Flags (0x0050) plen 7
        Status: Success (0x00)
        LE Address: CF:AC:A6:79:3D:B9 (Static)
@ MGMT Command: Set Device Flags (0x0050) plen 11
        LE Address: CF:AC:A6:79:3D:B9 (Static)
        Current Flags: 0x00000002
          Device Privacy Mode
@ MGMT Event: Command Complete (0x0001) plen 10
      Set Device Flags (0x0050) plen 7
        Status: Success (0x00)
        LE Address: CF:AC:A6:79:3D:B9 (Static)

In order to do this properly the code needs to track the pending_flags
being set and also call btd_device_flags_changed whenever a change is
complete since that event is not generated when MGMT_OP_SET_DEVICE_FLAGS
is sent by bluetoothd itself.
---
 src/adapter.c | 20 +++++++++++++++++---
 src/device.c  | 20 +++++++++++++++++++-
 src/device.h  |  2 ++
 3 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index bb49a1ecad23..85ddfc16568f 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5569,6 +5569,7 @@ void adapter_accept_list_remove(struct btd_adapter *adapter,
 static void set_device_privacy_complete(uint8_t status, uint16_t length,
 					 const void *param, void *user_data)
 {
+	struct btd_device *dev = user_data;
 	const struct mgmt_rp_set_device_flags *rp = param;
 
 	if (status != MGMT_STATUS_SUCCESS) {
@@ -5581,6 +5582,9 @@ static void set_device_privacy_complete(uint8_t status, uint16_t length,
 		error("Too small Set Device Flags complete event: %d", length);
 		return;
 	}
+
+	btd_device_flags_changed(dev, btd_device_get_supported_flags(dev),
+					btd_device_get_pending_flags(dev));
 }
 
 static void add_device_complete(uint8_t status, uint16_t length,
@@ -5626,7 +5630,7 @@ static void add_device_complete(uint8_t status, uint16_t length,
 			adapter_set_device_flags(adapter, dev, flags |
 						DEVICE_FLAG_DEVICE_PRIVACY,
 						set_device_privacy_complete,
-						NULL);
+						dev);
 		}
 	}
 }
@@ -5676,6 +5680,7 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
 {
 	struct mgmt_cp_set_device_flags cp;
 	uint32_t supported = btd_device_get_supported_flags(device);
+	uint32_t pending = btd_device_get_pending_flags(device);
 	const bdaddr_t *bdaddr;
 	uint8_t bdaddr_type;
 
@@ -5683,6 +5688,14 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
 				(supported | flags) != supported)
 		return;
 
+	/* Check if changing flags are pending */
+	if (flags == (flags & pending))
+		return;
+
+	/* Set Device Privacy Mode if it has not set the flag yet. */
+	if (btd_opts.device_privacy && !(flags & DEVICE_FLAG_DEVICE_PRIVACY))
+		flags |= DEVICE_FLAG_DEVICE_PRIVACY & supported & ~pending;
+
 	bdaddr = device_get_address(device);
 	bdaddr_type = btd_device_get_bdaddr_type(device);
 
@@ -5691,8 +5704,9 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
 	cp.addr.type = bdaddr_type;
 	cp.current_flags = cpu_to_le32(flags);
 
-	mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
-		  sizeof(cp), &cp, func, user_data, NULL);
+	if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
+		  sizeof(cp), &cp, func, user_data, NULL))
+		btd_device_set_pending_flags(device, flags);
 }
 
 static void device_flags_changed_callback(uint16_t index, uint16_t length,
diff --git a/src/device.c b/src/device.c
index 097b1fbba37d..a1dc0750ca41 100644
--- a/src/device.c
+++ b/src/device.c
@@ -214,6 +214,7 @@ struct btd_device {
 	GDBusPendingPropertySet wake_id;
 
 	uint32_t	supported_flags;
+	uint32_t	pending_flags;
 	uint32_t	current_flags;
 	GSList		*svc_callbacks;
 	GSList		*eir_uuids;
@@ -1569,7 +1570,7 @@ static void set_wake_allowed_complete(uint8_t status, uint16_t length,
 		return;
 	}
 
-	device_set_wake_allowed_complete(dev);
+	btd_device_flags_changed(dev, dev->supported_flags, dev->pending_flags);
 }
 
 void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
@@ -7243,6 +7244,22 @@ uint32_t btd_device_get_supported_flags(struct btd_device *dev)
 	return dev->supported_flags;
 }
 
+void btd_device_set_pending_flags(struct btd_device *dev, uint32_t flags)
+{
+	if (!dev)
+		return;
+
+	dev->pending_flags = flags;
+}
+
+uint32_t btd_device_get_pending_flags(struct btd_device *dev)
+{
+	if (!dev)
+		return 0;
+
+	return dev->pending_flags;
+}
+
 /* This event is sent immediately after add device on all mgmt sockets.
  * Afterwards, it is only sent to mgmt sockets other than the one which called
  * set_device_flags.
@@ -7255,6 +7272,7 @@ void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags,
 
 	dev->supported_flags = supported_flags;
 	dev->current_flags = current_flags;
+	dev->pending_flags = 0;
 
 	if (!changed_flags)
 		return;
diff --git a/src/device.h b/src/device.h
index 0794f92d0178..3742f6028040 100644
--- a/src/device.h
+++ b/src/device.h
@@ -191,6 +191,8 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services);
 
 uint32_t btd_device_get_current_flags(struct btd_device *dev);
 uint32_t btd_device_get_supported_flags(struct btd_device *dev);
+uint32_t btd_device_get_pending_flags(struct btd_device *dev);
+void btd_device_set_pending_flags(struct btd_device *dev, uint32_t flags);
 void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags,
 			      uint32_t current_flags);
 
-- 
2.45.2





[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