Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 2/3] client/btpclient: Replace advertising defines by shared ones
From: Frédéric Danis @ 2026-05-19 10:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260519105519.226648-1-frederic.danis@collabora.com>

The advertisement types are already defined in src/shared/ad.h
---
 client/btpclient/gap.c | 44 ++++++++++++++++--------------------------
 1 file changed, 17 insertions(+), 27 deletions(-)

diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index 916626f1d..2d393dd4d 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -17,6 +17,7 @@
 
 #include "bluetooth/bluetooth.h"
 #include "bluetooth/uuid.h"
+#include "src/shared/ad.h"
 #include "src/shared/btp.h"
 #include "btpclient.h"
 #include "core.h"
@@ -27,17 +28,6 @@
 #define AD_IFACE "org.bluez.LEAdvertisement1"
 #define AG_IFACE "org.bluez.Agent1"
 
-/* List of assigned numbers for advertising data and scan response */
-#define AD_TYPE_FLAGS				0x01
-#define AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST	0x02
-#define AD_TYPE_SHORT_NAME			0x08
-#define AD_TYPE_COMPLETE_NAME			0x09
-#define AD_TYPE_TX_POWER			0x0a
-#define AD_TYPE_SOLICIT_UUID16_SERVICE_LIST	0x14
-#define AD_TYPE_SERVICE_DATA_UUID16		0x16
-#define AD_TYPE_APPEARANCE			0x19
-#define AD_TYPE_MANUFACTURER_DATA		0xff
-
 static void register_gap_service(void);
 
 static struct l_dbus *dbus;
@@ -899,7 +889,7 @@ static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
 		ad_data = &data[adv_data_len - remaining_data_len + 2];
 
 		switch (ad_type) {
-		case AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST:
+		case BT_AD_UUID16_SOME:
 		{
 			char *uuid = dupuuid2str(ad_data, 16);
 
@@ -907,20 +897,28 @@ static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
 
 			break;
 		}
-		case AD_TYPE_SHORT_NAME:
-		case AD_TYPE_COMPLETE_NAME:
+		case BT_AD_NAME_SHORT:
+		case BT_AD_NAME_COMPLETE:
 			ad.local_name = malloc(ad_len + 1);
 			memcpy(ad.local_name, ad_data, ad_len);
 			ad.local_name[ad_len] = '\0';
 
 			break;
-		case AD_TYPE_TX_POWER:
+		case BT_AD_TX_POWER:
 			ad.tx_power = true;
 
 			/* XXX Value is omitted cause, stack fills it */
 
 			break;
-		case AD_TYPE_SERVICE_DATA_UUID16:
+		case BT_AD_SOLICIT16:
+		{
+			char *uuid = dupuuid2str(ad_data, 16);
+
+			l_queue_push_tail(ad.solicits, uuid);
+
+			break;
+		}
+		case BT_AD_SERVICE_DATA16:
 		{
 			struct service_data *sd;
 
@@ -933,11 +931,11 @@ static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
 
 			break;
 		}
-		case AD_TYPE_APPEARANCE:
+		case BT_AD_GAP_APPEARANCE:
 			memcpy(&ad.local_appearance, ad_data, ad_len);
 
 			break;
-		case AD_TYPE_MANUFACTURER_DATA:
+		case BT_AD_MANUFACTURER_DATA:
 		{
 			struct manufacturer_data *md;
 
@@ -954,14 +952,6 @@ static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
 
 			break;
 		}
-		case AD_TYPE_SOLICIT_UUID16_SERVICE_LIST:
-		{
-			char *uuid = dupuuid2str(ad_data, 16);
-
-			l_queue_push_tail(ad.solicits, uuid);
-
-			break;
-		}
 		default:
 			l_info("Unsupported advertising data type");
 
@@ -2455,7 +2445,7 @@ static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
 				ev->eir_len);
 			eir = &ev->eir[ev->eir_len - n - 4];
 			eir[0] = n + 3;
-			eir[1] = AD_TYPE_MANUFACTURER_DATA;
+			eir[1] = BT_AD_MANUFACTURER_DATA;
 			eir[2] = key >> 8;
 			eir[3] = key & 0xFF;
 			memcpy(&eir[4], data, n);
-- 
2.43.0


^ permalink raw reply related

* [PATCH BlueZ 1/3] client/btpclient: refactor read-commands bitmap building
From: Frédéric Danis @ 2026-05-19 10:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260519105519.226648-1-frederic.danis@collabora.com>

Add add_supported_command() and use it across all btp_*_read_commands
handlers.

This replaces fixed-size bitmask assembly with a dynamically growing
command bitmap based on opcode index, avoiding shift-width issues with
higher opcodes.
This will allow to add opcodes like GAP_SET_EXTENDED_ADVERTISING
(0x21).

Refactor core, gap, gatt and bap read-commands paths to build response
bitmaps through the shared helper and preserve existing error handling
for allocation failures.

Assisted-by: GPT:GPT-5.3-Codex
---
 client/btpclient/bap.c       | 27 +++++++++++++----
 client/btpclient/btpclient.c | 25 +++++++++++++++
 client/btpclient/btpclient.h |  5 +++
 client/btpclient/core.c      | 29 ++++++++++++++----
 client/btpclient/gap.c       | 59 +++++++++++++++++++++++-------------
 client/btpclient/gatt.c      | 39 ++++++++++++++++--------
 6 files changed, 139 insertions(+), 45 deletions(-)

diff --git a/client/btpclient/bap.c b/client/btpclient/bap.c
index d64828894..0302fc1c0 100644
--- a/client/btpclient/bap.c
+++ b/client/btpclient/bap.c
@@ -27,7 +27,13 @@ static bool bap_service_registered;
 static void btp_bap_read_commands(uint8_t index, const void *param,
 					uint16_t length, void *user_data)
 {
-	uint16_t commands = 0;
+	const uint8_t supported_commands[] = {
+		BTP_OP_BAP_READ_SUPPORTED_COMMANDS,
+		BTP_OP_BAP_DISCOVER,
+	};
+	uint8_t *commands = NULL;
+	size_t commands_len = 0;
+	size_t i;
 
 	if (index != BTP_INDEX_NON_CONTROLLER) {
 		btp_send_error(btp, BTP_BAP_SERVICE, index,
@@ -35,13 +41,22 @@ static void btp_bap_read_commands(uint8_t index, const void *param,
 		return;
 	}
 
-	commands |= (1 << BTP_OP_BAP_READ_SUPPORTED_COMMANDS);
-	commands |= (1 << BTP_OP_BAP_DISCOVER);
-
-	commands = L_CPU_TO_LE16(commands);
+	for (i = 0; i < L_ARRAY_SIZE(supported_commands); i++) {
+		if (!add_supported_command(&commands, &commands_len,
+						supported_commands[i]))
+			goto failed;
+	}
 
 	btp_send(btp, BTP_BAP_SERVICE, BTP_OP_BAP_READ_SUPPORTED_COMMANDS,
-			BTP_INDEX_NON_CONTROLLER, sizeof(commands), &commands);
+			BTP_INDEX_NON_CONTROLLER, commands_len, commands);
+
+	l_free(commands);
+
+	return;
+
+failed:
+	l_free(commands);
+	btp_send_error(btp, BTP_BAP_SERVICE, index, BTP_ERROR_FAIL);
 }
 
 static void btp_bap_discover(uint8_t index, const void *param, uint16_t length,
diff --git a/client/btpclient/btpclient.c b/client/btpclient/btpclient.c
index ee46966dc..0d124bc7a 100644
--- a/client/btpclient/btpclient.c
+++ b/client/btpclient/btpclient.c
@@ -38,6 +38,31 @@ static struct btp *btp;
 
 static struct btp_agent ag;
 
+bool add_supported_command(uint8_t **commands, size_t *commands_len,
+							uint8_t command)
+{
+	size_t cmd_byte = command / 8;
+
+	if (cmd_byte >= *commands_len) {
+		size_t old_len = *commands_len;
+		size_t new_len = cmd_byte + 1;
+		uint8_t *tmp;
+
+		tmp = l_realloc(*commands, new_len);
+		if (!tmp)
+			return false;
+
+		memset(tmp + old_len, 0, new_len - old_len);
+
+		*commands = tmp;
+		*commands_len = new_len;
+	}
+
+	(*commands)[cmd_byte] |= (1U << (command % 8));
+
+	return true;
+}
+
 struct l_queue *get_adapters_list(void)
 {
 	return adapters;
diff --git a/client/btpclient/btpclient.h b/client/btpclient/btpclient.h
index e26a08413..8a5ea2172 100644
--- a/client/btpclient/btpclient.h
+++ b/client/btpclient/btpclient.h
@@ -7,6 +7,8 @@
  *
  */
 
+#include <stddef.h>
+
 struct btp_adapter {
 	struct l_dbus_proxy *proxy;
 	struct l_dbus_proxy *ad_proxy;
@@ -54,3 +56,6 @@ struct btp_agent *get_agent(void);
 bool request_default_agent(l_dbus_client_proxy_result_func_t reply,
 						void *user_data,
 						l_dbus_destroy_func_t destroy);
+
+bool add_supported_command(uint8_t **commands, size_t *commands_len,
+							uint8_t command);
diff --git a/client/btpclient/core.c b/client/btpclient/core.c
index 772178670..f5d64904f 100644
--- a/client/btpclient/core.c
+++ b/client/btpclient/core.c
@@ -24,7 +24,15 @@ static struct l_dbus *dbus;
 static void btp_core_read_commands(uint8_t index, const void *param,
 					uint16_t length, void *user_data)
 {
-	uint8_t commands = 0;
+	const uint8_t supported_commands[] = {
+		BTP_OP_CORE_READ_SUPPORTED_COMMANDS,
+		BTP_OP_CORE_READ_SUPPORTED_SERVICES,
+		BTP_OP_CORE_REGISTER,
+		BTP_OP_CORE_UNREGISTER,
+	};
+	uint8_t *commands = NULL;
+	size_t commands_len = 0;
+	size_t i;
 
 	if (index != BTP_INDEX_NON_CONTROLLER) {
 		btp_send_error(btp, BTP_CORE_SERVICE, index,
@@ -32,13 +40,22 @@ static void btp_core_read_commands(uint8_t index, const void *param,
 		return;
 	}
 
-	commands |= (1 << BTP_OP_CORE_READ_SUPPORTED_COMMANDS);
-	commands |= (1 << BTP_OP_CORE_READ_SUPPORTED_SERVICES);
-	commands |= (1 << BTP_OP_CORE_REGISTER);
-	commands |= (1 << BTP_OP_CORE_UNREGISTER);
+	for (i = 0; i < L_ARRAY_SIZE(supported_commands); i++) {
+		if (!add_supported_command(&commands, &commands_len,
+						supported_commands[i]))
+			goto failed;
+	}
 
 	btp_send(btp, BTP_CORE_SERVICE, BTP_OP_CORE_READ_SUPPORTED_COMMANDS,
-			BTP_INDEX_NON_CONTROLLER, sizeof(commands), &commands);
+			BTP_INDEX_NON_CONTROLLER, commands_len, commands);
+
+	l_free(commands);
+
+	return;
+
+failed:
+	l_free(commands);
+	btp_send_error(btp, BTP_CORE_SERVICE, index, BTP_ERROR_FAIL);
 }
 
 static void btp_core_read_services(uint8_t index, const void *param,
diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index 68e029dcc..916626f1d 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -99,7 +99,30 @@ static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
 static void btp_gap_read_commands(uint8_t index, const void *param,
 					uint16_t length, void *user_data)
 {
-	uint16_t commands = 0;
+	const uint8_t supported_commands[] = {
+		BTP_OP_GAP_READ_SUPPORTED_COMMANDS,
+		BTP_OP_GAP_READ_CONTROLLER_INDEX_LIST,
+		BTP_OP_GAP_READ_CONTROLLER_INFO,
+		BTP_OP_GAP_RESET,
+		BTP_OP_GAP_SET_POWERED,
+		BTP_OP_GAP_SET_CONNECTABLE,
+		BTP_OP_GAP_SET_DISCOVERABLE,
+		BTP_OP_GAP_SET_BONDABLE,
+		BTP_OP_GAP_START_ADVERTISING,
+		BTP_OP_GAP_STOP_ADVERTISING,
+		BTP_OP_GAP_START_DISCOVERY,
+		BTP_OP_GAP_STOP_DISCOVERY,
+		BTP_OP_GAP_CONNECT,
+		BTP_OP_GAP_DISCONNECT,
+		BTP_OP_GAP_SET_IO_CAPA,
+		BTP_OP_GAP_PAIR,
+		BTP_OP_GAP_UNPAIR,
+		BTP_OP_GAP_PASSKEY_ENTRY_RSP,
+		BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
+	};
+	uint8_t *commands = NULL;
+	size_t commands_len = 0;
+	size_t i;
 
 	if (index != BTP_INDEX_NON_CONTROLLER) {
 		btp_send_error(btp, BTP_GAP_SERVICE, index,
@@ -107,28 +130,22 @@ static void btp_gap_read_commands(uint8_t index, const void *param,
 		return;
 	}
 
-	commands |= (1 << BTP_OP_GAP_READ_SUPPORTED_COMMANDS);
-	commands |= (1 << BTP_OP_GAP_READ_CONTROLLER_INDEX_LIST);
-	commands |= (1 << BTP_OP_GAP_READ_CONTROLLER_INFO);
-	commands |= (1 << BTP_OP_GAP_RESET);
-	commands |= (1 << BTP_OP_GAP_SET_POWERED);
-	commands |= (1 << BTP_OP_GAP_SET_CONNECTABLE);
-	commands |= (1 << BTP_OP_GAP_SET_DISCOVERABLE);
-	commands |= (1 << BTP_OP_GAP_SET_BONDABLE);
-	commands |= (1 << BTP_OP_GAP_START_ADVERTISING);
-	commands |= (1 << BTP_OP_GAP_STOP_ADVERTISING);
-	commands |= (1 << BTP_OP_GAP_START_DISCOVERY);
-	commands |= (1 << BTP_OP_GAP_STOP_DISCOVERY);
-	commands |= (1 << BTP_OP_GAP_CONNECT);
-	commands |= (1 << BTP_OP_GAP_DISCONNECT);
-	commands |= (1 << BTP_OP_GAP_SET_IO_CAPA);
-	commands |= (1 << BTP_OP_GAP_PAIR);
-	commands |= (1 << BTP_OP_GAP_UNPAIR);
-
-	commands = L_CPU_TO_LE16(commands);
+	for (i = 0; i < L_ARRAY_SIZE(supported_commands); i++) {
+		if (!add_supported_command(&commands, &commands_len,
+						supported_commands[i]))
+			goto failed;
+	}
 
 	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_READ_SUPPORTED_COMMANDS,
-			BTP_INDEX_NON_CONTROLLER, sizeof(commands), &commands);
+			BTP_INDEX_NON_CONTROLLER, commands_len, commands);
+
+	l_free(commands);
+
+	return;
+
+failed:
+	l_free(commands);
+	btp_send_error(btp, BTP_GAP_SERVICE, index, BTP_ERROR_FAIL);
 }
 
 static void btp_gap_read_controller_index(uint8_t index, const void *param,
diff --git a/client/btpclient/gatt.c b/client/btpclient/gatt.c
index 9d847141c..d384b9c74 100644
--- a/client/btpclient/gatt.c
+++ b/client/btpclient/gatt.c
@@ -44,7 +44,19 @@ static int create_uuid(bt_uuid_t *btuuid, uint8_t len, const uint8_t *data)
 static void btp_gatt_read_commands(uint8_t index, const void *param,
 					uint16_t length, void *user_data)
 {
-	uint16_t commands = 0;
+	const uint8_t supported_commands[] = {
+		BTP_OP_GATT_READ_SUPPORTED_COMMANDS,
+		BTP_OP_GATT_DISC_PRIM_UUID,
+		BTP_OP_GATT_DISC_CHRC_UUID,
+		BTP_OP_GATT_DISC_ALL_DESC,
+		BTP_OP_GATT_READ,
+		BTP_OP_GATT_READ_UUID,
+		BTP_OP_GATT_WRITE_WITHOUT_RSP,
+		BTP_OP_GATT_WRITE,
+	};
+	uint8_t *commands = NULL;
+	size_t commands_len = 0;
+	size_t i;
 
 	if (index != BTP_INDEX_NON_CONTROLLER) {
 		btp_send_error(btp, BTP_GATT_SERVICE, index,
@@ -52,19 +64,22 @@ static void btp_gatt_read_commands(uint8_t index, const void *param,
 		return;
 	}
 
-	commands |= (1 << BTP_OP_GATT_READ_SUPPORTED_COMMANDS);
-	commands |= (1 << BTP_OP_GATT_DISC_PRIM_UUID);
-	commands |= (1 << BTP_OP_GATT_DISC_CHRC_UUID);
-	commands |= (1 << BTP_OP_GATT_DISC_ALL_DESC);
-	commands |= (1 << BTP_OP_GATT_READ);
-	commands |= (1 << BTP_OP_GATT_READ_UUID);
-	commands |= (1 << BTP_OP_GATT_WRITE_WITHOUT_RSP);
-	commands |= (1 << BTP_OP_GATT_WRITE);
-
-	commands = L_CPU_TO_LE16(commands);
+	for (i = 0; i < L_ARRAY_SIZE(supported_commands); i++) {
+		if (!add_supported_command(&commands, &commands_len,
+						supported_commands[i]))
+			goto failed;
+	}
 
 	btp_send(btp, BTP_GATT_SERVICE, BTP_OP_GATT_READ_SUPPORTED_COMMANDS,
-			BTP_INDEX_NON_CONTROLLER, sizeof(commands), &commands);
+			BTP_INDEX_NON_CONTROLLER, commands_len, commands);
+
+	l_free(commands);
+
+	return;
+
+failed:
+	l_free(commands);
+	btp_send_error(btp, BTP_GATT_SERVICE, index, BTP_ERROR_FAIL);
 }
 
 static bool match_attribute_uuid(const void *attr, const void *uuid)
-- 
2.43.0


^ permalink raw reply related

* [PATCH BlueZ 0/3] client/btpclient: Add GAP extended advertising support
From: Frédéric Danis @ 2026-05-19 10:55 UTC (permalink / raw)
  To: linux-bluetooth

The BTP_OP_GAP_SET_EXTENDED_ADVERTISING command is used by at least the
BAP/USR/DISC/BV-01-C test.

Since this opcode is defined as 0x21 (33), it does not fit into the
current fixed-size command bitmap. This series refactors the way
btpclient reports supported auto-PTS commands so it can grow the bitmap
dynamically as needed.

The series also switches GAP advertising data handling to the
advertising type definitions already provided by src/shared/ad.h.

Frédéric Danis (3):
  client/btpclient: refactor read-commands bitmap building
  client/btpclient: Replace advertising defines by shared ones
  client/btpclient: Add BTP_OP_GAP_SET_EXTENDED_ADVERTISING support

 client/btpclient/bap.c       |  27 ++++--
 client/btpclient/btpclient.c |  25 +++++
 client/btpclient/btpclient.h |   5 +
 client/btpclient/core.c      |  29 ++++--
 client/btpclient/gap.c       | 171 +++++++++++++++++++++++++----------
 client/btpclient/gatt.c      |  39 +++++---
 src/shared/btp.h             |   7 ++
 7 files changed, 229 insertions(+), 74 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH BlueZ 3/3] client/btpclient: Add BTP_OP_GAP_SET_EXTENDED_ADVERTISING support
From: Frédéric Danis @ 2026-05-19 10:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260519105519.226648-1-frederic.danis@collabora.com>

This set LEAdvertisement1's SecondaryChannel property to "2M" to
force Extended advertisement type.
---
 client/btpclient/gap.c | 68 ++++++++++++++++++++++++++++++++++++++++--
 src/shared/btp.h       |  7 +++++
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index 2d393dd4d..7c7dad966 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -73,7 +73,7 @@ static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
 {
 	switch (len) {
 	case 16:
-		return l_strdup_printf("%hhx%hhx", uuid[0], uuid[1]);
+		return l_strdup_printf("%hhx%hhx", uuid[1], uuid[0]);
 	case 128:
 		return l_strdup_printf("%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx"
 					"%hhx%hhx%hhx%hhx%hhx%hhx%hhx", uuid[0],
@@ -109,6 +109,7 @@ static void btp_gap_read_commands(uint8_t index, const void *param,
 		BTP_OP_GAP_UNPAIR,
 		BTP_OP_GAP_PASSKEY_ENTRY_RSP,
 		BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
+		BTP_OP_GAP_SET_EXTENDED_ADVERTISING,
 	};
 	uint8_t *commands = NULL;
 	size_t commands_len = 0;
@@ -813,6 +814,22 @@ static bool ad_timeout_getter(struct l_dbus *dbus,
 	return true;
 }
 
+static bool ad_secondarychannel_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	struct btp_adapter *adapter = user_data;
+	uint32_t settings = adapter->current_settings;
+
+	if (!(settings & BTP_GAP_SETTINGS_EXTENDED_ADVERTISING))
+		return false;
+
+	l_dbus_message_builder_append_basic(builder, 's', "2M");
+
+	return true;
+}
+
 static void setup_ad_interface(struct l_dbus_interface *interface)
 {
 	l_dbus_interface_method(interface, "Release",
@@ -839,6 +856,8 @@ static void setup_ad_interface(struct l_dbus_interface *interface)
 						ad_duration_getter, NULL);
 	l_dbus_interface_property(interface, "Timeout", 0, "q",
 						ad_timeout_getter, NULL);
+	l_dbus_interface_property(interface, "SecondaryChannel", 0, "s",
+					ad_secondarychannel_getter, NULL);
 }
 
 static void start_advertising_reply(struct l_dbus_proxy *proxy,
@@ -889,6 +908,9 @@ static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
 		ad_data = &data[adv_data_len - remaining_data_len + 2];
 
 		switch (ad_type) {
+		case BT_AD_FLAGS:
+			/* Advertisement flags are set by bluetoothd */
+			break;
 		case BT_AD_UUID16_SOME:
 		{
 			char *uuid = dupuuid2str(ad_data, 16);
@@ -897,6 +919,14 @@ static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
 
 			break;
 		}
+		case BT_AD_UUID16_ALL:
+		{
+			char *uuid = dupuuid2str(ad_data, 16);
+
+			l_queue_push_tail(ad.uuids, uuid);
+
+			break;
+		}
 		case BT_AD_NAME_SHORT:
 		case BT_AD_NAME_COMPLETE:
 			ad.local_name = malloc(ad_len + 1);
@@ -1008,7 +1038,7 @@ static void btp_gap_start_advertising(uint8_t index, const void *param,
 		goto failed;
 	}
 
-	if (!l_dbus_object_add_interface(dbus, AD_PATH, AD_IFACE, NULL)) {
+	if (!l_dbus_object_add_interface(dbus, AD_PATH, AD_IFACE, adapter)) {
 		l_info("Unable to instantiate ad interface");
 
 		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
@@ -2380,6 +2410,36 @@ failed:
 	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
 }
 
+
+static void btp_gap_set_extended_advertising(uint8_t index, const void *param,
+					uint16_t length, void *user_data)
+{
+	struct btp_adapter *adapter = find_adapter_by_index(index);
+	const struct btp_gap_set_extended_advertising_cp *cp = param;
+	uint32_t new_settings;
+	uint8_t status = BTP_ERROR_FAIL;
+
+	if (!adapter) {
+		status = BTP_ERROR_INVALID_INDEX;
+		goto failed;
+	}
+
+	new_settings = adapter->current_settings;
+	if (cp->settings)
+		new_settings |= BTP_GAP_SETTINGS_EXTENDED_ADVERTISING;
+	else
+		new_settings &= ~BTP_GAP_SETTINGS_EXTENDED_ADVERTISING;
+	update_current_settings(adapter, new_settings);
+
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_EXTENDED_ADVERTISING,
+					adapter->index, sizeof(new_settings),
+					&new_settings);
+
+	return;
+failed:
+	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
 static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
 {
 	struct btp_device *device = find_device_by_proxy(proxy);
@@ -2632,6 +2692,10 @@ static void register_gap_service(void)
 
 	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
 					btp_gap_confirm_entry_rsp, NULL, NULL);
+
+	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_EXTENDED_ADVERTISING,
+					btp_gap_set_extended_advertising,
+								NULL, NULL);
 }
 
 void gap_proxy_added(struct l_dbus_proxy *proxy, void *user_data)
diff --git a/src/shared/btp.h b/src/shared/btp.h
index b99ad3a28..098c0c39f 100644
--- a/src/shared/btp.h
+++ b/src/shared/btp.h
@@ -82,6 +82,8 @@ struct btp_gap_read_index_rp {
 #define BTP_GAP_SETTING_PRIVACY			0x00002000
 #define BTP_GAP_SETTING_CONTROLLER_CONF		0x00004000
 #define BTP_GAP_SETTING_STATIC_ADDRESS		0x00008000
+#define BTP_GAP_SETTINGS_SC_ONLY		0x00010000
+#define BTP_GAP_SETTINGS_EXTENDED_ADVERTISING	0x00020000
 
 #define BTP_OP_GAP_READ_CONTROLLER_INFO		0x03
 struct btp_gap_read_info_rp {
@@ -224,6 +226,11 @@ struct btp_gap_passkey_confirm_rsp_cp {
 	uint8_t match;
 } __packed;
 
+#define BTP_OP_GAP_SET_EXTENDED_ADVERTISING	0x21
+struct btp_gap_set_extended_advertising_cp {
+	uint8_t settings;
+} __packed;
+
 #define BTP_EV_GAP_NEW_SETTINGS			0x80
 struct btp_new_settings_ev {
 	uint32_t current_settings;
-- 
2.43.0


^ permalink raw reply related

* [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in skb_dequeue (2)
From: syzbot @ 2026-05-19 10:47 UTC (permalink / raw)
  To: linux-bluetooth, linux-kernel, luiz.dentz, marcel, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    e98d21c170b0 Add linux-next specific files for 20260508
git tree:       linux-next
console output: https://syzkaller.appspot.com/x/log.txt?x=13d7df6c580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=59b98218d9b2edf4
dashboard link: https://syzkaller.appspot.com/bug?extid=d06554f43a8fb48030b0
compiler:       Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/66f2a00ee290/disk-e98d21c1.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/6b982257ce9e/vmlinux-e98d21c1.xz
kernel image: https://storage.googleapis.com/syzbot-assets/a73fbea43e1a/bzImage-e98d21c1.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+d06554f43a8fb48030b0@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: slab-use-after-free in __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:132 [inline]
BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x40/0x60 kernel/locking/spinlock.c:166
Read of size 1 at addr ffff888029fc01a8 by task kworker/1:1/10569

CPU: 1 UID: 0 PID: 10569 Comm: kworker/1:1 Tainted: G             L      syzkaller #0 PREEMPT_{RT,(full)} 
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
Workqueue: events btusb_rx_work
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 __kasan_check_byte+0x2a/0x40 mm/kasan/common.c:574
 kasan_check_byte include/linux/kasan.h:402 [inline]
 lock_acquire+0x84/0x350 kernel/locking/lockdep.c:5844
 __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:132 [inline]
 _raw_spin_lock_irqsave+0x40/0x60 kernel/locking/spinlock.c:166
 rtlock_slowlock kernel/locking/rtmutex.c:1918 [inline]
 rtlock_lock kernel/locking/spinlock_rt.c:43 [inline]
 __rt_spin_lock kernel/locking/spinlock_rt.c:49 [inline]
 rt_spin_lock+0x157/0x400 kernel/locking/spinlock_rt.c:57
 spin_lock include/linux/spinlock_rt.h:45 [inline]
 skb_dequeue+0x2d/0x150 net/core/skbuff.c:3943
 btusb_rx_work+0x27/0xd0 drivers/bluetooth/btusb.c:2477
 process_one_work+0x98b/0x1630 kernel/workqueue.c:3306
 process_scheduled_works kernel/workqueue.c:3389 [inline]
 worker_thread+0xb49/0x1140 kernel/workqueue.c:3470
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>

Allocated by task 8189:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __kmalloc_cache_noprof+0x3a6/0x690 mm/slub.c:5432
 kmalloc_noprof include/linux/slab.h:950 [inline]
 kzalloc_noprof include/linux/slab.h:1188 [inline]
 btusb_probe+0x396/0x3050 drivers/bluetooth/btusb.c:4086
 usb_probe_interface+0x659/0xc70 drivers/usb/core/driver.c:396
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x267/0xaf0 drivers/base/dd.c:707
 __driver_probe_device+0x1e2/0x350 drivers/base/dd.c:869
 driver_probe_device+0x4f/0x240 drivers/base/dd.c:899
 __device_attach_driver+0x270/0x410 drivers/base/dd.c:1027
 bus_for_each_drv+0x25b/0x2f0 drivers/base/bus.c:500
 __device_attach+0x2c8/0x450 drivers/base/dd.c:1099
 device_initial_probe+0xa1/0xd0 drivers/base/dd.c:1154
 bus_probe_device+0x12d/0x220 drivers/base/bus.c:620
 device_add+0x7ec/0xb90 drivers/base/core.c:3702
 usb_set_configuration+0x1a87/0x2110 drivers/usb/core/message.c:2268
 usb_generic_driver_probe+0x8d/0x150 drivers/usb/core/generic.c:250
 usb_probe_device+0x1c4/0x3b0 drivers/usb/core/driver.c:291
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x267/0xaf0 drivers/base/dd.c:707
 __driver_probe_device+0x1e2/0x350 drivers/base/dd.c:869
 driver_probe_device+0x4f/0x240 drivers/base/dd.c:899
 __device_attach_driver+0x270/0x410 drivers/base/dd.c:1027
 bus_for_each_drv+0x25b/0x2f0 drivers/base/bus.c:500
 __device_attach+0x2c8/0x450 drivers/base/dd.c:1099
 device_initial_probe+0xa1/0xd0 drivers/base/dd.c:1154
 bus_probe_device+0x12d/0x220 drivers/base/bus.c:620
 device_add+0x7ec/0xb90 drivers/base/core.c:3702
 usb_new_device+0x9f8/0x16e0 drivers/usb/core/hub.c:2695
 hub_port_connect drivers/usb/core/hub.c:5567 [inline]
 hub_port_connect_change drivers/usb/core/hub.c:5707 [inline]
 port_event drivers/usb/core/hub.c:5871 [inline]
 hub_event+0x2a49/0x4f60 drivers/usb/core/hub.c:5953
 process_one_work+0x98b/0x1630 kernel/workqueue.c:3306
 process_scheduled_works kernel/workqueue.c:3389 [inline]
 worker_thread+0xb49/0x1140 kernel/workqueue.c:3470
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

Freed by task 8189:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2700 [inline]
 slab_free mm/slub.c:6291 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6606
 usb_unbind_interface+0x26e/0x910 drivers/usb/core/driver.c:458
 device_remove drivers/base/dd.c:619 [inline]
 __device_release_driver drivers/base/dd.c:1350 [inline]
 device_release_driver_internal+0x4d9/0x870 drivers/base/dd.c:1373
 bus_remove_device+0x45a/0x570 drivers/base/bus.c:664
 device_del+0x52b/0x900 drivers/base/core.c:3891
 usb_disable_device+0x3d4/0x8d0 drivers/usb/core/message.c:1478
 usb_disconnect+0x315/0x970 drivers/usb/core/hub.c:2345
 hub_port_connect drivers/usb/core/hub.c:5407 [inline]
 hub_port_connect_change drivers/usb/core/hub.c:5707 [inline]
 port_event drivers/usb/core/hub.c:5871 [inline]
 hub_event+0x1cf9/0x4f60 drivers/usb/core/hub.c:5953
 process_one_work+0x98b/0x1630 kernel/workqueue.c:3306
 process_scheduled_works kernel/workqueue.c:3389 [inline]
 worker_thread+0xb49/0x1140 kernel/workqueue.c:3470
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

Last potentially related work creation:
 kasan_save_stack+0x3e/0x60 mm/kasan/common.c:57
 kasan_record_aux_stack+0xbd/0xd0 mm/kasan/generic.c:556
 insert_work+0x3d/0x330 kernel/workqueue.c:2226
 __queue_work+0xcfd/0x1010 kernel/workqueue.c:2381
 queue_delayed_work_on+0x11a/0x1e0 kernel/workqueue.c:2600
 queue_delayed_work include/linux/workqueue.h:713 [inline]
 schedule_delayed_work include/linux/workqueue.h:855 [inline]
 btusb_recv_event drivers/bluetooth/btusb.c:1233 [inline]
 btusb_recv_intr+0x48a/0x750 drivers/bluetooth/btusb.c:1296
 btusb_intr_complete+0x164/0x4c0 drivers/bluetooth/btusb.c:1481
 __usb_hcd_giveback_urb+0x3b3/0x5e0 drivers/usb/core/hcd.c:1657
 dummy_timer+0x8a9/0x47d0 drivers/usb/gadget/udc/dummy_hcd.c:2005
 __run_hrtimer kernel/time/hrtimer.c:2032 [inline]
 __hrtimer_run_queues+0x405/0xb10 kernel/time/hrtimer.c:2096
 hrtimer_run_softirq+0x18f/0x260 kernel/time/hrtimer.c:2113
 handle_softirqs+0x1de/0x6d0 kernel/softirq.c:626
 __do_softirq kernel/softirq.c:660 [inline]
 run_ktimerd+0x69/0x100 kernel/softirq.c:1155
 smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

The buggy address belongs to the object at ffff888029fc0000
 which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 424 bytes inside of
 freed 4096-byte region [ffff888029fc0000, ffff888029fc1000)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x29fc0
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x80000000000040(head|node=0|zone=1)
page_type: f5(slab)
raw: 0080000000000040 ffff88813fea2140 dead000000000100 dead000000000122
raw: 0000000000000000 0000000800040004 00000000f5000000 0000000000000000
head: 0080000000000040 ffff88813fea2140 dead000000000100 dead000000000122
head: 0000000000000000 0000000800040004 00000000f5000000 0000000000000000
head: 0080000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd2040(__GFP_IO|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 12506, tgid 12506 (udevd), ts 1311497819285, free_ts 1308795551293
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1861
 prep_new_page mm/page_alloc.c:1869 [inline]
 get_page_from_freelist+0x27d6/0x2850 mm/page_alloc.c:3949
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5292
 alloc_slab_page mm/slub.c:3289 [inline]
 allocate_slab+0x74/0x5e0 mm/slub.c:3404
 new_slab mm/slub.c:3447 [inline]
 refill_objects+0x33c/0x3d0 mm/slub.c:7319
 refill_sheaf mm/slub.c:2827 [inline]
 __pcs_replace_empty_main+0x373/0x720 mm/slub.c:4664
 alloc_from_pcs mm/slub.c:4762 [inline]
 slab_alloc_node mm/slub.c:4896 [inline]
 __do_kmalloc_node mm/slub.c:5307 [inline]
 __kmalloc_noprof+0x530/0x7b0 mm/slub.c:5320
 kmalloc_noprof include/linux/slab.h:954 [inline]
 tomoyo_realpath_from_path+0xe3/0x5d0 security/tomoyo/realpath.c:251
 tomoyo_get_realpath security/tomoyo/file.c:151 [inline]
 tomoyo_path2_perm+0x2e7/0x760 security/tomoyo/file.c:928
 tomoyo_path_rename+0x14e/0x1b0 security/tomoyo/tomoyo.c:300
 security_path_rename+0x248/0x460 security/security.c:1544
 filename_renameat2+0x4c1/0x9c0 fs/namei.c:6167
 __do_sys_rename fs/namei.c:6216 [inline]
 __se_sys_rename+0x55/0x2c0 fs/namei.c:6212
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
page last free pid 14890 tgid 14890 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1405 [inline]
 free_pages_prepare+0x900/0xa60 mm/page_alloc.c:1450
 __free_contig_range_common+0x174/0x340 mm/page_alloc.c:6883
 __free_contig_range mm/page_alloc.c:6928 [inline]
 free_pages_bulk+0x48/0x120 mm/page_alloc.c:5245
 vfree+0x292/0x390 mm/vmalloc.c:3467
 vb2_vmalloc_put+0x68/0xb0 drivers/media/common/videobuf2/videobuf2-vmalloc.c:68
 __vb2_buf_mem_free+0x119/0x2d0 drivers/media/common/videobuf2/videobuf2-core.c:275
 __vb2_free_mem drivers/media/common/videobuf2/videobuf2-core.c:571 [inline]
 __vb2_queue_free+0x414/0xb00 drivers/media/common/videobuf2/videobuf2-core.c:599
 vb2_core_reqbufs+0x7a0/0x1410 drivers/media/common/videobuf2/videobuf2-core.c:905
 __vb2_cleanup_fileio+0x109/0x1f0 drivers/media/common/videobuf2/videobuf2-core.c:2977
 vb2_core_queue_release+0x27/0x150 drivers/media/common/videobuf2/videobuf2-core.c:2676
 vb2_queue_release drivers/media/common/videobuf2/videobuf2-v4l2.c:956 [inline]
 _vb2_fop_release drivers/media/common/videobuf2/videobuf2-v4l2.c:1159 [inline]
 vb2_fop_release+0x171/0x200 drivers/media/common/videobuf2/videobuf2-v4l2.c:1173
 v4l2_release+0x1b2/0x370 drivers/media/v4l2-core/v4l2-dev.c:468
 __fput+0x461/0xa70 fs/file_table.c:510
 task_work_run+0x1d9/0x270 kernel/task_work.c:233
 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
 __exit_to_user_mode_loop kernel/entry/common.c:67 [inline]
 exit_to_user_mode_loop+0xf3/0x4d0 kernel/entry/common.c:98
 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
 syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
 syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
 do_syscall_64+0x33e/0xf80 arch/x86/entry/syscall_64.c:100

Memory state around the buggy address:
 ffff888029fc0080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff888029fc0100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff888029fc0180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                  ^
 ffff888029fc0200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff888029fc0280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* Re: [GIT PULL] bluetooth 2026-05-14
From: Greg KH @ 2026-05-19 10:30 UTC (permalink / raw)
  To: Thorsten Leemhuis
  Cc: stable@vger.kernel.org, Sasha Levin, linux-bluetooth, netdev,
	Luiz Augusto von Dentz, davem, kuba,
	Linux kernel regressions list, Linus Torvalds
In-Reply-To: <4946f5f3-b7e2-4949-89f7-6427015027c6@leemhuis.info>

On Tue, May 19, 2026 at 09:04:38AM +0200, Thorsten Leemhuis wrote:
> On 5/15/26 17:10, Thorsten Leemhuis wrote:
> > On 5/14/26 19:23, Luiz Augusto von Dentz wrote:
> >
> >> The following changes since commit c78bdba7b9666020c0832150a4fc4c0aebc7c6ac:
> >>   net: phy: DP83TC811: add reading of abilities (2026-05-14 15:17:12 +0200)
> >>
> >> are available in the Git repository at:
> >>
> >>   git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git tags/for-net-2026-05-14
> >>
> >> for you to fetch changes up to 375ba7484132662a4a8c7547d088fb6275c00282:
> >>
> >>   Bluetooth: hci_qca: Convert timeout from jiffies to ms (2026-05-14 09:58:08 -0400)
> > 
> > It seems this PR sadly came too late for this week's net PR to mainline
> > that was merged yesterday.
> > 
> > TWIMC, from my point of view, it would be great if we somehow could
> > still get the changes from this PR or at least the btmtk fix it
> > contains[1] to mainline this week before -rc4, as it is fixing a
> > regression known since 2026-04-24 that at least five people encountered
> > with mainline since -rc3 due to 634a4408c0615c ("Bluetooth: btmtk:
> > validate WMT event SKB length before struct access") [006b9943b982 in
> > -next].
> 
> Greg, Sasha, that [1] fix I was talking about now reached -next as
> 162b1adeb057d2 ("Bluetooth: btmtk: accept too short WMT FUNC_CTRL
> events") and will likely hit mainline on Thursday or so with the weekly
> -net PR to -mainline. If that's good enough for you, I'd say it would be
> good to pick this up for the next round of stable kernels.

That "Fixes:" tag is referring to something that is also not in any
tree, but that commit does have a cc: stable in it.  So do we need both
of these:

041e88fb0c08 ("Bluetooth: btmtk: validate WMT event SKB length before struct access")
162b1adeb057 ("Bluetooth: btmtk: accept too short WMT FUNC_CTRL events")

Or just one?

confused,

greg k-h

^ permalink raw reply

* RE: [v2] Bluetooth: RFCOMM: add minimum length check in rfcomm_recv_frame
From: bluez.test.bot @ 2026-05-19  9:14 UTC (permalink / raw)
  To: linux-bluetooth, meatuni001
In-Reply-To: <20260519073003.34206-1-meatuni001@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 936 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1097117

---Test result---

Test Summary:
CheckPatch                    PASS      0.42 seconds
GitLint                       PASS      0.18 seconds
SubjectPrefix                 PASS      0.06 seconds
BuildKernel                   PASS      21.39 seconds
CheckAllWarning               PASS      23.49 seconds
CheckSparse                   PASS      21.19 seconds
BuildKernel32                 PASS      20.51 seconds
TestRunnerSetup               PASS      420.35 seconds
TestRunner_rfcomm-tester      PASS      59.01 seconds
IncrementalBuild              PASS      19.56 seconds



https://github.com/bluez/bluetooth-next/pull/214

---
Regards,
Linux Bluetooth


^ permalink raw reply

* RE: [BlueZ,1/2] client/btpclient: Fix GAP unpair command
From: bluez.test.bot @ 2026-05-19  9:08 UTC (permalink / raw)
  To: linux-bluetooth, frederic.danis
In-Reply-To: <20260519074742.163473-1-frederic.danis@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 25436 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1097130

---Test result---

Test Summary:
CheckPatch                    PASS      0.94 seconds
GitLint                       PASS      0.67 seconds
BuildEll                      PASS      20.16 seconds
BluezMake                     FAIL      53.08 seconds
CheckSmatch                   FAIL      103.44 seconds
bluezmakeextell               FAIL      24.91 seconds
IncrementalBuild              FAIL      666.00 seconds
ScanBuild                     FAIL      110.46 seconds

Details
##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:

client/btpclient/gap.c: In function ‘btp_gap_reset’:
client/btpclient/gap.c:322:7: error: unused variable ‘prop’ [-Werror=unused-variable]
  322 |  bool prop;
      |       ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7058: client/btpclient/gap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12990:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12990 | int main(int argc, char *argv[])
      |     ^~~~
make: *** [Makefile:4172: all] Error 2
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:

src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1366:23: warning: Variable length array is used.
src/shared/gatt-server.c:271:25: warning: Variable length array is used.
src/shared/gatt-server.c:614:25: warning: Variable length array is used.
src/shared/gatt-server.c:712:25: warning: Variable length array is used.
src/shared/bap.c:312:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1366:23: warning: Variable length array is used.
src/shared/gatt-server.c:271:25: warning: Variable length array is used.
src/shared/gatt-server.c:614:25: warning: Variable length array is used.
src/shared/gatt-server.c:712:25: warning: Variable length array is used.
src/shared/bap.c:312:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
tools/mesh-cfgtest.c:1453:17: warning: unknown escape sequence: '\%'
tools/sco-tester.c: note: in included file:
./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures
./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structures
tools/bneptest.c:634:39: warning: unknown escape sequence: '\%'
tools/seq2bseq.c:57:26: warning: Variable length array is used.
tools/obex-client-tool.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
client/btpclient/gap.c: In function ‘btp_gap_reset’:
client/btpclient/gap.c:322:7: error: unused variable ‘prop’ [-Werror=unused-variable]
  322 |  bool prop;
      |       ^~~~
client/btpclient/gatt.c: note: in included file:
./src/shared/btp.h:328:41: warning: array of flexible structures
./src/shared/btp.h:333:55: warning: array of flexible structures
./src/shared/btp.h:356:47: warning: array of flexible structures
./src/shared/btp.h:385:42: warning: array of flexible structures
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7058: client/btpclient/gap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4172: all] Error 2
##############################
Test: bluezmakeextell - FAIL
Desc: Build Bluez with External ELL
Output:

client/btpclient/gap.c: In function ‘btp_gap_reset’:
client/btpclient/gap.c:322:7: error: unused variable ‘prop’ [-Werror=unused-variable]
  322 |  bool prop;
      |       ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7058: client/btpclient/gap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4172: all] Error 2
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:

client/btpclient/gap.c: In function ‘btp_gap_reset’:
client/btpclient/gap.c:322:7: error: unused variable ‘prop’ [-Werror=unused-variable]
  322 |  bool prop;
      |       ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7058: client/btpclient/gap.o] Error 1
make: *** [Makefile:4172: all] Error 2
[BlueZ,2/2] client/btpclient: Don't remove all devices on GAP Reset command

client/btpclient/gap.c: In function ‘btp_gap_reset’:
client/btpclient/gap.c:322:7: error: unused variable ‘prop’ [-Werror=unused-variable]
  322 |  bool prop;
      |       ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7058: client/btpclient/gap.o] Error 1
make: *** [Makefile:4172: all] Error 2
##############################
Test: ScanBuild - FAIL
Desc: Run Scan Build
Output:

src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed
        gatt_db_unregister(op->client->db, op->db_id);
                           ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed
        discovery_op_complete(op, false, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:992:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed
        discover_all(op);
        ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed
        notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
                                          ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed
                                                        discovery_op_ref(op),
                                                        ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed
        complete_write_long_op(req, success, 0, false);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed
        request_unref(req);
        ^~~~~~~~~~~~~~~~~~
13 warnings generated.
src/shared/bap.c:1529:8: warning: Use of memory after it is freed
        bap = bt_bap_ref_safe(bap);
              ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340:20: warning: Use of memory after it is freed
        return queue_find(stream->bap->streams, NULL, stream);
                          ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed
        gatt_db_unregister(op->client->db, op->db_id);
                           ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed
        discovery_op_complete(op, false, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:992:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed
        discover_all(op);
        ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed
        notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
                                          ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed
                                                        discovery_op_ref(op),
                                                        ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed
        complete_write_long_op(req, success, 0, false);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed
        request_unref(req);
        ^~~~~~~~~~~~~~~~~~
13 warnings generated.
tools/hciattach.c:817:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 10)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:865:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 4)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:887:8: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
                if ((n = read_hci_event(fd, resp, 10)) < 0) {
                     ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:909:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 4)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:930:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 4)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:974:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 6)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 warnings generated.
src/shared/bap.c:1529:8: warning: Use of memory after it is freed
        bap = bt_bap_ref_safe(bap);
              ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340:20: warning: Use of memory after it is freed
        return queue_find(stream->bap->streams, NULL, stream);
                          ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/oui.c:50:2: warning: Value stored to 'hwdb' is never read
        hwdb = udev_hwdb_unref(hwdb);
        ^      ~~~~~~~~~~~~~~~~~~~~~
src/oui.c:53:2: warning: Value stored to 'udev' is never read
        udev = udev_unref(udev);
        ^      ~~~~~~~~~~~~~~~~
2 warnings generated.
tools/rfcomm.c:234:3: warning: Value stored to 'i' is never read
                i = execvp(cmdargv[0], cmdargv);
                ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:234:7: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                i = execvp(cmdargv[0], cmdargv);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:354:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd'
                if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
                     ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:497:14: warning: Assigned value is garbage or undefined
        req.channel = raddr.rc_channel;
                    ^ ~~~~~~~~~~~~~~~~
tools/rfcomm.c:515:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd'
                if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
                     ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings generated.
tools/ciptool.c:351:7: warning: 5th function call argument is an uninitialized value
        sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK));
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdp-xml.c:126:10: warning: Assigned value is garbage or undefined
                buf[1] = data[i + 1];
                       ^ ~~~~~~~~~~~
src/sdp-xml.c:306:11: warning: Assigned value is garbage or undefined
                        buf[1] = data[i + 1];
                               ^ ~~~~~~~~~~~
src/sdp-xml.c:344:11: warning: Assigned value is garbage or undefined
                        buf[1] = data[i + 1];
                               ^ ~~~~~~~~~~~
3 warnings generated.
tools/sdptool.c:941:26: warning: Result of 'malloc' is converted to a pointer of type 'uint32_t', which is incompatible with sizeof operand type 'int'
                        uint32_t *value_int = malloc(sizeof(int));
                        ~~~~~~~~~~            ^~~~~~ ~~~~~~~~~~~
tools/sdptool.c:980:4: warning: 1st function call argument is an uninitialized value
                        free(allocArray[i]);
                        ^~~~~~~~~~~~~~~~~~~
tools/sdptool.c:3777:2: warning: Potential leak of memory pointed to by 'si.name'
        return add_service(0, &si);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/sdptool.c:4112:4: warning: Potential leak of memory pointed to by 'context.svc'
                        return -1;
                        ^~~~~~~~~
4 warnings generated.
tools/avtest.c:243:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:253:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:262:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:276:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:283:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:290:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:297:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:309:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:313:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:322:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:326:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:335:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:342:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:364:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:368:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:377:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:381:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:394:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:398:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:405:4: warning: Value stored to 'len' is never read
                        len = write(sk, buf, 2);
                        ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:415:4: warning: Value stored to 'len' is never read
                        len = write(sk, buf, 2);
                        ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:580:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 2);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:588:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, invalid ? 2 : 3);
                ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:602:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 4 + media_transport_size);
                ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:615:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:625:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:637:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:652:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:664:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:673:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:680:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 2);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:716:2: warning: Value stored to 'len' is never read
        len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed));
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 warnings generated.
tools/btproxy.c:836:15: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                        tcp_port = atoi(optarg);
                                   ^~~~~~~~~~~~
tools/btproxy.c:839:8: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                        if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
                            ^~~~~~~~~~~~~~
2 warnings generated.
tools/create-image.c:76:3: warning: Value stored to 'fd' is never read
                fd = -1;
                ^    ~~
tools/create-image.c:84:3: warning: Value stored to 'fd' is never read
                fd = -1;
                ^    ~~
tools/create-image.c:92:3: warning: Value stored to 'fd' is never read
                fd = -1;
                ^    ~~
tools/create-image.c:105:2: warning: Value stored to 'fd' is never read
        fd = -1;
        ^    ~~
4 warnings generated.
tools/btgatt-client.c:1822:2: warning: Value stored to 'argv' is never read
        argv += optind;
        ^       ~~~~~~
1 warning generated.
tools/btgatt-server.c:1204:2: warning: Value stored to 'argv' is never read
        argv -= optind;
        ^       ~~~~~~
1 warning generated.
tools/check-selftest.c:42:3: warning: Value stored to 'ptr' is never read
                ptr = fgets(result, sizeof(result), fp);
                ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/gatt-service.c:294:2: warning: 2nd function call argument is an uninitialized value
        chr_write(chr, value, len);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/obex-server-tool.c:133:13: warning: Null pointer passed to 1st parameter expecting 'nonnull'
        data->fd = open(name, O_WRONLY | O_CREAT | O_NOCTTY, 0600);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/obex-server-tool.c:192:13: warning: Null pointer passed to 1st parameter expecting 'nonnull'
        data->fd = open(name, O_RDONLY | O_NOCTTY, 0);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
client/btpclient/gap.c: In function ‘btp_gap_reset’:
client/btpclient/gap.c:322:7: error: unused variable ‘prop’ [-Werror=unused-variable]
  322 |  bool prop;
      |       ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:7058: client/btpclient/gap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
tools/test-runner.c:1370:2: warning: Address of stack memory associated with local variable 'kernel_path' is still referred to by the global variable 'kernel_image' upon returning to the caller.  This will be a dangling reference
        return EXIT_SUCCESS;
        ^~~~~~~~~~~~~~~~~~~
1 warning generated.
client/btpclient/btpclientctl.c:402:3: warning: Value stored to 'bit' is never read
                bit = 0;
                ^     ~
client/btpclient/btpclientctl.c:1655:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
        memcpy(cp->data, ad_data, ad_len);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
make: *** [Makefile:4172: all] Error 2


https://github.com/bluez/bluez/pull/2135

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH v3 7/9] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam, Bartosz Golaszewski,
	Dmitry Baryshkov
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Power supply to the M.2 Bluetooth device attached to the host using M.2
connector is controlled using the 'uart' pwrseq device. So add support for
getting the pwrseq device if the OF graph link is present. Once obtained,
the existing pwrseq APIs can be used to control the power supplies of the
M.2 card.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index cd1834246b47..c83fe72bc549 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -26,6 +26,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_graph.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/pwrseq/consumer.h>
@@ -2443,6 +2444,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 	case QCA_WCN6750:
 	case QCA_WCN6855:
 	case QCA_WCN7850:
+		/*
+		 * OF graph link is only present for BT devices attached through
+		 * the M.2 Key E connector.
+		 */
+		if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
+			qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->ctrl->dev,
+								   "uart");
+			if (IS_ERR(qcadev->bt_power->pwrseq))
+				return PTR_ERR(qcadev->bt_power->pwrseq);
+			break;
+		}
+
 		if (!device_property_present(&serdev->dev, "enable-gpios")) {
 			/*
 			 * Backward compatibility with old DT sources. If the

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 9/9] Bluetooth: hci_qca: Set 'bt_en_available' based on W_DISABLE2# presence in M.2 connector
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam, Bartosz Golaszewski
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Check if the M.2 connector supports the W_DISABLE2# property or not by
querying the pwrseq provider's DT node. If not available, then set
'bt_en_available' flag to 'false'. This flag is used to set the
HCI_QUIRK_NON_PERSISTENT_SETUP HCI quirk, which informs the HCI layer
whether the shutdown() callback for the device can be triggered or not.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 3e71a72ea7c7..b5439b9956cf 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2449,10 +2449,17 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		 * the M.2 Key E connector.
 		 */
 		if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
+			struct device *dev;
+
 			qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->ctrl->dev,
 								   "uart");
 			if (IS_ERR(qcadev->bt_power->pwrseq))
 				return PTR_ERR(qcadev->bt_power->pwrseq);
+
+			dev = pwrseq_to_device(qcadev->bt_power->pwrseq);
+			if (!device_property_present(dev, "w-disable2-gpios"))
+				bt_en_available = false;
+
 			break;
 		}
 

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 8/9] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam, Dmitry Baryshkov,
	Bartosz Golaszewski
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

'power_ctrl_enabled' flag is used to indicate the availability of the BT_EN
GPIO in devicetree. But the naming causes confusion with the new pwrctrl
framework.

So rename it to 'bt_en_available' to make it clear and explicit.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index c83fe72bc549..3e71a72ea7c7 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2391,7 +2391,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 	struct hci_dev *hdev;
 	const struct qca_device_data *data;
 	int err;
-	bool power_ctrl_enabled = true;
+	bool bt_en_available = true;
 
 	qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
 	if (!qcadev)
@@ -2499,7 +2499,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		    (data->soc_type == QCA_WCN6750 ||
 		     data->soc_type == QCA_WCN6855 ||
 		     data->soc_type == QCA_WCN7850))
-			power_ctrl_enabled = false;
+			bt_en_available = false;
 
 		qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
 					       GPIOD_IN);
@@ -2537,7 +2537,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		}
 
 		if (!qcadev->bt_en)
-			power_ctrl_enabled = false;
+			bt_en_available = false;
 
 		qcadev->susclk = devm_clk_get_optional_enabled_with_rate(
 					&serdev->dev, NULL, SUSCLK_RATE_32KHZ);
@@ -2555,7 +2555,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 
 	hdev = qcadev->serdev_hu.hdev;
 
-	if (power_ctrl_enabled) {
+	if (bt_en_available) {
 		hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP);
 		hdev->shutdown = qca_hci_shutdown;
 	}

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 5/9] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Currently, pwrseq_pcie_m2_create_bt_node() hardcodes the BT compatible for
creating the devicetree node. But to allow adding support for more devices
in the future, create the BT node based on the pci_device_id[] table. The
BT compatible is passed using 'driver_data'.

Co-developed-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Wei Deng <wei.deng@oss.qualcomm.com>
Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 8164c4428977..e82821655fc4 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -185,14 +185,29 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
 	return PWRSEQ_NO_MATCH;
 }
 
+static const struct pci_device_id pwrseq_m2_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107),
+	  .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
+	{ } /* Sentinel */
+};
+
 static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 					struct pwrseq_pci_dev *pci_dev,
-					struct device_node *parent)
+					struct device_node *parent,
+					struct pci_dev *pdev)
 {
+	const struct pci_device_id *id;
 	struct device *dev = ctx->dev;
+	const char *compatible;
 	struct device_node *np;
 	int ret;
 
+	id = pci_match_id(pwrseq_m2_pci_ids, pdev);
+	if (WARN_ON_ONCE(!id)) /* Shouldn't happen */
+		return -ENODEV;
+
+	compatible = (const char *)id->driver_data;
+
 	pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
 	if (!pci_dev->ocs)
 		return -ENOMEM;
@@ -206,7 +221,7 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 		goto err_destroy_changeset;
 	}
 
-	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
+	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", compatible);
 	if (ret) {
 		dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
 		goto err_destroy_changeset;
@@ -279,13 +294,14 @@ static int pwrseq_pcie_m2_create_serdev_one(struct pwrseq_pcie_m2_ctx *ctx,
 		goto err_free_pci_dev;
 	}
 
-	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
+	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent, pdev);
 	if (ret)
 		goto err_free_serdev;
 
 	ret = serdev_device_add(pci_dev->serdev);
 	if (ret) {
-		dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
+		dev_err(dev, "Failed to add serdev for PCI device (%s): %d\n",
+			pci_name(pdev), ret);
 		goto err_free_dt_node;
 	}
 
@@ -351,11 +367,6 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 	mutex_unlock(&ctx->list_lock);
 }
 
-static const struct pci_device_id pwrseq_m2_pci_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107) },
-	{ } /* Sentinel */
-};
-
 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 6/9] power: sequencing: Add an API to return the pwrseq device's 'dev' pointer
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

The consumer drivers can make use of the pwrseq device's 'dev' pointer to
query the pwrseq provider's DT node to check for existence of specific
properties.

Hence, add an API to return the pwrseq device's 'dev' pointer to consumers.

Note that since pwrseq_get() would've increased the pwrseq refcount, there
is no need to increase the refcount in this API again.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/core.c | 9 +++++++++
 include/linux/pwrseq/consumer.h | 7 +++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c
index 4dff71be11b6..96ad557297f5 100644
--- a/drivers/power/sequencing/core.c
+++ b/drivers/power/sequencing/core.c
@@ -965,6 +965,15 @@ int pwrseq_power_off(struct pwrseq_desc *desc)
 }
 EXPORT_SYMBOL_GPL(pwrseq_power_off);
 
+struct device *pwrseq_to_device(struct pwrseq_desc *desc)
+{
+	if (!desc)
+		return NULL;
+
+	return &desc->pwrseq->dev;
+}
+EXPORT_SYMBOL_GPL(pwrseq_to_device);
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 
 struct pwrseq_debugfs_count_ctx {
diff --git a/include/linux/pwrseq/consumer.h b/include/linux/pwrseq/consumer.h
index 7d583b4f266e..3c907c9e1885 100644
--- a/include/linux/pwrseq/consumer.h
+++ b/include/linux/pwrseq/consumer.h
@@ -23,6 +23,8 @@ devm_pwrseq_get(struct device *dev, const char *target);
 int pwrseq_power_on(struct pwrseq_desc *desc);
 int pwrseq_power_off(struct pwrseq_desc *desc);
 
+struct device *pwrseq_to_device(struct pwrseq_desc *desc);
+
 #else /* CONFIG_POWER_SEQUENCING */
 
 static inline struct pwrseq_desc * __must_check
@@ -51,6 +53,11 @@ static inline int pwrseq_power_off(struct pwrseq_desc *desc)
 	return -ENOSYS;
 }
 
+static inline struct device *pwrseq_to_device(struct pwrseq_desc *desc)
+{
+	return NULL;
+}
+
 #endif /* CONFIG_POWER_SEQUENCING */
 
 #endif /* __POWER_SEQUENCING_CONSUMER_H__ */

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 4/9] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:55 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

So far, the driver is registering a notifier to create serdev for the PCI
devices that are going to be attached after probe. But it doesn't handle
the devices present before probe. Due to this, serdev is not getting
created for those existing devices.

Hence, create serdev for PCI devices available before probe as well.

Note that the serdev for available devices are created before
registering the notifier. There is a small window where a device could
appear after pwrseq_pcie_m2_create_serdev(), before notifier registration.
But since M.2 cards are fixed to a slot, they are mostly added either
before booting the host or after using hotplug. So this window is mostly
theoretical.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 81 ++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 13 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 038271207a27..8164c4428977 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -236,7 +236,7 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 	return ret;
 }
 
-static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+static int pwrseq_pcie_m2_create_serdev_one(struct pwrseq_pcie_m2_ctx *ctx,
 					struct pci_dev *pdev)
 {
 	struct serdev_controller *serdev_ctrl;
@@ -259,6 +259,14 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 		return 0;
 	}
 
+	/* Bail out if the serdev device was already created for the PCI dev */
+	scoped_guard(mutex, &ctx->list_lock) {
+		list_for_each_entry(pci_dev, &ctx->pci_devices, list) {
+			if (pci_dev->pdev == pdev)
+				return 0;
+		}
+	}
+
 	pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
 	if (!pci_dev) {
 		ret = -ENOMEM;
@@ -368,7 +376,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 	switch (action) {
 	case BUS_NOTIFY_ADD_DEVICE:
 		if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
-			ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
+			ret = pwrseq_pcie_m2_create_serdev_one(ctx, pdev);
 			if (ret)
 				return notifier_from_errno(ret);
 		}
@@ -400,7 +408,7 @@ static bool pwrseq_pcie_m2_check_remote_node(struct device *dev, u8 port, u8 end
  * protocol device needs to be created manually with the help of the notifier
  * of the discoverable bus like PCIe.
  */
-static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, struct device *dev)
+static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx)
 {
 	int ret;
 
@@ -408,18 +416,56 @@ static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, stru
 	 * Register a PCI notifier for Key E connector that has PCIe as Port
 	 * 0/Endpoint 0 interface and Serial as Port 3/Endpoint 0 interface.
 	 */
-	if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) {
-		if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) {
-			ctx->dev = dev;
-			ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
-			ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
-			if (ret)
-				return dev_err_probe(dev, ret,
-						     "Failed to register notifier for serdev\n");
+	if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
+	    !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
+		return 0;
+
+	ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
+	ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
+	if (ret)
+		return dev_err_probe(ctx->dev, ret,
+				     "Failed to register notifier for serdev\n");
+	return 0;
+}
+
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+{
+	struct pci_dev *pdev = NULL;
+	int ret;
+
+	if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
+	    !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
+		return 0;
+
+	struct device_node *pci_parent __free(device_node) =
+				of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0);
+	if (!pci_parent)
+		return 0;
+
+	/* Create serdev for existing PCI devices if required */
+	for_each_pci_dev(pdev) {
+		if (!pdev->dev.parent || pci_parent != pdev->dev.parent->of_node)
+			continue;
+
+		if (!pci_match_id(pwrseq_m2_pci_ids, pdev))
+			continue;
+
+		ret = pwrseq_pcie_m2_create_serdev_one(ctx, pdev);
+		if (ret) {
+			dev_err_probe(ctx->dev, ret,
+				      "Failed to create serdev for PCI device (%s)\n",
+				      pci_name(pdev));
+			pci_dev_put(pdev);
+			goto err_remove_serdev;
 		}
 	}
 
 	return 0;
+
+err_remove_serdev:
+	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+
+	return ret;
 }
 
 static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
@@ -481,16 +527,25 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
 
 	mutex_init(&ctx->list_lock);
 	INIT_LIST_HEAD(&ctx->pci_devices);
+	ctx->dev = dev;
+
+	/* Create serdev for available PCI devices (if required) */
+	ret = pwrseq_pcie_m2_create_serdev(ctx);
+	if (ret)
+		goto err_destroy_mutex;
+
 	/*
 	 * Register a notifier for creating protocol devices for
 	 * non-discoverable busses like UART.
 	 */
-	ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
+	ret = pwrseq_pcie_m2_register_notifier(ctx);
 	if (ret)
-		goto err_destroy_mutex;
+		goto err_remove_serdev;
 
 	return 0;
 
+err_remove_serdev:
+	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
 err_destroy_mutex:
 	mutex_destroy(&ctx->list_lock);
 err_free_regulators:

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 3/9] power: sequencing: pcie-m2: Improve PCI device ID check
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:55 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam, Konrad Dybcio
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Instead of hardcoding the PCI device check, use pci_match_id() to check for
the known IDs using the pwrseq_m2_pci_ids[] array.

This makes adding support for new devices easier.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 469e130330fa..038271207a27 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -343,6 +343,11 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 	mutex_unlock(&ctx->list_lock);
 }
 
+static const struct pci_device_id pwrseq_m2_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107) },
+	{ } /* Sentinel */
+};
+
 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {
@@ -362,16 +367,14 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 
 	switch (action) {
 	case BUS_NOTIFY_ADD_DEVICE:
-		/* Create serdev device for WCN7850 */
-		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
+		if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
 			ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
 			if (ret)
 				return notifier_from_errno(ret);
 		}
 		break;
 	case BUS_NOTIFY_REMOVED_DEVICE:
-		/* Destroy serdev device for WCN7850 */
-		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
+		if (pci_match_id(pwrseq_m2_pci_ids, pdev))
 			pwrseq_pcie_m2_remove_serdev(ctx, pdev);
 
 		break;

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 1/9] power: sequencing: pcie-m2: Fix inconsistent function prefixes
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:55 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

All functions in this driver follow 'pwrseq_pcie_m2' prefix except a few.
Fix them to avoid inconsistency.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index ef69ae268059..b2ed336fd5ad 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -177,7 +177,7 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
 	return PWRSEQ_NO_MATCH;
 }
 
-static int pwrseq_m2_pcie_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 					struct device_node *parent)
 {
 	struct device *dev = ctx->dev;
@@ -254,7 +254,7 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 		goto err_put_ctrl;
 	}
 
-	ret = pwrseq_m2_pcie_create_bt_node(ctx, serdev_parent);
+	ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
 	if (ret)
 		goto err_free_serdev;
 
@@ -299,7 +299,7 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 	}
 }
 
-static int pwrseq_m2_pcie_notify(struct notifier_block *nb, unsigned long action,
+static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {
 	struct pwrseq_pcie_m2_ctx *ctx = container_of(nb, struct pwrseq_pcie_m2_ctx, nb);
@@ -364,7 +364,7 @@ static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, stru
 	if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) {
 		if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) {
 			ctx->dev = dev;
-			ctx->nb.notifier_call = pwrseq_m2_pcie_notify;
+			ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
 			ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
 			if (ret)
 				return dev_err_probe(dev, ret,

-- 
2.48.1



^ permalink raw reply related

* [PATCH v3 0/9] Fixes/improvements for the PCI M.2 power sequencing driver
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:55 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam, Konrad Dybcio,
	Bartosz Golaszewski, Dmitry Baryshkov

Hi,

This series has several key improvements and fixes to the M.2 power sequencing
driver and also the BT HCI_QCA driver. Notably, this series allows the M.2 power
sequencing driver to work with more M.2 cards, not just WCN7850. It also allows
the BT HCI_QCA driver to detect whether it can control BT_EN (or W_DISABLE2#)
signal on the connector and set the HCI_QUIRK_NON_PERSISTENT_SETUP quirk.

Testing
=======

This series was tested on Lenovo Thinkpad T14s together with the below DTS
patches:
https://github.com/Mani-Sadhasivam/linux/commit/29534d15307551b2355eb254601dec511169f0aa
https://github.com/Mani-Sadhasivam/linux/commit/f4eaacfe647674be200847092b43cdef2194fc55

Merge Strategy
==============

Since the BT HCI_QCA changes depend on the pwrseq changes, it would be good to
merge the whole series through pwrseq tree or through an immutable branch.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
Changes in v3:
- Renamed __pwrseq_pcie_m2_create_serdev() to pwrseq_pcie_m2_create_serdev_one()
- Moved the pwrseq patches together for creating the immutable pwrseq branch
- Collected tags

Changes in v2:
- Dropped the pwrseq_is_fixed() change in favor or exporting pwrseq device's dev
  pointer and using it to check for the presence of W_DISABLE2# property
- Dropped the BT_EN fix for the Qcom WCN devices since it will be handled
  separately
- Collected tags
- Link to v1: https://patch.msgid.link/20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com

---
Manivannan Sadhasivam (9):
      power: sequencing: pcie-m2: Fix inconsistent function prefixes
      power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
      power: sequencing: pcie-m2: Improve PCI device ID check
      power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
      power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
      power: sequencing: Add an API to return the pwrseq device's 'dev' pointer
      Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
      Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
      Bluetooth: hci_qca: Set 'bt_en_available' based on W_DISABLE2# presence in M.2 connector

 drivers/bluetooth/hci_qca.c               |  28 +++-
 drivers/power/sequencing/core.c           |   9 ++
 drivers/power/sequencing/pwrseq-pcie-m2.c | 232 ++++++++++++++++++++++--------
 include/linux/pwrseq/consumer.h           |   7 +
 4 files changed, 215 insertions(+), 61 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260422-pwrseq-m2-bt-abdaa71094eb

Best regards,
-- 
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>



^ permalink raw reply

* [PATCH v3 2/9] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-19  8:55 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
	Wei Deng, Manivannan Sadhasivam
In-Reply-To: <20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Current code makes it possible to create serdev for only one PCI device.
But for scaling this driver, it is necessary to allow creating serdev for
multiple PCI devices.

Hence, add provision for it by creating 'struct pwrseq_pci_dev' for each
PCI device that requires serdev and add them to
'pwrseq_pcie_m2_ctx::pci_devices' list.

Tested-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 127 +++++++++++++++++++++---------
 1 file changed, 88 insertions(+), 39 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index b2ed336fd5ad..469e130330fa 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -7,6 +7,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
+#include <linux/list.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -19,6 +20,13 @@
 #include <linux/serdev.h>
 #include <linux/slab.h>
 
+struct pwrseq_pci_dev {
+	struct serdev_device *serdev;
+	struct of_changeset *ocs;
+	struct pci_dev *pdev;
+	struct list_head list;
+};
+
 struct pwrseq_pcie_m2_pdata {
 	const struct pwrseq_target_data **targets;
 };
@@ -32,9 +40,9 @@ struct pwrseq_pcie_m2_ctx {
 	struct notifier_block nb;
 	struct gpio_desc *w_disable1_gpio;
 	struct gpio_desc *w_disable2_gpio;
-	struct serdev_device *serdev;
-	struct of_changeset *ocs;
 	struct device *dev;
+	struct list_head pci_devices;
+	struct mutex list_lock;
 };
 
 static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq)
@@ -178,38 +186,39 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
 }
 
 static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+					struct pwrseq_pci_dev *pci_dev,
 					struct device_node *parent)
 {
 	struct device *dev = ctx->dev;
 	struct device_node *np;
 	int ret;
 
-	ctx->ocs = kzalloc_obj(*ctx->ocs);
-	if (!ctx->ocs)
+	pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
+	if (!pci_dev->ocs)
 		return -ENOMEM;
 
-	of_changeset_init(ctx->ocs);
+	of_changeset_init(pci_dev->ocs);
 
-	np = of_changeset_create_node(ctx->ocs, parent, "bluetooth");
+	np = of_changeset_create_node(pci_dev->ocs, parent, "bluetooth");
 	if (!np) {
 		dev_err(dev, "Failed to create bluetooth node\n");
 		ret = -ENODEV;
 		goto err_destroy_changeset;
 	}
 
-	ret = of_changeset_add_prop_string(ctx->ocs, np, "compatible", "qcom,wcn7850-bt");
+	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
 	if (ret) {
 		dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
 		goto err_destroy_changeset;
 	}
 
-	ret = of_changeset_apply(ctx->ocs);
+	ret = of_changeset_apply(pci_dev->ocs);
 	if (ret) {
 		dev_err(dev, "Failed to apply changeset: %d\n", ret);
 		goto err_destroy_changeset;
 	}
 
-	ret = device_add_of_node(&ctx->serdev->dev, np);
+	ret = device_add_of_node(&pci_dev->serdev->dev, np);
 	if (ret) {
 		dev_err(dev, "Failed to add OF node: %d\n", ret);
 		goto err_revert_changeset;
@@ -218,19 +227,21 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 	return 0;
 
 err_revert_changeset:
-	of_changeset_revert(ctx->ocs);
+	of_changeset_revert(pci_dev->ocs);
 err_destroy_changeset:
-	of_changeset_destroy(ctx->ocs);
-	kfree(ctx->ocs);
-	ctx->ocs = NULL;
+	of_changeset_destroy(pci_dev->ocs);
+	kfree(pci_dev->ocs);
+	pci_dev->ocs = NULL;
 
 	return ret;
 }
 
-static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+					struct pci_dev *pdev)
 {
 	struct serdev_controller *serdev_ctrl;
 	struct device *dev = ctx->dev;
+	struct pwrseq_pci_dev *pci_dev;
 	int ret;
 
 	struct device_node *serdev_parent __free(device_node) =
@@ -248,17 +259,23 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 		return 0;
 	}
 
-	ctx->serdev = serdev_device_alloc(serdev_ctrl);
-	if (!ctx->serdev) {
+	pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
+	if (!pci_dev) {
 		ret = -ENOMEM;
 		goto err_put_ctrl;
 	}
 
-	ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
+	pci_dev->serdev = serdev_device_alloc(serdev_ctrl);
+	if (!pci_dev->serdev) {
+		ret = -ENOMEM;
+		goto err_free_pci_dev;
+	}
+
+	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
 	if (ret)
 		goto err_free_serdev;
 
-	ret = serdev_device_add(ctx->serdev);
+	ret = serdev_device_add(pci_dev->serdev);
 	if (ret) {
 		dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
 		goto err_free_dt_node;
@@ -266,37 +283,64 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 
 	serdev_controller_put(serdev_ctrl);
 
+	pci_dev->pdev = pci_dev_get(pdev);
+
+	mutex_lock(&ctx->list_lock);
+	list_add_tail(&pci_dev->list, &ctx->pci_devices);
+	mutex_unlock(&ctx->list_lock);
+
 	return 0;
 
 err_free_dt_node:
-	device_remove_of_node(&ctx->serdev->dev);
-	of_changeset_revert(ctx->ocs);
-	of_changeset_destroy(ctx->ocs);
-	kfree(ctx->ocs);
-	ctx->ocs = NULL;
+	device_remove_of_node(&pci_dev->serdev->dev);
+	of_changeset_revert(pci_dev->ocs);
+	of_changeset_destroy(pci_dev->ocs);
+	kfree(pci_dev->ocs);
+	pci_dev->ocs = NULL;
 err_free_serdev:
-	serdev_device_put(ctx->serdev);
-	ctx->serdev = NULL;
+	serdev_device_put(pci_dev->serdev);
+	pci_dev->serdev = NULL;
+err_free_pci_dev:
+	kfree(pci_dev);
 err_put_ctrl:
 	serdev_controller_put(serdev_ctrl);
 
 	return ret;
 }
 
-static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static void __pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+					   struct pwrseq_pci_dev *pci_dev)
 {
-	if (ctx->serdev) {
-		device_remove_of_node(&ctx->serdev->dev);
-		serdev_device_remove(ctx->serdev);
-		ctx->serdev = NULL;
+	if (pci_dev->serdev) {
+		device_remove_of_node(&pci_dev->serdev->dev);
+		serdev_device_remove(pci_dev->serdev);
 	}
 
-	if (ctx->ocs) {
-		of_changeset_revert(ctx->ocs);
-		of_changeset_destroy(ctx->ocs);
-		kfree(ctx->ocs);
-		ctx->ocs = NULL;
+	if (pci_dev->ocs) {
+		of_changeset_revert(pci_dev->ocs);
+		of_changeset_destroy(pci_dev->ocs);
+		kfree(pci_dev->ocs);
 	}
+
+	pci_dev_put(pci_dev->pdev);
+	list_del(&pci_dev->list);
+	kfree(pci_dev);
+}
+
+static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+					 struct pci_dev *pdev)
+{
+	struct pwrseq_pci_dev *pci_dev, *tmp;
+
+	mutex_lock(&ctx->list_lock);
+	list_for_each_entry_safe(pci_dev, tmp, &ctx->pci_devices, list) {
+		if (!pdev || pci_dev->pdev == pdev) {
+			__pwrseq_pcie_m2_remove_serdev(ctx, pci_dev);
+			if (pdev)
+				break;
+		}
+	}
+	mutex_unlock(&ctx->list_lock);
 }
 
 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
@@ -320,7 +364,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 	case BUS_NOTIFY_ADD_DEVICE:
 		/* Create serdev device for WCN7850 */
 		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
-			ret = pwrseq_pcie_m2_create_serdev(ctx);
+			ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
 			if (ret)
 				return notifier_from_errno(ret);
 		}
@@ -328,7 +372,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 	case BUS_NOTIFY_REMOVED_DEVICE:
 		/* Destroy serdev device for WCN7850 */
 		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
-			pwrseq_pcie_m2_remove_serdev(ctx);
+			pwrseq_pcie_m2_remove_serdev(ctx, pdev);
 
 		break;
 	}
@@ -432,16 +476,20 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
 		goto err_free_regulators;
 	}
 
+	mutex_init(&ctx->list_lock);
+	INIT_LIST_HEAD(&ctx->pci_devices);
 	/*
 	 * Register a notifier for creating protocol devices for
 	 * non-discoverable busses like UART.
 	 */
 	ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
 	if (ret)
-		goto err_free_regulators;
+		goto err_destroy_mutex;
 
 	return 0;
 
+err_destroy_mutex:
+	mutex_destroy(&ctx->list_lock);
 err_free_regulators:
 	regulator_bulk_free(ctx->num_vregs, ctx->regs);
 
@@ -453,7 +501,8 @@ static void pwrseq_pcie_m2_remove(struct platform_device *pdev)
 	struct pwrseq_pcie_m2_ctx *ctx = platform_get_drvdata(pdev);
 
 	bus_unregister_notifier(&pci_bus_type, &ctx->nb);
-	pwrseq_pcie_m2_remove_serdev(ctx);
+	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+	mutex_destroy(&ctx->list_lock);
 
 	regulator_bulk_free(ctx->num_vregs, ctx->regs);
 }

-- 
2.48.1



^ permalink raw reply related

* [bluez/bluez] f5cc1b: client/btpclient: Fix GAP unpair command
From: fdanis-oss @ 2026-05-19  8:51 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1097130
  Home:   https://github.com/bluez/bluez
  Commit: f5cc1b488ac39a1b869ae43c66cc68c667f5f584
      https://github.com/bluez/bluez/commit/f5cc1b488ac39a1b869ae43c66cc68c667f5f584
  Author: Frédéric Danis <frederic.danis@collabora.com>
  Date:   2026-05-19 (Tue, 19 May 2026)

  Changed paths:
    M client/btpclient/gap.c

  Log Message:
  -----------
  client/btpclient: Fix GAP unpair command

Fix unpair_reply() because the device is no more available on
RemoveDevice reply.


  Commit: e9de592034e48ad7fc0a10329e41a12ccd0c5c9d
      https://github.com/bluez/bluez/commit/e9de592034e48ad7fc0a10329e41a12ccd0c5c9d
  Author: Frédéric Danis <frederic.danis@collabora.com>
  Date:   2026-05-19 (Tue, 19 May 2026)

  Changed paths:
    M client/btpclient/gap.c

  Log Message:
  -----------
  client/btpclient: Don't remove all devices on GAP Reset command

Currently running auto-pts remove all paired devices, instead of just
removing the PTS devices.
This removes this behavior, expecting auto-pts to explicitly remove the
PTS devices using Unpair command.


Compare: https://github.com/bluez/bluez/compare/f5cc1b488ac3%5E...e9de592034e4

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [PATCH BlueZ v2 2/2] client/btpclient: Don't remove all devices on GAP Reset command
From: Frédéric Danis @ 2026-05-19  8:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260519085016.188744-1-frederic.danis@collabora.com>

Currently running auto-pts remove all paired devices, instead of just
removing the PTS devices.
This removes this behavior, expecting auto-pts to explicitly remove the
PTS devices using Unpair command.
---
v1->v2: Fix build error

 client/btpclient/gap.c | 55 +++---------------------------------------
 1 file changed, 4 insertions(+), 51 deletions(-)

diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index a14cd4795..f6b920b37 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -200,39 +200,6 @@ failed:
 	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
 }
 
-static void remove_device_setup(struct l_dbus_message *message,
-							void *user_data)
-{
-	struct btp_device *device = user_data;
-
-	l_dbus_message_set_arguments(message, "o",
-					l_dbus_proxy_get_path(device->proxy));
-}
-
-static void remove_device_reply(struct l_dbus_proxy *proxy,
-						struct l_dbus_message *result,
-						void *user_data)
-{
-	struct btp_device *device = user_data;
-	struct btp_adapter *adapter = find_adapter_by_proxy(proxy);
-
-	if (!adapter)
-		return;
-
-	if (l_dbus_message_is_error(result)) {
-		const char *name;
-
-		l_dbus_message_get_error(result, &name, NULL);
-
-		l_error("Failed to remove device %s (%s)",
-					l_dbus_proxy_get_path(device->proxy),
-					name);
-		return;
-	}
-
-	l_queue_remove(adapter->devices, device);
-}
-
 static void unreg_advertising_setup(struct l_dbus_message *message,
 								void *user_data)
 {
@@ -351,9 +318,7 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
 {
 	struct btp_adapter *adapter = find_adapter_by_index(index);
 	struct btp_agent *ag = get_agent();
-	const struct l_queue_entry *entry;
 	uint8_t status;
-	bool prop;
 	uint32_t default_settings;
 
 	if (!adapter) {
@@ -361,22 +326,10 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
 		goto failed;
 	}
 
-	/* Adapter needs to be powered to be able to remove devices */
-	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
-									!prop) {
-		status = BTP_ERROR_FAIL;
-		goto failed;
-	}
-
-	for (entry = l_queue_get_entries(adapter->devices); entry;
-							entry = entry->next) {
-		struct btp_device *device = entry->data;
-
-		l_dbus_proxy_method_call(adapter->proxy, "RemoveDevice",
-						remove_device_setup,
-						remove_device_reply, device,
-						NULL);
-	}
+	/* PTS devices should be removed explicitly by calling
+	 * BTP_OP_GAP_UNPAIR to prevent removing all paired devices
+	 * from the IUT.
+	 */
 
 	if (adapter->ad_proxy && ad.registered)
 		if (!l_dbus_proxy_method_call(adapter->ad_proxy,
-- 
2.43.0


^ permalink raw reply related

* [PATCH BlueZ v2 1/2] client/btpclient: Fix GAP unpair command
From: Frédéric Danis @ 2026-05-19  8:50 UTC (permalink / raw)
  To: linux-bluetooth

Fix unpair_reply() because the device is no more available on
RemoveDevice reply.
---
 client/btpclient/gap.c | 40 +++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index 68e029dcc..a14cd4795 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -2174,17 +2174,15 @@ failed:
 	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
 }
 
+struct unpair_req {
+	uint8_t index;
+	struct btp_device *device;
+};
+
 static void unpair_reply(struct l_dbus_proxy *proxy,
 				struct l_dbus_message *result, void *user_data)
 {
-	struct btp_device *device = user_data;
-	struct btp_adapter *adapter = find_adapter_by_device(device);
-
-	if (!adapter) {
-		btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
-								BTP_ERROR_FAIL);
-		return;
-	}
+	struct unpair_req *req = user_data;
 
 	if (l_dbus_message_is_error(result)) {
 		const char *name, *desc;
@@ -2192,19 +2190,19 @@ static void unpair_reply(struct l_dbus_proxy *proxy,
 		l_dbus_message_get_error(result, &name, &desc);
 		l_error("Failed to unpair (%s), %s", name, desc);
 
-		btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
-								BTP_ERROR_FAIL);
+		btp_send_error(btp, BTP_GAP_SERVICE, req->index,
+							BTP_ERROR_FAIL);
 		return;
 	}
 
-	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, adapter->index, 0,
-									NULL);
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, req->index, 0,
+								NULL);
 }
 
 static void unpair_setup(struct l_dbus_message *message, void *user_data)
 {
-	struct btp_device *device = user_data;
-	const char *path = l_dbus_proxy_get_path(device->proxy);
+	struct unpair_req *req = user_data;
+	const char *path = l_dbus_proxy_get_path(req->device->proxy);
 	struct l_dbus_message_builder *builder;
 
 	builder = l_dbus_message_builder_new(message);
@@ -2223,6 +2221,7 @@ static void btp_gap_unpair(uint8_t index, const void *param, uint16_t length,
 	uint8_t status = BTP_ERROR_FAIL;
 	struct btp_device *device;
 	bool prop;
+	struct unpair_req *req;
 
 	if (!adapter) {
 		status = BTP_ERROR_INVALID_INDEX;
@@ -2237,14 +2236,21 @@ static void btp_gap_unpair(uint8_t index, const void *param, uint16_t length,
 	device = find_device_by_address(adapter, &cp->address,
 							cp->address_type);
 
-	if (!device)
-		goto failed;
+	if (!device) {
+		btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR,
+							adapter->index, 0,
+							NULL);
+		return;
+	}
 
 	/* There is no direct unpair method, removing device will clear pairing
 	 * information.
 	 */
+	req = l_new(struct unpair_req, 1);
+	req->index = index;
+	req->device = device;
 	l_dbus_proxy_method_call(adapter->proxy, "RemoveDevice", unpair_setup,
-						unpair_reply, device, NULL);
+						unpair_reply, req, l_free);
 
 	return;
 
-- 
2.43.0


^ permalink raw reply related

* [Bug 221547] New: MT7902 Bluetooth: Failed to send wmt func ctrl (-22) regression in 6.18.31 and 6.12.32
From: bugzilla-daemon @ 2026-05-19  8:24 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221547

            Bug ID: 221547
           Summary: MT7902 Bluetooth: Failed to send wmt func ctrl (-22)
                    regression in 6.18.31 and 6.12.32
           Product: Drivers
           Version: 2.5
          Hardware: AMD
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P3
         Component: Bluetooth
          Assignee: linux-bluetooth@vger.kernel.org
          Reporter: olle@vixit.nu
        Regression: No

Adapter: Foxconn/Hon Hai 0489:e0f5 (MediaTek MT7902)
Machine: ASUS laptop (asus_wmi)

Works: linux-lts 6.18.26-2
Fails: linux-lts 6.18.31-1, 6.18.32-1
Works: linux 7.0.9-arch1-1

Kernel error:
[8.509092] Bluetooth: hci0: Failed to send wmt func ctrl (-22)
[8.509685] Bluetooth: hci0: HCI Enhanced Setup Synchronous Connection command
is advertised, but not supported.

bluetoothctl shows "No default controller available" and power on fails.
rfkill unblock bluetooth required after each boot when using working kernel.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* [PATCH BlueZ 2/2] client/btpclient: Don't remove all devices on GAP Reset command
From: Frédéric Danis @ 2026-05-19  7:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260519074742.163473-1-frederic.danis@collabora.com>

Currently running auto-pts remove all paired devices, instead of just
removing the PTS devices.
This removes this behavior, expecting auto-pts to explicitly remove the
PTS devices using Unpair command.
---
 client/btpclient/gap.c | 54 ++++--------------------------------------
 1 file changed, 4 insertions(+), 50 deletions(-)

diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index a14cd4795..f108ae5de 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -200,39 +200,6 @@ failed:
 	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
 }
 
-static void remove_device_setup(struct l_dbus_message *message,
-							void *user_data)
-{
-	struct btp_device *device = user_data;
-
-	l_dbus_message_set_arguments(message, "o",
-					l_dbus_proxy_get_path(device->proxy));
-}
-
-static void remove_device_reply(struct l_dbus_proxy *proxy,
-						struct l_dbus_message *result,
-						void *user_data)
-{
-	struct btp_device *device = user_data;
-	struct btp_adapter *adapter = find_adapter_by_proxy(proxy);
-
-	if (!adapter)
-		return;
-
-	if (l_dbus_message_is_error(result)) {
-		const char *name;
-
-		l_dbus_message_get_error(result, &name, NULL);
-
-		l_error("Failed to remove device %s (%s)",
-					l_dbus_proxy_get_path(device->proxy),
-					name);
-		return;
-	}
-
-	l_queue_remove(adapter->devices, device);
-}
-
 static void unreg_advertising_setup(struct l_dbus_message *message,
 								void *user_data)
 {
@@ -351,7 +318,6 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
 {
 	struct btp_adapter *adapter = find_adapter_by_index(index);
 	struct btp_agent *ag = get_agent();
-	const struct l_queue_entry *entry;
 	uint8_t status;
 	bool prop;
 	uint32_t default_settings;
@@ -361,22 +327,10 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
 		goto failed;
 	}
 
-	/* Adapter needs to be powered to be able to remove devices */
-	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
-									!prop) {
-		status = BTP_ERROR_FAIL;
-		goto failed;
-	}
-
-	for (entry = l_queue_get_entries(adapter->devices); entry;
-							entry = entry->next) {
-		struct btp_device *device = entry->data;
-
-		l_dbus_proxy_method_call(adapter->proxy, "RemoveDevice",
-						remove_device_setup,
-						remove_device_reply, device,
-						NULL);
-	}
+	/* PTS devices should be removed explicitly by calling
+	 * BTP_OP_GAP_UNPAIR to prevent removing all paired devices
+	 * from the IUT.
+	 */
 
 	if (adapter->ad_proxy && ad.registered)
 		if (!l_dbus_proxy_method_call(adapter->ad_proxy,
-- 
2.43.0


^ permalink raw reply related

* [PATCH BlueZ 1/2] client/btpclient: Fix GAP unpair command
From: Frédéric Danis @ 2026-05-19  7:47 UTC (permalink / raw)
  To: linux-bluetooth

Fix unpair_reply() because the device is no more available on
RemoveDevice reply.
---
 client/btpclient/gap.c | 40 +++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index 68e029dcc..a14cd4795 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -2174,17 +2174,15 @@ failed:
 	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
 }
 
+struct unpair_req {
+	uint8_t index;
+	struct btp_device *device;
+};
+
 static void unpair_reply(struct l_dbus_proxy *proxy,
 				struct l_dbus_message *result, void *user_data)
 {
-	struct btp_device *device = user_data;
-	struct btp_adapter *adapter = find_adapter_by_device(device);
-
-	if (!adapter) {
-		btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
-								BTP_ERROR_FAIL);
-		return;
-	}
+	struct unpair_req *req = user_data;
 
 	if (l_dbus_message_is_error(result)) {
 		const char *name, *desc;
@@ -2192,19 +2190,19 @@ static void unpair_reply(struct l_dbus_proxy *proxy,
 		l_dbus_message_get_error(result, &name, &desc);
 		l_error("Failed to unpair (%s), %s", name, desc);
 
-		btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
-								BTP_ERROR_FAIL);
+		btp_send_error(btp, BTP_GAP_SERVICE, req->index,
+							BTP_ERROR_FAIL);
 		return;
 	}
 
-	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, adapter->index, 0,
-									NULL);
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, req->index, 0,
+								NULL);
 }
 
 static void unpair_setup(struct l_dbus_message *message, void *user_data)
 {
-	struct btp_device *device = user_data;
-	const char *path = l_dbus_proxy_get_path(device->proxy);
+	struct unpair_req *req = user_data;
+	const char *path = l_dbus_proxy_get_path(req->device->proxy);
 	struct l_dbus_message_builder *builder;
 
 	builder = l_dbus_message_builder_new(message);
@@ -2223,6 +2221,7 @@ static void btp_gap_unpair(uint8_t index, const void *param, uint16_t length,
 	uint8_t status = BTP_ERROR_FAIL;
 	struct btp_device *device;
 	bool prop;
+	struct unpair_req *req;
 
 	if (!adapter) {
 		status = BTP_ERROR_INVALID_INDEX;
@@ -2237,14 +2236,21 @@ static void btp_gap_unpair(uint8_t index, const void *param, uint16_t length,
 	device = find_device_by_address(adapter, &cp->address,
 							cp->address_type);
 
-	if (!device)
-		goto failed;
+	if (!device) {
+		btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR,
+							adapter->index, 0,
+							NULL);
+		return;
+	}
 
 	/* There is no direct unpair method, removing device will clear pairing
 	 * information.
 	 */
+	req = l_new(struct unpair_req, 1);
+	req->index = index;
+	req->device = device;
 	l_dbus_proxy_method_call(adapter->proxy, "RemoveDevice", unpair_setup,
-						unpair_reply, device, NULL);
+						unpair_reply, req, l_free);
 
 	return;
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2] Bluetooth: RFCOMM: add minimum length check in rfcomm_recv_frame
From: Muhammad Bilal @ 2026-05-19  7:30 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: netdev, linux-kernel, marcel, luiz.dentz, kees, kuba, stable,
	Muhammad Bilal

rfcomm_recv_frame() casts skb->data to struct rfcomm_hdr * and
immediately dereferences hdr->addr and hdr->ctrl without first
validating that skb->len is large enough to hold the header. A
remote device can send a crafted short RFCOMM frame over L2CAP to
trigger an out-of-bounds read before any session state is checked.

The FCS trimming code that follows compounds the problem:

skb->len--; skb->tail--;

If skb->len is already zero the decrement wraps to UINT_MAX, causing
skb_tail_pointer() to return a pointer far outside the skb and
producing a second out-of-bounds read when the FCS byte is consumed.

Add a minimum length check before the header pointer is assigned. A
well-formed RFCOMM frame requires at least addr(1) + ctrl(1) +
len(1) + fcs(1) = sizeof(struct rfcomm_hdr) + 1 bytes. This single
guard prevents both the header out-of-bounds read and the skb->len
integer underflow.

Note: SeungJu Cheon posted a related patch that adds equivalent
length checks inside the individual MCC sub-handlers
(rfcomm_recv_pn, rfcomm_recv_rpn, rfcomm_recv_rls, rfcomm_recv_msc,
rfcomm_recv_mcc). That fix and this one are complementary and
independent; neither subsumes the other.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
---
 net/bluetooth/rfcomm/core.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index d11bd5337..6b300237c 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1741,7 +1741,7 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk
 static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
 						struct sk_buff *skb)
 {
-	struct rfcomm_hdr *hdr = (void *) skb->data;
+	struct rfcomm_hdr *hdr;
 	u8 type, dlci, fcs;
 
 	if (!s) {
@@ -1750,10 +1750,17 @@ static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
 		return s;
 	}
 
+	/* Minimum valid frame: addr(1) + ctrl(1) + len(1) + fcs(1) */
+	if (skb->len < sizeof(*hdr) + 1) {
+		kfree_skb(skb);
+		return s;
+	}
+
+	hdr = (void *) skb->data;
 	dlci = __get_dlci(hdr->addr);
 	type = __get_type(hdr->ctrl);
 
-	/* Trim FCS */
+	/* Trim FCS - safe: skb->len >= sizeof(*hdr) + 1 >= 1 */
 	skb->len--; skb->tail--;
 	fcs = *(u8 *)skb_tail_pointer(skb);
 
-- 
2.54.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox