* [BlueZ 6/6] btattach: Use _cleanup_fd_ to simplify error paths
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260609135837.476561-1-hadess@hadess.net>
Use _cleanup_fd_ and _steal_fd() to simplify error paths, and only
"steal" the file descriptor on success.
---
tools/btattach.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/tools/btattach.c b/tools/btattach.c
index 5f7d19093698..4918c79f65c7 100644
--- a/tools/btattach.c
+++ b/tools/btattach.c
@@ -40,7 +40,8 @@
static int open_serial(const char *path, unsigned int speed, bool flowctl)
{
struct termios ti;
- int fd, saved_ldisc, ldisc = N_HCI;
+ _cleanup_fd_ int fd = -1;
+ int saved_ldisc, ldisc = N_HCI;
fd = open(path, O_RDWR | O_NOCTTY);
if (fd < 0) {
@@ -50,13 +51,11 @@ static int open_serial(const char *path, unsigned int speed, bool flowctl)
if (tcflush(fd, TCIOFLUSH) < 0) {
perror("Failed to flush serial port");
- close(fd);
return -1;
}
if (ioctl(fd, TIOCGETD, &saved_ldisc) < 0) {
perror("Failed get serial line discipline");
- close(fd);
return -1;
}
@@ -73,19 +72,17 @@ static int open_serial(const char *path, unsigned int speed, bool flowctl)
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
perror("Failed to set serial port settings");
- close(fd);
return -1;
}
if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
perror("Failed set serial line discipline");
- close(fd);
return -1;
}
printf("Switched line discipline from %d to %d\n", saved_ldisc, ldisc);
- return fd;
+ return _steal_fd_(fd);
}
static void local_version_callback(const void *data, uint8_t size,
@@ -99,7 +96,8 @@ static void local_version_callback(const void *data, uint8_t size,
static int attach_proto(const char *path, unsigned int proto,
unsigned int speed, bool flowctl, unsigned int flags)
{
- int fd, dev_id;
+ _cleanup_fd_ int fd = -1;
+ int dev_id;
fd = open_serial(path, speed, flowctl);
if (fd < 0)
@@ -107,20 +105,17 @@ static int attach_proto(const char *path, unsigned int proto,
if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
perror("Failed to set flags");
- close(fd);
return -1;
}
if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
perror("Failed to set protocol");
- close(fd);
return -1;
}
dev_id = ioctl(fd, HCIUARTGETDEVICE);
if (dev_id < 0) {
perror("Failed to get device id");
- close(fd);
return -1;
}
@@ -140,7 +135,6 @@ static int attach_proto(const char *path, unsigned int proto,
if (!hci) {
fprintf(stderr, "Failed to open HCI user channel\n");
- close(fd);
return -1;
}
@@ -149,7 +143,7 @@ static int attach_proto(const char *path, unsigned int proto,
(bt_hci_destroy_func_t) bt_hci_unref);
}
- return fd;
+ return _steal_fd_(fd);
}
static void uart_callback(int fd, uint32_t events, void *user_data)
--
2.54.0
^ permalink raw reply related
* [BlueZ 5/6] client: Use _cleanup_fd_ to simplify urandom access
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260609135837.476561-1-hadess@hadess.net>
fd gets auto-closed before exiting the scope.
---
client/mgmt.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/client/mgmt.c b/client/mgmt.c
index 50558a313866..e199c30540e4 100644
--- a/client/mgmt.c
+++ b/client/mgmt.c
@@ -2681,7 +2681,7 @@ static void cmd_privacy(int argc, char **argv)
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
} else {
- int fd;
+ _cleanup_fd_ int fd = -1;
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
@@ -2691,11 +2691,8 @@ static void cmd_privacy(int argc, char **argv)
if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) {
error("Reading from urandom failed");
- close(fd);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
-
- close(fd);
}
if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
--
2.54.0
^ permalink raw reply related
* [BlueZ 3/6] doc: Recommend using _cleanup_ and friends
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260609135837.476561-1-hadess@hadess.net>
---
doc/maintainer-guidelines.rst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/doc/maintainer-guidelines.rst b/doc/maintainer-guidelines.rst
index 44d3e258db6e..6f2d63d7c76a 100644
--- a/doc/maintainer-guidelines.rst
+++ b/doc/maintainer-guidelines.rst
@@ -98,6 +98,12 @@ do this:
The above assumes that a kernel tree resides in ``~/src/linux/``.
+Also make sure to use ``_cleanup_free_`` and ``_cleanup_(free_func)`` when
+possible. It makes your code much nicer to read (and shorter), and avoids
+common memory leaks on error paths.
+
+If you need to return a variable that would normally be cleaned up by
+``_cleanup_free_``, use ``_steal_``.
Rule 4: Pay extra attention to adding new files to the tree
-----------------------------------------------------------
--
2.54.0
^ permalink raw reply related
* [BlueZ 2/6] shared/util: Better type-checking in _steal_* commands
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260609135837.476561-1-hadess@hadess.net>
Replace _steal_() and _steal_fd_() inline functions with macros, so that
we can have better type-checking. This would have avoided crashes seen
in the original patchset, where we passed a pointer instead of a pointer
to a pointer.
Example usage:
CLEANUP_FREEFUNC(GKeyFile, g_key_file_free);
GKeyfile *load_config(void) {
_cleanup_type_(GKeyFile) GKeyFile *keyfile = NULL;
[...]
return _steal_(keyfile);
}
static int open_file(void) {
_cleanup_fd_ int fd = -1;
[...]
return _steal_fd_(fd);
}
This is inspired by similar code in Pipewire's spa helpers, as pointed
out by Pauli Virtanen <pav@iki.fi>.
---
src/shared/util.h | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/src/shared/util.h b/src/shared/util.h
index dd8e5288f55b..dacbff67f067 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -100,20 +100,15 @@ static inline void freep(void *p)
free(*(void **) p);
}
-static inline void *_steal_(void *p)
-{
- void **orig = (void **) p;
- void *ret = *orig;
- *orig = NULL;
- return ret;
-}
+#define _exchange_(var, new_value) ({ \
+ __typeof__(var) *orig = &(var); \
+ __typeof__(var) ret = *orig; \
+ *orig = new_value; \
+ ret; \
+})
-static inline int _steal_fd_(int *fdp)
-{
- int fd = *fdp;
- *fdp = -1;
- return fd;
-}
+#define _steal_(p) _exchange_(p, NULL)
+#define _steal_fd_(fd) _exchange_(fd, -1)
static inline void closefd(int *fdp)
{
--
2.54.0
^ permalink raw reply related
* Re: [BlueZ v3 0/6] Add helper for "cleanup" variable attribute
From: Bastien Nocera @ 2026-06-09 13:58 UTC (permalink / raw)
To: Pauli Virtanen, Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <fa6f77805bd81b200a0af16287fb81c3fc16e7b2.camel@iki.fi>
Hey,
Coming back to this nearly a month later.
On Tue, 2026-05-12 at 23:40 +0300, Pauli Virtanen wrote:
> I think it needed something like the below.
>
> I think it would be better to have _steal_() and _steal_fd_() be
> macros
> so that compiler can check the types so you can't mistake
> _steal_(keyfile) and _steal_(&keyfile)
>
> https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/spa/include/spa/utils/cleanup.h
I've implemented something "similar" (only so many ways to skin a
cat...), thanks.
> Not sure what can be done about the _cleanup_(g_free) char *str ---
> it
> would be great if this generated compiler warning/error but it looks
> like it didn't, so maybe this macro should be private so you're
> forced
> to declare the CLEANUP_FREEFUNC always.
Nowadays, calling g_free() just calls free():
https://github.com/GNOME/glib/blob/main/glib/gmem.c#L208
so we could replace this all with _cleanup_free_(), if we were to bump
the glib requirements to match when glib started just calling free(),
in 2.46 (released in 2021).
Or we could use g_autofree, but that also would require bumping glib
requirements to 2.44.
I've implemented it the same way you did, copy/pasting the "free()"
functions in src/shared/util.h
> diff --git a/src/main.c b/src/main.c
> index 9053e74aa..9d1074c11 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -205,8 +205,20 @@ static const struct group_table {
> { }
> };
>
> -CLEANUP_FREEFUNC(GError, g_error_free);
> -CLEANUP_FREEFUNC(GKeyFile, g_key_file_free);
> +static void cleanup_g_error(GError *err)
> +{
> + if (err)
> + g_error_free(err);
> +}
> +
> +static void cleanup_g_key_file(GKeyFile *keyfile)
> +{
> + if (keyfile)
> + g_key_file_free(keyfile);
I added the "if p != NULL" conditional to the macro directly.
> +}
> +
> +CLEANUP_FREEFUNC(GError, cleanup_g_error);
> +CLEANUP_FREEFUNC(GKeyFile, cleanup_g_key_file);
>
> static int8_t check_sirk_alpha_numeric(char *str)
> {
> @@ -291,7 +303,7 @@ static GKeyFile *load_config(const char *name)
> return NULL;
> }
>
> - return _steal_(keyfile);
> + return _steal_(&keyfile);
> }
>
> static void parse_did(const char *did)
> @@ -457,12 +469,19 @@ static bool parse_config_string(GKeyFile
> *config,
> const char *group,
> return true;
> }
>
> +static inline void cleanup_g_free(void *p)
> +{
> + g_free(*(void **) p);
> +}
> +
> +#define _cleanup_g_free_ _cleanup_(cleanup_g_free)
> +
> static bool parse_config_int(GKeyFile *config, const char *group,
> const char *key, int *val,
> size_t min, size_t max)
> {
> size_t tmp;
> - _cleanup_(g_free) char *str = NULL;
> + _cleanup_g_free_ char *str = NULL;
> char *endptr = NULL;
>
> if (!parse_config_string(config, group, key, &str))
>
> and so on for the rest of _cleanup_(g_free)
^ permalink raw reply
* [BlueZ 0/6] "cleanup" variable attribute follow-up
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
Follow-up to the partially applied "Add helper for "cleanup" variable
attribute" patchset.
This new version:
- fixes the crasher seen starting up bluetoothd
- fixes the warnings seen starting up bluetoothd, seen when free'ing
NULL variables
- reimplements the _steal_ functions as macros to better type-check at
compile-time
- mentions _steal_ macros in the style docs.
The original patchset also caught a bug in the meson port where the
config file path wasn't made absolute, so bluetoothd couldn't find the
config file when starting up, so I never saw those warnings and crashes.
This bug is now fixed in the meson port branch.
Bastien Nocera (6):
shared/util: Fix warnings when cleaning up NULL pointers
shared/util: Better type-checking in _steal_* commands
doc: Recommend using _cleanup_ and friends
main: Use _cleanup_() to simplify configuration parsing
client: Use _cleanup_fd_ to simplify urandom access
btattach: Use _cleanup_fd_ to simplify error paths
client/mgmt.c | 5 +-
doc/maintainer-guidelines.rst | 6 ++
src/main.c | 108 ++++++++++++----------------------
src/shared/util.h | 23 +++-----
tools/btattach.c | 18 ++----
5 files changed, 60 insertions(+), 100 deletions(-)
--
2.54.0
^ permalink raw reply
* [BlueZ 1/6] shared/util: Fix warnings when cleaning up NULL pointers
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260609135837.476561-1-hadess@hadess.net>
Don't try to free NULL pointers in cleanup callbacks, some of the
functions we use to free pointers might not support being passed
non-NULL values.
Fixes: 2e0533f977cc ("shared/util: Add helper for "cleanup" variable attribute")
---
src/shared/util.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/util.h b/src/shared/util.h
index 562a5af31751..dd8e5288f55b 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -127,7 +127,7 @@ static inline void closefd(int *fdp)
}
#define CLEANUP_FREEFUNC(type, func) \
- static inline void cleanup_##type (type **_ptr) { (func) (*_ptr); }
+ static inline void cleanup_##type (type **_ptr) { if (*_ptr != NULL) (func) (*_ptr); }
#define _cleanup_(f) __attribute__((cleanup(f)))
#define _cleanup_type_(type) __attribute__((cleanup(cleanup_##type)))
--
2.54.0
^ permalink raw reply related
* [BlueZ 4/6] main: Use _cleanup_() to simplify configuration parsing
From: Bastien Nocera @ 2026-06-09 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260609135837.476561-1-hadess@hadess.net>
Use helpers to simplify temporary string usage, and cleanup in error
paths.
---
src/main.c | 108 +++++++++++++++++++----------------------------------
1 file changed, 38 insertions(+), 70 deletions(-)
diff --git a/src/main.c b/src/main.c
index 8aa19a3e3346..bde295986869 100644
--- a/src/main.c
+++ b/src/main.c
@@ -205,6 +205,16 @@ static const struct group_table {
{ }
};
+CLEANUP_FREEFUNC(GError, g_error_free);
+CLEANUP_FREEFUNC(GKeyFile, g_key_file_free);
+
+static inline void cleanup_g_free(void *p)
+{
+ g_free(*(void **) p);
+}
+
+#define _cleanup_g_free_ _cleanup_(cleanup_g_free)
+
static int8_t check_sirk_alpha_numeric(char *str)
{
int8_t val = 0;
@@ -252,8 +262,8 @@ GKeyFile *btd_get_main_conf(void)
static GKeyFile *load_config(const char *name)
{
- GError *err = NULL;
- GKeyFile *keyfile;
+ _cleanup_type_(GError) GError *err = NULL;
+ _cleanup_type_(GKeyFile) GKeyFile *keyfile = NULL;
int len;
if (name)
@@ -285,12 +295,10 @@ static GKeyFile *load_config(const char *name)
if (!g_error_matches(err, G_FILE_ERROR, G_FILE_ERROR_NOENT))
error("Parsing %s failed: %s", main_conf_file_path,
err->message);
- g_error_free(err);
- g_key_file_free(keyfile);
return NULL;
}
- return keyfile;
+ return _steal_(keyfile);
}
static void parse_did(const char *did)
@@ -436,14 +444,13 @@ static int get_mode(const char *str)
static bool parse_config_string(GKeyFile *config, const char *group,
const char *key, char **val)
{
- GError *err = NULL;
+ _cleanup_type_(GError) GError *err = NULL;
char *tmp;
tmp = g_key_file_get_string(config, group, key, &err);
if (err) {
if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
DBG("%s", err->message);
- g_error_free(err);
return false;
}
@@ -462,7 +469,7 @@ static bool parse_config_int(GKeyFile *config, const char *group,
size_t min, size_t max)
{
size_t tmp;
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
char *endptr = NULL;
if (!parse_config_string(config, group, key, &str))
@@ -471,25 +478,21 @@ static bool parse_config_int(GKeyFile *config, const char *group,
tmp = strtol(str, &endptr, 0);
if (!endptr || *endptr != '\0') {
error("%s.%s = %s is not integer", group, key, str);
- g_free(str);
return false;
}
if (tmp < min) {
- g_free(str);
warn("%s.%s = %zu is out of range (< %zu)", group, key, tmp,
min);
return false;
}
if (tmp > max) {
- g_free(str);
warn("%s.%s = %zu is out of range (> %zu)", group, key, tmp,
max);
return false;
}
- g_free(str);
if (val)
*val = tmp;
@@ -500,10 +503,9 @@ static bool parse_config_signed_int(GKeyFile *config, const char *group,
const char *key, int8_t *val,
long min, long max)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
char *endptr = NULL;
long tmp;
- bool result = false;
str = g_key_file_get_string(config, group, key, NULL);
if (!str)
@@ -512,28 +514,24 @@ static bool parse_config_signed_int(GKeyFile *config, const char *group,
tmp = strtol(str, &endptr, 0);
if (!endptr || *endptr != '\0') {
warn("%s.%s = %s is not integer", group, key, str);
- goto cleanup;
+ return false;
}
if (tmp < min) {
warn("%s.%s = %ld is out of range (< %ld)", group, key, tmp,
min);
- goto cleanup;
+ return false;
}
if (tmp > max) {
warn("%s.%s = %ld is out of range (> %ld)", group, key, tmp,
max);
- goto cleanup;
+ return false;
}
if (val)
*val = (int8_t) tmp;
- result = true;
-
-cleanup:
- g_free(str);
- return result;
+ return true;
}
struct config_param {
@@ -894,14 +892,13 @@ static bool parse_config_u8(GKeyFile *config, const char *group,
static bool parse_config_bool(GKeyFile *config, const char *group,
const char *key, bool *val)
{
- GError *err = NULL;
+ _cleanup_type_(GError) GError *err = NULL;
gboolean tmp;
tmp = g_key_file_get_boolean(config, group, key, &err);
if (err) {
if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
DBG("%s", err->message);
- g_error_free(err);
return false;
}
@@ -915,7 +912,7 @@ static bool parse_config_bool(GKeyFile *config, const char *group,
static void parse_privacy(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "General", "Privacy", &str)) {
btd_opts.privacy = 0x00;
@@ -948,13 +945,11 @@ static void parse_privacy(GKeyFile *config)
DBG("Invalid privacy option: %s", str);
btd_opts.privacy = 0x00;
}
-
- g_free(str);
}
static void parse_repairing(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "General", "JustWorksRepairing",
&str)) {
@@ -963,13 +958,12 @@ static void parse_repairing(GKeyFile *config)
}
btd_opts.jw_repairing = parse_jw_repairing(str);
- g_free(str);
}
static bool parse_config_hex(GKeyFile *config, char *group,
const char *key, uint32_t *val)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, group, key, &str))
return false;
@@ -977,37 +971,34 @@ static bool parse_config_hex(GKeyFile *config, char *group,
if (val)
*val = strtol(str, NULL, 16);
- g_free(str);
return true;
}
static void parse_device_id(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
parse_config_string(config, "General", "DeviceID", &str);
if (!str)
return;
parse_did(str);
- g_free(str);
}
static void parse_ctrl_mode(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
parse_config_string(config, "General", "ControllerMode", &str);
if (!str)
return;
btd_opts.mode = get_mode(str);
- g_free(str);
}
static void parse_multi_profile(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
parse_config_string(config, "General", "MultiProfile", &str);
if (!str)
@@ -1019,8 +1010,6 @@ static void parse_multi_profile(GKeyFile *config)
btd_opts.mps = MPS_MULTIPLE;
else
btd_opts.mps = MPS_OFF;
-
- g_free(str);
}
static gboolean parse_kernel_experimental(const char *key, const char *value,
@@ -1043,20 +1032,18 @@ static gboolean parse_kernel_experimental(const char *key, const char *value,
static void parse_kernel_exp(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "General", "KernelExperimental",
&str))
return;
parse_kernel_experimental(NULL, str, NULL, NULL);
-
- g_free(str);
}
static void parse_secure_conns(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "General", "SecureConnections",
&str))
@@ -1068,8 +1055,6 @@ static void parse_secure_conns(GKeyFile *config)
btd_opts.secure_conn = SC_ON;
else if (!strcmp(str, "only"))
btd_opts.secure_conn = SC_ONLY;
-
- g_free(str);
}
static void parse_general(GKeyFile *config)
@@ -1120,14 +1105,13 @@ static void parse_general(GKeyFile *config)
static void parse_gatt_cache(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
parse_config_string(config, "GATT", "Cache", &str);
if (!str)
return;
btd_opts.gatt_cache = parse_gatt_cache_str(str);
- g_free(str);
}
static enum bt_gatt_export_t parse_gatt_export_str(const char *str)
@@ -1147,14 +1131,13 @@ static enum bt_gatt_export_t parse_gatt_export_str(const char *str)
static void parse_gatt_export(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
parse_config_string(config, "GATT", "ExportClaimedServices", &str);
if (!str)
return;
btd_opts.gatt_export = parse_gatt_export_str(str);
- g_free(str);
}
static uint8_t parse_gatt_seclevel_str(const char *str)
@@ -1176,7 +1159,7 @@ static uint8_t parse_gatt_seclevel_str(const char *str)
static void parse_gatt_seclevel(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!btd_opts.testing)
return;
@@ -1186,7 +1169,6 @@ static void parse_gatt_seclevel(GKeyFile *config)
return;
btd_opts.gatt_seclevel = parse_gatt_seclevel_str(str);
- g_free(str);
}
static void parse_gatt(GKeyFile *config)
@@ -1204,7 +1186,7 @@ static void parse_gatt(GKeyFile *config)
static void parse_csis_sirk(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "CSIS", "SIRK", &str))
return;
@@ -1213,8 +1195,6 @@ static void parse_csis_sirk(GKeyFile *config)
hex2bin(str, btd_opts.csis.sirk, sizeof(btd_opts.csis.sirk));
else if (!gen_sirk(str))
DBG("Unable to generate SIRK from string");
-
- g_free(str);
}
static void parse_csis(GKeyFile *config)
@@ -1231,8 +1211,8 @@ static void parse_csis(GKeyFile *config)
static bool parse_cs_role(GKeyFile *config, const char *group,
const char *key, uint8_t *val)
{
- GError *err = NULL;
- char *str = NULL;
+ _cleanup_type_(GError) GError *err = NULL;
+ _cleanup_g_free_ char *str = NULL;
char *endptr = NULL;
int numeric_val;
@@ -1241,7 +1221,6 @@ static bool parse_cs_role(GKeyFile *config, const char *group,
if (err) {
if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
DBG("%s", err->message);
- g_error_free(err);
return false;
}
@@ -1251,17 +1230,14 @@ static bool parse_cs_role(GKeyFile *config, const char *group,
if (!strcmp(str, "Initiator") || !strcmp(str, "initiator")) {
if (val)
*val = 1;
- g_free(str);
return true;
} else if (!strcmp(str, "Reflector") || !strcmp(str, "reflector")) {
if (val)
*val = 2;
- g_free(str);
return true;
} else if (!strcmp(str, "Both") || !strcmp(str, "both")) {
if (val)
*val = 3;
- g_free(str);
return true;
}
@@ -1272,7 +1248,6 @@ static bool parse_cs_role(GKeyFile *config, const char *group,
warn("%s.%s = %s is not a valid value. "
"Expected: 1/Initiator, 2/Reflector, or 3/Both",
group, key, str);
- g_free(str);
return false;
}
@@ -1280,14 +1255,12 @@ static bool parse_cs_role(GKeyFile *config, const char *group,
warn("%s.%s = %d is out of range. "
"Valid values: 1 (Initiator), 2 (Reflector), 3 (Both)",
group, key, numeric_val);
- g_free(str);
return false;
}
if (val)
*val = numeric_val;
- g_free(str);
return true;
}
@@ -1305,7 +1278,7 @@ static void parse_le_cs_config(GKeyFile *config)
static void parse_avdtp_session_mode(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "AVDTP", "SessionMode", &str))
return;
@@ -1318,13 +1291,11 @@ static void parse_avdtp_session_mode(GKeyFile *config)
DBG("Invalid mode option: %s", str);
btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC;
}
-
- g_free(str);
}
static void parse_avdtp_stream_mode(GKeyFile *config)
{
- char *str = NULL;
+ _cleanup_g_free_ char *str = NULL;
if (!parse_config_string(config, "AVDTP", "StreamMode", &str))
return;
@@ -1337,8 +1308,6 @@ static void parse_avdtp_stream_mode(GKeyFile *config)
DBG("Invalid mode option: %s", str);
btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC;
}
-
- g_free(str);
}
static void parse_avdtp(GKeyFile *config)
@@ -1605,7 +1574,7 @@ static GOptionEntry options[] = {
int main(int argc, char *argv[])
{
GOptionContext *context;
- GError *err = NULL;
+ _cleanup_type_(GError) GError *err = NULL;
uint16_t sdp_mtu = 0;
uint32_t sdp_flags = 0;
int gdbus_flags = 0;
@@ -1618,7 +1587,6 @@ int main(int argc, char *argv[])
if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
if (err != NULL) {
g_printerr("%s\n", err->message);
- g_error_free(err);
} else
g_printerr("An unknown error occurred\n");
exit(1);
--
2.54.0
^ permalink raw reply related
* RE: shared/bap: add ASE Control Point error responses
From: bluez.test.bot @ 2026-06-09 12:48 UTC (permalink / raw)
To: linux-bluetooth, raghavendra.rao
In-Reply-To: <20260609102548.6887-2-raghavendra.rao@collabora.com>
[-- Attachment #1: Type: text/plain, Size: 1600 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=1108483
---Test result---
Test Summary:
CheckPatch PASS 0.98 seconds
GitLint PASS 0.65 seconds
BuildEll PASS 20.32 seconds
BluezMake PASS 611.99 seconds
MakeCheck PASS 18.42 seconds
MakeDistcheck PASS 236.40 seconds
CheckValgrind PASS 275.40 seconds
CheckSmatch WARNING 324.66 seconds
bluezmakeextell PASS 165.73 seconds
IncrementalBuild PASS 913.48 seconds
ScanBuild PASS 925.24 seconds
Details
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
src/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
https://github.com/bluez/bluez/pull/2199
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: Initial Channel Sounding Support for
From: bluez.test.bot @ 2026-06-09 12:29 UTC (permalink / raw)
To: linux-bluetooth, naga.akella
In-Reply-To: <20260609104953.3122718-2-naga.akella@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 61923 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=1108507
---Test result---
Test Summary:
CheckPatch FAIL 1.11 seconds
GitLint FAIL 0.42 seconds
BuildEll PASS 20.12 seconds
BluezMake FAIL 646.69 seconds
CheckSmatch FAIL 344.91 seconds
bluezmakeextell FAIL 176.73 seconds
IncrementalBuild FAIL 637.18 seconds
ScanBuild FAIL 493.70 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v1,2/2] profiles: ranging: Add command flow and event support for CS Initiator
WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: __always_unused or __maybe_unused is preferred over __attribute__((__unused__))
#216: FILE: profiles/ranging/rap_hci.c:30:
+#define __maybe_unused __attribute__((unused))
WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#1089: FILE: profiles/ranging/rap_hci.c:1485:
+ * keeping it unused till DBUS API is added */
WARNING:BRACES: braces {} are not necessary for single statement blocks
#1113: FILE: profiles/ranging/rap_hci.c:1509:
+ for (i = 2; i <= 22; i++) {
+ default_map[i / 8] |= (1 << (i % 8));
+ }
WARNING:BRACES: braces {} are not necessary for single statement blocks
#1116: FILE: profiles/ranging/rap_hci.c:1512:
+ for (i = 26; i <= 76; i++) {
+ default_map[i / 8] |= (1 << (i % 8));
+ }
WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#1232: FILE: profiles/ranging/rap_hci.c:1628:
+ * keeping it unused till DBUS API is added */
/github/workspace/src/patch/14619214.patch total: 0 errors, 5 warnings, 1131 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14619214.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v1,1/2] shared: rap: Add the is_central parameter to verify whether the local role is central before sending the HCI CS Security Enable command.
1: T1 Title exceeds max length (151>80): "[BlueZ,v1,1/2] shared: rap: Add the is_central parameter to verify whether the local role is central before sending the HCI CS Security Enable command."
1: T3 Title has trailing punctuation (.): "[BlueZ,v1,1/2] shared: rap: Add the is_central parameter to verify whether the local role is central before sending the HCI CS Security Enable command."
[BlueZ,v1,2/2] profiles: ranging: Add command flow and event support for CS Initiator
1: T1 Title exceeds max length (85>80): "[BlueZ,v1,2/2] profiles: ranging: Add command flow and event support for CS Initiator"
##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:
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[])
| ^~~~
unit/test-avdtp.c: In function ‘main’:
unit/test-avdtp.c:766:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
766 | int main(int argc, char *argv[])
| ^~~~
unit/test-avrcp.c: In function ‘main’:
unit/test-avrcp.c:989:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
989 | int main(int argc, char *argv[])
| ^~~~
profiles/ranging/rap_hci.c:1486:21: error: no previous declaration for ‘bt_rap_set_channel_classification’ [-Werror=missing-declarations]
1486 | bool __maybe_unused bt_rap_set_channel_classification(void *hci_sm,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9007: profiles/ranging/bluetoothd-rap_hci.o] Error 1
make[1]: *** Waiting for unfinished jobs....
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/gatt.c: note: in included file:
./src/shared/btp.h:335:41: warning: array of flexible structures
./src/shared/btp.h:340:55: warning: array of flexible structures
./src/shared/btp.h:363:47: warning: array of flexible structures
./src/shared/btp.h:392:42: warning: array of flexible structures
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/agent.c: note: in included file:
src/shared/queue.h:19:20: error: redefinition of struct queue_entry
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
unit/avctp.c:505:34: warning: Variable length array is used.
unit/avctp.c:556:34: warning: Variable length array is used.
unit/test-avrcp.c:373:26: warning: Variable length array is used.
unit/test-avrcp.c:398:26: warning: Variable length array is used.
unit/test-avrcp.c:414:24: warning: Variable length array is used.
unit/avrcp-lib.c:1085:34: warning: Variable length array is used.
unit/avrcp-lib.c:1583:34: warning: Variable length array is used.
unit/avrcp-lib.c:1612:34: warning: Variable length array is used.
unit/avrcp-lib.c:1638:34: warning: Variable length array is used.
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/agent.c: note: in included file:
src/shared/queue.h:19:20: error: redefinition of struct queue_entry
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/main.c: note: in included file (through src/device.h):
./src/shared/queue.h:19:20: error: redefinition of struct queue_entry
mesh/mesh-io-mgmt.c:525:67: warning: Variable length array is used.
client/display.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'
monitor/packet.c:2002:26: warning: Variable length array is used.
monitor/packet.c: note: in included file:
monitor/bt.h:3924:52: warning: array of flexible structures
monitor/bt.h:3912:40: warning: array of flexible structures
monitor/msft.c: note: in included file:
monitor/msft.h:88:44: warning: array of flexible structures
tools/rctest.c:631:33: warning: non-ANSI function declaration of function 'automated_send_recv'
tools/hex2hcd.c:136:26: warning: Variable length array is used.
tools/meshctl.c:324:33: warning: non-ANSI function declaration of function 'forget_mesh_devices'
tools/mesh-gatt/node.c:456:39: warning: non-ANSI function declaration of function 'node_get_local_node'
tools/mesh-gatt/net.c:1239:30: warning: non-ANSI function declaration of function 'get_next_seq'
tools/mesh-gatt/net.c:2193:29: warning: non-ANSI function declaration of function 'net_get_default_ttl'
tools/mesh-gatt/net.c:2207:26: warning: non-ANSI function declaration of function 'net_get_seq_num'
tools/mesh-gatt/prov.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-gatt/onoff-model.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'
ell/log.c:431:65: warning: non-ANSI function declaration of function 'register_debug_section'
ell/log.c:439:68: warning: non-ANSI function declaration of function 'free_debug_sections'
ell/random.c:60:42: warning: non-ANSI function declaration of function 'l_getrandom_is_supported'
ell/cipher.c:660:28: warning: non-ANSI function declaration of function 'init_supported'
ell/checksum.c:382:28: warning: non-ANSI function declaration of function 'init_supported'
ell/checksum.c:444:47: warning: non-ANSI function declaration of function 'l_checksum_cmac_aes_supported'
ell/cipher.c:519:24: warning: Variable length array is used.
ell/cert-crypto.c:36:33: warning: Variable length array is used.
ell/cert-crypto.c:142:36: warning: Variable length array is used.
ell/cert-crypto.c:198:36: warning: Variable length array is used.
ell/cert-crypto.c:251:31: warning: Variable length array is used.
ell/key.c:550:25: warning: Variable length array is used.
ell/dbus-service.c:548:49: warning: non-ANSI function declaration of function '_dbus_object_tree_new'
ell/dbus-filter.c:233:46: warning: Variable length array is used.
ell/tls.c:45:25: warning: Variable length array is used.
ell/tls.c:86:22: warning: Variable length array is used.
ell/tls.c:86:46: warning: Variable length array is used.
ell/tls-suites.c:1079:25: warning: Variable length array is used.
ell/tls-suites.c:1081:34: warning: Variable length array is used.
ell/tls-suites.c:1084:41: warning: Variable length array is used.
ell/tls-suites.c:1133:41: warning: Variable length array is used.
ell/tls.c:1819:26: warning: Variable length array is used.
emulator/btdev.c:478:29: warning: Variable length array is used.
emulator/bthost.c:703:28: warning: Variable length array is used.
emulator/bthost.c:704:32: warning: Variable length array is used.
emulator/bthost.c:944:28: warning: Variable length array is used.
emulator/bthost.c:978:28: warning: Variable length array is used.
emulator/bthost.c:979:32: warning: Variable length array is used.
attrib/gatttool.c:236:23: warning: Variable length array is used.
attrib/interactive.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'
attrib/interactive.c:175:27: warning: non-ANSI function declaration of function 'disconnect_io'
attrib/interactive.c:300:23: warning: Variable length array is used.
profiles/ranging/rap_hci.c:1486:21: error: no previous declaration for ‘bt_rap_set_channel_classification’ [-Werror=missing-declarations]
1486 | bool __maybe_unused bt_rap_set_channel_classification(void *hci_sm,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9007: profiles/ranging/bluetoothd-rap_hci.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:
profiles/ranging/rap_hci.c:1486:21: error: no previous declaration for ‘bt_rap_set_channel_classification’ [-Werror=missing-declarations]
1486 | bool __maybe_unused bt_rap_set_channel_classification(void *hci_sm,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9007: profiles/ranging/bluetoothd-rap_hci.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:
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[])
| ^~~~
unit/test-avdtp.c: In function ‘main’:
unit/test-avdtp.c:766:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
766 | int main(int argc, char *argv[])
| ^~~~
unit/test-avrcp.c: In function ‘main’:
unit/test-avrcp.c:989:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
989 | int main(int argc, char *argv[])
| ^~~~
profiles/ranging/rap.c: In function ‘rap_accept’:
profiles/ranging/rap.c:421:4: error: too few arguments to function ‘bt_rap_set_conn_handle’
421 | bt_rap_set_conn_handle(data->hci_sm,
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from profiles/ranging/rap.c:35:
./src/shared/rap.h:215:6: note: declared here
215 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [Makefile:8993: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
profiles/ranging/rap_hci.c:1107:6: error: conflicting types for ‘bt_rap_set_conn_handle’
1107 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from profiles/ranging/rap_hci.c:23:
./src/shared/rap.h:215:6: note: previous declaration of ‘bt_rap_set_conn_handle’ was here
215 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [Makefile:9007: profiles/ranging/bluetoothd-rap_hci.o] Error 1
make: *** [Makefile:4172: all] Error 2
[BlueZ,v1,1/2] shared: rap: Add the is_central parameter to verify whether the local role is central before sending the HCI CS Security Enable command.
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[])
| ^~~~
unit/test-avdtp.c: In function ‘main’:
unit/test-avdtp.c:766:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
766 | int main(int argc, char *argv[])
| ^~~~
unit/test-avrcp.c: In function ‘main’:
unit/test-avrcp.c:989:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
989 | int main(int argc, char *argv[])
| ^~~~
profiles/ranging/rap.c: In function ‘rap_accept’:
profiles/ranging/rap.c:421:4: error: too few arguments to function ‘bt_rap_set_conn_handle’
421 | bt_rap_set_conn_handle(data->hci_sm,
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from profiles/ranging/rap.c:35:
./src/shared/rap.h:215:6: note: declared here
215 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [Makefile:8993: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
profiles/ranging/rap_hci.c:1107:6: error: conflicting types for ‘bt_rap_set_conn_handle’
1107 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from profiles/ranging/rap_hci.c:23:
./src/shared/rap.h:215:6: note: previous declaration of ‘bt_rap_set_conn_handle’ was here
215 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [Makefile:9007: profiles/ranging/bluetoothd-rap_hci.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/check-selftest.c:42:3: warning: Value stored to 'ptr' is never read
ptr = fgets(result, sizeof(result), fp);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning 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/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.
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.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer
(*ctxt)->cb = cb;
~~~~~~~~~~~~^~~~
1 warning generated.
src/sdpd-request.c:209:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t'
pElem = malloc(sizeof(uint16_t));
^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:237:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t'
pElem = malloc(sizeof(uint32_t));
^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/gatt-database.c:1171:10: warning: Value stored to 'bits' during its initialization is never read
uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
^~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed
notify_client_unref(client);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
unit/avrcp-lib.c:1968:3: warning: 1st function call argument is an uninitialized value
g_free(text[i]);
^~~~~~~~~~~~~~~
1 warning generated.
unit/avdtp.c:756:25: warning: Use of memory after it is freed
session->prio_queue = g_slist_remove(session->prio_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unit/avdtp.c:763:24: warning: Use of memory after it is freed
session->req_queue = g_slist_remove(session->req_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
unit/test-util.c:33:8: warning: Potential leak of memory pointed to by 'p1'
p2[0] = 1;
~~~~~~^~~
unit/test-util.c:36:3: warning: Potential leak of memory pointed to by 'p2'
_cleanup_free_ uint8_t *data = NULL;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:134:24: note: expanded from macro '_cleanup_free_'
#define _cleanup_free_ _cleanup_(freep)
^
./src/shared/util.h:132:22: note: expanded from macro '_cleanup_'
#define _cleanup_(f) __attribute__((cleanup(f)))
^
unit/test-util.c:42:3: warning: Potential leak of memory pointed to by 'data'
assert(is_null_too == NULL);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/assert.h:108:11: note: expanded from macro 'assert'
((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \
^~~~~~~~~~~~~~~~~~~~~~~
unit/test-util.c:50:2: warning: Potential leak of memory pointed to by 'data'
assert(is_null == NULL);
^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/assert.h:108:11: note: expanded from macro 'assert'
((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \
^~~~~~~~~~~~~~~~~~~~~~~
4 warnings generated.
profiles/audio/avdtp.c:895:25: warning: Use of memory after it is freed
session->prio_queue = g_slist_remove(session->prio_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
profiles/audio/avdtp.c:902:24: warning: Use of memory after it is freed
session->req_queue = g_slist_remove(session->req_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
profiles/audio/a2dp.c:442:8: warning: Use of memory after it is freed
if (!cb->resume_cb)
^~~~~~~~~~~~~
profiles/audio/a2dp.c:3354:20: warning: Access to field 'starting' results in a dereference of a null pointer (loaded from variable 'stream')
stream->starting = TRUE;
~~~~~~ ^
profiles/audio/a2dp.c:3357:8: warning: Access to field 'suspending' results in a dereference of a null pointer (loaded from variable 'stream')
if (!stream->suspending && stream->suspend_timer) {
^~~~~~~~~~~~~~~~~~
profiles/audio/a2dp.c:3417:22: warning: Access to field 'suspending' results in a dereference of a null pointer (loaded from variable 'stream')
stream->suspending = TRUE;
~~~~~~ ^
4 warnings generated.
profiles/audio/avrcp.c:1968:2: warning: Value stored to 'operands' is never read
operands += sizeof(*pdu);
^ ~~~~~~~~~~~~
1 warning generated.
attrib/gatt.c:970:2: warning: Potential leak of memory pointed to by 'long_write'
return prepare_write(long_write);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdpd-request.c:209:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t'
pElem = malloc(sizeof(uint16_t));
^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:237:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t'
pElem = malloc(sizeof(uint32_t));
^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer
(*ctxt)->cb = cb;
~~~~~~~~~~~~^~~~
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.
src/gatt-database.c:1171:10: warning: Value stored to 'bits' during its initialization is never read
uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
^~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed
notify_client_unref(client);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-header.c:95:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
memcpy(to, from, count);
^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-transfer.c:423:7: warning: Use of memory after it is freed
if (!g_slist_find(transfers, transfer))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
mesh/main.c:162:3: warning: Value stored to 'optarg' is never read
optarg += strlen("auto");
^ ~~~~~~~~~~~~~~
1 warning generated.
lib/bluetooth/hci.c:93:4: warning: Value stored to 'ptr' is never read
ptr += sprintf(ptr, "%s", m->str);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
client/player.c:2363:8: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
if (!strcmp(ep->path, pattern))
^~~~~~~~~~~~~~~~~~~~~~~~~
client/player.c:3640:16: warning: Null pointer passed to 1st parameter expecting 'nonnull'
codec->name = strdup(name);
^~~~~~~~~~~~
2 warnings generated.
gdbus/watch.c:226:3: warning: Attempt to free released memory
g_free(l->data);
^~~~~~~~~~~~~~~
1 warning generated.
lib/bluetooth/sdp.c:509:17: warning: Dereference of undefined pointer value
uint8_t dtd = *(uint8_t *) dtds[i];
^~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:539:17: warning: Dereference of undefined pointer value
uint8_t dtd = *(uint8_t *) dtds[i];
^~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:1891:26: warning: Potential leak of memory pointed to by 'ap'
for (; pdlist; pdlist = pdlist->next) {
^~~~~~
lib/bluetooth/sdp.c:1905:6: warning: Potential leak of memory pointed to by 'pds'
ap = sdp_list_append(ap, pds);
~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:1950:10: warning: Potential leak of memory pointed to by 'u'
*seqp = sdp_list_append(*seqp, u);
~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:2055:4: warning: Potential leak of memory pointed to by 'lang'
sdp_list_free(*langSeq, free);
^~~~~~~~~~~~~
lib/bluetooth/sdp.c:2144:9: warning: Potential leak of memory pointed to by 'profDesc'
return 0;
^
lib/bluetooth/sdp.c:3276:8: warning: Potential leak of memory pointed to by 'pSvcRec'
pSeq = sdp_list_append(pSeq, pSvcRec);
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:3277:9: warning: Potential leak of memory pointed to by 'pSeq'
pdata += sizeof(uint32_t);
~~~~~~^~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:4613:13: warning: Potential leak of memory pointed to by 'rec_list'
} while (scanned < attr_list_len && pdata_len > 0);
^~~~~~~
lib/bluetooth/sdp.c:4909:40: warning: Potential leak of memory pointed to by 'tseq'
for (d = sdpdata->val.dataseq; d; d = d->next) {
^
lib/bluetooth/sdp.c:4945:8: warning: Potential leak of memory pointed to by 'subseq'
tseq = sdp_list_append(tseq, subseq);
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 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.
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.
monitor/l2cap.c:1676:4: warning: Value stored to 'data' is never read
data += len;
^ ~~~
monitor/l2cap.c:1677:4: warning: Value stored to 'size' is never read
size -= len;
^ ~~~
2 warnings generated.
monitor/hwdb.c:59:2: warning: Value stored to 'hwdb' is never read
hwdb = udev_hwdb_unref(hwdb);
^ ~~~~~~~~~~~~~~~~~~~~~
monitor/hwdb.c:64:2: warning: Value stored to 'udev' is never read
udev = udev_unref(udev);
^ ~~~~~~~~~~~~~~~~
monitor/hwdb.c:106:2: warning: Value stored to 'hwdb' is never read
hwdb = udev_hwdb_unref(hwdb);
^ ~~~~~~~~~~~~~~~~~~~~~
monitor/hwdb.c:111:2: warning: Value stored to 'udev' is never read
udev = udev_unref(udev);
^ ~~~~~~~~~~~~~~~~
4 warnings generated.
tools/bluemoon.c:1102:8: warning: Null pointer passed to 1st parameter expecting 'nonnull'
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
^~~~~~~~~~~~~~
1 warning generated.
tools/meshctl.c:326:19: warning: Access to field 'mesh_devices' results in a dereference of a null pointer (loaded from variable 'default_ctrl')
g_list_free_full(default_ctrl->mesh_devices, g_free);
^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/meshctl.c:762:2: warning: 2nd function call argument is an uninitialized value
bt_shell_printf("Attempting to disconnect from %s\n", addr);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/meshctl.c:1957:2: warning: Value stored to 'len' is never read
len = len + extra + strlen("local_node.json");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:291:9: warning: 1st function call argument is an uninitialized value
return be32_to_cpu(get_unaligned((const uint32_t *) ptr));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:41:26: note: expanded from macro 'be32_to_cpu'
#define be32_to_cpu(val) bswap_32(val)
^~~~~~~~~~~~~
/usr/include/byteswap.h:34:21: note: expanded from macro 'bswap_32'
#define bswap_32(x) __bswap_32 (x)
^~~~~~~~~~~~~~
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:301:9: warning: 1st function call argument is an uninitialized value
return be64_to_cpu(get_unaligned((const uint64_t *) ptr));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:42:26: note: expanded from macro 'be64_to_cpu'
#define be64_to_cpu(val) bswap_64(val)
^~~~~~~~~~~~~
/usr/include/byteswap.h:37:21: note: expanded from macro 'bswap_64'
#define bswap_64(x) __bswap_64 (x)
^~~~~~~~~~~~~~
2 warnings generated.
ell/util.c:853:8: warning: The left operand of '>' is a garbage value
if (x > UINT8_MAX)
~ ^
ell/util.c:871:8: warning: The left operand of '>' is a garbage value
if (x > UINT16_MAX)
~ ^
2 warnings generated.
ell/pem.c:131:8: warning: Dereference of null pointer (loaded from variable 'eol')
if (*eol == '\r' || *eol == '\n')
^~~~
ell/pem.c:166:18: warning: Dereference of null pointer (loaded from variable 'eol')
if (buf_len && *eol == '\r' && *buf_ptr == '\n') {
^~~~
ell/pem.c:166:34: warning: Dereference of null pointer (loaded from variable 'buf_ptr')
if (buf_len && *eol == '\r' && *buf_ptr == '\n') {
^~~~~~~~
ell/pem.c:304:11: warning: 1st function call argument is an uninitialized value
result = pem_load_buffer(file.data, file.st.st_size,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ell/pem.c:469:9: warning: 1st function call argument is an uninitialized value
list = l_pem_load_certificate_list_from_data(file.data,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings generated.
ell/cert.c:645:41: warning: Access to field 'asn1_len' results in a dereference of a null pointer (loaded from variable 'cert')
key = l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len);
^~~~~~~~~~~~~~
1 warning generated.
ell/gvariant-util.c:143:18: warning: The left operand of '>' is a garbage value
if (alignment > max_alignment)
~~~~~~~~~ ^
ell/gvariant-util.c:456:5: warning: Dereference of null pointer
!children[0].fixed_size) {
^~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
emulator/serial.c:150:2: warning: Assigned value is garbage or undefined
enum btdev_type uninitialized_var(type);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/serial.c:150:36: warning: Value stored to 'type' during its initialization is never read
enum btdev_type uninitialized_var(type);
^~~~
emulator/serial.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
^ ~
emulator/serial.c:213:2: warning: Assigned value is garbage or undefined
enum btdev_type uninitialized_var(dev_type);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/serial.c:213:36: warning: Value stored to 'dev_type' during its initialization is never read
enum btdev_type uninitialized_var(dev_type);
^~~~~~~~
emulator/serial.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
^ ~
4 warnings generated.
ell/ecc-external.c:77:11: warning: Assigned value is garbage or undefined
dest[i] = src[i];
^ ~~~~~~
ell/ecc-external.c:160:18: warning: The right operand of '-' is a garbage value
diff = left[i] - right[i] - borrow;
^ ~~~~~~~~
ell/ecc-external.c:227:14: warning: 2nd function call argument is an uninitialized value
product = mul_64_64(left[i], right[k - i]);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ell/ecc-external.c:408:9: warning: Assigned value is garbage or undefined
tmp[1] = product[3];
^ ~~~~~~~~~~
ell/ecc-external.c:435:22: warning: The left operand of '&' is a garbage value
tmp[1] = product[3] & 0xffffffff00000000ull;
~~~~~~~~~~ ^
ell/ecc-external.c:483:22: warning: The left operand of '&' is a garbage value
tmp[1] = product[5] & 0xffffffff00000000ull;
~~~~~~~~~~ ^
ell/ecc-external.c:688:28: warning: The left operand of '>>' is a garbage value
tmp[i] = (product[8 + i] >> 9) | (product[9 + i] << 55);
~~~~~~~~~~~~~~ ^
7 warnings generated.
emulator/server.c:230:2: warning: Assigned value is garbage or undefined
enum btdev_type uninitialized_var(type);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/server.c:230:36: warning: Value stored to 'type' during its initialization is never read
enum btdev_type uninitialized_var(type);
^~~~
emulator/server.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
^ ~
2 warnings generated.
emulator/b1ee.c:258:3: warning: Potential leak of memory pointed to by 'server_port'
int opt;
^~~~~~~
emulator/b1ee.c:258:3: warning: Potential leak of memory pointed to by 'sniffer_port'
int opt;
^~~~~~~
emulator/b1ee.c:289:2: warning: Value stored to 'argc' is never read
argc = argc - optind;
^ ~~~~~~~~~~~~~
3 warnings generated.
gobex/gobex-header.c:95:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
memcpy(to, from, count);
^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-transfer.c:423:7: warning: Use of memory after it is freed
if (!g_slist_find(transfers, transfer))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
attrib/gatt.c:970:2: warning: Potential leak of memory pointed to by 'long_write'
return prepare_write(long_write);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
emulator/btdev.c:6662:20: warning: Access to field 'link' results in a dereference of a null pointer (loaded from variable 'acl')
le_past_received(acl->link, pa);
^~~~~~~~~
emulator/btdev.c:6762:25: warning: Access to field 'link' results in a dereference of a null pointer (loaded from variable 'acl')
le_past_info_received(acl->link, ea);
^~~~~~~~~
2 warnings generated.
profiles/ranging/rap.c: In function ‘rap_accept’:
profiles/ranging/rap.c:421:4: error: too few arguments to function ‘bt_rap_set_conn_handle’
421 | bt_rap_set_conn_handle(data->hci_sm,
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from profiles/ranging/rap.c:35:
./src/shared/rap.h:215:6: note: declared here
215 | bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
| ^~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [Makefile:8993: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
profiles/audio/media.c:1112:7: warning: Use of memory after it is freed
if (req->cb != pac_select_cb) {
^~~~~~~
1 warning generated.
make: *** [Makefile:4172: all] Error 2
https://github.com/bluez/bluez/pull/2200
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH] Bluetooth: btmtksdio: fix infinite loop in btmtksdio_txrx_work()
From: Sergey Senozhatsky @ 2026-06-09 12:10 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Mark-yw Chen, Sean Wang
Cc: Tomasz Figa, linux-bluetooth, linux-kernel, linux-arm-kernel,
linux-mediatek, Sergey Senozhatsky, stable
Every once in a while we see a hung btmtksdio_flush() task:
INFO: task kworker/u17:0:189 blocked for more than 122 seconds.
__cancel_work_timer+0x3f4/0x460
cancel_work_sync+0x1c/0x2c
btmtksdio_flush+0x2c/0x40
hci_dev_open_sync+0x10c4/0x2190
[..]
It all boils down to incorrect time_is_before_jiffies() usage in
btmtksdio_txrx_work(). The btmtksdio_txrx_work() loop is expected
to be terminated if running for longer than 5*HZ. However the
timeout check is twisted: time_is_before_jiffies(old_jiffies + 5*HZ)
evaluates to true when old_jiffies + 5*HZ is in the past i.e. when a
timeout has occurred. Using OR with time_is_before_jiffies(txrx_timeout)
means that:
- before the 5-second timeout: the condition is `int_status || false`,
so it loops as long as there are pending interrupts.
- after the 5-second timeout: the condition becomes `int_status || true`,
which is always true.
When the loop becomes infinite btmtksdio_txrx_work() loop never
terminates and never releases the SDIO host.
Fix loop termination condition to actually enforce a 5*HZ timeout.
Fixes: 26270bc189ea4 ("Bluetooth: btmtksdio: move interrupt service to work")
Cc: stable@vger.kernel.org
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/bluetooth/btmtksdio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index 5b0fab7b89b5..c6f80c419e90 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -620,7 +620,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
if (btmtksdio_rx_packet(bdev, rx_size) < 0)
bdev->hdev->stat.err_rx++;
}
- } while (int_status || time_is_before_jiffies(txrx_timeout));
+ } while (int_status && time_is_after_jiffies(txrx_timeout));
/* Enable interrupt */
if (bdev->func->irq_handler)
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related
* [Kernel Bug] possible deadlock in vhci_send_frame
From: Longxing Li @ 2026-06-09 11:59 UTC (permalink / raw)
To: syzkaller, marcel, Luiz Augusto von Dentz, linux-bluetooth,
linux-kernel
Dear Linux kernel developers and maintainers,
We would like to report a new kernel bug found by our tool. possible
deadlock in vhci_send_frame. Details are as follows.
Kernel commit: v5.15.189
Kernel config: see attachment
report: see attachment
C repro and Syz repro: see attachment
We are currently analyzing the root cause. We will provide further
updates in this thread as soon as we have more information.
Best regards,
Longxing Li
======================================================
WARNING: possible circular locking dependency detected
5.15.189 #1 Not tainted
------------------------------------------------------
kworker/u3:2/7652 is trying to acquire lock:
ffff88801c5ea518 (&data->open_mutex){+.+.}-{3:3}, at:
vhci_send_frame+0xb0/0x120 drivers/bluetooth/hci_vhci.c:71
but task is already holding lock:
ffffc90001effda0 ((work_completion)(&hdev->cmd_work)){+.+.}-{0:0}, at:
process_one_work+0x8f5/0x1530 kernel/workqueue.c:2285
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #3 ((work_completion)(&hdev->cmd_work)){+.+.}-{0:0}:
__flush_work+0x12d/0xc10 kernel/workqueue.c:3090
hci_dev_do_open+0xab6/0x1b40 net/bluetooth/hci_core.c:1626
hci_power_on+0x133/0x680 net/bluetooth/hci_core.c:2265
process_one_work+0x9db/0x1530 kernel/workqueue.c:2310
worker_thread+0x686/0x1180 kernel/workqueue.c:2457
kthread+0x3d0/0x4c0 kernel/kthread.c:334
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:287
-> #2 (&hdev->req_lock){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:596 [inline]
__mutex_lock+0x183/0x1300 kernel/locking/mutex.c:729
hci_dev_do_close+0x5d/0x1250 net/bluetooth/hci_core.c:1737
hci_rfkill_set_block+0x1be/0x210 net/bluetooth/hci_core.c:2235
rfkill_set_block+0x200/0x550 net/rfkill/core.c:345
rfkill_sync_work+0x8a/0xc0 net/rfkill/core.c:1030
process_one_work+0x9db/0x1530 kernel/workqueue.c:2310
worker_thread+0x686/0x1180 kernel/workqueue.c:2457
kthread+0x3d0/0x4c0 kernel/kthread.c:334
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:287
-> #1 (rfkill_global_mutex){+.+.}-{3:3}:
__mutex_lock_common kernel/locking/mutex.c:596 [inline]
__mutex_lock+0x183/0x1300 kernel/locking/mutex.c:729
rfkill_register+0x36/0xb00 net/rfkill/core.c:1045
hci_register_dev+0x440/0xd90 net/bluetooth/hci_core.c:3960
__vhci_create_device+0x2c8/0x5e0 drivers/bluetooth/hci_vhci.c:129
vhci_create_device drivers/bluetooth/hci_vhci.c:153 [inline]
vhci_get_user drivers/bluetooth/hci_vhci.c:210 [inline]
vhci_write+0x2c0/0x460 drivers/bluetooth/hci_vhci.c:290
call_write_iter include/linux/fs.h:2172 [inline]
new_sync_write+0x4b2/0x680 fs/read_write.c:507
vfs_write+0x7d9/0xb40 fs/read_write.c:594
ksys_write+0x13a/0x260 fs/read_write.c:647
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x34/0x80 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x66/0xd0
-> #0 (&data->open_mutex){+.+.}-{3:3}:
check_prev_add kernel/locking/lockdep.c:3053 [inline]
check_prevs_add kernel/locking/lockdep.c:3172 [inline]
validate_chain kernel/locking/lockdep.c:3788 [inline]
__lock_acquire+0x293e/0x5590 kernel/locking/lockdep.c:5012
lock_acquire kernel/locking/lockdep.c:5623 [inline]
lock_acquire+0x1a8/0x4c0 kernel/locking/lockdep.c:5588
__mutex_lock_common kernel/locking/mutex.c:596 [inline]
__mutex_lock+0x183/0x1300 kernel/locking/mutex.c:729
vhci_send_frame+0xb0/0x120 drivers/bluetooth/hci_vhci.c:71
hci_send_frame+0x1c0/0x400 net/bluetooth/hci_core.c:4256
hci_cmd_work+0x223/0x3b0 net/bluetooth/hci_core.c:5201
process_one_work+0x9db/0x1530 kernel/workqueue.c:2310
worker_thread+0x686/0x1180 kernel/workqueue.c:2457
kthread+0x3d0/0x4c0 kernel/kthread.c:334
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:287
other info that might help us debug this:
Chain exists of:
&data->open_mutex --> &hdev->req_lock --> (work_completion)(&hdev->cmd_work)
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock((work_completion)(&hdev->cmd_work));
lock(&hdev->req_lock);
lock((work_completion)(&hdev->cmd_work));
lock(&data->open_mutex);
*** DEADLOCK ***
2 locks held by kworker/u3:2/7652:
#0: ffff888057be9938 ((wq_completion)hci0#3){+.+.}-{0:0}, at:
arch_atomic64_set arch/x86/include/asm/atomic64_64.h:34 [inline]
#0: ffff888057be9938 ((wq_completion)hci0#3){+.+.}-{0:0}, at:
arch_atomic_long_set include/linux/atomic/atomic-long.h:41 [inline]
#0: ffff888057be9938 ((wq_completion)hci0#3){+.+.}-{0:0}, at:
atomic_long_set include/linux/atomic/atomic-instrumented.h:1198
[inline]
#0: ffff888057be9938 ((wq_completion)hci0#3){+.+.}-{0:0}, at:
set_work_data kernel/workqueue.c:635 [inline]
#0: ffff888057be9938 ((wq_completion)hci0#3){+.+.}-{0:0}, at:
set_work_pool_and_clear_pending kernel/workqueue.c:662 [inline]
#0: ffff888057be9938 ((wq_completion)hci0#3){+.+.}-{0:0}, at:
process_one_work+0x8c1/0x1530 kernel/workqueue.c:2281
#1: ffffc90001effda0
((work_completion)(&hdev->cmd_work)){+.+.}-{0:0}, at:
process_one_work+0x8f5/0x1530 kernel/workqueue.c:2285
stack backtrace:
CPU: 0 PID: 7652 Comm: kworker/u3:2 Not tainted 5.15.189 #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
Workqueue: hci0 hci_cmd_work
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0xfc/0x174 lib/dump_stack.c:106
check_noncircular+0x277/0x310 kernel/locking/lockdep.c:2133
check_prev_add kernel/locking/lockdep.c:3053 [inline]
check_prevs_add kernel/locking/lockdep.c:3172 [inline]
validate_chain kernel/locking/lockdep.c:3788 [inline]
__lock_acquire+0x293e/0x5590 kernel/locking/lockdep.c:5012
lock_acquire kernel/locking/lockdep.c:5623 [inline]
lock_acquire+0x1a8/0x4c0 kernel/locking/lockdep.c:5588
__mutex_lock_common kernel/locking/mutex.c:596 [inline]
__mutex_lock+0x183/0x1300 kernel/locking/mutex.c:729
vhci_send_frame+0xb0/0x120 drivers/bluetooth/hci_vhci.c:71
hci_send_frame+0x1c0/0x400 net/bluetooth/hci_core.c:4256
hci_cmd_work+0x223/0x3b0 net/bluetooth/hci_core.c:5201
process_one_work+0x9db/0x1530 kernel/workqueue.c:2310
worker_thread+0x686/0x1180 kernel/workqueue.c:2457
kthread+0x3d0/0x4c0 kernel/kthread.c:334
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:287
</TASK>
==================================================================
https://drive.google.com/file/d/13nr1pPRHCrZqYxz08ngNiCvmcRe-d_oK/view?usp=drive_link
https://drive.google.com/file/d/11Ox0bimeaa3r8BaGqhXBBymrs03Haz8o/view?usp=drive_link
https://drive.google.com/file/d/1yA-bbVeMCxS_p7ZjDH97NK4iI_1CLeAz/view?usp=drive_link
https://drive.google.com/file/d/1XqJJtZ0jKV_oFm8M6SuQV2YAuKEqWHbn/view?usp=drive_link
^ permalink raw reply
* [bluez/bluez]
From: BluezTestBot @ 2026-06-09 11:49 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1105699
Home: https://github.com/bluez/bluez
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] 0828cc: shared: rap: Add the is_central parameter to verif...
From: Bhavani @ 2026-06-09 11:49 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1108507
Home: https://github.com/bluez/bluez
Commit: 0828ccc601b1a2a788b21a5aef31d06fb5f42055
https://github.com/bluez/bluez/commit/0828ccc601b1a2a788b21a5aef31d06fb5f42055
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-06-09 (Tue, 09 Jun 2026)
Changed paths:
M src/shared/rap.h
Log Message:
-----------
shared: rap: Add the is_central parameter to verify whether the local role is central before sending the HCI CS Security Enable command.
Commit: d6cc95002b6b86b843711f04be4175fad1473fdd
https://github.com/bluez/bluez/commit/d6cc95002b6b86b843711f04be4175fad1473fdd
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-06-09 (Tue, 09 Jun 2026)
Changed paths:
M profiles/ranging/rap.c
M profiles/ranging/rap_hci.c
Log Message:
-----------
profiles: ranging: Add command flow and event support for CS Initiator
Introduce support for LE Channel Sounding (CS)
ranging procedures in the Initiator role by enabling required
HCI command sequencing and event handling.
- Add transmission of core HCI LE CS commands:
HCI_LE_CS_Read_Local_Supported_Capabilities,
HCI_LE_CS_Read_Remote_Supported_Capabilities,
HCI_LE_CS_Security_Enable,
HCI_LE_CS_Create_Config,
HCI_LE_CS_Remove_Config,
HCI_LE_CS_Read_Remote_FAE_Table,
HCI_LE_CS_Set_Channel_Classification,
HCI_LE_CS_Set_Procedure_Parameters,
HCI_LE_CS_Procedure_Enable
- Add handling of event:
HCI_LE_CS_Read_Remote_FAE_Table_Complete
This enables cs capability discovery, cs configuration management
and execution of CS ranging procedures in the Initiator role.
- CS init pipeline not yet wired up pending D-Bus API.
bt_rap_read_local_supported_capabilities() has no caller,
mark __maybe_unused till DBus APIs are introduced.
Compare: https://github.com/bluez/bluez/compare/0828ccc601b1%5E...d6cc95002b6b
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] cb89e8: shared/bap: add ASE Control Point error responses
From: raghava447 @ 2026-06-09 11:49 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1108483
Home: https://github.com/bluez/bluez
Commit: cb89e837f32c3d7fde71f588ac87e6f912392128
https://github.com/bluez/bluez/commit/cb89e837f32c3d7fde71f588ac87e6f912392128
Author: raghu447 <raghavendra.rao@collabora.com>
Date: 2026-06-09 (Tue, 09 Jun 2026)
Changed paths:
M src/shared/bap.c
Log Message:
-----------
shared/bap: add ASE Control Point error responses
These changes are required to Pass BAP/USR/SPE/BI-01[5]-C tests.
Commit: 29bfabd2e21982b8cd70f4f846fa2d3d64ece7c7
https://github.com/bluez/bluez/commit/29bfabd2e21982b8cd70f4f846fa2d3d64ece7c7
Author: raghu447 <raghavendra.rao@collabora.com>
Date: 2026-06-09 (Tue, 09 Jun 2026)
Changed paths:
M unit/test-bap.c
Log Message:
-----------
unit/bap: add SPE tests
Add unit tests for the PTS BAP/USR/SPE/BI-01[5]-C tests.
Compare: https://github.com/bluez/bluez/compare/cb89e837f32c%5E...29bfabd2e219
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* Re: [PATCH v4 4/8] block: implement NVMEM provider
From: Bartosz Golaszewski @ 2026-06-09 11:05 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Srinivas Kandagatla,
Andrew Lunn, Heiner Kallweit, Russell King, Saravana Kannan,
Bartosz Golaszewski
In-Reply-To: <CAFEp6-1syMQsvuQ+dLU39bnDeL5Ok7vK1mA7CS0v1m7cjhyMQw@mail.gmail.com>
On Tue, 9 Jun 2026 12:13:08 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> Hi bartosz,
>
...
>>
>> On the other hand, we don't want to not provide the block device just because
>> someone added a DT property on one that's too big. I'd say: warn, but return 0.
>> Does it make sense?
>
> It’s still technically an error in the sense that we cannot provide
> the required nvmem feature. However, it only becomes a real issue if a
> consumer actually attempts to use it.
> Also, the block device should still be added, since the return code
> from add_dev is not checked. In any case, I’m fine with either
> approach, as long as we emit a warning message.
>
We don't check the return value now (why?) but if we ever do, the safer option
is to return 0 IMO.
>>
>> > + }
>> > +
>> > + config.id = NVMEM_DEVID_NONE;
>> > + config.dev = dev;
>> > + config.name = dev_name(dev);
>> > + config.owner = THIS_MODULE;
>> > + config.priv = (void *)(uintptr_t)dev->devt;
>> > + config.reg_read = blk_nvmem_reg_read;
>> > + config.size = bdev_nr_bytes(bdev);
>> > + config.word_size = 1;
>> > + config.stride = 1;
>> > + config.read_only = true;
>> > + config.root_only = true;
>> > + config.ignore_wp = true;
>> > + config.of_node = to_of_node(dev->fwnode);
>> > +
>> > + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
>>
>> And that was a wrong suggestion on my part too because I was under the
>> impression that we're in the probe() path, not device_add(). You can't use
>> devres here as the device at this point is not yet bound and may never be.
>
> So I understand The bd_device is purely a class device with no bus, no driver.
> For driverless devices, devres_release_all() is called explicitly
> within device_del() .
>
Right.
>>
>> Which leads me to the second point: this is not the moment to add the nvmem
>> provider. This should happen at or after probe(). Once nvmem_register()
>> returns, you have a visible nvmem resource but nothing backing it in the block
>> layer.
>
> There is a short window during which a read attempt will 'properly'
> fail, but this does seem somewhat fragile indeed.
>
>> Either do this in block core when registering a new device or schedule
>> a notifier here for the BUS_NOTIFY_BOUND_DRIVER event and do it in the notifier
>> callback.
>
> So in the end, it seems that the simpler and more robust approach is
> probably to move away from the class_interface driver and instead
> register/unregister the nvmem directly in add_disk/del_gendisk.
> If that's ok I will move to this approach in the next version.
>
Yes, I think it's the right approach.
Bart
^ permalink raw reply
* [PATCH BlueZ v1 2/2] profiles: ranging: Add command flow and event support for CS Initiator
From: Naga Bhavani Akella @ 2026-06-09 10:49 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
Naga Bhavani Akella
In-Reply-To: <20260609104953.3122718-1-naga.akella@oss.qualcomm.com>
Introduce support for LE Channel Sounding (CS)
ranging procedures in the Initiator role by enabling required
HCI command sequencing and event handling.
- Add transmission of core HCI LE CS commands:
HCI_LE_CS_Read_Local_Supported_Capabilities,
HCI_LE_CS_Read_Remote_Supported_Capabilities,
HCI_LE_CS_Security_Enable,
HCI_LE_CS_Create_Config,
HCI_LE_CS_Remove_Config,
HCI_LE_CS_Read_Remote_FAE_Table,
HCI_LE_CS_Set_Channel_Classification,
HCI_LE_CS_Set_Procedure_Parameters,
HCI_LE_CS_Procedure_Enable
- Add handling of event:
HCI_LE_CS_Read_Remote_FAE_Table_Complete
This enables cs capability discovery, cs configuration management
and execution of CS ranging procedures in the Initiator role.
- CS init pipeline not yet wired up pending D-Bus API.
bt_rap_read_local_supported_capabilities() has no caller,
mark __maybe_unused till DBus APIs are introduced.
---
profiles/ranging/rap.c | 3 +-
profiles/ranging/rap_hci.c | 876 +++++++++++++++++++++++++++++++++----
2 files changed, 783 insertions(+), 96 deletions(-)
diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
index e0a46a87a..e3b50c145 100644
--- a/profiles/ranging/rap.c
+++ b/profiles/ranging/rap.c
@@ -421,7 +421,8 @@ static int rap_accept(struct btd_service *service)
bt_rap_set_conn_handle(data->hci_sm,
data->rap, handle,
(const uint8_t *) bdaddr,
- bdaddr_type);
+ bdaddr_type,
+ btd_device_is_initiator(device));
} else {
error("Failed to find connection handle for device %s",
addr);
diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
index febe23384..873bbe6cb 100644
--- a/profiles/ranging/rap_hci.c
+++ b/profiles/ranging/rap_hci.c
@@ -16,14 +16,20 @@
#include <unistd.h>
#include <string.h>
#include <endian.h>
+#include <time.h>
#include "lib/bluetooth/bluetooth.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
#include "src/shared/rap.h"
+#include "src/shared/att.h"
#include "src/log.h"
#include "monitor/bt.h"
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((unused))
+#endif
+
/* Macro to sign-extend an N-bit value to 16-bit signed integer */
#define SIGN_EXTEND_TO_16(val, bits) \
((int16_t)(((val) ^ (1U << ((bits)-1))) - (1U << ((bits)-1))))
@@ -67,6 +73,7 @@ struct cs_state_machine {
struct bt_rap_hci_cs_options cs_opt; /* Per-instance CS options */
uint8_t role_enable; /* Role value for HCI commands (1, 2, or 3) */
struct queue *conn_mappings; /* Per-instance connection mappings */
+ struct timespec last_chan_class_time; /* For 1-second rate limit */
};
/* Connection Handle Mapping */
@@ -74,10 +81,18 @@ struct rap_conn_mapping {
uint16_t handle;
uint8_t bdaddr[6];
uint8_t bdaddr_type;
+ bool is_central; /* true if local device is BLE Central on this link */
struct bt_att *att;
struct bt_rap *rap;
};
+/* Function declarations */
+static bool bt_rap_read_remote_fae_table(void *hci_sm, uint16_t handle);
+static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
+ uint16_t handle);
+static bool bt_rap_read_remote_supported_capabilities(void *hci_sm,
+ uint16_t handle);
+
/* Connection Mapping Helper Functions */
static void mapping_free(void *data)
{
@@ -97,14 +112,6 @@ static bool match_mapping_handle(const void *a, const void *b)
return mapping->handle == handle;
}
-static bool match_mapping_rap(const void *a, const void *b)
-{
- const struct rap_conn_mapping *mapping = a;
- const struct bt_rap *rap = b;
-
- return mapping->rap == rap;
-}
-
static struct rap_conn_mapping *find_mapping_by_handle(
struct cs_state_machine *sm,
uint16_t handle)
@@ -118,19 +125,14 @@ static struct rap_conn_mapping *find_mapping_by_handle(
static bool add_conn_mapping(struct cs_state_machine *sm, uint16_t handle,
const uint8_t *bdaddr, uint8_t bdaddr_type,
- struct bt_att *att, struct bt_rap *rap)
+ bool is_central, struct bt_att *att,
+ struct bt_rap *rap)
{
struct rap_conn_mapping *mapping;
if (!sm)
return false;
- if (!sm->conn_mappings) {
- sm->conn_mappings = queue_new();
- if (!sm->conn_mappings)
- return false;
- }
-
/* Check if mapping already exists */
mapping = find_mapping_by_handle(sm, handle);
if (mapping) {
@@ -138,6 +140,7 @@ static bool add_conn_mapping(struct cs_state_machine *sm, uint16_t handle,
if (bdaddr)
memcpy(mapping->bdaddr, bdaddr, 6);
mapping->bdaddr_type = bdaddr_type;
+ mapping->is_central = is_central;
mapping->att = att;
mapping->rap = rap;
return true;
@@ -152,6 +155,7 @@ static bool add_conn_mapping(struct cs_state_machine *sm, uint16_t handle,
if (bdaddr)
memcpy(mapping->bdaddr, bdaddr, 6);
mapping->bdaddr_type = bdaddr_type;
+ mapping->is_central = is_central;
mapping->att = att;
mapping->rap = rap;
@@ -171,13 +175,28 @@ static void remove_conn_mapping(struct cs_state_machine *sm, uint16_t handle)
mapping_free(mapping);
}
-static void remove_rap_mappings(struct cs_state_machine *sm)
+static struct bt_rap *resolve_handle_to_rap(struct cs_state_machine *sm,
+ uint16_t handle)
{
- if (!sm || !sm->conn_mappings)
- return;
+ struct rap_conn_mapping *mapping;
- queue_remove_all(sm->conn_mappings, match_mapping_rap, sm->rap,
- mapping_free);
+ if (!sm)
+ return NULL;
+
+ /* Try to find in mapping cache */
+ mapping = find_mapping_by_handle(sm, handle);
+ if (mapping && mapping->rap) {
+ DBG("Found handle 0x%04X in mapping cache", handle);
+ return mapping->rap;
+ }
+
+ /* Profile layer should have called bt_rap_set_conn_handle() during
+ * connection establishment. If we reach here, the mapping was not set.
+ */
+ DBG("No mapping found for handle 0x%04X", handle);
+ DBG("Profile layer should call bt_rap_set_conn_handle() on connect");
+
+ return NULL;
}
/* State Machine Functions */
@@ -194,6 +213,7 @@ static void cs_state_machine_init(struct cs_state_machine *sm,
sm->hci = hci;
sm->initiator = false;
sm->procedure_active = false;
+ sm->conn_mappings = queue_new();
/* Store role_enable for HCI commands (1, 2, or 3 from config) */
sm->role_enable = role;
@@ -219,8 +239,8 @@ static void cs_set_state(struct cs_state_machine *sm,
return;
/* Validate state values before array access */
- if (sm->current_state > CS_STATE_UNSPECIFIED ||
- new_state > CS_STATE_UNSPECIFIED) {
+ if ((unsigned int)sm->current_state >= ARRAY_SIZE(state_names) ||
+ (unsigned int)new_state >= ARRAY_SIZE(state_names)) {
error("Invalid state transition attempted");
return;
}
@@ -238,11 +258,85 @@ static enum cs_state cs_get_current_state(struct cs_state_machine *sm)
return sm ? sm->current_state : CS_STATE_UNSPECIFIED;
}
+static bool is_initiator_role(const struct cs_state_machine *sm)
+{
+ return sm->role_enable == 0x01 || sm->role_enable == 0x03;
+}
+
+/* Helper function to send read remote capabilities for all connections */
+static void send_read_remote_cap_for_mapping(void *data, void *user_data)
+{
+ struct rap_conn_mapping *mapping = data;
+ struct cs_state_machine *sm = user_data;
+
+ if (!mapping || !sm)
+ return;
+
+ DBG("Sending read remote capabilities for handle 0x%04X",
+ mapping->handle);
+ bt_rap_read_remote_supported_capabilities(sm, mapping->handle);
+}
+
/* HCI Event Callbacks */
+static void rap_rd_loc_supp_cap_done_cb(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_le_cs_rd_loc_supp_cap *rsp;
+ struct cs_state_machine *sm = (struct cs_state_machine *) user_data;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_rsp_le_cs_rd_loc_supp_cap))
+ return;
+
+ DBG("size=0x%02X", size);
+
+ rsp = (const struct bt_hci_rsp_le_cs_rd_loc_supp_cap *) data;
+
+ if (rsp->status != 0) {
+ error("Read Local Supported Capabilities failed: 0x%02X",
+ rsp->status);
+ return;
+ }
+
+ DBG("Local CS Capabilities:");
+ DBG(" Num Config Supported: %u", rsp->num_config_supported);
+ DBG(" Max Consecutive Procedures: %u",
+ rsp->max_consecutive_procedures_supported);
+ DBG(" Num Antennas: %u", rsp->num_antennas_supported);
+ DBG(" Max Antenna Paths: %u", rsp->max_antenna_paths_supported);
+ DBG(" Roles Supported: 0x%02X", rsp->roles_supported);
+ DBG(" Modes Supported: 0x%02X", rsp->modes_supported);
+ DBG(" RTT Capability: 0x%02X", rsp->rtt_capability);
+ DBG(" RTT AA Only N: %u", rsp->rtt_aa_only_n);
+ DBG(" RTT Sounding N: %u", rsp->rtt_sounding_n);
+ DBG(" RTT Random Payload N: %u", rsp->rtt_random_payload_n);
+ DBG(" NADM Sounding Capability: 0x%04X",
+ rsp->nadm_sounding_capability);
+ DBG(" NADM Random Capability: 0x%04X", rsp->nadm_random_capability);
+ DBG(" CS Sync PHYs Supported: 0x%02X", rsp->cs_sync_phys_supported);
+ DBG(" Subfeatures Supported: 0x%04X", rsp->subfeatures_supported);
+ DBG(" T_IP1 Times Supported: 0x%04X", rsp->t_ip1_times_supported);
+ DBG(" T_IP2 Times Supported: 0x%04X", rsp->t_ip2_times_supported);
+ DBG(" T_FCS Times Supported: 0x%04X", rsp->t_fcs_times_supported);
+ DBG(" T_PM Times Supported: 0x%04X", rsp->t_pm_times_supported);
+ DBG(" T_SW Time Supported: %u", rsp->t_sw_time_supported);
+ DBG(" TX SNR Capability: 0x%02X", rsp->tx_snr_capability);
+
+ /* Transition to INIT state before reading remote capabilities */
+ cs_set_state(sm, CS_STATE_INIT);
+
+ /* Send read remote capabilities for all connected devices */
+ if (sm->conn_mappings) {
+ DBG("Sending read remote capabilities for all connections");
+ queue_foreach(sm->conn_mappings,
+ send_read_remote_cap_for_mapping, sm);
+ }
+}
+
static void rap_def_settings_done_cb(const void *data, uint8_t size,
void *user_data)
{
- struct bt_hci_rsp_le_cs_set_def_settings *rp;
+ const struct bt_hci_rsp_le_cs_set_def_settings *rp;
struct cs_state_machine *sm = user_data;
if (!sm || !data || size < sizeof(*rp))
@@ -250,10 +344,11 @@ static void rap_def_settings_done_cb(const void *data, uint8_t size,
DBG("size=0x%02X", size);
- rp = (struct bt_hci_rsp_le_cs_set_def_settings *) data;
+ rp = (const struct bt_hci_rsp_le_cs_set_def_settings *) data;
- if (cs_get_current_state(sm) != CS_STATE_INIT) {
- DBG("Event received in Wrong State!! Expected : CS_STATE_INIT");
+ if (cs_get_current_state(sm) == CS_STATE_STOPPED ||
+ cs_get_current_state(sm) == CS_STATE_UNSPECIFIED) {
+ DBG("Def settings response in terminal state, ignoring");
return;
}
@@ -261,9 +356,13 @@ static void rap_def_settings_done_cb(const void *data, uint8_t size,
/* Success - proceed to configuration */
cs_set_state(sm, CS_STATE_WAIT_CONFIG_CMPLT);
- /* Reflector role */
- DBG("Waiting for CS Config Completed event...");
- /* TODO: Initiator role - Send CS Config complete cmd */
+ /* If role is initiator, send CS Create Config command */
+ if (is_initiator_role(sm)) {
+ rap_send_hci_cs_create_config_command(sm, rp->handle);
+ } else {
+ /* Reflector role */
+ DBG("Reflector role: Waiting for CS Config Completed");
+ }
} else {
/* Error - transition to stopped */
error("CS Set default setting failed with status 0x%02X",
@@ -272,8 +371,196 @@ static void rap_def_settings_done_cb(const void *data, uint8_t size,
}
}
-static void rap_send_hci_def_settings_command(struct cs_state_machine *sm,
+static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
+ uint16_t handle)
+{
+ struct bt_hci_cmd_le_cs_create_config cmd;
+ unsigned int status;
+
+ uint8_t channel_map[10] = {
+ 0xFC, 0xFF, 0x7F, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x1F
+ };
+
+ if (!sm || !sm->hci) {
+ error("CS Create Config: sm or hci is null");
+ return;
+ }
+
+ DBG("Sending CS Create Config command for handle 0x%04X", handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+ cmd.create_context = 1;
+ /* Default values, will change to pick user given values later */
+ cmd.config_id = 0x00;
+ cmd.main_mode_type = 0x01;
+ cmd.sub_mode_type = 0xFF;
+ cmd.min_main_mode_steps = 0x02;
+ cmd.max_main_mode_steps = 0x03;
+ cmd.main_mode_repetition = 0x01;
+ cmd.mode_0_steps = 0x02;
+ cmd.role = 0x00;
+ cmd.rtt_type = 0x00;
+ cmd.cs_sync_phy = 0x01;
+ memcpy(cmd.channel_map, channel_map, 10);
+ cmd.channel_map_repetition = 0x01;
+ cmd.channel_selection_type = 0x00;
+ cmd.ch3c_shape = 0x00;
+ cmd.ch3c_jump = 0x02;
+ cmd.reserved = 0x00;
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_CREATE_CONFIG,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send CS Create Config command");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ DBG("CS Create Config command sent successfully");
+}
+
+static void rap_send_hci_cs_remove_config_command(struct cs_state_machine *sm,
uint16_t handle)
+{
+ struct bt_hci_cmd_le_cs_remove_config cmd;
+ unsigned int status;
+
+ if (!sm || !sm->hci) {
+ error("CS Remove Config: sm or hci is null");
+ return;
+ }
+
+ DBG("Sending CS Remove Config command for handle 0x%04X", handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+ cmd.config_id = 0x00; /* Default config ID */
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_REMOVE_CONFIG,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send CS Remove Config command");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ DBG("CS Remove Config command sent successfully");
+}
+
+static void rap_send_hci_cs_security_enable_command(
+ struct cs_state_machine *sm, uint16_t handle)
+{
+ struct bt_hci_cmd_le_cs_sec_enable cmd;
+ unsigned int status;
+
+ if (!sm || !sm->hci) {
+ error("CS Security Enable: sm or hci is null");
+ return;
+ }
+
+ DBG("Sending CS Security Enable command for handle 0x%04X", handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SEC_ENABLE,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send CS Security Enable command");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ DBG("CS Security Enable command sent successfully");
+}
+
+static bool rap_send_hci_cs_set_procedure_parameters(
+ struct cs_state_machine *sm, uint16_t handle)
+{
+ struct bt_hci_cmd_le_cs_set_proc_params cmd;
+ unsigned int status;
+ uint8_t min_sub_event_len[3] = {
+ 0x00, 0x20, 0x00
+ };
+
+ uint8_t max_sub_event_len[3] = {
+ 0x03, 0x20, 0x00
+ };
+
+ if (!sm || !sm->hci) {
+ error("CS Set Procedure Parameters: sm or hci is null");
+ return false;
+ }
+
+ DBG("Sending CS Set Procedure Parameters for handle 0x%04X", handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+ /* Default values, will change to pick user given values later */
+ cmd.config_id = 0x00;
+ cmd.max_procedure_len = 0x0640;
+ cmd.min_procedure_interval = 0x1E;
+ cmd.max_procedure_interval = 0x96;
+ cmd.max_procedure_count = 0x00;
+ memcpy(cmd.min_subevent_len, min_sub_event_len, 3);
+ memcpy(cmd.max_subevent_len, max_sub_event_len, 3);
+ cmd.tone_antenna_config_selection = 0x07;
+ cmd.phy = 0x01;
+ cmd.tx_power_delta = 0x80;
+ cmd.preferred_peer_antenna = 0x03;
+ cmd.snr_control_initiator = 0xFF;
+ cmd.snr_control_reflector = 0xFF;
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SET_PROC_PARAMS,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send CS Set Procedure Parameters command");
+ return false;
+ }
+
+ DBG("CS Set Procedure Parameters command sent successfully");
+ return true;
+}
+
+static bool rap_send_hci_cs_procedure_enable(struct cs_state_machine *sm,
+ uint16_t handle,
+ bool enable_proc)
+{
+ struct bt_hci_cmd_le_cs_proc_enable cmd;
+ unsigned int status;
+
+ if (!sm || !sm->hci) {
+ error("CS Procedure Enable: sm or hci is null");
+ return false;
+ }
+
+ DBG("Sending CS Procedure Enable for handle 0x%04X", handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+ cmd.config_id = 0x00; /* Default config Id */
+ cmd.enable = enable_proc ? 0x01 : 0x00;
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_PROC_ENABLE,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send CS Procedure Enable command");
+ return false;
+ }
+
+ DBG("CS Procedure Enable command sent successfully");
+ return true;
+}
+
+static void rap_send_hci_def_settings_command(struct cs_state_machine *sm,
+ const struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *ev)
{
struct bt_hci_cmd_le_cs_set_def_settings cp;
unsigned int status;
@@ -285,8 +572,8 @@ static void rap_send_hci_def_settings_command(struct cs_state_machine *sm,
memset(&cp, 0, sizeof(cp));
- if (handle)
- cp.handle = handle;
+ if (ev->handle)
+ cp.handle = ev->handle;
cp.role_enable = sm->role_enable; /* Use preserved HCI command value */
cp.cs_sync_antenna_selection = sm->cs_opt.cs_sync_ant_sel;
@@ -302,12 +589,93 @@ static void rap_send_hci_def_settings_command(struct cs_state_machine *sm,
error("Failed to send default settings cmd");
}
+static void rap_rd_rem_fae_cmplt_evt(const void *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine *sm = (struct cs_state_machine *) user_data;
+ const struct bt_hci_evt_le_cs_rd_rem_fae_complete *evt;
+ struct iovec iov;
+ int i;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_rd_rem_fae_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *) data;
+ iov.iov_len = size;
+
+ /* Pull the entire structure at once */
+ evt = util_iov_pull_mem(&iov, sizeof(*evt));
+
+ if (!evt) {
+ error("Failed to pull remote FAE complete struct");
+ return;
+ }
+
+ DBG("status=0x%02X, handle=0x%04X", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ /* Status 0x11 (Unsupported Feature or Parameter Value) means
+ * the remote has zero FAE, the procedure continues
+ * to the Default Settings step.
+ */
+ if (evt->status == 0x11) {
+ DBG("Remote FAE=0 (No_FAE), proceed to Def Settings");
+ if (is_initiator_role(sm)) {
+ struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete
+ tmp_ev;
+
+ memset(&tmp_ev, 0, sizeof(tmp_ev));
+ tmp_ev.handle = evt->handle;
+ DBG("Initiator: send def settings (No_FAE)");
+ rap_send_hci_def_settings_command(sm, &tmp_ev);
+ } else {
+ DBG("Reflector role: continuing after No_FAE");
+ cs_set_state(sm, CS_STATE_INIT);
+ }
+ return;
+ }
+ error("Remote FAE Table read failed with status 0x%02X",
+ evt->status);
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ DBG("Remote FAE Table received:");
+ for (i = 0; i < 72; i += 8) {
+ DBG(" [%02d-%02d]: %02X %02X %02X %02X %02X %02X %02X %02X",
+ i, i+7,
+ evt->remote_fae_table[i], evt->remote_fae_table[i+1],
+ evt->remote_fae_table[i+2], evt->remote_fae_table[i+3],
+ evt->remote_fae_table[i+4], evt->remote_fae_table[i+5],
+ evt->remote_fae_table[i+6], evt->remote_fae_table[i+7]);
+ }
+
+ /* After receiving FAE Table, send default settings */
+ /* Local capabilities already read before this event */
+ if (is_initiator_role(sm)) {
+ struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete tmp_ev;
+
+ memset(&tmp_ev, 0, sizeof(tmp_ev));
+ tmp_ev.handle = evt->handle;
+ DBG("Initiator role: send def settings after FAE table");
+ rap_send_hci_def_settings_command(sm, &tmp_ev);
+ } else {
+ DBG("Reflector role: Proceeding after FAE Table");
+ cs_set_state(sm, CS_STATE_INIT);
+ }
+}
+
static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
void *user_data)
{
struct cs_state_machine *sm = user_data;
const struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *evt;
+ struct bt_rap *rap;
struct iovec iov;
+ uint16_t subfeatures_supported;
if (!sm || !data || size < sizeof(*evt))
return;
@@ -334,6 +702,16 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
return;
}
+ /* Resolve handle to RAP instance */
+ rap = resolve_handle_to_rap(sm, evt->handle);
+
+ if (!rap) {
+ DBG("[WARN] Could not resolve handle 0x%04X to RAP instance",
+ evt->handle);
+ /* Continue with state machine RAP for now */
+ rap = sm->rap;
+ }
+
DBG("num_config=%u, ",
evt->num_config_supported);
DBG("max_consecutive_proc=%u, num_antennas=%u, ",
@@ -343,9 +721,26 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
evt->max_antenna_paths_supported,
evt->roles_supported,
evt->modes_supported);
+ subfeatures_supported = le16_to_cpu(evt->subfeatures_supported);
+ DBG("subfeatures_supported=0x%04X", subfeatures_supported);
- rap_send_hci_def_settings_command(sm, evt->handle);
- cs_set_state(sm, CS_STATE_INIT);
+ /* Check Bit 1 of subfeatures_supported (0x0002) */
+ if (!(subfeatures_supported & 0x0002)) {
+ DBG("Bit 1 not set, sending Read Remote FAE Table");
+ bt_rap_read_remote_fae_table(sm, evt->handle);
+ return;
+ }
+
+ /* Local capabilities already read before this event */
+ if (is_initiator_role(sm)) {
+ DBG("Initiator role: send def settings cmd for handle 0x%04X",
+ evt->handle);
+ rap_send_hci_def_settings_command(sm, evt);
+ } else {
+ DBG("Reflector role: send def settings cmd");
+ cs_set_state(sm, CS_STATE_INIT);
+ rap_send_hci_def_settings_command(sm, evt);
+ }
}
static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
@@ -383,8 +778,15 @@ static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
/* Check status */
if (evt->status != 0) {
- error("Configuration failed with status 0x%02X",
- evt->status);
+ if (evt->action != 0x00) {
+ /* Create/update failed — try to remove the config */
+ error("Configuration failed with status 0x%02X",
+ evt->status);
+ rap_send_hci_cs_remove_config_command(sm, evt->handle);
+ } else {
+ error("CS Config Remove failed with status 0x%02X",
+ evt->status);
+ }
cs_set_state(sm, CS_STATE_STOPPED);
return;
}
@@ -428,12 +830,40 @@ static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
rap_ev.main_mode_type, rap_ev.sub_mode_type,
rap_ev.role, rap_ev.rtt_type);
+ if (rap_ev.action == 0x00) {
+ cs_set_state(sm, CS_STATE_UNSPECIFIED);
+ DBG("CS Config Removed !!!");
+ bt_rap_hci_cs_config_complete_callback(size, &rap_ev, sm->rap);
+ return;
+ }
/* Success - proceed to Security enable complete */
cs_set_state(sm, CS_STATE_WAIT_SEC_CMPLT);
- /* Reflector role */
- DBG("Waiting for security enable event...");
- /* TODO: Initiator role - Send CS Security enable cmd */
+ /* CS Security Enable may only be issued by the BLE Central */
+ if (rap_ev.role == 0x00) {
+ /* Initiator role */
+ struct rap_conn_mapping *mapping;
+
+ mapping = find_mapping_by_handle(sm, evt->handle);
+ if (!mapping || !mapping->is_central) {
+ error("CS Security Enable skipped: not BLE Central");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ if (bt_att_get_security(mapping->att, NULL) <
+ BT_ATT_SECURITY_MEDIUM) {
+ error("CS Security Enable skipped: not encrypted");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ DBG("Central,encrypted: Sending CS Security Enable command");
+ rap_send_hci_cs_security_enable_command(sm, evt->handle);
+ } else {
+ /* Reflector role */
+ DBG("Reflector role: Waiting for security enable event...");
+ }
/* Send callback to RAP Profile */
bt_rap_hci_cs_config_complete_callback(size, &rap_ev, sm->rap);
@@ -486,9 +916,27 @@ static void rap_cs_sec_enable_cmplt_evt(const void *data, uint8_t size,
/* Success - proceed to configuration */
cs_set_state(sm, CS_STATE_WAIT_PROC_CMPLT);
- /* Reflector role */
- DBG("Waiting for CS Proc complete event...");
- /* TODO: Initiator - Send CS Proc Set Parameter and enable */
+ /* Check if role is initiator */
+ if (sm->cs_opt.role == CS_INITIATOR) {
+ DBG("Initiator role: Sending CS Set Procedure Params");
+ if (!rap_send_hci_cs_set_procedure_parameters(
+ sm, handle)) {
+ error("Failed to send CS Set Procedure Params");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+
+ DBG("Initiator role: Sending CS Procedure Enable");
+ if (!rap_send_hci_cs_procedure_enable(sm, handle,
+ true)) {
+ error("Failed to send CS Procedure Enable");
+ cs_set_state(sm, CS_STATE_STOPPED);
+ return;
+ }
+ } else {
+ // Reflector role
+ DBG("Reflector role: Waiting for CS Proc compl event");
+ }
} else {
/* Error - transition to stopped */
error("Security enable failed with status 0x%02X",
@@ -565,8 +1013,13 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
rap_ev.proc_intrvl);
/* Success - procedure started */
- cs_set_state(sm, CS_STATE_STARTED);
- sm->procedure_active = true;
+ if (rap_ev.state == 0x01) {
+ cs_set_state(sm, CS_STATE_STARTED);
+ sm->procedure_active = true;
+ } else if (rap_ev.state == 0x00) {
+ cs_set_state(sm, CS_STATE_STOPPED);
+ sm->procedure_active = false;
+ }
/* Send callback to RAP Profile */
bt_rap_hci_cs_procedure_enable_complete_callback(size,
@@ -800,6 +1253,54 @@ static void parse_cs_step(struct iovec *iov, struct cs_step_data *step,
}
}
+/*
+ * Handle the common step-parsing tail shared by both subevent result variants.
+ * Fixes truncation (num_steps_reported > CS_MAX_STEPS) by zeroing the step
+ * count and trimming send_len to header_size, matching the abort-status path.
+ */
+static void cs_parse_steps(struct iovec *iov,
+ uint8_t num_steps_reported,
+ uint8_t proc_done_status,
+ uint8_t subevt_done_status,
+ uint8_t abort_reason,
+ uint8_t cs_role, uint8_t cs_rtt_type,
+ uint8_t max_paths,
+ struct cs_step_data *step_data,
+ uint8_t *num_steps_out,
+ size_t *send_len,
+ size_t header_size)
+{
+ uint8_t steps = MIN(num_steps_reported, CS_MAX_STEPS);
+ uint8_t i;
+
+ if (num_steps_reported > CS_MAX_STEPS) {
+ DBG("Too many steps reported: %u (max %u)",
+ num_steps_reported, CS_MAX_STEPS);
+ *num_steps_out = 0;
+ *send_len = header_size;
+ return;
+ }
+
+ if (subevt_done_status == 0xF || proc_done_status == 0xF) {
+ DBG("CS Procedure/Subevent aborted: ");
+ DBG("sub evt status = %d, proc status = %d, reason = %d",
+ subevt_done_status, proc_done_status, abort_reason);
+ /*
+ * Step bytes were never parsed; zero-initialised step_data[]
+ * entries would appear as spurious mode-0 quality=0 steps to
+ * the BCS algorithm. Clear the count so an aborted subevent
+ * carries no fake measurements.
+ */
+ *num_steps_out = 0;
+ *send_len = header_size;
+ return;
+ }
+
+ for (i = 0; i < steps; i++)
+ parse_cs_step(iov, &step_data[i], cs_role, cs_rtt_type,
+ max_paths);
+}
+
static void rap_cs_subevt_result_evt(const void *data, uint8_t size,
void *user_data)
{
@@ -822,7 +1323,6 @@ static void rap_cs_subevt_result_evt(const void *data, uint8_t size,
uint8_t abort_reason;
uint8_t num_ant_paths;
uint8_t num_steps_reported;
- uint8_t i;
if (!sm || !data ||
size < sizeof(struct bt_hci_evt_le_cs_subevent_result))
@@ -883,28 +1383,13 @@ static void rap_cs_subevt_result_evt(const void *data, uint8_t size,
rap_ev->num_ant_paths = num_ant_paths;
rap_ev->num_steps_reported = steps;
- if (num_steps_reported > CS_MAX_STEPS) {
- DBG("Too many steps reported: %u (max %u)",
- num_steps_reported, CS_MAX_STEPS);
- goto send_event;
- }
-
- /* Early exit for error conditions */
- if (rap_ev->subevt_done_status == 0xF ||
- rap_ev->proc_done_status == 0xF) {
- DBG("CS Procedure/Subevent aborted: ");
- DBG("sub evt status = %d, proc status = %d, reason = %d",
- rap_ev->subevt_done_status, rap_ev->proc_done_status,
- rap_ev->abort_reason);
- goto send_event;
- }
+ cs_parse_steps(&iov, num_steps_reported,
+ proc_done_status, subevt_done_status, abort_reason,
+ cs_role, cs_rtt_type, max_paths,
+ rap_ev->step_data, &rap_ev->num_steps_reported,
+ &send_len,
+ offsetof(struct rap_ev_cs_subevent_result, step_data));
- /* Parse interleaved step data from remaining iovec data */
- for (i = 0; i < steps; i++)
- parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
- max_paths);
-
-send_event:
DBG("CS subevent result processed: %zu bytes, ", send_len);
bt_rap_hci_cs_subevent_result_callback(send_len, rap_ev, sm->rap);
free(rap_ev);
@@ -920,7 +1405,7 @@ static void rap_cs_subevt_result_cont_evt(const void *data, uint8_t size,
uint8_t cs_rtt_type;
uint8_t max_paths;
uint8_t steps;
- size_t send_len = 0;
+ size_t send_len;
uint16_t handle;
uint8_t config_id;
uint8_t proc_done_status;
@@ -928,7 +1413,6 @@ static void rap_cs_subevt_result_cont_evt(const void *data, uint8_t size,
uint8_t abort_reason;
uint8_t num_ant_paths;
uint8_t num_steps_reported;
- uint8_t i;
if (!sm || !data ||
size < sizeof(struct bt_hci_evt_le_cs_subevent_result_continue))
@@ -981,28 +1465,14 @@ static void rap_cs_subevt_result_cont_evt(const void *data, uint8_t size,
rap_ev->num_ant_paths = num_ant_paths;
rap_ev->num_steps_reported = steps;
- if (num_steps_reported > CS_MAX_STEPS) {
- DBG("Too many steps reported: %u (max %u)",
- num_steps_reported, CS_MAX_STEPS);
- goto send_event;
- }
-
- /* Early exit for error conditions */
- if (rap_ev->subevt_done_status == 0xF ||
- rap_ev->proc_done_status == 0xF) {
- DBG("CS Procedure/Subevent aborted: ");
- DBG("sub evt status = %d, proc status = %d, reason = %d",
- rap_ev->subevt_done_status, rap_ev->proc_done_status,
- rap_ev->abort_reason);
- goto send_event;
- }
-
- /* Parse interleaved step data from remaining iovec data */
- for (i = 0; i < steps; i++)
- parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
- max_paths);
+ cs_parse_steps(&iov, num_steps_reported,
+ proc_done_status, subevt_done_status, abort_reason,
+ cs_role, cs_rtt_type, max_paths,
+ rap_ev->step_data, &rap_ev->num_steps_reported,
+ &send_len,
+ offsetof(struct rap_ev_cs_subevent_result_cont,
+ step_data));
-send_event:
DBG("CS subevent result cont processed: %zu bytes, ", send_len);
bt_rap_hci_cs_subevent_result_cont_callback(send_len, rap_ev, sm->rap);
free(rap_ev);
@@ -1010,6 +1480,208 @@ send_event:
/* Subevent handler function type */
+/* This cmd is used by host to update channel classification
+ * function will be used when user sets channel classification
+ * keeping it unused till DBUS API is added */
+bool __maybe_unused bt_rap_set_channel_classification(void *hci_sm,
+ const uint8_t *channel_map)
+{
+ struct cs_state_machine *sm = hci_sm;
+ struct bt_hci_cmd_le_cs_set_chan_class cmd;
+ struct timespec now;
+ unsigned int status;
+ uint8_t default_map[10];
+ int i, enabled_count = 0;
+ long diff_ms;
+
+ if (!sm || !sm->hci) {
+ error("Invalid state machine or HCI");
+ return false;
+ }
+
+ /* If no channel map provided, create default map */
+ if (!channel_map) {
+ memset(default_map, 0, sizeof(default_map));
+
+ /* Enable channels 2-22 and 26-76 (total 72 channels)
+ * Channels 0, 1, 23, 24, 25, 77, 78, 79 are reserved/disabled
+ */
+ for (i = 2; i <= 22; i++) {
+ default_map[i / 8] |= (1 << (i % 8));
+ }
+ for (i = 26; i <= 76; i++) {
+ default_map[i / 8] |= (1 << (i % 8));
+ }
+
+ channel_map = default_map;
+ } else {
+ /* Validate the provided channel map */
+ /* Check reserved channels are disabled */
+ if ((channel_map[0] & 0x03) != 0) { /* Channels 0, 1 */
+ error("Channels 0 and 1 must be disabled (reserved)");
+ return false;
+ }
+ if ((channel_map[2] & 0x80) != 0) { /* Channel 23 */
+ error("Channel 23 must be disabled (reserved)");
+ return false;
+ }
+ if ((channel_map[3] & 0x03) != 0) { /* Channels 24, 25 */
+ error("Channels 24 and 25 must be disabled (reserved)");
+ return false;
+ }
+ if ((channel_map[9] & 0xE0) != 0) { /* Ch 77, 78 and RFU bit */
+ error("Channels 77, 78, 79 must be disabled (res)");
+ return false;
+ }
+
+ /* Count enabled channels using popcount; mask reserved bits:
+ * ch 0-1 (byte 0 bits 0-1), ch 23 (byte 2 bit 7),
+ * ch 24-25 (byte 3 bits 0-1), ch 77-79 (byte 9 bits 5-7).
+ */
+ {
+ uint8_t masked[10];
+
+ memcpy(masked, channel_map, 10);
+ masked[0] &= 0xFC;
+ masked[2] &= 0x7F;
+ masked[3] &= 0xFC;
+ masked[9] &= 0x1F;
+ for (i = 0; i < 10; i++)
+ enabled_count += __builtin_popcount(masked[i]);
+ }
+
+ if (enabled_count < 15) {
+ error("At least 15 channels must be enabled (found %d)",
+ enabled_count);
+ return false;
+ }
+ }
+
+ /* Controller rejects with Command Disallowed (0x0C)
+ * if less than 1 second has elapsed since the
+ * last invocation. Enforce the limit here to avoid silent failures.
+ */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (sm->last_chan_class_time.tv_sec != 0 ||
+ sm->last_chan_class_time.tv_nsec != 0) {
+ diff_ms = (now.tv_sec -
+ sm->last_chan_class_time.tv_sec) * 1000 +
+ (now.tv_nsec -
+ sm->last_chan_class_time.tv_nsec) / 1000000;
+
+ if (diff_ms < 1000) {
+ error("CS Set Channel Classification throttled: "
+ "only %ldms since last call (min 1000ms)",
+ diff_ms);
+ return false;
+ }
+ }
+ sm->last_chan_class_time = now;
+
+ DBG("Sending CS Set Channel Classification command");
+
+ memset(&cmd, 0, sizeof(cmd));
+ memcpy(cmd.channel_classification, channel_map, 10);
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SET_CHAN_CLASS,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send CS Set Channel Classification command");
+ return false;
+ }
+
+ DBG("CS Set Channel Classification command sent successfully");
+ return true;
+}
+
+static bool bt_rap_read_remote_fae_table(void *hci_sm, uint16_t handle)
+{
+ struct cs_state_machine *sm = hci_sm;
+ struct bt_hci_cmd_le_cs_rd_rem_fae cmd;
+ unsigned int status;
+
+ if (!sm || !sm->hci) {
+ error("Invalid state machine or HCI");
+ return false;
+ }
+
+ DBG("Sending Read Remote FAE Table for handle 0x%04X", handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_RD_REM_FAE,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send Read Remote FAE Table command");
+ return false;
+ }
+
+ DBG("Read Remote FAE Table command sent successfully");
+ return true;
+}
+
+/* This cmd is used by host to start cs distance measurement procedure
+ * function will be used when user start distance measurement
+ * keeping it unused till DBUS API is added */
+static bool __maybe_unused bt_rap_read_local_supported_capabilities(
+ void *hci_sm)
+{
+ struct cs_state_machine *sm = hci_sm;
+ unsigned int status;
+
+ if (!sm || !sm->hci) {
+ error("Invalid state machine or HCI");
+ return false;
+ }
+
+ DBG("Sending Read Local Supported Capabilities command");
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_RD_LOC_SUPP_CAP,
+ NULL, 0, rap_rd_loc_supp_cap_done_cb,
+ sm, NULL);
+
+ if (!status) {
+ error("Failed to send Read Local Supported Capabilities");
+ return false;
+ }
+
+ DBG("Read Local Supported Capabilities command sent successfully");
+ return true;
+}
+
+static bool bt_rap_read_remote_supported_capabilities(void *hci_sm,
+ uint16_t handle)
+{
+ struct cs_state_machine *sm = hci_sm;
+ struct bt_hci_cmd_le_cs_rd_rem_supp_cap cmd;
+ unsigned int status;
+
+ if (!sm || !sm->hci) {
+ error("Invalid state machine or HCI");
+ return false;
+ }
+
+ DBG("Sending Read Remote Supported Capabilities for handle 0x%04X",
+ handle);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.handle = cpu_to_le16(handle);
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_RD_REM_SUPP_CAP,
+ &cmd, sizeof(cmd), NULL, sm, NULL);
+
+ if (!status) {
+ error("Failed to send Read Remote Capabilities command");
+ return false;
+ }
+
+ DBG("Read Remote Capabilities command sent successfully");
+ return true;
+}
+
static void unregister_event_id(void *data, void *user_data)
{
struct bt_hci *hci = user_data;
@@ -1041,6 +1713,11 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
max_tx_power);
sm->event_ids = queue_new();
+ if (!sm->event_ids) {
+ error("Failed to allocate event_ids queue");
+ free(sm);
+ return NULL;
+ }
/* Register each LE Meta subevent individually */
id = bt_hci_register_subevent(hci,
@@ -1051,6 +1728,15 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+ id = bt_hci_register_subevent(hci,
+ BT_HCI_EVT_LE_CS_RD_REM_FAE_COMPLETE,
+ rap_rd_rem_fae_cmplt_evt, sm, NULL);
+
+ if (!id)
+ goto fail;
+
+ queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+
id = bt_hci_register_subevent(hci,
BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
rap_cs_config_cmplt_evt, sm, NULL);
@@ -1100,12 +1786,14 @@ fail:
error("Failed to register hci le meta subevents");
queue_foreach(sm->event_ids, unregister_event_id, hci);
queue_destroy(sm->event_ids, NULL);
+ queue_destroy(sm->conn_mappings, mapping_free);
free(sm);
return NULL;
}
-bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
- const uint8_t *bdaddr, uint8_t bdaddr_type)
+bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap,
+ uint16_t handle, const uint8_t *bdaddr, uint8_t bdaddr_type,
+ bool is_central)
{
struct cs_state_machine *sm = hci_sm;
struct bt_att *att;
@@ -1124,7 +1812,8 @@ bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
bdaddr[2], bdaddr[1], bdaddr[0], bdaddr_type);
}
- return add_conn_mapping(sm, handle, bdaddr, bdaddr_type, att, rap);
+ return add_conn_mapping(sm, handle, bdaddr, bdaddr_type, is_central,
+ att, rap);
}
void bt_rap_clear_conn_handle(void *hci_sm, uint16_t handle)
@@ -1157,9 +1846,6 @@ void bt_rap_detach_hci(struct bt_rap *rap, void *hci_sm)
queue_destroy(sm->event_ids, NULL);
/* Clean up per-instance connection mappings */
- remove_rap_mappings(sm);
-
- /* Destroy the connection mappings queue */
queue_destroy(sm->conn_mappings, mapping_free);
/* Free the state machine */
--
^ permalink raw reply related
* [PATCH BlueZ v1 1/2] shared: rap: Add the is_central parameter to verify whether the local role is central before sending the HCI CS Security Enable command.
From: Naga Bhavani Akella @ 2026-06-09 10:49 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
Naga Bhavani Akella
In-Reply-To: <20260609104953.3122718-1-naga.akella@oss.qualcomm.com>
---
src/shared/rap.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/shared/rap.h b/src/shared/rap.h
index d3ced61b1..4d6a3d1c8 100644
--- a/src/shared/rap.h
+++ b/src/shared/rap.h
@@ -213,5 +213,6 @@ void bt_rap_detach_hci(struct bt_rap *rap, void *hci_sm);
/* Connection handle mapping functions */
bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
- const uint8_t *bdaddr, uint8_t bdaddr_type);
+ const uint8_t *bdaddr, uint8_t bdaddr_type,
+ bool is_central);
void bt_rap_clear_conn_handle(void *hci_sm, uint16_t handle);
--
^ permalink raw reply related
* [PATCH BlueZ v1 0/2] Initial Channel Sounding Support for
From: Naga Bhavani Akella @ 2026-06-09 10:49 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
Naga Bhavani Akella
This series adds initial LE Channel Sounding (CS) Initiator support by
introducing the required HCI command flow and event handling for CS
procedures.
The changes include
1. Adding an is_central parameter to validate that
current local role is central before issuing
HCI_LE_CS_Security_Enable command.
2. Introduction of initial LE Channel Sounding (CS)
Initiator support by adding required HCI command flow
and event handling for CS capability discovery,
configuration management, and ranging procedures.
The CS init pipeline is not yet wired to D-Bus APIs,
so bt_rap_read_local_supported_capabilities()
is currently marked __maybe_unused.
Naga Bhavani Akella (2):
shared: rap: Add the is_central parameter to verify whether the local
role is central before sending the HCI CS Security Enable command.
profiles: ranging: Add command flow and event support for CS
Initiator
profiles/ranging/rap.c | 3 +-
profiles/ranging/rap_hci.c | 876 +++++++++++++++++++++++++++++++++----
src/shared/rap.h | 3 +-
3 files changed, 785 insertions(+), 97 deletions(-)
--
^ permalink raw reply
* Re: [PATCH v1] Bluetooth: qca: Add BT FW build version log
From: Bartosz Golaszewski @ 2026-06-09 10:49 UTC (permalink / raw)
To: Paul Menzel
Cc: Xiuzhuo Shang, Marcel Holtmann, Luiz Augusto von Dentz,
linux-arm-msm, linux-bluetooth, linux-kernel, cheng.jiang,
quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li,
Bartosz Golaszewski
In-Reply-To: <8697f148-5e21-44b4-a949-9d348e39c2ea@molgen.mpg.de>
On Tue, 9 Jun 2026 12:29:41 +0200, Paul Menzel <pmenzel@molgen.mpg.de> said:
> Dear Xiuzhuo, dear Bartosz
>
>
> Am 09.06.26 um 11:39 schrieb Bartosz Golaszewski:
>> On Tue, 9 Jun 2026 09:54:17 +0200, Xiuzhuo Shang said:
>>> Printf BT FW build version log after BT FW downloaded.
>
> Please paste the new lines, so reviewers see how it is going to look
> like. Please also document a motivation (answering Why?).
>
>>> Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com>
>>> ---
>>> drivers/bluetooth/btqca.c | 2 ++
>>> 1 file changed, 2 insertions(+)
>>>
>>> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
>>> index dda76365726f..04ebe290bc78 100644
>>> --- a/drivers/bluetooth/btqca.c
>>> +++ b/drivers/bluetooth/btqca.c
>>> @@ -143,6 +143,8 @@ static int qca_read_fw_build_info(struct hci_dev *hdev)
>>>
>>> hci_set_fw_info(hdev, "%s", build_label);
>>>
>>> + bt_dev_info(hdev, "QCA FW build version: %s", build_label);
>>> +
>>> kfree(build_label);
>>> out:
>>> kfree_skb(skb);
>>
>> This string can be read from debugfs, do we need an additional message in the
>> kernel log?
>
> In my opinion the firmware version should be part of the Linux logs, as
> that is what users share with bug reports, and you do not want to have
> several cycles collecting information. For example, currently for
> QCA6174 it’s currently:
>
> Bluetooth: hci0: QCA: patch rome 0x302 build 0x3e8, firmware rome
> 0x302 build 0x111
>
>
> Kind regards,
>
> Paul
>
>
> PS:
>
> ```
> $ sudo dmesg | grep -e ath10k -e Bluetooth
> [ 17.880668] ath10k_pci 0000:3a:00.0: enabling device (0000 -> 0002)
> [ 17.883428] ath10k_pci 0000:3a:00.0: pci irq msi oper_irq_mode 2
> irq_mode 0 reset_mode 0
> [ 18.138972] ath10k_pci 0000:3a:00.0: qca6174 hw3.2 target 0x05030000
> chip_id 0x00340aff sub 1a56:1535
> [ 18.138977] ath10k_pci 0000:3a:00.0: kconfig debug 1 debugfs 1
> tracing 1 dfs 0 testmode 0
> [ 18.139068] ath10k_pci 0000:3a:00.0: firmware ver
> WLAN.RM.4.4.1-00309- api 6 features wowlan,ignore-otp,mfp crc32 0793bcf2
> [ 18.206593] ath10k_pci 0000:3a:00.0: board_file api 2 bmi_id N/A
> crc32 d2863f91
> [ 18.221145] Bluetooth: Core ver 2.22
> [ 18.221802] Bluetooth: HCI device and connection manager initialized
> [ 18.221807] Bluetooth: HCI socket layer initialized
> [ 18.221808] Bluetooth: L2CAP socket layer initialized
> [ 18.221813] Bluetooth: SCO socket layer initialized
> [ 18.258187] Bluetooth: hci0: using rampatch file:
> qca/rampatch_usb_00000302.bin
> [ 18.258192] Bluetooth: hci0: QCA: patch rome 0x302 build 0x3e8,
> firmware rome 0x302 build 0x111
> [ 18.301557] ath10k_pci 0000:3a:00.0: htt-ver 3.87 wmi-op 4 htt-op 3
> cal otp max-sta 32 raw 0 hwcrypto 1
> [ 18.381567] ath10k_pci 0000:3a:00.0 wlp58s0: renamed from wlan0
> [ 18.619003] Bluetooth: hci0: using NVM file: qca/nvm_usb_00000302.bin
> [ 18.643646] Bluetooth: hci0: HCI Enhanced Setup Synchronous
> Connection command is advertised, but not supported.
> ```
>
Fair enough.
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v1] Bluetooth: qca: Add BT FW build version log
From: Paul Menzel @ 2026-06-09 10:29 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Xiuzhuo Shang, Marcel Holtmann, Luiz Augusto von Dentz,
linux-arm-msm, linux-bluetooth, linux-kernel, cheng.jiang,
quic_chezhou, wei.deng, shuai.zhang, mengshi.wu, jinwang.li
In-Reply-To: <CAMRc=Met_U-1gDmGFM9hSWFc5vvs4SuRQOa3hZcfUo190rh59w@mail.gmail.com>
Dear Xiuzhuo, dear Bartosz
Am 09.06.26 um 11:39 schrieb Bartosz Golaszewski:
> On Tue, 9 Jun 2026 09:54:17 +0200, Xiuzhuo Shang said:
>> Printf BT FW build version log after BT FW downloaded.
Please paste the new lines, so reviewers see how it is going to look
like. Please also document a motivation (answering Why?).
>> Signed-off-by: Xiuzhuo Shang <xiuzhuo.shang@oss.qualcomm.com>
>> ---
>> drivers/bluetooth/btqca.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
>> index dda76365726f..04ebe290bc78 100644
>> --- a/drivers/bluetooth/btqca.c
>> +++ b/drivers/bluetooth/btqca.c
>> @@ -143,6 +143,8 @@ static int qca_read_fw_build_info(struct hci_dev *hdev)
>>
>> hci_set_fw_info(hdev, "%s", build_label);
>>
>> + bt_dev_info(hdev, "QCA FW build version: %s", build_label);
>> +
>> kfree(build_label);
>> out:
>> kfree_skb(skb);
>
> This string can be read from debugfs, do we need an additional message in the
> kernel log?
In my opinion the firmware version should be part of the Linux logs, as
that is what users share with bug reports, and you do not want to have
several cycles collecting information. For example, currently for
QCA6174 it’s currently:
Bluetooth: hci0: QCA: patch rome 0x302 build 0x3e8, firmware rome
0x302 build 0x111
Kind regards,
Paul
PS:
```
$ sudo dmesg | grep -e ath10k -e Bluetooth
[ 17.880668] ath10k_pci 0000:3a:00.0: enabling device (0000 -> 0002)
[ 17.883428] ath10k_pci 0000:3a:00.0: pci irq msi oper_irq_mode 2
irq_mode 0 reset_mode 0
[ 18.138972] ath10k_pci 0000:3a:00.0: qca6174 hw3.2 target 0x05030000
chip_id 0x00340aff sub 1a56:1535
[ 18.138977] ath10k_pci 0000:3a:00.0: kconfig debug 1 debugfs 1
tracing 1 dfs 0 testmode 0
[ 18.139068] ath10k_pci 0000:3a:00.0: firmware ver
WLAN.RM.4.4.1-00309- api 6 features wowlan,ignore-otp,mfp crc32 0793bcf2
[ 18.206593] ath10k_pci 0000:3a:00.0: board_file api 2 bmi_id N/A
crc32 d2863f91
[ 18.221145] Bluetooth: Core ver 2.22
[ 18.221802] Bluetooth: HCI device and connection manager initialized
[ 18.221807] Bluetooth: HCI socket layer initialized
[ 18.221808] Bluetooth: L2CAP socket layer initialized
[ 18.221813] Bluetooth: SCO socket layer initialized
[ 18.258187] Bluetooth: hci0: using rampatch file:
qca/rampatch_usb_00000302.bin
[ 18.258192] Bluetooth: hci0: QCA: patch rome 0x302 build 0x3e8,
firmware rome 0x302 build 0x111
[ 18.301557] ath10k_pci 0000:3a:00.0: htt-ver 3.87 wmi-op 4 htt-op 3
cal otp max-sta 32 raw 0 hwcrypto 1
[ 18.381567] ath10k_pci 0000:3a:00.0 wlp58s0: renamed from wlan0
[ 18.619003] Bluetooth: hci0: using NVM file: qca/nvm_usb_00000302.bin
[ 18.643646] Bluetooth: hci0: HCI Enhanced Setup Synchronous
Connection command is advertised, but not supported.
```
^ permalink raw reply
* [BlueZ PATCH v3 1/2] shared/bap: add ASE Control Point error responses
From: raghu447 @ 2026-06-09 10:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: raghu447
In-Reply-To: <20260609102548.6887-1-raghavendra.rao@collabora.com>
These changes are required to Pass BAP/USR/SPE/BI-01[5]-C tests.
---
src/shared/bap.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 88 insertions(+), 2 deletions(-)
diff --git a/src/shared/bap.c b/src/shared/bap.c
index 8fc2fb14d..edb84efca 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -57,6 +57,11 @@
(1<<BAP_DURATION_LTV_TYPE)|\
(1<<BAP_FRAME_LEN_LTV_TYPE))
+#define BAP_METADATA_PREF_CONTEXT_LTV_TYPE 0x01
+#define BAP_METADATA_CONTEXT_LTV_TYPE 0x02
+#define BAP_METADATA_PROGRAM_INFO_LTV_TYPE 0x03
+#define BAP_METADATA_LANGUAGE_LTV_TYPE 0x04
+
struct bt_bap_pac_changed {
unsigned int id;
bt_bap_pac_func_t added;
@@ -3304,6 +3309,40 @@ static uint8_t stream_enable(struct bt_bap_stream *stream, struct iovec *meta,
return 0;
}
+static bool ascs_metadata_rsp(struct bt_bap_endpoint *ep, struct iovec *meta,
+ struct iovec *rsp)
+{
+ struct bt_ltv *ltv;
+ uint16_t supported_context = 0;
+ uint16_t context;
+
+ if (ep->stream && ep->stream->lpac)
+ supported_context = ep->stream->lpac->qos.supported_context;
+
+ ltv = meta->iov_base;
+ if (meta->iov_len >= sizeof(*ltv) &&
+ (ltv->type < BAP_METADATA_PREF_CONTEXT_LTV_TYPE ||
+ ltv->type > BAP_METADATA_LANGUAGE_LTV_TYPE)) {
+ ascs_ase_rsp_add(rsp, ep->id,
+ BT_ASCS_RSP_METADATA_UNSUPPORTED, ltv->type);
+ return true;
+ }
+
+ if (meta->iov_len >= sizeof(*ltv) + sizeof(context) &&
+ ltv->type == BAP_METADATA_CONTEXT_LTV_TYPE &&
+ ltv->len == sizeof(context) + 1) {
+ context = get_le16(ltv->value);
+ if (!context || (context & ~supported_context)) {
+ ascs_ase_rsp_add(rsp, ep->id,
+ BT_ASCS_RSP_METADATA_INVALID,
+ ltv->type);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap,
struct bt_ascs_enable *req, struct iovec *iov,
struct iovec *rsp)
@@ -3335,6 +3374,9 @@ static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap,
return 0;
}
+ if (ascs_metadata_rsp(ep, &meta, rsp))
+ return 0;
+
if (!ep->stream) {
DBG(bap, "No stream found");
ascs_ase_rsp_add(rsp, ep->id,
@@ -3568,6 +3610,9 @@ static uint8_t ep_metadata(struct bt_bap_endpoint *ep,
meta.iov_base = util_iov_pull_mem(iov, req->len);
meta.iov_len = req->len;
+ if (ascs_metadata_rsp(ep, &meta, rsp))
+ return 0;
+
return stream_metadata(ep->stream, &meta, rsp);
}
@@ -3673,6 +3718,23 @@ static struct iovec *ascs_ase_cp_rsp_new(uint8_t op)
return iov;
}
+static void ascs_ase_cp_rsp_add_truncated(struct iovec *rsp)
+{
+ ascs_ase_rsp_add_errno(rsp, 0x00, -ENOMSG);
+}
+
+static bool ascs_ase_cp_rsp_invalid_len(uint8_t op, size_t len, uint8_t num)
+{
+ switch (op) {
+ case BT_ASCS_METADATA:
+ return len == num;
+ case BT_ASCS_RELEASE:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
@@ -3697,7 +3759,7 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
return;
}
- if (len < sizeof(*hdr)) {
+ if (!len) {
DBG(bap, "invalid len %u < %u sizeof(*hdr)", len,
sizeof(*hdr));
gatt_db_attribute_write_result(attrib, id,
@@ -3705,9 +3767,26 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
return;
}
+ if (len < sizeof(*hdr)) {
+ DBG(bap, "invalid len %u < %u sizeof(*hdr)", len,
+ sizeof(*hdr));
+
+ rsp = ascs_ase_cp_rsp_new(value[0]);
+ ascs_ase_cp_rsp_add_truncated(rsp);
+ ret = 0;
+ goto respond;
+ }
+
hdr = util_iov_pull_mem(&iov, sizeof(*hdr));
rsp = ascs_ase_cp_rsp_new(hdr->op);
+ if (!hdr->num) {
+ DBG(bap, "invalid Number_of_ASEs 0");
+ ascs_ase_cp_rsp_add_truncated(rsp);
+ ret = 0;
+ goto respond;
+ }
+
for (handler = handlers; handler && handler->str; handler++) {
if (handler->op != hdr->op)
continue;
@@ -3716,7 +3795,14 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
DBG(bap, "invalid len %u < %u "
"hdr->num * handler->size", len,
hdr->num * handler->size);
- ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+
+ if (ascs_ase_cp_rsp_invalid_len(hdr->op, iov.iov_len,
+ hdr->num)) {
+ ascs_ase_cp_rsp_add_truncated(rsp);
+ ret = 0;
+ } else
+ ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+
goto respond;
}
^ permalink raw reply related
* [BlueZ PATCH v3 2/2] unit/bap: add SPE tests
From: raghu447 @ 2026-06-09 10:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: raghu447
In-Reply-To: <20260609102548.6887-1-raghavendra.rao@collabora.com>
Add unit tests for the PTS BAP/USR/SPE/BI-01[5]-C tests.
---
unit/test-bap.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/unit/test-bap.c b/unit/test-bap.c
index 3a67e7016..e43d1d2ef 100644
--- a/unit/test-bap.c
+++ b/unit/test-bap.c
@@ -4349,6 +4349,69 @@ static void test_scc_metadata(void)
test_usr_scc_metadata();
}
+#define ASE_CP_RSP(_op, _ase, _code, _reason) \
+ IOV_DATA(0x1b, CP_HND, _op, 0x01, _ase, _code, _reason)
+
+#define ASE_CP_RSP_TRUNCATED(_op) \
+ IOV_DATA(0x1b, CP_HND, _op, 0xff, 0x00, 0x02, 0x00)
+
+#define SPE_CP_TRUNCATED(_op) \
+ IOV_DATA(0x52, CP_HND, _op), \
+ ASE_CP_RSP_TRUNCATED(_op)
+
+#define SPE_CP_ZERO_ASES(_op) \
+ IOV_DATA(0x52, CP_HND, _op, 0x00), \
+ ASE_CP_RSP_TRUNCATED(_op)
+
+#define SPE_METADATA_TRUNCATED(_ase) \
+ IOV_DATA(0x52, CP_HND, 0x07, 0x01, _ase), \
+ ASE_CP_RSP_TRUNCATED(0x07)
+
+#define SPE_METADATA_UNSUPPORTED(_ase) \
+ SCC_SRC_ENABLE, \
+ IOV_DATA(0x52, CP_HND, 0x07, 0x01, _ase, 0x02, 0x01, 0xfc), \
+ ASE_CP_RSP(0x07, _ase, 0x0a, 0xfc)
+
+#define SPE_METADATA_INVALID_CONTEXT(_ase) \
+ SCC_SRC_ENABLE, \
+ IOV_DATA(0x52, CP_HND, 0x07, 0x01, _ase, 0x04, 0x03, 0x02, \
+ 0x00, 0x10), \
+ ASE_CP_RSP(0x07, _ase, 0x0c, 0x02)
+
+/* Unicast Server Rejects Invalid ASE Control Point Procedures
+ *
+ * Test Purpose:
+ * Verify the behavior of a Unicast Server IUT when a Unicast Client writes
+ * invalid ASE Control Point parameters.
+ *
+ * Pass verdict:
+ * The IUT sends a notification of the ASE Control Point characteristic with
+ * the expected Response_Code and Reason values.
+ */
+static void test_usr_spe(void)
+{
+ define_test("BAP/USR/SPE/BI-01-C [USR ASE Control Point truncated]",
+ test_setup_server, test_server, NULL,
+ SPE_CP_TRUNCATED(0x03));
+ define_test("BAP/USR/SPE/BI-02-C [USR ASE Control Point zero ASEs]",
+ test_setup_server, test_server, NULL,
+ SPE_CP_ZERO_ASES(0x03));
+ define_test("BAP/USR/SPE/BI-03-C [USR Update Metadata truncated]",
+ test_setup_server, test_server, NULL,
+ SPE_METADATA_TRUNCATED(SRC_ID(0)));
+ define_test("BAP/USR/SPE/BI-04-C [USR Update Metadata unsupported]",
+ test_setup_server, test_server, &cfg_src_enable,
+ SPE_METADATA_UNSUPPORTED(SRC_ID(0)));
+ define_test("BAP/USR/SPE/BI-05-C [USR Update Metadata invalid context]",
+ test_setup_server, test_server, &cfg_src_enable,
+ SPE_METADATA_INVALID_CONTEXT(SRC_ID(0)));
+}
+
+static void test_spe(void)
+{
+ test_usr_spe();
+}
+
#define SNK_ENABLE \
IOV_DATA(0x52, 0x22, 0x00, 0x03, 0x01, 0x01, 0x04, 0x03, 0x02, 0x01, \
00), \
@@ -10259,6 +10322,7 @@ int main(int argc, char *argv[])
tester_init(&argc, &argv);
test_disc();
+ test_spe();
test_scc();
test_bsrc_scc();
test_bsnk_scc();
^ permalink raw reply related
* [BlueZ PATCH v3 0/2] shared/bap: add ASE Control Point error responses
From: raghu447 @ 2026-06-09 10:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: raghu447
In-Reply-To: <CABBYNZKQuFeXvtEE3d3nOUbkKZTAFsfB=1=NDFp48CFEg2e-=Q@mail.gmail.com>
Added bap unit tests in a seperate patch.
These changes are required to Pass BAP/USR/SPE/BI-01[5]-C tests.
raghu447 (2):
shared/bap: add ASE Control Point error responses
unit/bap: add SPE tests
src/shared/bap.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++--
unit/test-bap.c | 64 ++++++++++++++++++++++++++++++++++
2 files changed, 152 insertions(+), 2 deletions(-)
^ permalink raw reply
* Re: [PATCH v4 4/8] block: implement NVMEM provider
From: Loic Poulain @ 2026-06-09 10:13 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Srinivas Kandagatla,
Andrew Lunn, Heiner Kallweit, Russell King, Saravana Kannan
In-Reply-To: <CAMRc=MfuiPMkSm=-G6VEJpqKhos0TD_pf0ScBGqfwLHT0uk8yQ@mail.gmail.com>
Hi bartosz,
On Tue, Jun 9, 2026 at 10:52 AM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Tue, 9 Jun 2026 09:52:29 +0200, Loic Poulain
> <loic.poulain@oss.qualcomm.com> said:
> > From: Daniel Golle <daniel@makrotopia.org>
> >
> > On embedded devices using an eMMC it is common that one or more partitions
> > on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
> > data. Allow referencing the partition in device tree for the kernel and
> > Wi-Fi drivers accessing it via the NVMEM layer.
> >
> > Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> > Co-developed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > ---
> > block/Kconfig | 9 +++++
> > block/Makefile | 1 +
> > block/blk-nvmem.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 124 insertions(+)
> >
> > diff --git a/block/Kconfig b/block/Kconfig
> > index 15027963472d7b40e27b9097a5993c457b5b3054..0b33747e16dc33473683706f75c92bdf8b648f7c 100644
> > --- a/block/Kconfig
> > +++ b/block/Kconfig
> > @@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
> > by falling back to the kernel crypto API when inline
> > encryption hardware is not present.
> >
> > +config BLK_NVMEM
> > + bool "Block device NVMEM provider"
> > + depends on OF
> > + depends on NVMEM
> > + help
> > + Allow block devices (or partitions) to act as NVMEM providers,
> > + typically used with eMMC to store MAC addresses or Wi-Fi
> > + calibration data on embedded devices.
> > +
> > source "block/partitions/Kconfig"
> >
> > config BLK_PM
> > diff --git a/block/Makefile b/block/Makefile
> > index 7dce2e44276c4274c11a0a61121c83d9c43d6e0c..d7ac389e71902bc091a8800ea266190a43b3e63d 100644
> > --- a/block/Makefile
> > +++ b/block/Makefile
> > @@ -36,3 +36,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
> > blk-crypto-sysfs.o
> > obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
> > obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
> > +obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
> > diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..a6e62fa98675ee9bcb9c7035a611b5a573ab9091
> > --- /dev/null
> > +++ b/block/blk-nvmem.c
> > @@ -0,0 +1,114 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * block device NVMEM provider
> > + *
> > + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + *
> > + * Useful on devices using a partition on an eMMC for MAC addresses or
> > + * Wi-Fi calibration EEPROM data.
> > + */
> > +
> > +#include <linux/file.h>
> > +#include <linux/nvmem-provider.h>
> > +#include <linux/nvmem-consumer.h>
> > +#include <linux/of.h>
> > +#include <linux/pagemap.h>
> > +#include <linux/property.h>
> > +
> > +#include "blk.h"
> > +
> > +static int blk_nvmem_reg_read(void *priv, unsigned int from,
> > + void *val, size_t bytes)
> > +{
> > + blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES;
> > + dev_t devt = (dev_t)(uintptr_t)priv;
> > + size_t bytes_left = bytes;
> > + loff_t pos = from;
> > + int ret = 0;
> > +
> > + struct file *bdev_file __free(fput) = bdev_file_open_by_dev(devt, mode, priv, NULL);
> > + if (IS_ERR(bdev_file))
> > + return PTR_ERR(bdev_file);
> > +
> > + while (bytes_left) {
> > + pgoff_t f_index = pos >> PAGE_SHIFT;
> > + struct folio *folio;
> > + size_t folio_off;
> > + size_t to_read;
> > +
> > + folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
> > + if (IS_ERR(folio)) {
> > + ret = PTR_ERR(folio);
> > + break;
> > + }
> > +
> > + folio_off = offset_in_folio(folio, pos);
> > + to_read = min(bytes_left, folio_size(folio) - folio_off);
> > + memcpy_from_folio(val, folio, folio_off, to_read);
> > + pos += to_read;
> > + bytes_left -= to_read;
> > + val += to_read;
> > + folio_put(folio);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int blk_nvmem_register(struct device *dev)
> > +{
> > + struct block_device *bdev = dev_to_bdev(dev);
> > + struct nvmem_config config = {};
> > +
> > + /* skip devices which do not have a device tree node */
> > + if (!dev_of_node(dev))
> > + return 0;
> > +
> > + /* skip devices without an nvmem layout defined */
> > + struct device_node *child __free(device_node) =
> > + of_get_child_by_name(dev_of_node(dev), "nvmem-layout");
> > + if (!child)
> > + return 0;
> > +
> > + /*
> > + * skip block device too large to be represented as NVMEM devices,
> > + * the NVMEM reg_read callback uses an unsigned int offset
> > + */
> > + if (bdev_nr_bytes(bdev) > UINT_MAX) {
> > + dev_warn(dev, "block device too large to be an NVMEM provider\n");
> > + return -ENODEV;
>
> Wait, I must have suggested -ENODEV here on too little coffee. This callback
> is called from device_add(), not when the device is bound so it's not the same
> thing as returning -ENODEV from probe().
>
> On the other hand, we don't want to not provide the block device just because
> someone added a DT property on one that's too big. I'd say: warn, but return 0.
> Does it make sense?
It’s still technically an error in the sense that we cannot provide
the required nvmem feature. However, it only becomes a real issue if a
consumer actually attempts to use it.
Also, the block device should still be added, since the return code
from add_dev is not checked. In any case, I’m fine with either
approach, as long as we emit a warning message.
>
> > + }
> > +
> > + config.id = NVMEM_DEVID_NONE;
> > + config.dev = dev;
> > + config.name = dev_name(dev);
> > + config.owner = THIS_MODULE;
> > + config.priv = (void *)(uintptr_t)dev->devt;
> > + config.reg_read = blk_nvmem_reg_read;
> > + config.size = bdev_nr_bytes(bdev);
> > + config.word_size = 1;
> > + config.stride = 1;
> > + config.read_only = true;
> > + config.root_only = true;
> > + config.ignore_wp = true;
> > + config.of_node = to_of_node(dev->fwnode);
> > +
> > + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
>
> And that was a wrong suggestion on my part too because I was under the
> impression that we're in the probe() path, not device_add(). You can't use
> devres here as the device at this point is not yet bound and may never be.
So I understand The bd_device is purely a class device with no bus, no driver.
For driverless devices, devres_release_all() is called explicitly
within device_del() .
>
> Which leads me to the second point: this is not the moment to add the nvmem
> provider. This should happen at or after probe(). Once nvmem_register()
> returns, you have a visible nvmem resource but nothing backing it in the block
> layer.
There is a short window during which a read attempt will 'properly'
fail, but this does seem somewhat fragile indeed.
> Either do this in block core when registering a new device or schedule
> a notifier here for the BUS_NOTIFY_BOUND_DRIVER event and do it in the notifier
> callback.
So in the end, it seems that the simpler and more robust approach is
probably to move away from the class_interface driver and instead
register/unregister the nvmem directly in add_disk/del_gendisk.
If that's ok I will move to this approach in the next version.
Regards,
Loic
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox