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