1 /*
2  * Copyright (c) 2023-2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11 
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/att.h>
14 #include <zephyr/bluetooth/audio/cap.h>
15 #include <zephyr/bluetooth/audio/csip.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/gatt.h>
19 #include <zephyr/bluetooth/uuid.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/sys/atomic.h>
22 #include <zephyr/sys/check.h>
23 #include <zephyr/sys/util.h>
24 
25 #include "cap_internal.h"
26 #include "csip_internal.h"
27 
28 LOG_MODULE_REGISTER(bt_cap_common, CONFIG_BT_CAP_COMMON_LOG_LEVEL);
29 
30 #include "common/bt_str.h"
31 
32 static struct bt_cap_common_client bt_cap_common_clients[CONFIG_BT_MAX_CONN];
33 static const struct bt_uuid *cas_uuid = BT_UUID_CAS;
34 static struct bt_cap_common_proc active_proc;
35 
bt_cap_common_get_active_proc(void)36 struct bt_cap_common_proc *bt_cap_common_get_active_proc(void)
37 {
38 	return &active_proc;
39 }
40 
bt_cap_common_clear_active_proc(void)41 void bt_cap_common_clear_active_proc(void)
42 {
43 	(void)memset(&active_proc, 0, sizeof(active_proc));
44 }
45 
bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type,size_t proc_cnt)46 void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt)
47 {
48 	LOG_DBG("Setting proc to %d for %zu streams", proc_type, proc_cnt);
49 
50 	atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE);
51 	active_proc.proc_cnt = proc_cnt;
52 	active_proc.proc_type = proc_type;
53 	active_proc.proc_done_cnt = 0U;
54 	active_proc.proc_initiated_cnt = 0U;
55 }
56 
57 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type)58 void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type)
59 {
60 	LOG_DBG("Setting subproc to %d", subproc_type);
61 
62 	active_proc.proc_done_cnt = 0U;
63 	active_proc.proc_initiated_cnt = 0U;
64 	active_proc.subproc_type = subproc_type;
65 }
66 
bt_cap_common_proc_is_type(enum bt_cap_common_proc_type proc_type)67 bool bt_cap_common_proc_is_type(enum bt_cap_common_proc_type proc_type)
68 {
69 	return active_proc.proc_type == proc_type;
70 }
71 
bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type)72 bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type)
73 {
74 	return active_proc.subproc_type == subproc_type;
75 }
76 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
77 
bt_cap_common_get_member_conn(enum bt_cap_set_type type,const union bt_cap_set_member * member)78 struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type,
79 					      const union bt_cap_set_member *member)
80 {
81 	if (member == NULL) {
82 		return NULL;
83 	}
84 
85 	if (type == BT_CAP_SET_TYPE_CSIP) {
86 		struct bt_cap_common_client *client;
87 
88 		/* We have verified that `client` won't be NULL in
89 		 * `valid_change_volume_param`.
90 		 */
91 
92 		client = bt_cap_common_get_client_by_csis(member->csip);
93 		if (client == NULL) {
94 			return NULL;
95 		}
96 
97 		return client->conn;
98 	}
99 
100 	return member->member;
101 }
102 
bt_cap_common_proc_is_active(void)103 bool bt_cap_common_proc_is_active(void)
104 {
105 	return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE);
106 }
107 
bt_cap_common_proc_is_aborted(void)108 bool bt_cap_common_proc_is_aborted(void)
109 {
110 	return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED);
111 }
112 
bt_cap_common_proc_all_handled(void)113 bool bt_cap_common_proc_all_handled(void)
114 {
115 	return active_proc.proc_done_cnt == active_proc.proc_initiated_cnt;
116 }
117 
bt_cap_common_proc_is_done(void)118 bool bt_cap_common_proc_is_done(void)
119 {
120 	return active_proc.proc_done_cnt == active_proc.proc_cnt;
121 }
122 
bt_cap_common_abort_proc(struct bt_conn * conn,int err)123 void bt_cap_common_abort_proc(struct bt_conn *conn, int err)
124 {
125 	if (bt_cap_common_proc_is_aborted()) {
126 		/* no-op */
127 		return;
128 	}
129 
130 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
131 	LOG_DBG("Aborting proc %d with subproc %d for %p: %d", active_proc.proc_type,
132 		active_proc.subproc_type, (void *)conn, err);
133 #else  /* !CONFIG_BT_CAP_INITIATOR_UNICAST */
134 	LOG_DBG("Aborting proc %d for %p: %d", active_proc.proc_type, (void *)conn, err);
135 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
136 
137 	active_proc.err = err;
138 	active_proc.failed_conn = conn;
139 	atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED);
140 }
141 
142 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
active_proc_is_initiator(void)143 static bool active_proc_is_initiator(void)
144 {
145 	switch (active_proc.proc_type) {
146 	case BT_CAP_COMMON_PROC_TYPE_START:
147 	case BT_CAP_COMMON_PROC_TYPE_UPDATE:
148 	case BT_CAP_COMMON_PROC_TYPE_STOP:
149 		return true;
150 	default:
151 		return false;
152 	}
153 }
154 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
155 
156 #if defined(CONFIG_BT_CAP_COMMANDER)
active_proc_is_commander(void)157 static bool active_proc_is_commander(void)
158 {
159 	switch (active_proc.proc_type) {
160 	case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE:
161 	case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE:
162 	case BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE:
163 	case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_GAIN_CHANGE:
164 	case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE:
165 	case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START:
166 	case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP:
167 	case BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE:
168 		return true;
169 	default:
170 		return false;
171 	}
172 }
173 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
174 
bt_cap_common_conn_in_active_proc(const struct bt_conn * conn)175 bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn)
176 {
177 	if (!bt_cap_common_proc_is_active()) {
178 		return false;
179 	}
180 
181 	for (size_t i = 0U; i < active_proc.proc_initiated_cnt; i++) {
182 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
183 		if (active_proc_is_initiator()) {
184 			if (active_proc.proc_param.initiator[i].stream->bap_stream.conn == conn) {
185 				return true;
186 			}
187 		}
188 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
189 #if defined(CONFIG_BT_CAP_COMMANDER)
190 		if (active_proc_is_commander()) {
191 			if (active_proc.proc_param.commander[i].conn == conn) {
192 				return true;
193 			}
194 		}
195 #endif /* CONFIG_BT_CAP_COMMANDER */
196 	}
197 
198 	return false;
199 }
200 
bt_cap_common_stream_in_active_proc(const struct bt_cap_stream * cap_stream)201 bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream)
202 {
203 	if (!bt_cap_common_proc_is_active()) {
204 		return false;
205 	}
206 
207 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
208 	if (active_proc_is_initiator()) {
209 		for (size_t i = 0U; i < active_proc.proc_cnt; i++) {
210 			if (active_proc.proc_param.initiator[i].stream == cap_stream) {
211 				return true;
212 			}
213 		}
214 	}
215 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
216 
217 	return false;
218 }
219 
bt_cap_common_disconnected(struct bt_conn * conn,uint8_t reason)220 void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason)
221 {
222 	struct bt_cap_common_client *client = bt_cap_common_get_client_by_acl(conn);
223 
224 	if (client->conn != NULL) {
225 		bt_conn_unref(client->conn);
226 	}
227 	(void)memset(client, 0, sizeof(*client));
228 
229 	if (bt_cap_common_conn_in_active_proc(conn)) {
230 		bt_cap_common_abort_proc(conn, -ENOTCONN);
231 	}
232 }
233 
234 BT_CONN_CB_DEFINE(conn_callbacks) = {
235 	.disconnected = bt_cap_common_disconnected,
236 };
237 
bt_cap_common_get_client_by_acl(const struct bt_conn * acl)238 struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl)
239 {
240 	if (acl == NULL) {
241 		return NULL;
242 	}
243 
244 	return &bt_cap_common_clients[bt_conn_index(acl)];
245 }
246 
247 struct bt_cap_common_client *
bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst * csis_inst)248 bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst)
249 {
250 	if (csis_inst == NULL) {
251 		return NULL;
252 	}
253 
254 	for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_common_clients); i++) {
255 		struct bt_cap_common_client *client = &bt_cap_common_clients[i];
256 
257 		if (client->csis_inst == csis_inst) {
258 			return client;
259 		}
260 	}
261 
262 	return NULL;
263 }
264 
cap_common_discover_complete(struct bt_conn * conn,int err,const struct bt_csip_set_coordinator_set_member * member,const struct bt_csip_set_coordinator_csis_inst * csis_inst)265 static void cap_common_discover_complete(struct bt_conn *conn, int err,
266 					 const struct bt_csip_set_coordinator_set_member *member,
267 					 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
268 {
269 	struct bt_cap_common_client *client;
270 
271 	client = bt_cap_common_get_client_by_acl(conn);
272 	if (client != NULL && client->discover_cb_func != NULL) {
273 		const bt_cap_common_discover_func_t cb_func = client->discover_cb_func;
274 
275 		client->discover_cb_func = NULL;
276 		cb_func(conn, err, member, csis_inst);
277 	}
278 }
279 
csis_client_discover_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_set_member * member,int err,size_t set_count)280 static void csis_client_discover_cb(struct bt_conn *conn,
281 				    const struct bt_csip_set_coordinator_set_member *member,
282 				    int err, size_t set_count)
283 {
284 	struct bt_cap_common_client *client;
285 
286 	if (err != 0) {
287 		LOG_DBG("CSIS client discover failed: %d", err);
288 
289 		cap_common_discover_complete(conn, err, NULL, NULL);
290 
291 		return;
292 	}
293 
294 	client = bt_cap_common_get_client_by_acl(conn);
295 	client->csis_inst =
296 		bt_csip_set_coordinator_csis_inst_by_handle(conn, client->csis_start_handle);
297 
298 	if (member == NULL || set_count == 0 || client->csis_inst == NULL) {
299 		LOG_ERR("Unable to find CSIS for CAS");
300 
301 		cap_common_discover_complete(conn, -ENODATA, NULL, NULL);
302 	} else {
303 		LOG_DBG("Found CAS with CSIS");
304 		cap_common_discover_complete(conn, 0, member, client->csis_inst);
305 	}
306 }
307 
bt_cap_common_discover_included_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)308 static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn,
309 						  const struct bt_gatt_attr *attr,
310 						  struct bt_gatt_discover_params *params)
311 {
312 	if (attr == NULL) {
313 		LOG_DBG("CAS CSIS include not found");
314 
315 		cap_common_discover_complete(conn, 0, NULL, NULL);
316 	} else {
317 		const struct bt_gatt_include *included_service = attr->user_data;
318 		struct bt_cap_common_client *client =
319 			CONTAINER_OF(params, struct bt_cap_common_client, param);
320 
321 		/* If the remote CAS includes CSIS, we first check if we
322 		 * have already discovered it, and if so we can just retrieve it
323 		 * and forward it to the application. If not, then we start
324 		 * CSIS discovery
325 		 */
326 		client->csis_start_handle = included_service->start_handle;
327 		client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle(
328 			conn, client->csis_start_handle);
329 		if (client->csis_inst == NULL) {
330 			static struct bt_csip_set_coordinator_cb csis_client_cb = {
331 				.discover = csis_client_discover_cb,
332 			};
333 			static bool csis_cbs_registered;
334 			int err;
335 
336 			LOG_DBG("CAS CSIS not known, discovering");
337 
338 			if (!csis_cbs_registered) {
339 				bt_csip_set_coordinator_register_cb(&csis_client_cb);
340 				csis_cbs_registered = true;
341 			}
342 
343 			err = bt_csip_set_coordinator_discover(conn);
344 			if (err != 0) {
345 				LOG_DBG("Discover failed (err %d)", err);
346 				cap_common_discover_complete(conn, err, NULL, NULL);
347 			}
348 		} else {
349 			const struct bt_csip_set_coordinator_set_member *member =
350 				bt_csip_set_coordinator_set_member_by_conn(conn);
351 
352 			LOG_DBG("Found CAS with CSIS");
353 
354 			cap_common_discover_complete(conn, 0, member, client->csis_inst);
355 		}
356 	}
357 
358 	return BT_GATT_ITER_STOP;
359 }
360 
bt_cap_common_discover_cas_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)361 static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
362 					     struct bt_gatt_discover_params *params)
363 {
364 	if (attr == NULL) {
365 		cap_common_discover_complete(conn, -ENODATA, NULL, NULL);
366 	} else {
367 		const struct bt_gatt_service_val *prim_service = attr->user_data;
368 		struct bt_cap_common_client *client =
369 			CONTAINER_OF(params, struct bt_cap_common_client, param);
370 		int err;
371 
372 		client->conn = bt_conn_ref(conn);
373 
374 		if (attr->handle == prim_service->end_handle) {
375 			LOG_DBG("Found CAS without CSIS");
376 			cap_common_discover_complete(conn, 0, NULL, NULL);
377 
378 			return BT_GATT_ITER_STOP;
379 		}
380 
381 		LOG_DBG("Found CAS, discovering included CSIS");
382 
383 		params->uuid = NULL;
384 		params->start_handle = attr->handle + 1;
385 		params->end_handle = prim_service->end_handle;
386 		params->type = BT_GATT_DISCOVER_INCLUDE;
387 		params->func = bt_cap_common_discover_included_cb;
388 
389 		err = bt_gatt_discover(conn, params);
390 		if (err != 0) {
391 			LOG_DBG("Discover failed (err %d)", err);
392 
393 			cap_common_discover_complete(conn, err, NULL, NULL);
394 		}
395 	}
396 
397 	return BT_GATT_ITER_STOP;
398 }
399 
bt_cap_common_discover(struct bt_conn * conn,bt_cap_common_discover_func_t func)400 int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func)
401 {
402 	struct bt_gatt_discover_params *param;
403 	struct bt_cap_common_client *client;
404 	int err;
405 
406 	client = bt_cap_common_get_client_by_acl(conn);
407 	if (client->discover_cb_func != NULL) {
408 		return -EBUSY;
409 	}
410 
411 	param = &client->param;
412 	param->func = bt_cap_common_discover_cas_cb;
413 	param->uuid = cas_uuid;
414 	param->type = BT_GATT_DISCOVER_PRIMARY;
415 	param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
416 	param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
417 
418 	client->discover_cb_func = func;
419 
420 	err = bt_gatt_discover(conn, param);
421 	if (err != 0) {
422 		client->discover_cb_func = NULL;
423 
424 		/* Report expected possible errors */
425 		if (err == -ENOTCONN || err == -ENOMEM) {
426 			return err;
427 		}
428 
429 		LOG_DBG("Unexpected err %d from bt_gatt_discover", err);
430 		return -ENOEXEC;
431 	}
432 
433 	return 0;
434 }
435