1 /* btp_csip.c - Bluetooth CSIP Tester */
2 
3 /*
4  * Copyright (c) 2023 Codecoup
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 #include "btp/btp.h"
9 #include <zephyr/bluetooth/audio/csip.h>
10 
11 #include "../bluetooth/audio/csip_internal.h"
12 #include <zephyr/logging/log.h>
13 #define LOG_MODULE_NAME bttester_csip
14 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
15 
16 const struct bt_csip_set_coordinator_set_member *btp_csip_set_members[CONFIG_BT_MAX_CONN];
17 static const struct bt_csip_set_coordinator_csis_inst *cur_csis_inst;
18 static struct bt_csip_set_coordinator_svc_inst *csip_inst;
19 static uint8_t members_count;
20 
btp_csip_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)21 static uint8_t btp_csip_supported_commands(const void *cmd, uint16_t cmd_len,
22 					   void *rsp, uint16_t *rsp_len)
23 {
24 	struct btp_csip_read_supported_commands_rp *rp = rsp;
25 
26 	/* octet 0 */
27 	tester_set_bit(rp->data, BTP_CSIP_READ_SUPPORTED_COMMANDS);
28 	tester_set_bit(rp->data, BTP_CSIP_DISCOVER);
29 	tester_set_bit(rp->data, BTP_CSIP_START_ORDERED_ACCESS);
30 	tester_set_bit(rp->data, BTP_CSIP_SET_COORDINATOR_LOCK);
31 	tester_set_bit(rp->data, BTP_CSIP_SET_COORDINATOR_RELEASE);
32 
33 	*rsp_len = sizeof(*rp) + 1;
34 
35 	return BTP_STATUS_SUCCESS;
36 }
37 
btp_send_csip_discovered_ev(struct bt_conn * conn,uint16_t sirk_handle,uint16_t size_handle,uint16_t lock_handle,uint16_t rank_handle,uint8_t status)38 static void btp_send_csip_discovered_ev(struct bt_conn *conn, uint16_t sirk_handle,
39 					uint16_t size_handle, uint16_t lock_handle,
40 					uint16_t rank_handle, uint8_t status)
41 {
42 	struct btp_csip_discovered_ev ev;
43 
44 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
45 
46 	ev.status = status;
47 	ev.sirk_handle = sys_cpu_to_le16(sirk_handle);
48 	ev.size_handle = sys_cpu_to_le16(size_handle);
49 	ev.lock_handle = sys_cpu_to_le16(lock_handle);
50 	ev.rank_handle = sys_cpu_to_le16(rank_handle);
51 
52 	tester_event(BTP_SERVICE_ID_CSIP, BTP_CSIP_DISCOVERED_EV, &ev, sizeof(ev));
53 }
54 
btp_send_csip_sirk_ev(struct bt_conn * conn,uint8_t * sirk,size_t sirk_size)55 static void btp_send_csip_sirk_ev(struct bt_conn *conn, uint8_t *sirk, size_t sirk_size)
56 {
57 	struct btp_csip_sirk_ev ev;
58 
59 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
60 
61 	memcpy(ev.sirk, sirk, sirk_size);
62 
63 	tester_event(BTP_SERVICE_ID_CSIP, BTP_CSIP_SIRK_EV, &ev, sizeof(ev));
64 }
65 
btp_send_csip_lock_ev(int err)66 static void btp_send_csip_lock_ev(int err)
67 {
68 	struct btp_csip_lock_ev ev;
69 
70 	ev.status = err;
71 
72 	tester_event(BTP_SERVICE_ID_CSIP, BTP_CSIP_LOCK_EV, &ev, sizeof(ev));
73 }
74 
csip_set_coordinator_lock_set_cb(int err)75 static void csip_set_coordinator_lock_set_cb(int err)
76 {
77 	LOG_DBG("");
78 
79 	btp_send_csip_lock_ev(err);
80 }
81 
csip_set_coordinator_lock_release_cb(int err)82 static void csip_set_coordinator_lock_release_cb(int err)
83 {
84 	LOG_DBG("");
85 
86 	btp_send_csip_lock_ev(err);
87 }
88 
csip_discover_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_set_member * member,int err,size_t set_count)89 static void csip_discover_cb(struct bt_conn *conn,
90 			     const struct bt_csip_set_coordinator_set_member *member,
91 			     int err, size_t set_count)
92 {
93 	LOG_DBG("");
94 
95 	uint8_t sirk[BT_CSIP_SIRK_SIZE];
96 	size_t sirk_size = ARRAY_SIZE(sirk);
97 	uint8_t conn_index;
98 
99 	if (err != 0) {
100 		LOG_DBG("discover failed (%d)", err);
101 		return;
102 	}
103 
104 	if (set_count == 0) {
105 		LOG_DBG("Device has no sets");
106 		return;
107 	}
108 
109 	conn_index = bt_conn_index(conn);
110 
111 	LOG_DBG("Found %zu sets on member[%u]", set_count, conn_index);
112 
113 	cur_csis_inst = &member->insts[0];
114 
115 	memcpy(sirk, cur_csis_inst->info.sirk, sizeof(cur_csis_inst->info.sirk));
116 
117 	btp_send_csip_sirk_ev(conn, sirk, sirk_size);
118 
119 	for (size_t i = 0U; i < set_count; i++) {
120 		LOG_DBG("CSIS[%zu]: %p", i, &member->insts[i]);
121 		LOG_DBG("Rank: %u", member->insts[i].info.rank);
122 		LOG_DBG("Set Size: %u", member->insts[i].info.set_size);
123 		LOG_DBG("Lockable: %u", member->insts[i].info.lockable);
124 	}
125 
126 	btp_csip_set_members[conn_index] = member;
127 
128 	csip_inst = bt_csip_set_coordinator_lookup_instance_by_index(conn, conn_index);
129 	btp_send_csip_discovered_ev(conn, csip_inst->sirk_handle, csip_inst->set_size_handle,
130 				    csip_inst->set_lock_handle, csip_inst->rank_handle, err);
131 }
132 
csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst * inst,bool locked)133 static void csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst,
134 				 bool locked)
135 {
136 	LOG_DBG("");
137 }
138 
csip_set_coordinator_ordered_access_cb(const struct bt_csip_set_coordinator_set_info * set_info,int err,bool locked,struct bt_csip_set_coordinator_set_member * member)139 static void csip_set_coordinator_ordered_access_cb(
140 	const struct bt_csip_set_coordinator_set_info *set_info, int err,
141 	bool locked,  struct bt_csip_set_coordinator_set_member *member)
142 {
143 	LOG_DBG("");
144 
145 	if (err) {
146 		LOG_ERR("Ordered access failed with err %d", err);
147 	} else if (locked) {
148 		LOG_DBG("Ordered access procedure locked member %p", member);
149 	} else {
150 		LOG_DBG("Ordered access procedure finished");
151 	}
152 }
153 
154 static struct bt_csip_set_coordinator_cb set_coordinator_cbs = {
155 	.lock_set = csip_set_coordinator_lock_set_cb,
156 	.release_set = csip_set_coordinator_lock_release_cb,
157 	.discover = csip_discover_cb,
158 	.lock_changed = csip_lock_changed_cb,
159 	.ordered_access = csip_set_coordinator_ordered_access_cb
160 };
161 
csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info * set_info,struct bt_csip_set_coordinator_set_member * members[],size_t count)162 static bool csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info *set_info,
163 					struct bt_csip_set_coordinator_set_member *members[],
164 					size_t count)
165 {
166 	for (size_t i = 0; i < count; i++) {
167 		LOG_DBG("Ordered access for members[%zu]: %p", i, members[i]);
168 	}
169 
170 	return true;
171 }
172 
btp_csip_discover(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)173 static uint8_t btp_csip_discover(const void *cmd, uint16_t cmd_len,
174 				 void *rsp, uint16_t *rsp_len)
175 {
176 	int err;
177 	struct bt_conn *conn;
178 	const struct btp_csip_discover_cmd *cp = cmd;
179 
180 	conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
181 	if (!conn) {
182 		LOG_ERR("Unknown connection");
183 
184 		return BTP_STATUS_FAILED;
185 	}
186 
187 	err = bt_csip_set_coordinator_discover(conn);
188 	bt_conn_unref(conn);
189 
190 	return BTP_STATUS_VAL(err);
191 }
192 
get_available_members(const struct bt_csip_set_coordinator_set_member ** members)193 static int get_available_members(const struct bt_csip_set_coordinator_set_member **members)
194 {
195 	members_count = 0;
196 
197 	if (cur_csis_inst == NULL) {
198 		LOG_ERR("No CISP instance available");
199 		return BTP_STATUS_FAILED;
200 	}
201 
202 	for (size_t i = 0; i < (size_t)ARRAY_SIZE(btp_csip_set_members); i++) {
203 		if (btp_csip_set_members[i] == NULL) {
204 			continue;
205 		}
206 
207 		members[members_count++] = btp_csip_set_members[i];
208 	}
209 
210 	if (members_count == 0) {
211 		LOG_ERR("No set members available");
212 		return BTP_STATUS_FAILED;
213 	}
214 
215 	return BTP_STATUS_SUCCESS;
216 }
217 
btp_csip_set_coordinator_lock(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)218 static uint8_t btp_csip_set_coordinator_lock(const void *cmd, uint16_t cmd_len, void *rsp,
219 					     uint16_t *rsp_len)
220 {
221 	const struct bt_csip_set_coordinator_set_member *members[ARRAY_SIZE(btp_csip_set_members)];
222 	const struct btp_csip_set_coordinator_lock_cmd *cp = cmd;
223 	int err;
224 	int rc;
225 
226 	LOG_DBG("");
227 
228 	if (cp->addr_cnt != 0) {
229 		/* TODO: add support for lock request procedure on subset of set members */
230 		return BTP_STATUS_FAILED;
231 	}
232 
233 	rc = get_available_members(members);
234 
235 	if (rc) {
236 		return BTP_STATUS_FAILED;
237 	}
238 
239 	err = bt_csip_set_coordinator_lock(members, members_count, &cur_csis_inst->info);
240 
241 	if (err) {
242 		LOG_DBG("Failed to lock set members");
243 		return BTP_STATUS_FAILED;
244 	}
245 
246 	return BTP_STATUS_SUCCESS;
247 }
248 
btp_csip_set_coordinator_release(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)249 static uint8_t btp_csip_set_coordinator_release(const void *cmd, uint16_t cmd_len, void *rsp,
250 					     uint16_t *rsp_len)
251 {
252 	const struct bt_csip_set_coordinator_set_member *members[ARRAY_SIZE(btp_csip_set_members)];
253 	const struct btp_csip_set_coordinator_release_cmd *cp = cmd;
254 	int err;
255 	int rc;
256 
257 	LOG_DBG("");
258 
259 	if (cp->addr_cnt != 0) {
260 		/* TODO: add support for lock release procedure on subset of set members */
261 		return BTP_STATUS_FAILED;
262 	}
263 
264 	rc = get_available_members(members);
265 
266 	if (rc) {
267 		return BTP_STATUS_FAILED;
268 	}
269 
270 	err = bt_csip_set_coordinator_release(members, members_count, &cur_csis_inst->info);
271 
272 	if (err) {
273 		LOG_DBG("Failed to release set members");
274 		return BTP_STATUS_FAILED;
275 	}
276 
277 	return BTP_STATUS_SUCCESS;
278 }
279 
btp_csip_start_ordered_access(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)280 static uint8_t btp_csip_start_ordered_access(const void *cmd, uint16_t cmd_len,
281 					     void *rsp, uint16_t *rsp_len)
282 {
283 	const struct bt_csip_set_coordinator_set_member *members[ARRAY_SIZE(btp_csip_set_members)];
284 	unsigned long member_count = 0;
285 	int err;
286 
287 	LOG_DBG("");
288 
289 	if (cur_csis_inst == NULL) {
290 		LOG_ERR("No CISP instance available");
291 
292 		return BTP_STATUS_FAILED;
293 	}
294 
295 	for (size_t i = 0; i < (size_t)ARRAY_SIZE(btp_csip_set_members); i++) {
296 		if (btp_csip_set_members[i] == NULL) {
297 			continue;
298 		}
299 
300 		members[member_count++] = btp_csip_set_members[i];
301 	}
302 
303 	if (member_count == 0) {
304 		LOG_ERR("No set members available");
305 
306 		return BTP_STATUS_FAILED;
307 	}
308 
309 	err = bt_csip_set_coordinator_ordered_access(members,
310 						     member_count,
311 						     &cur_csis_inst->info,
312 						     csip_set_coordinator_oap_cb);
313 
314 	return BTP_STATUS_VAL(err);
315 }
316 
317 static const struct btp_handler csip_handlers[] = {
318 	{
319 		.opcode = BTP_CSIP_READ_SUPPORTED_COMMANDS,
320 		.index = BTP_INDEX_NONE,
321 		.expect_len = 0,
322 		.func = btp_csip_supported_commands
323 	},
324 	{
325 		.opcode = BTP_CSIP_DISCOVER,
326 		.expect_len = sizeof(struct btp_csip_discover_cmd),
327 		.func = btp_csip_discover
328 	},
329 	{
330 		.opcode = BTP_CSIP_START_ORDERED_ACCESS,
331 		.expect_len = sizeof(struct btp_csip_start_ordered_access_cmd),
332 		.func = btp_csip_start_ordered_access
333 	},
334 	{
335 		.opcode = BTP_CSIP_SET_COORDINATOR_LOCK,
336 		.expect_len = sizeof(struct btp_csip_set_coordinator_lock_cmd),
337 		.func = btp_csip_set_coordinator_lock,
338 	},
339 	{
340 		.opcode = BTP_CSIP_SET_COORDINATOR_RELEASE,
341 		.expect_len = sizeof(struct btp_csip_set_coordinator_release_cmd),
342 		.func = btp_csip_set_coordinator_release,
343 	},
344 };
345 
tester_init_csip(void)346 uint8_t tester_init_csip(void)
347 {
348 	bt_csip_set_coordinator_register_cb(&set_coordinator_cbs);
349 
350 	tester_register_command_handlers(BTP_SERVICE_ID_CSIP, csip_handlers,
351 					 ARRAY_SIZE(csip_handlers));
352 
353 	return BTP_STATUS_SUCCESS;
354 }
355 
tester_unregister_csip(void)356 uint8_t tester_unregister_csip(void)
357 {
358 	return BTP_STATUS_SUCCESS;
359 }
360