linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/5] Add initial code for handling BASS
@ 2023-05-05  8:29 Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 1/5] lib/uuid: Add BASS UUIDs Iulia Tanasescu
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Iulia Tanasescu @ 2023-05-05  8:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Iulia Tanasescu

This patch series adds initial code for handling Broadcast Audio Scan Service.

Iulia Tanasescu (5):
  lib/uuid: Add BASS UUIDs
  shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code
  shared/util: Add iovec helpers for pulling/pushing le32 and le24
    values
  shared/bass: Add initial code for handling BASS
  profiles: Add initial code for BASS plugin

 Makefile.am            |    1 +
 Makefile.plugins       |    5 +
 configure.ac           |    4 +
 lib/uuid.h             |    5 +
 profiles/audio/bass.c  |  305 ++++++++++++
 src/shared/att-types.h |    4 +-
 src/shared/bass.c      | 1012 ++++++++++++++++++++++++++++++++++++++++
 src/shared/bass.h      |  122 +++++
 src/shared/util.c      |   53 +++
 src/shared/util.h      |    5 +
 10 files changed, 1515 insertions(+), 1 deletion(-)
 create mode 100644 profiles/audio/bass.c
 create mode 100644 src/shared/bass.c
 create mode 100644 src/shared/bass.h


base-commit: 3818b99c764efe84cd3455081f6392c256564085
-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 1/5] lib/uuid: Add BASS UUIDs
  2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
@ 2023-05-05  8:29 ` Iulia Tanasescu
  2023-05-05 10:24   ` [BlueZ,1/5] " bluez.test.bot
  2023-05-05  8:29 ` [PATCH BlueZ 2/5] shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code Iulia Tanasescu
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 8+ messages in thread
From: Iulia Tanasescu @ 2023-05-05  8:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Iulia Tanasescu

This adds BASS UUIDs which will be used by Basic Audio Profile.

---
 lib/uuid.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 84ff46cd8..ddde4bfa3 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -5,6 +5,7 @@
  *
  *  Copyright (C) 2011  Nokia Corporation
  *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -164,6 +165,10 @@ extern "C" {
 #define ASE_SOURCE_UUID					0x2bc5
 #define ASE_CP_UUID					0x2bc6
 
+#define BASS_UUID					0x184f
+#define BCAST_AUDIO_SCAN_CP_UUID			0x2bc7
+#define BCAST_RECV_STATE_UUID				0x2bc8
+
 #define VCS_UUID					0x1844
 #define VOL_OFFSET_CS_UUID				0x1845
 #define AUDIO_INPUT_CS_UUID				0x1843
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 2/5] shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code
  2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 1/5] lib/uuid: Add BASS UUIDs Iulia Tanasescu
@ 2023-05-05  8:29 ` Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values Iulia Tanasescu
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Iulia Tanasescu @ 2023-05-05  8:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Iulia Tanasescu

This adds Write Request Rejected Common Profile and Service
Error Code.

---
 src/shared/att-types.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index a08b24155..69f45b6aa 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2014  Google Inc.
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -101,9 +102,10 @@ struct bt_att_pdu_error_rsp {
 /*
  * Common Profile and Service Error Code descriptions (see Supplement to the
  * Bluetooth Core Specification, sections 1.2 and 2). The error codes within
- * 0xE0-0xFC are reserved for future use. The remaining 3 are defined as the
+ * 0xE0-0xFB are reserved for future use. The remaining 4 are defined as the
  * following:
  */
+#define BT_ERROR_WRITE_REQUEST_REJECTED         0xfc
 #define BT_ERROR_CCC_IMPROPERLY_CONFIGURED      0xfd
 #define BT_ERROR_ALREADY_IN_PROGRESS            0xfe
 #define BT_ERROR_OUT_OF_RANGE                   0xff
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values
  2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 1/5] lib/uuid: Add BASS UUIDs Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 2/5] shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code Iulia Tanasescu
@ 2023-05-05  8:29 ` Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 4/5] shared/bass: Add initial code for handling BASS Iulia Tanasescu
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Iulia Tanasescu @ 2023-05-05  8:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Iulia Tanasescu

This adds iovec helper functions for handling le32 and le24 values.

---
 src/shared/util.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/util.h |  5 +++++
 2 files changed, 58 insertions(+)

diff --git a/src/shared/util.c b/src/shared/util.c
index 9a4a8d77a..f9d8ecbaa 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2012-2014  Intel Corporation. All rights reserved.
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -28,6 +29,8 @@
 #include <sys/random.h>
 #endif
 
+#include <lib/bluetooth.h>
+
 /* define MAX_INPUT for musl */
 #ifndef MAX_INPUT
 #define MAX_INPUT _POSIX_MAX_INPUT
@@ -274,6 +277,32 @@ void *util_iov_push_mem(struct iovec *iov, size_t len, const void *data)
 	return p;
 }
 
+void *util_iov_push_le32(struct iovec *iov, uint32_t val)
+{
+	void *p;
+
+	p = util_iov_push(iov, sizeof(uint32_t));
+	if (!p)
+		return NULL;
+
+	put_le32(val, p);
+
+	return p;
+}
+
+void *util_iov_push_le24(struct iovec *iov, uint32_t val)
+{
+	void *p;
+
+	p = util_iov_push(iov, sizeof(uint24_t));
+	if (!p)
+		return NULL;
+
+	put_le24(val, p);
+
+	return p;
+}
+
 void *util_iov_pull(struct iovec *iov, size_t len)
 {
 	if (!iov)
@@ -298,6 +327,30 @@ void *util_iov_pull_mem(struct iovec *iov, size_t len)
 	return NULL;
 }
 
+void *util_iov_pull_le32(struct iovec *iov, uint32_t *val)
+{
+	void *data = iov->iov_base;
+
+	if (util_iov_pull(iov, sizeof(uint32_t))) {
+		*val = get_le32(data);
+		return data;
+	}
+
+	return NULL;
+}
+
+void *util_iov_pull_le24(struct iovec *iov, uint32_t *val)
+{
+	void *data = iov->iov_base;
+
+	if (util_iov_pull(iov, sizeof(uint24_t))) {
+		*val = get_le24(data);
+		return data;
+	}
+
+	return NULL;
+}
+
 static const struct {
 	uint16_t uuid;
 	const char *str;
diff --git a/src/shared/util.h b/src/shared/util.h
index dc84f9635..b99a959b8 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2012-2014  Intel Corporation. All rights reserved.
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -115,8 +116,12 @@ int util_iov_memcmp(const struct iovec *iov1, const struct iovec *iov2);
 void util_iov_memcpy(struct iovec *iov, void *src, size_t len);
 void *util_iov_push(struct iovec *iov, size_t len);
 void *util_iov_push_mem(struct iovec *iov, size_t len, const void *data);
+void *util_iov_push_le32(struct iovec *iov, uint32_t val);
+void *util_iov_push_le24(struct iovec *iov, uint32_t val);
 void *util_iov_pull(struct iovec *iov, size_t len);
 void *util_iov_pull_mem(struct iovec *iov, size_t len);
+void *util_iov_pull_le32(struct iovec *iov, uint32_t *val);
+void *util_iov_pull_le24(struct iovec *iov, uint32_t *val);
 void util_iov_free(struct iovec *iov, size_t cnt);
 
 const char *bt_uuid16_to_str(uint16_t uuid);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 4/5] shared/bass: Add initial code for handling BASS
  2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
                   ` (2 preceding siblings ...)
  2023-05-05  8:29 ` [PATCH BlueZ 3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values Iulia Tanasescu
@ 2023-05-05  8:29 ` Iulia Tanasescu
  2023-05-05  8:29 ` [PATCH BlueZ 5/5] profiles: Add initial code for BASS plugin Iulia Tanasescu
  2023-05-05 18:50 ` [PATCH BlueZ 0/5] Add initial code for handling BASS patchwork-bot+bluetooth
  5 siblings, 0 replies; 8+ messages in thread
From: Iulia Tanasescu @ 2023-05-05  8:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Iulia Tanasescu

This adds initial code for Broadcast Audio Scan Service.

---
 Makefile.am       |    1 +
 src/shared/bass.c | 1012 +++++++++++++++++++++++++++++++++++++++++++++
 src/shared/bass.h |  122 ++++++
 3 files changed, 1135 insertions(+)
 create mode 100644 src/shared/bass.c
 create mode 100644 src/shared/bass.h

diff --git a/Makefile.am b/Makefile.am
index 7ded3ba75..48f0cefa7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -234,6 +234,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/mcs.h src/shared/mcp.h src/shared/mcp.c \
 			src/shared/vcp.c src/shared/vcp.h \
 			src/shared/csip.c src/shared/csip.h \
+			src/shared/bass.h src/shared/bass.c \
 			src/shared/lc3.h src/shared/tty.h
 
 if READLINE
diff --git a/src/shared/bass.c b/src/shared/bass.c
new file mode 100644
index 000000000..fd4f28ac5
--- /dev/null
+++ b/src/shared/bass.c
@@ -0,0 +1,1012 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright 2023 NXP
+ *
+ */
+
+#define _GNU_SOURCE
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/bass.h"
+
+#define DBG(_bass, fmt, arg...) \
+	bass_debug(_bass, "%s:%s() " fmt, __FILE__, __func__, ## arg)
+
+struct bt_bass_db;
+
+struct bt_bass_cb {
+	unsigned int id;
+	bt_bass_func_t attached;
+	bt_bass_func_t detached;
+	void *user_data;
+};
+
+struct bt_bcast_recv_state {
+	struct bt_bass_db *bdb;
+	struct gatt_db_attribute *attr;
+	struct gatt_db_attribute *ccc;
+};
+
+struct bt_bass_db {
+	struct gatt_db *db;
+	struct queue *bcast_srcs;
+	struct gatt_db_attribute *service;
+	struct gatt_db_attribute *bcast_audio_scan_cp;
+	struct bt_bcast_recv_state *bcast_recv_states[NUM_BCAST_RECV_STATES];
+};
+
+struct bt_bass {
+	int ref_count;
+	struct bt_bass_db *ldb;
+	struct bt_bass_db *rdb;
+	struct bt_gatt_client *client;
+	struct bt_att *att;
+
+	struct queue *notify;
+
+	bt_bass_debug_func_t debug_func;
+	bt_bass_destroy_func_t debug_destroy;
+	void *debug_data;
+
+	void *user_data;
+};
+
+typedef void (*bass_notify_t)(struct bt_bass *bass, uint16_t value_handle,
+				const uint8_t *value, uint16_t length,
+				void *user_data);
+
+struct bt_bass_notify {
+	unsigned int id;
+	struct bt_bass *bass;
+	bass_notify_t func;
+	void *user_data;
+};
+
+static struct queue *bass_db;
+static struct queue *bass_cbs;
+static struct queue *sessions;
+
+static void bass_debug(struct bt_bass *bass, const char *format, ...)
+{
+	va_list ap;
+
+	if (!bass || !format || !bass->debug_func)
+		return;
+
+	va_start(ap, format);
+	util_debug_va(bass->debug_func, bass->debug_data, format, ap);
+	va_end(ap);
+}
+
+static int
+bass_build_bcast_src_from_notif(struct bt_bcast_src *bcast_src,
+				const uint8_t *value, uint16_t length)
+{
+	struct bt_bass_subgroup_data *subgroup_data = NULL;
+	uint8_t *id;
+	uint8_t *addr_type;
+	uint8_t *addr;
+	uint8_t *sid;
+	uint32_t bid;
+	uint8_t *pa_sync_state;
+	uint8_t *enc;
+	uint8_t *bad_code = NULL;
+	uint8_t *num_subgroups;
+	uint32_t bis_sync_state;
+	uint8_t *meta_len;
+	uint8_t *meta;
+
+	struct iovec iov = {
+		.iov_base = (void *) value,
+		.iov_len = length,
+	};
+
+	/* Extract all fields from notification */
+	id = util_iov_pull_mem(&iov, sizeof(*id));
+	if (!id) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	addr_type = util_iov_pull_mem(&iov, sizeof(*addr_type));
+	if (!addr_type) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	addr = util_iov_pull_mem(&iov, sizeof(bdaddr_t));
+	if (!addr) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	sid = util_iov_pull_mem(&iov, sizeof(*sid));
+	if (!sid) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	if (!util_iov_pull_le24(&iov, &bid)) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	pa_sync_state = util_iov_pull_mem(&iov, sizeof(*pa_sync_state));
+	if (!pa_sync_state) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	enc = util_iov_pull_mem(&iov, sizeof(*enc));
+	if (!enc) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	if (*enc == BT_BASS_BIG_ENC_STATE_BAD_CODE) {
+		bad_code = util_iov_pull_mem(&iov, BT_BASS_BCAST_CODE_SIZE);
+		if (!bad_code) {
+			DBG(bcast_src->bass, "Unable to parse "
+				"Broadcast Receive State");
+			return -1;
+		}
+	}
+
+	num_subgroups = util_iov_pull_mem(&iov, sizeof(*num_subgroups));
+	if (!num_subgroups) {
+		DBG(bcast_src->bass, "Unable to parse Broadcast Receive State");
+		return -1;
+	}
+
+	if (*num_subgroups == 0)
+		goto done;
+
+	subgroup_data = malloc((*num_subgroups) * sizeof(*subgroup_data));
+	if (!subgroup_data) {
+		DBG(bcast_src->bass, "Unable to allocate memory");
+		return -1;
+	}
+
+	memset(subgroup_data, 0, (*num_subgroups) * sizeof(*subgroup_data));
+
+	for (int i = 0; i < *num_subgroups; i++) {
+		if (!util_iov_pull_le32(&iov, &bis_sync_state)) {
+			DBG(bcast_src->bass, "Unable to parse "
+				"Broadcast Receive State");
+
+			for (int j = 0; j < i; j++)
+				free(subgroup_data[j].meta);
+
+			free(subgroup_data);
+			return -1;
+		}
+
+		subgroup_data[i].bis_sync = bis_sync_state;
+
+		meta_len = util_iov_pull_mem(&iov, sizeof(*meta_len));
+		if (!meta_len) {
+			DBG(bcast_src->bass, "Unable to parse "
+				"Broadcast Receive State");
+
+			for (int j = 0; j < i; j++)
+				free(subgroup_data[j].meta);
+
+			free(subgroup_data);
+			return -1;
+		}
+
+		subgroup_data[i].meta_len = *meta_len;
+
+		if (*meta_len == 0)
+			continue;
+
+		subgroup_data[i].meta = malloc(*meta_len);
+		if (!subgroup_data[i].meta) {
+			DBG(bcast_src->bass, "Unable to allocate memory");
+
+			for (int j = 0; j < i; j++)
+				free(subgroup_data[j].meta);
+
+			free(subgroup_data);
+			return -1;
+		}
+
+		meta = util_iov_pull_mem(&iov, *meta_len);
+		if (!meta) {
+			DBG(bcast_src->bass, "Unable to parse "
+				"Broadcast Receive State");
+
+			for (int j = 0; j < i; j++)
+				free(subgroup_data[j].meta);
+
+			free(subgroup_data);
+			return -1;
+		}
+
+		memcpy(subgroup_data[i].meta, meta, *meta_len);
+	}
+
+done:
+	/*
+	 * If no errors occurred, copy extracted fields into
+	 * the broadcast source structure
+	 */
+	if (bcast_src->subgroup_data) {
+		for (int i = 0; i < bcast_src->num_subgroups; i++)
+			free(bcast_src->subgroup_data[i].meta);
+
+		free(bcast_src->subgroup_data);
+	}
+
+	bcast_src->id = *id;
+	bcast_src->addr_type = *addr_type;
+	memcpy(&bcast_src->addr, addr, sizeof(bdaddr_t));
+	bcast_src->sid = *sid;
+	bcast_src->bid = bid;
+	bcast_src->sync_state = *pa_sync_state;
+	bcast_src->enc = *enc;
+
+	if (*enc == BT_BASS_BIG_ENC_STATE_BAD_CODE)
+		memcpy(bcast_src->bad_code, bad_code, BT_BASS_BCAST_CODE_SIZE);
+	else
+		memset(bcast_src->bad_code, 0, BT_BASS_BCAST_CODE_SIZE);
+
+	bcast_src->num_subgroups = *num_subgroups;
+
+	bcast_src->subgroup_data = subgroup_data;
+
+	return 0;
+}
+
+static int
+bass_build_bcast_src_from_read_rsp(struct bt_bcast_src *bcast_src,
+				const uint8_t *value, uint16_t length)
+{
+	return bass_build_bcast_src_from_notif(bcast_src, value, length);
+}
+
+static uint8_t *bass_build_notif_from_bcast_src(struct bt_bcast_src *bcast_src,
+							size_t *notif_len)
+{
+	size_t len = 0;
+	uint8_t *notif = NULL;
+	struct iovec iov;
+
+	*notif_len = 0;
+
+	if (!bcast_src)
+		return NULL;
+
+	len = BT_BASS_BCAST_SRC_LEN + bcast_src->num_subgroups *
+			BT_BASS_BCAST_SRC_SUBGROUP_LEN;
+
+	if (bcast_src->enc == BT_BASS_BIG_ENC_STATE_BAD_CODE)
+		len += BT_BASS_BCAST_CODE_SIZE;
+
+	for (size_t i = 0; i < bcast_src->num_subgroups; i++) {
+		/* Add length for subgroup metadata */
+		len += bcast_src->subgroup_data[i].meta_len;
+	}
+
+	notif = malloc(len);
+	if (!notif)
+		return NULL;
+
+	memset(notif, 0, len);
+
+	iov.iov_base = notif;
+	iov.iov_len = 0;
+
+	util_iov_push_mem(&iov, sizeof(bcast_src->id),
+			&bcast_src->id);
+	util_iov_push_mem(&iov, sizeof(bcast_src->addr_type),
+			&bcast_src->addr_type);
+	util_iov_push_mem(&iov, sizeof(bcast_src->addr),
+			&bcast_src->addr);
+	util_iov_push_mem(&iov, sizeof(bcast_src->sid),
+			&bcast_src->sid);
+	util_iov_push_le24(&iov, bcast_src->bid);
+	util_iov_push_mem(&iov, sizeof(bcast_src->sync_state),
+			&bcast_src->sync_state);
+	util_iov_push_mem(&iov, sizeof(bcast_src->enc),
+			&bcast_src->enc);
+
+	if (bcast_src->enc == BT_BASS_BIG_ENC_STATE_BAD_CODE)
+		util_iov_push_mem(&iov, sizeof(bcast_src->bad_code),
+					bcast_src->bad_code);
+
+	util_iov_push_mem(&iov, sizeof(bcast_src->num_subgroups),
+				&bcast_src->num_subgroups);
+
+	for (size_t i = 0; i < bcast_src->num_subgroups; i++) {
+		/* Add subgroup bis_sync */
+		util_iov_push_le32(&iov, bcast_src->subgroup_data[i].bis_sync);
+
+		/* Add subgroup meta_len */
+		util_iov_push_mem(&iov,
+			sizeof(bcast_src->subgroup_data[i].meta_len),
+			&bcast_src->subgroup_data[i].meta_len);
+
+		/* Add subgroup metadata */
+		if (bcast_src->subgroup_data[i].meta_len > 0)
+			util_iov_push_mem(&iov,
+				bcast_src->subgroup_data[i].meta_len,
+				bcast_src->subgroup_data[i].meta);
+	}
+
+	*notif_len = len;
+	return notif;
+}
+
+static uint8_t *
+bass_build_read_rsp_from_bcast_src(struct bt_bcast_src *bcast_src,
+					size_t *rsp_len)
+{
+	return bass_build_notif_from_bcast_src(bcast_src, rsp_len);
+}
+
+static bool bass_check_cp_command_subgroup_data_len(uint8_t num_subgroups,
+							struct iovec *iov)
+{
+	uint32_t bis_sync_state;
+	uint8_t *meta_len;
+	uint8_t *meta;
+
+	for (int i = 0; i < num_subgroups; i++) {
+		if (!util_iov_pull_le32(iov, &bis_sync_state))
+			return false;
+
+		meta_len = util_iov_pull_mem(iov,
+					sizeof(*meta_len));
+		if (!meta_len)
+			return false;
+
+		meta = util_iov_pull_mem(iov, *meta_len);
+		if (!meta)
+			return false;
+	}
+
+	return true;
+}
+
+static bool bass_check_cp_command_len(struct iovec *iov)
+{
+	struct bt_bass_bcast_audio_scan_cp_hdr *hdr;
+	union {
+		struct bt_bass_add_src_params *add_src_params;
+		struct bt_bass_mod_src_params *mod_src_params;
+		struct bt_bass_set_bcast_code_params *set_bcast_code_params;
+		struct bt_bass_remove_src_params *remove_src_params;
+	} params;
+
+	/* Get command header */
+	hdr = util_iov_pull_mem(iov, sizeof(*hdr));
+
+	if (!hdr)
+		return false;
+
+	/* Check command parameters */
+	switch (hdr->op) {
+	case BT_BASS_ADD_SRC:
+		params.add_src_params = util_iov_pull_mem(iov,
+						sizeof(*params.add_src_params));
+		if (!params.add_src_params)
+			return false;
+
+		if (!bass_check_cp_command_subgroup_data_len(
+					params.add_src_params->num_subgroups,
+					iov))
+			return false;
+
+		break;
+	case BT_BASS_MOD_SRC:
+		params.mod_src_params = util_iov_pull_mem(iov,
+						sizeof(*params.mod_src_params));
+		if (!params.mod_src_params)
+			return false;
+
+		if (!bass_check_cp_command_subgroup_data_len(
+					params.mod_src_params->num_subgroups,
+					iov))
+			return false;
+
+		break;
+	case BT_BASS_SET_BCAST_CODE:
+		params.set_bcast_code_params = util_iov_pull_mem(iov,
+					sizeof(*params.set_bcast_code_params));
+		if (!params.set_bcast_code_params)
+			return false;
+
+		break;
+	case BT_BASS_REMOVE_SRC:
+		params.remove_src_params = util_iov_pull_mem(iov,
+					sizeof(*params.remove_src_params));
+		if (!params.remove_src_params)
+			return false;
+
+		break;
+	case BT_BASS_REMOTE_SCAN_STOPPED:
+	case BT_BASS_REMOTE_SCAN_STARTED:
+		break;
+	default:
+		return true;
+	}
+
+	if (iov->iov_len > 0)
+		return false;
+
+	return true;
+}
+
+static void bass_bcast_audio_scan_cp_write(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	struct iovec iov = {
+		.iov_base = (void *)value,
+		.iov_len = len,
+	};
+
+	/* Validate written command length */
+	if (!bass_check_cp_command_len(&iov)) {
+		if (opcode == BT_ATT_OP_WRITE_REQ) {
+			gatt_db_attribute_write_result(attrib, id,
+					BT_ERROR_WRITE_REQUEST_REJECTED);
+		}
+		return;
+	}
+
+	/* TODO: Implement handlers for the written opcodes */
+	gatt_db_attribute_write_result(attrib, id,
+			BT_BASS_ERROR_OPCODE_NOT_SUPPORTED);
+}
+
+static bool bass_src_match_attrib(const void *data, const void *match_data)
+{
+	const struct bt_bcast_src *bcast_src = data;
+	const struct gatt_db_attribute *attr = match_data;
+
+	return (bcast_src->attr == attr);
+}
+
+static void bass_bcast_recv_state_read(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					uint8_t opcode, struct bt_att *att,
+					void *user_data)
+{
+	struct bt_bass_db *bdb = user_data;
+	uint8_t *rsp;
+	size_t rsp_len;
+	struct bt_bcast_src *bcast_src;
+
+	bcast_src = queue_find(bdb->bcast_srcs,
+					bass_src_match_attrib,
+					attrib);
+
+	if (!bcast_src) {
+		gatt_db_attribute_read_result(attrib, id, 0, NULL,
+							0);
+		return;
+	}
+
+	/* Build read response */
+	rsp = bass_build_read_rsp_from_bcast_src(bcast_src, &rsp_len);
+
+	if (!rsp) {
+		gatt_db_attribute_read_result(attrib, id,
+					BT_ATT_ERROR_UNLIKELY,
+					NULL, 0);
+		return;
+	}
+
+	gatt_db_attribute_read_result(attrib, id, 0, (void *)rsp,
+						rsp_len);
+
+	free(rsp);
+}
+
+static void bcast_recv_new(struct bt_bass_db *bdb, int i)
+{
+	struct bt_bcast_recv_state *bcast_recv_state;
+	bt_uuid_t uuid;
+
+	if (!bdb)
+		return;
+
+	bcast_recv_state = new0(struct bt_bcast_recv_state, 1);
+	bcast_recv_state->bdb = bdb;
+
+	bt_uuid16_create(&uuid, BCAST_RECV_STATE_UUID);
+	bcast_recv_state->attr =
+		gatt_db_service_add_characteristic(bdb->service, &uuid,
+				BT_ATT_PERM_READ,
+				BT_GATT_CHRC_PROP_READ |
+				BT_GATT_CHRC_PROP_NOTIFY,
+				bass_bcast_recv_state_read, NULL,
+				bdb);
+
+	bcast_recv_state->ccc = gatt_db_service_add_ccc(bdb->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	bdb->bcast_recv_states[i] = bcast_recv_state;
+}
+
+static void bass_new(struct bt_bass_db *bdb)
+{
+	bt_uuid_t uuid;
+	int i;
+
+	/* Populate DB with BASS attributes */
+	bt_uuid16_create(&uuid, BASS_UUID);
+	bdb->service = gatt_db_add_service(bdb->db, &uuid, true,
+					3 + (NUM_BCAST_RECV_STATES * 3));
+
+	for (i = 0; i < NUM_BCAST_RECV_STATES; i++)
+		bcast_recv_new(bdb, i);
+
+	bt_uuid16_create(&uuid, BCAST_AUDIO_SCAN_CP_UUID);
+	bdb->bcast_audio_scan_cp =
+		gatt_db_service_add_characteristic(bdb->service,
+				&uuid,
+				BT_ATT_PERM_WRITE,
+				BT_GATT_CHRC_PROP_WRITE,
+				NULL, bass_bcast_audio_scan_cp_write,
+				bdb);
+
+	gatt_db_service_set_active(bdb->service, true);
+}
+
+static void bass_bcast_src_free(void *data)
+{
+	struct bt_bcast_src *bcast_src = data;
+
+	for (int i = 0; i < bcast_src->num_subgroups; i++)
+		free(bcast_src->subgroup_data[i].meta);
+
+	free(bcast_src->subgroup_data);
+	free(bcast_src);
+}
+
+static void read_bcast_recv_state(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_bcast_src *bcast_src = user_data;
+
+	if (!success) {
+		DBG(bcast_src->bass, "Unable to read "
+			"Broadcast Receive State: error 0x%02x",
+			att_ecode);
+		return;
+	}
+
+	if (length == 0) {
+		queue_remove(bcast_src->bass->rdb->bcast_srcs, bcast_src);
+		bass_bcast_src_free(bcast_src);
+		return;
+	}
+
+	if (bass_build_bcast_src_from_read_rsp(bcast_src, value, length)) {
+		queue_remove(bcast_src->bass->rdb->bcast_srcs, bcast_src);
+		bass_bcast_src_free(bcast_src);
+		return;
+	}
+}
+
+static void bcast_recv_state_notify(struct bt_bass *bass, uint16_t value_handle,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct gatt_db_attribute *attr = user_data;
+	struct bt_bcast_src *bcast_src;
+	bool new_src = false;
+
+	bcast_src = queue_find(bass->rdb->bcast_srcs,
+					bass_src_match_attrib, attr);
+	if (!bcast_src) {
+		new_src = true;
+		bcast_src = malloc(sizeof(*bcast_src));
+
+		if (!bcast_src) {
+			DBG(bass, "Failed to allocate "
+				"memory for broadcast source");
+			return;
+		}
+
+		memset(bcast_src, 0, sizeof(struct bt_bcast_src));
+		bcast_src->bass = bass;
+		bcast_src->attr = attr;
+	}
+
+	if (bass_build_bcast_src_from_notif(bcast_src, value, length)
+							&& new_src) {
+		bass_bcast_src_free(bcast_src);
+		return;
+	}
+
+	if (new_src)
+		queue_push_tail(bass->rdb->bcast_srcs, bcast_src);
+}
+
+static void bass_register(uint16_t att_ecode, void *user_data)
+{
+	struct bt_bass_notify *notify = user_data;
+
+	if (att_ecode)
+		DBG(notify->bass, "BASS register notify failed: 0x%04x",
+					att_ecode);
+}
+
+static void bass_notify(uint16_t value_handle, const uint8_t *value,
+				uint16_t length, void *user_data)
+{
+	struct bt_bass_notify *notify = user_data;
+
+	if (notify->func)
+		notify->func(notify->bass, value_handle, value, length,
+						notify->user_data);
+}
+
+static void bass_notify_destroy(void *data)
+{
+	struct bt_bass_notify *notify = data;
+	struct bt_bass *bass = notify->bass;
+
+	if (queue_remove_if(bass->notify, NULL, notify))
+		free(notify);
+}
+
+static unsigned int bass_register_notify(struct bt_bass *bass,
+					uint16_t value_handle,
+					bass_notify_t func,
+					void *user_data)
+{
+	struct bt_bass_notify *notify;
+
+	notify = new0(struct bt_bass_notify, 1);
+	notify->bass = bass;
+	notify->func = func;
+	notify->user_data = user_data;
+
+	notify->id = bt_gatt_client_register_notify(bass->client,
+						value_handle, bass_register,
+						bass_notify, notify,
+						bass_notify_destroy);
+	if (!notify->id) {
+		DBG(bass, "Unable to register for notifications");
+		free(notify);
+		return 0;
+	}
+
+	queue_push_tail(bass->notify, notify);
+
+	return notify->id;
+}
+
+static void foreach_bass_char(struct gatt_db_attribute *attr, void *user_data)
+{
+	struct bt_bass *bass = user_data;
+	uint16_t value_handle;
+	bt_uuid_t uuid, uuid_bcast_audio_scan_cp, uuid_bcast_recv_state;
+
+	/* Get attribute value handle and uuid */
+	if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
+						NULL, NULL, &uuid))
+		return;
+
+	bt_uuid16_create(&uuid_bcast_audio_scan_cp, BCAST_AUDIO_SCAN_CP_UUID);
+	bt_uuid16_create(&uuid_bcast_recv_state, BCAST_RECV_STATE_UUID);
+
+	if (!bt_uuid_cmp(&uuid, &uuid_bcast_audio_scan_cp)) {
+		/* Found Broadcast Audio Scan Control Point characteristic */
+		bass->rdb->bcast_audio_scan_cp = attr;
+
+		DBG(bass, "Broadcast Audio Scan Control Point "
+			"found: handle 0x%04x", value_handle);
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_bcast_recv_state)) {
+		/* Found Broadcast Receive State characteristic */
+		struct bt_bcast_src *bcast_src =
+				queue_find(bass->rdb->bcast_srcs,
+						bass_src_match_attrib, attr);
+
+		if (!bcast_src) {
+			bcast_src = malloc(sizeof(struct bt_bcast_src));
+
+			if (bcast_src == NULL) {
+				DBG(bass, "Failed to allocate "
+					"memory for broadcast source");
+				return;
+			}
+
+			memset(bcast_src, 0, sizeof(struct bt_bcast_src));
+			bcast_src->bass = bass;
+			bcast_src->attr = attr;
+
+			queue_push_tail(bass->rdb->bcast_srcs, bcast_src);
+		}
+
+		bt_gatt_client_read_value(bass->client, value_handle,
+						read_bcast_recv_state,
+						bcast_src, NULL);
+
+		(void)bass_register_notify(bass, value_handle,
+						bcast_recv_state_notify,
+						attr);
+
+		DBG(bass, "Broadcast Receive State found: handle 0x%04x",
+							value_handle);
+	}
+}
+
+static void foreach_bass_service(struct gatt_db_attribute *attr,
+						void *user_data)
+{
+	struct bt_bass *bass = user_data;
+
+	/* Store BASS service reference */
+	bass->rdb->service = attr;
+
+	/* Handle BASS characteristics */
+	gatt_db_service_foreach_char(attr, foreach_bass_char, bass);
+}
+
+bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client)
+{
+	bt_uuid_t uuid;
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, bass);
+
+	if (!client)
+		return true;
+
+	if (bass->client)
+		return false;
+
+	bass->client = bt_gatt_client_clone(client);
+	if (!bass->client)
+		return false;
+
+	bt_uuid16_create(&uuid, BASS_UUID);
+	gatt_db_foreach_service(bass->rdb->db, &uuid, foreach_bass_service,
+				bass);
+
+	return true;
+}
+
+static void bass_detached(void *data, void *user_data)
+{
+	struct bt_bass_cb *cb = data;
+	struct bt_bass *bass = user_data;
+
+	cb->detached(bass, cb->user_data);
+}
+
+void bt_bass_detach(struct bt_bass *bass)
+{
+	if (!queue_remove(sessions, bass))
+		return;
+
+	bt_gatt_client_unref(bass->client);
+	bass->client = NULL;
+
+	queue_foreach(bass_cbs, bass_detached, bass);
+}
+
+static void bass_db_free(void *data)
+{
+	struct bt_bass_db *bdb = data;
+
+	if (!bdb)
+		return;
+
+	gatt_db_unref(bdb->db);
+	queue_destroy(bdb->bcast_srcs, bass_bcast_src_free);
+
+	free(bdb);
+}
+
+static void bass_free(void *data)
+{
+	struct bt_bass *bass = data;
+
+	bt_bass_detach(bass);
+	bass_db_free(bass->rdb);
+	queue_destroy(bass->notify, NULL);
+
+	free(bass);
+}
+
+void bt_bass_unref(struct bt_bass *bass)
+{
+	if (!bass)
+		return;
+
+	if (__sync_sub_and_fetch(&bass->ref_count, 1))
+		return;
+
+	bass_free(bass);
+}
+
+bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data)
+{
+	if (!bass)
+		return false;
+
+	bass->user_data = user_data;
+
+	return true;
+}
+
+static struct bt_bass_db *bass_db_new(struct gatt_db *db)
+{
+	struct bt_bass_db *bdb;
+
+	if (!db)
+		return NULL;
+
+	bdb = new0(struct bt_bass_db, 1);
+	bdb->db = gatt_db_ref(db);
+	bdb->bcast_srcs = queue_new();
+
+	if (!bass_db)
+		bass_db = queue_new();
+
+	bass_new(bdb);
+
+	queue_push_tail(bass_db, bdb);
+
+	return bdb;
+}
+
+static bool bass_db_match(const void *data, const void *match_data)
+{
+	const struct bt_bass_db *bdb = data;
+	const struct gatt_db *db = match_data;
+
+	return (bdb->db == db);
+}
+
+static struct bt_bass_db *bass_get_db(struct gatt_db *db)
+{
+	struct bt_bass_db *bdb;
+
+	bdb = queue_find(bass_db, bass_db_match, db);
+	if (bdb)
+		return bdb;
+
+	return bass_db_new(db);
+}
+
+static struct bt_bass *bt_bass_ref(struct bt_bass *bass)
+{
+	if (!bass)
+		return NULL;
+
+	__sync_fetch_and_add(&bass->ref_count, 1);
+
+	return bass;
+}
+
+struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb)
+{
+	struct bt_bass *bass;
+	struct bt_bass_db *db;
+
+	if (!ldb)
+		return NULL;
+
+	db = bass_get_db(ldb);
+	if (!db)
+		return NULL;
+
+	bass = new0(struct bt_bass, 1);
+	bass->ldb = db;
+	bass->notify = queue_new();
+
+	if (!rdb)
+		goto done;
+
+	db = new0(struct bt_bass_db, 1);
+	db->db = gatt_db_ref(rdb);
+	db->bcast_srcs = queue_new();
+
+	bass->rdb = db;
+
+done:
+	bt_bass_ref(bass);
+
+	return bass;
+}
+
+struct bt_att *bt_bass_get_att(struct bt_bass *bass)
+{
+	if (!bass)
+		return NULL;
+
+	if (bass->att)
+		return bass->att;
+
+	return bt_gatt_client_get_att(bass->client);
+}
+
+bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func,
+			void *user_data, bt_bass_destroy_func_t destroy)
+{
+	if (!bass)
+		return false;
+
+	if (bass->debug_destroy)
+		bass->debug_destroy(bass->debug_data);
+
+	bass->debug_func = func;
+	bass->debug_destroy = destroy;
+	bass->debug_data = user_data;
+
+	return true;
+}
+
+unsigned int bt_bass_register(bt_bass_func_t attached, bt_bass_func_t detached,
+							void *user_data)
+{
+	struct bt_bass_cb *cb;
+	static unsigned int id;
+
+	if (!attached && !detached)
+		return 0;
+
+	if (!bass_cbs)
+		bass_cbs = queue_new();
+
+	cb = new0(struct bt_bass_cb, 1);
+	cb->id = ++id ? id : ++id;
+	cb->attached = attached;
+	cb->detached = detached;
+	cb->user_data = user_data;
+
+	queue_push_tail(bass_cbs, cb);
+
+	return cb->id;
+}
+static bool match_id(const void *data, const void *match_data)
+{
+	const struct bt_bass_cb *cb = data;
+	unsigned int id = PTR_TO_UINT(match_data);
+
+	return (cb->id == id);
+}
+
+bool bt_bass_unregister(unsigned int id)
+{
+	struct bt_bass_cb *cb;
+
+	cb = queue_remove_if(bass_cbs, match_id, UINT_TO_PTR(id));
+	if (!cb)
+		return false;
+
+	free(cb);
+
+	return true;
+}
diff --git a/src/shared/bass.h b/src/shared/bass.h
new file mode 100644
index 000000000..d3474f7cf
--- /dev/null
+++ b/src/shared/bass.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright 2023 NXP
+ *
+ */
+
+struct bt_bass;
+
+#define NUM_BCAST_RECV_STATES				2
+#define BT_BASS_BCAST_CODE_SIZE				16
+#define BT_BASS_BIG_SYNC_FAILED_BITMASK			0xFFFFFFFF
+#define BT_BASS_BCAST_SRC_LEN				15
+#define BT_BASS_BCAST_SRC_SUBGROUP_LEN			5
+
+/* Application error codes */
+#define BT_BASS_ERROR_OPCODE_NOT_SUPPORTED		0x80
+#define BT_BASS_ERROR_INVALID_SOURCE_ID			0x81
+
+/* PA_Sync_State values */
+#define BT_BASS_NOT_SYNCHRONIZED_TO_PA			0x00
+#define BT_BASS_SYNC_INFO_RE				0x01
+#define BT_BASS_SYNCHRONIZED_TO_PA			0x02
+#define BT_BASS_FAILED_TO_SYNCHRONIZE_TO_PA		0x03
+#define BT_BASS_NO_PAST					0x04
+
+/* BIG_Encryption values */
+#define BT_BASS_BIG_ENC_STATE_NO_ENC			0x00
+#define BT_BASS_BIG_ENC_STATE_BCODE_REQ			0x01
+#define BT_BASS_BIG_ENC_STATE_DEC			0x02
+#define BT_BASS_BIG_ENC_STATE_BAD_CODE			0x03
+
+/* BASS subgroup field of the Broadcast
+ * Receive State characteristic
+ */
+struct bt_bass_subgroup_data {
+	uint32_t bis_sync;
+	uint32_t pending_bis_sync;
+	uint8_t meta_len;
+	uint8_t *meta;
+};
+
+/* BASS Broadcast Source structure */
+struct bt_bcast_src {
+	struct bt_bass *bass;
+	struct gatt_db_attribute *attr;
+	uint8_t id;
+	uint8_t addr_type;
+	bdaddr_t addr;
+	uint8_t sid;
+	uint32_t bid;
+	uint8_t sync_state;
+	uint8_t enc;
+	uint8_t bad_code[BT_BASS_BCAST_CODE_SIZE];
+	uint8_t num_subgroups;
+	struct bt_bass_subgroup_data *subgroup_data;
+};
+
+/* Broadcast Audio Scan Control Point
+ * header structure
+ */
+struct bt_bass_bcast_audio_scan_cp_hdr {
+	uint8_t op;
+} __packed;
+
+#define BT_BASS_REMOTE_SCAN_STOPPED			0x00
+
+#define BT_BASS_REMOTE_SCAN_STARTED			0x01
+
+#define BT_BASS_ADD_SRC					0x02
+
+struct bt_bass_add_src_params {
+	uint8_t addr_type;
+	bdaddr_t addr;
+	uint8_t sid;
+	uint8_t bid[3];
+	uint8_t pa_sync;
+	uint16_t pa_interval;
+	uint8_t num_subgroups;
+	uint8_t subgroup_data[];
+} __packed;
+
+#define BT_BASS_MOD_SRC					0x03
+
+struct bt_bass_mod_src_params {
+	uint8_t id;
+	uint8_t pa_sync;
+	uint16_t pa_interval;
+	uint8_t num_subgroups;
+	uint8_t subgroup_data[];
+} __packed;
+
+#define BT_BASS_SET_BCAST_CODE				0x04
+
+struct bt_bass_set_bcast_code_params {
+	uint8_t id;
+	uint8_t bcast_code[BT_BASS_BCAST_CODE_SIZE];
+} __packed;
+
+#define BT_BASS_REMOVE_SRC				0x05
+
+struct bt_bass_remove_src_params {
+	uint8_t id;
+} __packed;
+
+typedef void (*bt_bass_func_t)(struct bt_bass *bass, void *user_data);
+typedef void (*bt_bass_destroy_func_t)(void *user_data);
+typedef void (*bt_bass_debug_func_t)(const char *str, void *user_data);
+
+struct bt_att *bt_bass_get_att(struct bt_bass *bass);
+unsigned int bt_bass_register(bt_bass_func_t attached, bt_bass_func_t detached,
+							void *user_data);
+bool bt_bass_unregister(unsigned int id);
+bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func,
+			void *user_data, bt_bass_destroy_func_t destroy);
+struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb);
+bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data);
+void bt_bass_unref(struct bt_bass *bass);
+bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client);
+void bt_bass_detach(struct bt_bass *bass);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 5/5] profiles: Add initial code for BASS plugin
  2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
                   ` (3 preceding siblings ...)
  2023-05-05  8:29 ` [PATCH BlueZ 4/5] shared/bass: Add initial code for handling BASS Iulia Tanasescu
@ 2023-05-05  8:29 ` Iulia Tanasescu
  2023-05-05 18:50 ` [PATCH BlueZ 0/5] Add initial code for handling BASS patchwork-bot+bluetooth
  5 siblings, 0 replies; 8+ messages in thread
From: Iulia Tanasescu @ 2023-05-05  8:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Iulia Tanasescu

This adds initial code for BASS plugin.

---
 Makefile.plugins      |   5 +
 configure.ac          |   4 +
 profiles/audio/bass.c | 305 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 314 insertions(+)
 create mode 100644 profiles/audio/bass.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 0f119e871..fc19522e4 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -122,6 +122,11 @@ builtin_modules += bap
 builtin_sources += profiles/audio/bap.c
 endif
 
+if BASS
+builtin_modules += bass
+builtin_sources += profiles/audio/bass.c
+endif
+
 if MCP
 builtin_modules += mcp
 builtin_sources += profiles/audio/mcp.c
diff --git a/configure.ac b/configure.ac
index 6f890110f..c5c5d7f00 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,10 @@ AC_ARG_ENABLE(bap, AS_HELP_STRING([--disable-bap],
 		[disable BAP profile]), [enable_bap=${enableval}])
 AM_CONDITIONAL(BAP, test "${enable_bap}" != "no")
 
+AC_ARG_ENABLE(bass, AS_HELP_STRING([--disable-bass],
+		[disable BASS service]), [enable_bass=${enableval}])
+AM_CONDITIONAL(BASS, test "${enable_bass}" != "no")
+
 AC_ARG_ENABLE(mcp, AS_HELP_STRING([--disable-mcp],
         [disable MCP profile]), [enable_mcp=${enableval}])
 AM_CONDITIONAL(MCP, test "${enable_mcp}" != "no")
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
new file mode 100644
index 000000000..a7fcc9718
--- /dev/null
+++ b/profiles/audio/bass.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright 2023 NXP
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "gdbus/gdbus.h"
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+
+#include "src/dbus-common.h"
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/bass.h"
+
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/gatt-database.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+#include "src/log.h"
+#include "src/error.h"
+
+#define BASS_UUID_STR "0000184f-0000-1000-8000-00805f9b34fb"
+
+struct bass_data {
+	struct btd_device *device;
+	struct btd_service *service;
+	struct bt_bass *bass;
+};
+
+static struct queue *sessions;
+
+static void bass_debug(const char *str, void *user_data)
+{
+	DBG_IDX(0xffff, "%s", str);
+}
+
+static struct bass_data *bass_data_new(struct btd_device *device)
+{
+	struct bass_data *data;
+
+	data = new0(struct bass_data, 1);
+	data->device = device;
+
+	return data;
+}
+
+static void bass_data_add(struct bass_data *data)
+{
+	DBG("data %p", data);
+
+	if (queue_find(sessions, NULL, data)) {
+		error("data %p already added", data);
+		return;
+	}
+
+	bt_bass_set_debug(data->bass, bass_debug, NULL, NULL);
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, data);
+
+	if (data->service)
+		btd_service_set_user_data(data->service, data);
+}
+
+static bool match_data(const void *data, const void *match_data)
+{
+	const struct bass_data *bdata = data;
+	const struct bt_bass *bass = match_data;
+
+	return bdata->bass == bass;
+}
+
+static void bass_data_free(struct bass_data *data)
+{
+	if (data->service) {
+		btd_service_set_user_data(data->service, NULL);
+		bt_bass_set_user_data(data->bass, NULL);
+	}
+
+	bt_bass_unref(data->bass);
+	free(data);
+}
+
+static void bass_data_remove(struct bass_data *data)
+{
+	DBG("data %p", data);
+
+	if (!queue_remove(sessions, data))
+		return;
+
+	bass_data_free(data);
+
+	if (queue_isempty(sessions)) {
+		queue_destroy(sessions, NULL);
+		sessions = NULL;
+	}
+}
+
+static void bass_detached(struct bt_bass *bass, void *user_data)
+{
+	struct bass_data *data;
+
+	DBG("%p", bass);
+
+	data = queue_find(sessions, match_data, bass);
+	if (!data) {
+		error("Unable to find bass session");
+		return;
+	}
+
+	/* If there is a service it means there is BASS thus we can keep
+	 * instance allocated.
+	 */
+	if (data->service)
+		return;
+
+	bass_data_remove(data);
+}
+
+static void bass_attached(struct bt_bass *bass, void *user_data)
+{
+	struct bass_data *data;
+	struct bt_att *att;
+	struct btd_device *device;
+
+	DBG("%p", bass);
+
+	data = queue_find(sessions, match_data, bass);
+	if (data)
+		return;
+
+	att = bt_bass_get_att(bass);
+	if (!att)
+		return;
+
+	device = btd_adapter_find_device_by_fd(bt_att_get_fd(att));
+	if (!device) {
+		error("Unable to find device");
+		return;
+	}
+
+	data = bass_data_new(device);
+	data->bass = bass;
+
+	bass_data_add(data);
+}
+
+static int bass_probe(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct btd_adapter *adapter = device_get_adapter(device);
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+	struct bass_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	/* Ignore, if we were probed for this device already */
+	if (data) {
+		error("Profile probed twice for the same device!");
+		return -EINVAL;
+	}
+
+	data = bass_data_new(device);
+	data->service = service;
+
+	data->bass = bt_bass_new(btd_gatt_database_get_db(database),
+					btd_device_get_gatt_db(device));
+	if (!data->bass) {
+		error("Unable to create BASS instance");
+		free(data);
+		return -EINVAL;
+	}
+
+	bass_data_add(data);
+	bt_bass_set_user_data(data->bass, service);
+
+	return 0;
+}
+
+static void bass_remove(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct bass_data *data;
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	data = btd_service_get_user_data(service);
+	if (!data) {
+		error("BASS service not handled by profile");
+		return;
+	}
+
+	bass_data_remove(data);
+}
+static int bass_accept(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+	struct bass_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	if (!data) {
+		error("BASS service not handled by profile");
+		return -EINVAL;
+	}
+
+	if (!bt_bass_attach(data->bass, client)) {
+		error("BASS unable to attach");
+		return -EINVAL;
+	}
+
+	btd_service_connecting_complete(service, 0);
+
+	return 0;
+}
+
+static int bass_disconnect(struct btd_service *service)
+{
+	struct bass_data *data = btd_service_get_user_data(service);
+	struct btd_device *device = btd_service_get_device(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	bt_bass_detach(data->bass);
+
+	btd_service_disconnecting_complete(service, 0);
+
+	return 0;
+}
+
+static struct btd_profile bass_service = {
+	.name		= "bass",
+	.priority	= BTD_PROFILE_PRIORITY_MEDIUM,
+	.remote_uuid	= BASS_UUID_STR,
+	.device_probe	= bass_probe,
+	.device_remove	= bass_remove,
+	.accept		= bass_accept,
+	.disconnect	= bass_disconnect,
+};
+
+static unsigned int bass_id;
+
+static int bass_init(void)
+{
+	if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) {
+		warn("D-Bus experimental not enabled");
+		return -ENOTSUP;
+	}
+
+	btd_profile_register(&bass_service);
+	bass_id = bt_bass_register(bass_attached, bass_detached, NULL);
+
+	return 0;
+}
+
+static void bass_exit(void)
+{
+	if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+		btd_profile_unregister(&bass_service);
+		bt_bass_unregister(bass_id);
+	}
+}
+
+BLUETOOTH_PLUGIN_DEFINE(bass, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+							bass_init, bass_exit)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* RE: [BlueZ,1/5] lib/uuid: Add BASS UUIDs
  2023-05-05  8:29 ` [PATCH BlueZ 1/5] lib/uuid: Add BASS UUIDs Iulia Tanasescu
@ 2023-05-05 10:24   ` bluez.test.bot
  0 siblings, 0 replies; 8+ messages in thread
From: bluez.test.bot @ 2023-05-05 10:24 UTC (permalink / raw)
  To: linux-bluetooth, iulia.tanasescu

[-- Attachment #1: Type: text/plain, Size: 2826 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=745222

---Test result---

Test Summary:
CheckPatch                    PASS      3.69 seconds
GitLint                       FAIL      1.98 seconds
BuildEll                      PASS      27.18 seconds
BluezMake                     PASS      876.48 seconds
MakeCheck                     PASS      12.32 seconds
MakeDistcheck                 PASS      154.47 seconds
CheckValgrind                 PASS      249.05 seconds
CheckSmatch                   PASS      338.42 seconds
bluezmakeextell               PASS      101.88 seconds
IncrementalBuild              PASS      3620.01 seconds
ScanBuild                     WARNING   1030.84 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (83>80): "[BlueZ,3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values"
##############################
Test: ScanBuild - WARNING
Desc: Run Scan Build
Output:
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:174:9: warning: 1st function call argument is an uninitialized value
        return be32_to_cpu(get_unaligned((const uint32_t *) ptr));
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:32: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:184:9: warning: 1st function call argument is an uninitialized value
        return be64_to_cpu(get_unaligned((const uint64_t *) ptr));
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:33: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.



---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH BlueZ 0/5] Add initial code for handling BASS
  2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
                   ` (4 preceding siblings ...)
  2023-05-05  8:29 ` [PATCH BlueZ 5/5] profiles: Add initial code for BASS plugin Iulia Tanasescu
@ 2023-05-05 18:50 ` patchwork-bot+bluetooth
  5 siblings, 0 replies; 8+ messages in thread
From: patchwork-bot+bluetooth @ 2023-05-05 18:50 UTC (permalink / raw)
  To: Iulia Tanasescu; +Cc: linux-bluetooth

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Fri,  5 May 2023 11:29:38 +0300 you wrote:
> This patch series adds initial code for handling Broadcast Audio Scan Service.
> 
> Iulia Tanasescu (5):
>   lib/uuid: Add BASS UUIDs
>   shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code
>   shared/util: Add iovec helpers for pulling/pushing le32 and le24
>     values
>   shared/bass: Add initial code for handling BASS
>   profiles: Add initial code for BASS plugin
> 
> [...]

Here is the summary with links:
  - [BlueZ,1/5] lib/uuid: Add BASS UUIDs
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=4e549cf48b71
  - [BlueZ,2/5] shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=d5d921881b7e
  - [BlueZ,3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values
    (no matching commit)
  - [BlueZ,4/5] shared/bass: Add initial code for handling BASS
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=a56c7fd16230
  - [BlueZ,5/5] profiles: Add initial code for BASS plugin
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=6bafe1c66515

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-05-05 18:50 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-05  8:29 [PATCH BlueZ 0/5] Add initial code for handling BASS Iulia Tanasescu
2023-05-05  8:29 ` [PATCH BlueZ 1/5] lib/uuid: Add BASS UUIDs Iulia Tanasescu
2023-05-05 10:24   ` [BlueZ,1/5] " bluez.test.bot
2023-05-05  8:29 ` [PATCH BlueZ 2/5] shared/att-types: Add BT_ERROR_WRITE_REQUEST_REJECTED error code Iulia Tanasescu
2023-05-05  8:29 ` [PATCH BlueZ 3/5] shared/util: Add iovec helpers for pulling/pushing le32 and le24 values Iulia Tanasescu
2023-05-05  8:29 ` [PATCH BlueZ 4/5] shared/bass: Add initial code for handling BASS Iulia Tanasescu
2023-05-05  8:29 ` [PATCH BlueZ 5/5] profiles: Add initial code for BASS plugin Iulia Tanasescu
2023-05-05 18:50 ` [PATCH BlueZ 0/5] Add initial code for handling BASS patchwork-bot+bluetooth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).