diff mbox series

[BlueZ,3/7] bass: Add support to request bcode

Message ID 20241008080126.48703-4-iulia.tanasescu@nxp.com
State New
Headers show
Series Add Scan Delegator support for Set Broadcast Code op | expand

Commit Message

Iulia Tanasescu Oct. 8, 2024, 8:01 a.m. UTC
This adds support for a Scan Delegator to request the Broadcast Code
from peer Broadcast Assistants and to update a BAP stream QoS with the
value.

A BASS API is added to update the BIG encryption status of a Broadcast
Receive State characteristic and to notify peers. When a peer provides
the Code using the BASS "Set Broadcast Code" operation, the BAP stream
QoS is updated. The driver calling this API will pass a callback as
parameter, which will be called to signal that the Broadcast Code has
been received and stored in the stream QoS.

A timeout is set to wait for Broadcast Assistants to provide the Code.
If the timeout expires, the callback will be code with the appropriate
error status.
---
 profiles/audio/bass.c | 141 ++++++++++++++++++++++++++++++++++++++++++
 profiles/audio/bass.h |   6 ++
 2 files changed, 147 insertions(+)
diff mbox series

Patch

diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index 7553d1bec..6237f5acc 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -104,6 +104,15 @@  struct bass_delegator {
 	struct bt_bcast_src *src;
 	struct bt_bap *bap;
 	unsigned int state_id;
+	uint8_t *bcode;
+	unsigned int timeout;
+	struct queue *bcode_reqs;
+};
+
+struct bass_bcode_req {
+	struct bt_bap_stream *stream;
+	bt_bass_bcode_func_t cb;
+	void *user_data;
 };
 
 static struct queue *sessions;
@@ -117,6 +126,90 @@  static void bass_debug(const char *str, void *user_data)
 	DBG_IDX(0xffff, "%s", str);
 }
 
+static gboolean req_timeout(gpointer user_data)
+{
+	struct bass_delegator *dg = user_data;
+	struct bass_bcode_req *req;
+
+	DBG("delegator %p", dg);
+
+	dg->timeout = 0;
+
+	while ((req = queue_pop_head(dg->bcode_reqs))) {
+		if (req->cb)
+			req->cb(req->user_data, -ETIMEDOUT);
+
+		free(req);
+	}
+
+	return FALSE;
+}
+
+static bool delegator_match_bap(const void *data, const void *match_data)
+{
+	const struct bass_delegator *dg = data;
+	const struct bt_bap *bap = match_data;
+
+	return dg->bap == bap;
+}
+
+static void stream_set_bcode(uint8_t *bcode, struct bt_bap_stream *stream,
+				bt_bass_bcode_func_t cb, void *user_data)
+{
+	struct bt_bap_qos *qos = bt_bap_stream_get_qos(stream);
+
+	/* Allocate Broadcast Code inside stream QoS */
+	qos->bcast.bcode = util_iov_new(bcode, BT_BASS_BCAST_CODE_SIZE);
+
+	if (cb)
+		cb(user_data, 0);
+}
+
+void bass_req_bcode(struct bt_bap_stream *stream,
+				bt_bass_bcode_func_t cb,
+				void *user_data)
+{
+	struct bt_bap *bap = bt_bap_stream_get_session(stream);
+	struct bass_delegator *dg;
+	struct bass_bcode_req *req;
+
+	dg = queue_find(delegators, delegator_match_bap, bap);
+	if (!dg) {
+		cb(user_data, -EINVAL);
+		return;
+	}
+
+	if (dg->bcode) {
+		/* Broadcast Code has already been received before. */
+		stream_set_bcode(dg->bcode, stream, cb, user_data);
+		return;
+	}
+
+	/* Create a request for the Broadcast Code. The request
+	 * will be considered handled when the Broadcast Code is
+	 * received from a Broadcast Assistant.
+	 */
+	req = new0(struct bass_bcode_req, 1);
+	if (!req)
+		return;
+
+	req->stream = stream;
+	req->cb = cb;
+	req->user_data = user_data;
+
+	queue_push_tail(dg->bcode_reqs, req);
+
+	/* Mark the encryption status as "Broadcast Code Required"
+	 * in the Broadcast Receive State characteristic and notify
+	 * Broadcast Assistants.
+	 */
+	bt_bass_set_enc(dg->src, BT_BASS_BIG_ENC_STATE_BCODE_REQ);
+
+	/* Add timeout for Broadcast Assistants to provide the Code. */
+	if (!dg->timeout)
+		dg->timeout = g_timeout_add_seconds(10, req_timeout, dg);
+}
+
 static bool delegator_match_device(const void *data, const void *match_data)
 {
 	const struct bass_delegator *dg = data;
@@ -233,6 +326,13 @@  bool bass_bcast_remove(struct btd_device *device)
 	/* Unregister BAP stream state changed callback. */
 	bt_bap_state_unregister(dg->bap, dg->state_id);
 
+	if (dg->timeout)
+		g_source_remove(dg->timeout);
+
+	queue_destroy(dg->bcode_reqs, free);
+
+	free(dg->bcode);
+
 	free(dg);
 
 	return true;
@@ -794,6 +894,7 @@  probe:
 
 	dg->device = device;
 	dg->src = bcast_src;
+	dg->bcode_reqs = queue_new();
 
 	if (!delegators)
 		delegators = queue_new();
@@ -808,6 +909,43 @@  probe:
 	return 0;
 }
 
+static bool delegator_match_src(const void *data, const void *match_data)
+{
+	const struct bass_delegator *dg = data;
+	const struct bt_bcast_src *src = match_data;
+
+	return dg->src == src;
+}
+
+static int handle_set_bcode_req(struct bt_bcast_src *bcast_src,
+			struct bt_bass_set_bcast_code_params *params,
+			struct bass_data *data)
+{
+	struct bass_delegator *dg;
+	struct bass_bcode_req *req;
+
+	dg = queue_find(delegators, delegator_match_src, bcast_src);
+	if (!dg)
+		return -EINVAL;
+
+	dg->bcode = new0(uint8_t, BT_BASS_BCAST_CODE_SIZE);
+	memcpy(dg->bcode, params->bcast_code, BT_BASS_BCAST_CODE_SIZE);
+
+	if (dg->timeout) {
+		g_source_remove(dg->timeout);
+		dg->timeout = 0;
+	}
+
+	/* Set the Broadcast Code for each stream that required it. */
+	while ((req = queue_pop_head(dg->bcode_reqs))) {
+		stream_set_bcode(dg->bcode, req->stream, req->cb,
+							req->user_data);
+		free(req);
+	}
+
+	return 0;
+}
+
 static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params,
 		void *user_data)
 {
@@ -818,6 +956,9 @@  static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params,
 	case BT_BASS_ADD_SRC:
 		err = handle_add_src_req(bcast_src, params, data);
 		break;
+	case BT_BASS_SET_BCAST_CODE:
+		err = handle_set_bcode_req(bcast_src, params, data);
+		break;
 	}
 
 	return err;
diff --git a/profiles/audio/bass.h b/profiles/audio/bass.h
index 5e34db90a..257346374 100644
--- a/profiles/audio/bass.h
+++ b/profiles/audio/bass.h
@@ -16,3 +16,9 @@  bool bass_bcast_probe(struct btd_device *device, struct bt_bap *bap);
 bool bass_bcast_remove(struct btd_device *device);
 
 bool bass_check_bis(struct btd_device *device, uint8_t bis);
+
+typedef void (*bt_bass_bcode_func_t)(void *user_data, int err);
+
+void bass_req_bcode(struct bt_bap_stream *stream,
+				bt_bass_bcode_func_t cb,
+				void *user_data);