1 /** @file
2  *  @brief Bluetooth Object Transfer Client
3  *
4  * Copyright (c) 2020-2022 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/bluetooth/uuid.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/types.h>
12 
13 #include <zephyr/device.h>
14 #include <zephyr/init.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/sys/check.h>
17 
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/gatt.h>
21 #include <zephyr/bluetooth/l2cap.h>
22 
23 #include <zephyr/bluetooth/services/ots.h>
24 #include "ots_internal.h"
25 #include "ots_client_internal.h"
26 #include "ots_l2cap_internal.h"
27 #include "ots_dir_list_internal.h"
28 #include "ots_oacp_internal.h"
29 #include "ots_olcp_internal.h"
30 
31 #define LOG_LEVEL CONFIG_BT_OTS_CLIENT_LOG_LEVEL
32 #include <zephyr/logging/log.h>
33 LOG_MODULE_REGISTER(bt_otc);
34 
35 /* TODO: KConfig options */
36 #define OTS_CLIENT_INST_COUNT     1
37 
38 #define OTS_CLIENT_MAX_WRITE_SIZE    23
39 /* 64-bit value, outside of 48-bit Object ID range */
40 #define OTS_CLIENT_UNKNOWN_ID      0x0001000000000000
41 
42 struct dirlisting_record_t {
43 	uint16_t                      len;
44 	uint8_t                       flags;
45 	uint8_t                       name_len;
46 	struct bt_ots_obj_metadata    metadata;
47 };
48 
49 /**@brief String literals for the OACP result codes. Used for logging output.*/
50 static const char * const lit_request[] = {
51 	"RFU",
52 	"Create",
53 	"Delete",
54 	"Calculate Checksum",
55 	"Execute",
56 	"Read",
57 	"Write",
58 	"Abort",
59 };
60 
61 /**@brief String literals for the OACP result codes. Used for logging output.*/
62 static const char * const lit_result[] = {
63 	"RFU",
64 	"Success",
65 	"Op Code Not Supported",
66 	"Invalid Parameter",
67 	"Insufficient Resources",
68 	"Invalid Object",
69 	"Channel Unavailable",
70 	"Unsupported Type",
71 	"Procedure Not Permitted",
72 	"Object Locked",
73 	"Operation Failed"
74 };
75 
76 /**@brief String literals for the OLCP request codes. Used for logging output.*/
77 static const char * const lit_olcp_request[] = {
78 	"RFU",
79 	"FIRST",
80 	"LAST",
81 	"PREV",
82 	"NEXT",
83 	"GOTO",
84 	"ORDER",
85 	"REQ_NUM_OBJS",
86 	"CLEAR_MARKING",
87 };
88 
89 /**@brief String literals for the OLCP result codes. Used for logging output.*/
90 static const char * const lit_olcp_result[] = {
91 	"RFU",
92 	"Success",
93 	"Op Code Not Supported",
94 	"Invalid Parameter",
95 	"Operation Failed",
96 	"Out of Bonds",
97 	"Too Many Objects",
98 	"No Object",
99 	"Object ID not found",
100 };
101 
102 struct bt_otc_internal_instance_t {
103 	struct bt_ots_client *otc_inst;
104 	struct bt_gatt_ots_l2cap l2cap_ctx;
105 	bool busy;
106 	/** Bitfield that is used to determine how much metadata to read */
107 	uint8_t metadata_to_read;
108 	/** Bitfield of how much metadata has been attempted to read */
109 	uint8_t metadata_read_attempted;
110 	/** Bitfield of how much metadata has been read */
111 	uint8_t metadata_read;
112 	int metadata_err;
113 	uint32_t rcvd_size;
114 	uint32_t sent_size;
115 };
116 
117 /* The profile clients that uses the OTS are responsible for discovery and
118  * will simply register any OTS instances as pointers, which is stored here.
119  */
120 static struct bt_otc_internal_instance_t otc_insts[OTS_CLIENT_INST_COUNT];
121 NET_BUF_SIMPLE_DEFINE_STATIC(otc_tx_buf, OTS_CLIENT_MAX_WRITE_SIZE);
122 static struct bt_otc_internal_instance_t *cur_inst;
123 
124 static int oacp_read(struct bt_conn *conn,
125 		     struct bt_otc_internal_instance_t *inst);
126 static int oacp_write(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
127 		      const void *buf, uint32_t len, uint32_t offset,
128 		      enum bt_ots_oacp_write_op_mode mode);
129 static int oacp_checksum(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
130 			 uint32_t offset, uint32_t len);
131 static void read_next_metadata(struct bt_conn *conn,
132 			       struct bt_otc_internal_instance_t *inst);
133 static int read_attr(struct bt_conn *conn,
134 		     struct bt_otc_internal_instance_t *inst,
135 		     uint16_t handle, bt_gatt_read_func_t cb);
136 
137 /* L2CAP callbacks */
tx_done(struct bt_gatt_ots_l2cap * l2cap_ctx,struct bt_conn * conn)138 static void tx_done(struct bt_gatt_ots_l2cap *l2cap_ctx,
139 		    struct bt_conn *conn)
140 {
141 	/* Not doing any writes yet */
142 	LOG_ERR("Unexpected call, context: %p, conn: %p", l2cap_ctx, (void *)conn);
143 }
144 
write_obj_tx_done(struct bt_gatt_ots_l2cap * l2cap_ctx,struct bt_conn * conn)145 static void write_obj_tx_done(struct bt_gatt_ots_l2cap *l2cap_ctx,
146 			      struct bt_conn *conn)
147 {
148 	int err;
149 	size_t written;
150 
151 	if (cur_inst == NULL) {
152 		LOG_ERR("OTS instance invalid\n");
153 		return;
154 	}
155 
156 	written = cur_inst->sent_size;
157 	LOG_DBG("ctx: %p, conn: %p, written: %d", l2cap_ctx, (void *)conn, written);
158 
159 	err = bt_gatt_ots_l2cap_disconnect(l2cap_ctx);
160 	if (err < 0) {
161 		LOG_WRN("Disconnecting L2CAP returned error %d", err);
162 	}
163 
164 	if ((cur_inst->otc_inst != NULL) && (cur_inst->otc_inst->cb != NULL)) {
165 		if (cur_inst->otc_inst->cb->obj_data_written) {
166 			cur_inst->otc_inst->cb->obj_data_written(0, conn, written);
167 		}
168 	}
169 
170 	cur_inst = NULL;
171 }
172 
rx_done(struct bt_gatt_ots_l2cap * l2cap_ctx,struct bt_conn * conn,struct net_buf * buf)173 static ssize_t rx_done(struct bt_gatt_ots_l2cap *l2cap_ctx,
174 		       struct bt_conn *conn, struct net_buf *buf)
175 {
176 	const uint32_t offset = cur_inst->rcvd_size;
177 	bool is_complete = false;
178 	const struct bt_ots_obj_metadata *cur_object =
179 		&cur_inst->otc_inst->cur_object;
180 	int cb_ret;
181 
182 	LOG_DBG("Incoming L2CAP data, context: %p, conn: %p, len: %u, offset: %u", l2cap_ctx,
183 		(void *)conn, buf->len, offset);
184 
185 	cur_inst->rcvd_size += buf->len;
186 
187 	if (cur_inst->rcvd_size >= cur_object->size.cur) {
188 		is_complete = true;
189 	}
190 
191 	if (cur_inst->rcvd_size > cur_object->size.cur) {
192 		LOG_WRN("Received %u but expected maximum %u", cur_inst->rcvd_size,
193 			cur_object->size.cur);
194 	}
195 
196 	cb_ret = cur_inst->otc_inst->cb->obj_data_read(0, conn, offset,
197 						       buf->len, buf->data,
198 						       is_complete);
199 
200 	if (is_complete) {
201 		const uint32_t rcv_size = cur_object->size.cur;
202 		int err;
203 
204 		LOG_DBG("Received the whole object (%u bytes). "
205 		       "Disconnecting L2CAP CoC", rcv_size);
206 		err = bt_gatt_ots_l2cap_disconnect(l2cap_ctx);
207 		if (err < 0) {
208 			LOG_WRN("Disconnecting L2CAP returned error %d", err);
209 		}
210 
211 		cur_inst = NULL;
212 	} else if (cb_ret == BT_OTS_STOP) {
213 		const uint32_t rcv_size = cur_object->size.cur;
214 		int err;
215 
216 		LOG_DBG("Stopped receiving after%u bytes. "
217 		       "Disconnecting L2CAP CoC", rcv_size);
218 		err = bt_gatt_ots_l2cap_disconnect(l2cap_ctx);
219 
220 		if (err < 0) {
221 			LOG_WRN("Disconnecting L2CAP returned error %d", err);
222 		}
223 
224 		cur_inst = NULL;
225 	}
226 
227 	return 0;
228 }
229 
chan_closed(struct bt_gatt_ots_l2cap * l2cap_ctx,struct bt_conn * conn)230 static void chan_closed(struct bt_gatt_ots_l2cap *l2cap_ctx,
231 			struct bt_conn *conn)
232 {
233 	LOG_DBG("L2CAP closed, context: %p, conn: %p", l2cap_ctx, (void *)conn);
234 	if (cur_inst) {
235 		cur_inst = NULL;
236 	}
237 }
238 /* End L2CAP callbacks */
239 
print_oacp_response(enum bt_gatt_ots_oacp_proc_type req_opcode,enum bt_gatt_ots_oacp_res_code result_code)240 static void print_oacp_response(enum bt_gatt_ots_oacp_proc_type req_opcode,
241 				enum bt_gatt_ots_oacp_res_code result_code)
242 {
243 	LOG_DBG("Request OP Code: %s", lit_request[req_opcode]);
244 	LOG_DBG("Result Code    : %s", lit_result[result_code]);
245 }
246 
print_olcp_response(enum bt_gatt_ots_olcp_proc_type req_opcode,enum bt_gatt_ots_olcp_res_code result_code)247 static void print_olcp_response(enum bt_gatt_ots_olcp_proc_type req_opcode,
248 				enum bt_gatt_ots_olcp_res_code result_code)
249 {
250 	LOG_DBG("Request OP Code: %s", lit_olcp_request[req_opcode]);
251 	LOG_DBG("Result Code    : %s", lit_olcp_result[result_code]);
252 }
253 
date_time_decode(struct net_buf_simple * buf,struct bt_ots_date_time * p_date_time)254 static void date_time_decode(struct net_buf_simple *buf,
255 			     struct bt_ots_date_time *p_date_time)
256 {
257 	p_date_time->year = net_buf_simple_pull_le16(buf);
258 	p_date_time->month = net_buf_simple_pull_u8(buf);
259 	p_date_time->day = net_buf_simple_pull_u8(buf);
260 	p_date_time->hours = net_buf_simple_pull_u8(buf);
261 	p_date_time->minutes = net_buf_simple_pull_u8(buf);
262 	p_date_time->seconds = net_buf_simple_pull_u8(buf);
263 }
264 
lookup_inst_by_handle(uint16_t handle)265 static struct bt_otc_internal_instance_t *lookup_inst_by_handle(uint16_t handle)
266 {
267 	for (int i = 0; i < ARRAY_SIZE(otc_insts); i++) {
268 		if (otc_insts[i].otc_inst &&
269 		    otc_insts[i].otc_inst->start_handle <= handle &&
270 		    otc_insts[i].otc_inst->end_handle >= handle) {
271 			return &otc_insts[i];
272 		}
273 	}
274 
275 	LOG_DBG("Could not find OTS instance with handle 0x%04x", handle);
276 
277 	return NULL;
278 }
279 
on_object_selected(struct bt_conn * conn,enum bt_gatt_ots_olcp_res_code res,struct bt_ots_client * otc_inst)280 static void on_object_selected(struct bt_conn *conn,
281 			       enum bt_gatt_ots_olcp_res_code res,
282 			       struct bt_ots_client *otc_inst)
283 {
284 	memset(&otc_inst->cur_object, 0, sizeof(otc_inst->cur_object));
285 	otc_inst->cur_object.id = OTS_CLIENT_UNKNOWN_ID;
286 
287 	if (otc_inst->cb->obj_selected) {
288 		otc_inst->cb->obj_selected(otc_inst, conn, res);
289 	}
290 
291 	LOG_DBG("Object selected");
292 }
293 
olcp_ind_handler(struct bt_conn * conn,struct bt_ots_client * otc_inst,const void * data,uint16_t length)294 static void olcp_ind_handler(struct bt_conn *conn,
295 			     struct bt_ots_client *otc_inst,
296 			     const void *data, uint16_t length)
297 {
298 	enum bt_gatt_ots_olcp_proc_type op_code;
299 	struct net_buf_simple net_buf;
300 
301 	if (length < sizeof(op_code)) {
302 		LOG_DBG("Invalid indication length: %u", length);
303 		return;
304 	}
305 
306 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
307 
308 	op_code = net_buf_simple_pull_u8(&net_buf);
309 
310 	LOG_DBG("OLCP indication");
311 
312 	if (op_code == BT_GATT_OTS_OLCP_PROC_RESP) {
313 		if (net_buf.len < (sizeof(uint8_t) + sizeof(uint8_t))) {
314 			LOG_DBG("Invalid indication length for op_code %u: %u", op_code,
315 				net_buf.len);
316 			return;
317 		}
318 
319 		enum bt_gatt_ots_olcp_proc_type req_opcode =
320 			net_buf_simple_pull_u8(&net_buf);
321 		enum bt_gatt_ots_olcp_res_code result_code =
322 			net_buf_simple_pull_u8(&net_buf);
323 
324 		print_olcp_response(req_opcode, result_code);
325 
326 		switch (req_opcode) {
327 		case BT_GATT_OTS_OLCP_PROC_FIRST:
328 			LOG_DBG("First");
329 			on_object_selected(conn, result_code, otc_inst);
330 			break;
331 		case BT_GATT_OTS_OLCP_PROC_LAST:
332 			LOG_DBG("Last");
333 			on_object_selected(conn, result_code, otc_inst);
334 			break;
335 		case BT_GATT_OTS_OLCP_PROC_PREV:
336 			LOG_DBG("Previous");
337 			on_object_selected(conn, result_code, otc_inst);
338 			break;
339 		case BT_GATT_OTS_OLCP_PROC_NEXT:
340 			LOG_DBG("Next");
341 			on_object_selected(conn, result_code, otc_inst);
342 			break;
343 		case BT_GATT_OTS_OLCP_PROC_GOTO:
344 			LOG_DBG("Goto");
345 			on_object_selected(conn, result_code, otc_inst);
346 			break;
347 		case BT_GATT_OTS_OLCP_PROC_ORDER:
348 			LOG_DBG("Order");
349 			on_object_selected(conn, result_code, otc_inst);
350 			break;
351 		case BT_GATT_OTS_OLCP_PROC_REQ_NUM_OBJS:
352 			LOG_DBG("Request number of objects");
353 			if (net_buf.len == sizeof(uint32_t)) {
354 				uint32_t obj_cnt =
355 					net_buf_simple_pull_le32(&net_buf);
356 				LOG_DBG("Number of objects %u", obj_cnt);
357 			}
358 			break;
359 		case BT_GATT_OTS_OLCP_PROC_CLEAR_MARKING:
360 			LOG_DBG("Clear marking");
361 			break;
362 		default:
363 			LOG_DBG("Invalid indication req opcode %u", req_opcode);
364 			break;
365 		}
366 	} else {
367 		LOG_DBG("Invalid indication opcode %u", op_code);
368 	}
369 }
370 
oacp_ind_handler(struct bt_conn * conn,struct bt_ots_client * otc_inst,const void * data,uint16_t length)371 static void oacp_ind_handler(struct bt_conn *conn,
372 			     struct bt_ots_client *otc_inst,
373 			     const void *data, uint16_t length)
374 {
375 	enum bt_gatt_ots_oacp_proc_type op_code;
376 	enum bt_gatt_ots_oacp_proc_type req_opcode;
377 	enum bt_gatt_ots_oacp_res_code result_code;
378 	uint32_t checksum;
379 	struct net_buf_simple net_buf;
380 
381 	if (length < sizeof(op_code)) {
382 		LOG_DBG("Invalid indication length: %u", length);
383 		return;
384 	}
385 
386 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
387 
388 	op_code = net_buf_simple_pull_u8(&net_buf);
389 
390 	LOG_DBG("OACP indication");
391 
392 	if (op_code == BT_GATT_OTS_OACP_PROC_RESP) {
393 		if (net_buf.len >= (sizeof(req_opcode) + sizeof(result_code))) {
394 			req_opcode = net_buf_simple_pull_u8(&net_buf);
395 			result_code = net_buf_simple_pull_u8(&net_buf);
396 		} else {
397 			LOG_ERR("Invalid indication data len %u", net_buf.len);
398 			return;
399 		}
400 
401 		if (req_opcode == BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC) {
402 			if (net_buf.len == sizeof(checksum)) {
403 				checksum = net_buf_simple_pull_le32(&net_buf);
404 				LOG_DBG("Object checksum 0x%08x\n", checksum);
405 				if (otc_inst->cb->obj_checksum_calculated) {
406 					otc_inst->cb->obj_checksum_calculated(
407 						otc_inst, conn, result_code, checksum);
408 				}
409 			} else {
410 				LOG_ERR("Invalid indication data len %u after opcode and result "
411 					"pulled", net_buf.len);
412 				return;
413 			}
414 		}
415 
416 		print_oacp_response(req_opcode, result_code);
417 	} else {
418 		LOG_DBG("Invalid indication opcode %u", op_code);
419 	}
420 }
421 
bt_ots_client_indicate_handler(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)422 uint8_t bt_ots_client_indicate_handler(struct bt_conn *conn,
423 				       struct bt_gatt_subscribe_params *params,
424 				       const void *data, uint16_t length)
425 {
426 	uint16_t handle = params->value_handle;
427 	struct bt_otc_internal_instance_t *inst;
428 
429 	if (conn == NULL) {
430 		return BT_GATT_ITER_CONTINUE;
431 	}
432 
433 	inst = lookup_inst_by_handle(handle);
434 
435 	/* TODO: Can we somehow avoid exposing this
436 	 * callback via the public API?
437 	 */
438 
439 	if (!inst) {
440 		LOG_ERR("Instance not found");
441 		return BT_GATT_ITER_STOP;
442 	}
443 
444 	inst->busy = false;
445 
446 	if (data) {
447 		if (handle == inst->otc_inst->olcp_handle) {
448 			olcp_ind_handler(conn, inst->otc_inst, data, length);
449 		} else if (handle == inst->otc_inst->oacp_handle) {
450 			oacp_ind_handler(conn, inst->otc_inst, data, length);
451 		}
452 	}
453 	return BT_GATT_ITER_CONTINUE;
454 }
455 
read_feature_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)456 static uint8_t read_feature_cb(struct bt_conn *conn, uint8_t err,
457 			       struct bt_gatt_read_params *params,
458 			       const void *data, uint16_t length)
459 {
460 	uint8_t cb_err = err;
461 	struct bt_otc_internal_instance_t *inst =
462 		lookup_inst_by_handle(params->single.handle);
463 	struct net_buf_simple net_buf;
464 
465 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
466 
467 	if (!inst) {
468 		LOG_ERR("Instance not found");
469 		return BT_GATT_ITER_STOP;
470 	}
471 
472 	inst->busy = false;
473 
474 	if (err) {
475 		LOG_DBG("err: 0x%02X", err);
476 	} else if (data) {
477 		if (length == OTS_FEATURE_LEN) {
478 			inst->otc_inst->features.oacp =
479 				net_buf_simple_pull_le32(&net_buf);
480 
481 			inst->otc_inst->features.olcp =
482 				net_buf_simple_pull_le32(&net_buf);
483 
484 			LOG_DBG("features : oacp 0x%x, olcp 0x%x", inst->otc_inst->features.oacp,
485 				inst->otc_inst->features.olcp);
486 		} else {
487 			LOG_DBG("Invalid length %u (expected %u)", length, OTS_FEATURE_LEN);
488 			cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
489 		}
490 	}
491 
492 	return BT_GATT_ITER_STOP;
493 }
494 
bt_ots_client_register(struct bt_ots_client * otc_inst)495 int bt_ots_client_register(struct bt_ots_client *otc_inst)
496 {
497 	for (int i = 0; i < ARRAY_SIZE(otc_insts); i++) {
498 		int err;
499 
500 		if (otc_insts[i].otc_inst) {
501 			continue;
502 		}
503 
504 		LOG_DBG("%u", i);
505 		err = bt_gatt_ots_l2cap_register(&otc_insts[i].l2cap_ctx);
506 		if (err) {
507 			LOG_WRN("Could not register L2CAP context %d", err);
508 			return err;
509 		}
510 
511 		otc_insts[i].otc_inst = otc_inst;
512 		return 0;
513 	}
514 
515 	return -ENOMEM;
516 }
517 
bt_ots_client_unregister(uint8_t index)518 int bt_ots_client_unregister(uint8_t index)
519 {
520 	if (index < ARRAY_SIZE(otc_insts)) {
521 		memset(&otc_insts[index], 0, sizeof(otc_insts[index]));
522 	} else {
523 		return -EINVAL;
524 	}
525 
526 	return 0;
527 }
528 
bt_ots_client_read_feature(struct bt_ots_client * otc_inst,struct bt_conn * conn)529 int bt_ots_client_read_feature(struct bt_ots_client *otc_inst,
530 			       struct bt_conn *conn)
531 {
532 	if (OTS_CLIENT_INST_COUNT > 0) {
533 		struct bt_otc_internal_instance_t *inst;
534 		int err;
535 
536 		if (!conn) {
537 			LOG_WRN("Invalid Connection");
538 			return -ENOTCONN;
539 		} else if (!otc_inst) {
540 			LOG_ERR("Invalid OTC instance");
541 			return -EINVAL;
542 		} else if (!otc_inst->feature_handle) {
543 			LOG_DBG("Handle not set");
544 			return -EINVAL;
545 		}
546 
547 		inst = lookup_inst_by_handle(otc_inst->start_handle);
548 
549 		if (!inst) {
550 			LOG_ERR("Invalid OTC instance");
551 			return -EINVAL;
552 		} else if (inst->busy) {
553 			return -EBUSY;
554 		}
555 
556 		otc_inst->read_proc.func = read_feature_cb;
557 		otc_inst->read_proc.handle_count = 1;
558 		otc_inst->read_proc.single.handle = otc_inst->feature_handle;
559 		otc_inst->read_proc.single.offset = 0U;
560 
561 		err = bt_gatt_read(conn, &otc_inst->read_proc);
562 		if (!err) {
563 			inst->busy = true;
564 		}
565 		return err;
566 	}
567 
568 	LOG_DBG("Not supported");
569 	return -EOPNOTSUPP;
570 }
571 
write_olcp_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)572 static void write_olcp_cb(struct bt_conn *conn, uint8_t err,
573 			  struct bt_gatt_write_params *params)
574 {
575 	struct bt_otc_internal_instance_t *inst =
576 		lookup_inst_by_handle(params->handle);
577 
578 	LOG_DBG("Write %s (0x%02X)", err ? "failed" : "successful", err);
579 
580 	if (!inst) {
581 		LOG_ERR("Instance not found");
582 		return;
583 	}
584 
585 	inst->busy = false;
586 }
587 
write_olcp(struct bt_otc_internal_instance_t * inst,struct bt_conn * conn,enum bt_gatt_ots_olcp_proc_type opcode,uint8_t * params,uint8_t param_len)588 static int write_olcp(struct bt_otc_internal_instance_t *inst,
589 		      struct bt_conn *conn, enum bt_gatt_ots_olcp_proc_type opcode,
590 		      uint8_t *params, uint8_t param_len)
591 {
592 	int err;
593 
594 	net_buf_simple_reset(&otc_tx_buf);
595 
596 	net_buf_simple_add_u8(&otc_tx_buf, opcode);
597 
598 	if (param_len && params) {
599 		net_buf_simple_add_mem(&otc_tx_buf, params, param_len);
600 	}
601 
602 	inst->otc_inst->write_params.offset = 0;
603 	inst->otc_inst->write_params.data = otc_tx_buf.data;
604 	inst->otc_inst->write_params.length = otc_tx_buf.len;
605 	inst->otc_inst->write_params.handle = inst->otc_inst->olcp_handle;
606 	inst->otc_inst->write_params.func = write_olcp_cb;
607 
608 	err = bt_gatt_write(conn, &inst->otc_inst->write_params);
609 
610 	if (!err) {
611 		inst->busy = true;
612 	}
613 	return err;
614 }
615 
bt_ots_client_select_id(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint64_t obj_id)616 int bt_ots_client_select_id(struct bt_ots_client *otc_inst,
617 			    struct bt_conn *conn,
618 			    uint64_t obj_id)
619 {
620 	CHECKIF(!BT_OTS_VALID_OBJ_ID(obj_id)) {
621 		LOG_DBG("Invalid object ID 0x%016llx", obj_id);
622 
623 		return -EINVAL;
624 	}
625 
626 	if (OTS_CLIENT_INST_COUNT > 0) {
627 		struct bt_otc_internal_instance_t *inst;
628 		uint8_t param[BT_OTS_OBJ_ID_SIZE];
629 
630 		if (!conn) {
631 			LOG_WRN("Invalid Connection");
632 			return -ENOTCONN;
633 		} else if (!otc_inst) {
634 			LOG_ERR("Invalid OTC instance");
635 			return -EINVAL;
636 		} else if (!otc_inst->olcp_handle) {
637 			LOG_DBG("Handle not set");
638 			return -EINVAL;
639 		}
640 
641 		inst = lookup_inst_by_handle(otc_inst->start_handle);
642 
643 		if (!inst) {
644 			LOG_ERR("Invalid OTC instance");
645 			return -EINVAL;
646 		} else if (inst->busy) {
647 			return -EBUSY;
648 		}
649 
650 		/* TODO: Should not update this before ID is read */
651 		otc_inst->cur_object.id = obj_id;
652 		sys_put_le48(obj_id, param);
653 
654 		return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_GOTO,
655 				  param, BT_OTS_OBJ_ID_SIZE);
656 	}
657 
658 	LOG_DBG("Not supported");
659 	return -EOPNOTSUPP;
660 }
661 
bt_ots_client_select_first(struct bt_ots_client * otc_inst,struct bt_conn * conn)662 int bt_ots_client_select_first(struct bt_ots_client *otc_inst,
663 			       struct bt_conn *conn)
664 {
665 	if (OTS_CLIENT_INST_COUNT > 0) {
666 		struct bt_otc_internal_instance_t *inst;
667 
668 		if (!conn) {
669 			LOG_WRN("Invalid Connection");
670 			return -ENOTCONN;
671 		} else if (!otc_inst) {
672 			LOG_ERR("Invalid OTC instance");
673 			return -EINVAL;
674 		} else if (!otc_inst->olcp_handle) {
675 			LOG_DBG("Handle not set");
676 			return -EINVAL;
677 		}
678 
679 		inst = lookup_inst_by_handle(otc_inst->start_handle);
680 
681 		if (!inst) {
682 			LOG_ERR("Invalid OTC instance");
683 			return -EINVAL;
684 		} else if (inst->busy) {
685 			return -EBUSY;
686 		}
687 
688 		return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_FIRST,
689 				  NULL, 0);
690 	}
691 
692 	LOG_DBG("Not supported");
693 	return -EOPNOTSUPP;
694 }
695 
bt_ots_client_select_last(struct bt_ots_client * otc_inst,struct bt_conn * conn)696 int bt_ots_client_select_last(struct bt_ots_client *otc_inst,
697 			      struct bt_conn *conn)
698 {
699 	if (OTS_CLIENT_INST_COUNT > 0) {
700 		struct bt_otc_internal_instance_t *inst;
701 
702 		if (!conn) {
703 			LOG_WRN("Invalid Connection");
704 			return -ENOTCONN;
705 		} else if (!otc_inst) {
706 			LOG_ERR("Invalid OTC instance");
707 			return -EINVAL;
708 		} else if (!otc_inst->olcp_handle) {
709 			LOG_DBG("Handle not set");
710 			return -EINVAL;
711 		}
712 
713 		inst = lookup_inst_by_handle(otc_inst->start_handle);
714 
715 		if (!inst) {
716 			LOG_ERR("Invalid OTC instance");
717 			return -EINVAL;
718 		} else if (inst->busy) {
719 			return -EBUSY;
720 		}
721 
722 		return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_LAST,
723 				  NULL, 0);
724 
725 	}
726 
727 	LOG_DBG("Not supported");
728 	return -EOPNOTSUPP;
729 }
730 
bt_ots_client_select_next(struct bt_ots_client * otc_inst,struct bt_conn * conn)731 int bt_ots_client_select_next(struct bt_ots_client *otc_inst,
732 			      struct bt_conn *conn)
733 {
734 	if (OTS_CLIENT_INST_COUNT > 0) {
735 		struct bt_otc_internal_instance_t *inst;
736 
737 		if (!conn) {
738 			LOG_WRN("Invalid Connection");
739 			return -ENOTCONN;
740 		} else if (!otc_inst) {
741 			LOG_ERR("Invalid OTC instance");
742 			return -EINVAL;
743 		} else if (!otc_inst->olcp_handle) {
744 			LOG_DBG("Handle not set");
745 			return -EINVAL;
746 		}
747 
748 		inst = lookup_inst_by_handle(otc_inst->start_handle);
749 
750 		if (!inst) {
751 			LOG_ERR("Invalid OTC instance");
752 			return -EINVAL;
753 		} else if (inst->busy) {
754 			return -EBUSY;
755 		}
756 
757 		return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_NEXT,
758 				  NULL, 0);
759 	}
760 
761 	LOG_DBG("Not supported");
762 	return -EOPNOTSUPP;
763 }
764 
bt_ots_client_select_prev(struct bt_ots_client * otc_inst,struct bt_conn * conn)765 int bt_ots_client_select_prev(struct bt_ots_client *otc_inst,
766 			      struct bt_conn *conn)
767 {
768 	if (OTS_CLIENT_INST_COUNT > 0) {
769 		struct bt_otc_internal_instance_t *inst;
770 
771 		if (!conn) {
772 			LOG_WRN("Invalid Connection");
773 			return -ENOTCONN;
774 		} else if (!otc_inst) {
775 			LOG_ERR("Invalid OTC instance");
776 			return -EINVAL;
777 		} else if (!otc_inst->olcp_handle) {
778 			LOG_DBG("Handle not set");
779 			return -EINVAL;
780 		}
781 
782 		inst = lookup_inst_by_handle(otc_inst->start_handle);
783 
784 		if (!inst) {
785 			LOG_ERR("Invalid OTC instance");
786 			return -EINVAL;
787 		} else if (inst->busy) {
788 			return -EBUSY;
789 		}
790 
791 		return write_olcp(inst, conn, BT_GATT_OTS_OLCP_PROC_PREV,
792 				  NULL, 0);
793 	}
794 
795 	LOG_DBG("Not supported");
796 	return -EOPNOTSUPP;
797 }
798 
read_object_size_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)799 static uint8_t read_object_size_cb(struct bt_conn *conn, uint8_t err,
800 				   struct bt_gatt_read_params *params,
801 				   const void *data, uint16_t length)
802 {
803 	struct bt_otc_internal_instance_t *inst =
804 		lookup_inst_by_handle(params->single.handle);
805 	struct net_buf_simple net_buf;
806 
807 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
808 
809 	LOG_DBG("handle %d, length %u", params->single.handle, length);
810 
811 	if (!inst) {
812 		LOG_ERR("Instance not found");
813 		return BT_GATT_ITER_STOP;
814 	}
815 
816 	if (err) {
817 		LOG_DBG("err: 0x%02X", err);
818 	} else if (data) {
819 		if (length != OTS_SIZE_LEN) {
820 			LOG_DBG("Invalid length %u (expected %u)", length, OTS_SIZE_LEN);
821 			err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
822 		} else {
823 			struct bt_ots_obj_metadata *cur_object =
824 				&inst->otc_inst->cur_object;
825 			cur_object->size.cur =
826 				net_buf_simple_pull_le32(&net_buf);
827 			cur_object->size.alloc =
828 				net_buf_simple_pull_le32(&net_buf);
829 
830 			LOG_DBG("Object Size : current size %u, "
831 			       "allocated size %u",
832 			       cur_object->size.cur,
833 			       cur_object->size.alloc);
834 
835 			if (cur_object->size.cur == 0) {
836 				LOG_WRN("Obj size read returned a current "
837 					"size of 0");
838 			} else if (cur_object->size.cur >
839 					cur_object->size.alloc &&
840 				   cur_object->size.alloc != 0) {
841 				LOG_WRN("Allocated size %u is smaller than "
842 					"current size %u",
843 					cur_object->size.alloc,
844 					cur_object->size.cur);
845 			}
846 
847 			BT_OTS_SET_METADATA_REQ_SIZE(inst->metadata_read);
848 		}
849 	}
850 
851 	if (err) {
852 		LOG_WRN("err: 0x%02X", err);
853 		if (!inst->metadata_err) {
854 			inst->metadata_err = err;
855 		}
856 	}
857 
858 	read_next_metadata(conn, inst);
859 
860 	return BT_GATT_ITER_STOP;
861 }
862 
read_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)863 static uint8_t read_obj_id_cb(struct bt_conn *conn, uint8_t err,
864 			      struct bt_gatt_read_params *params,
865 			      const void *data, uint16_t length)
866 {
867 	struct bt_otc_internal_instance_t *inst =
868 		lookup_inst_by_handle(params->single.handle);
869 	struct net_buf_simple net_buf;
870 
871 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
872 
873 	LOG_DBG("handle %d, length %u", params->single.handle, length);
874 
875 	if (!inst) {
876 		LOG_ERR("Instance not found");
877 		return BT_GATT_ITER_STOP;
878 	}
879 
880 	if (err) {
881 		LOG_DBG("err: 0x%02X", err);
882 	} else if (data) {
883 		if (length == BT_OTS_OBJ_ID_SIZE) {
884 			uint64_t obj_id = net_buf_simple_pull_le48(&net_buf);
885 			char t[BT_OTS_OBJ_ID_STR_LEN];
886 			struct bt_ots_obj_metadata *cur_object =
887 				&inst->otc_inst->cur_object;
888 
889 			(void)bt_ots_obj_id_to_str(obj_id, t, sizeof(t));
890 			LOG_DBG("Object Id : %s", t);
891 
892 			if (cur_object->id != OTS_CLIENT_UNKNOWN_ID &&
893 			    cur_object->id != obj_id) {
894 				char str[BT_OTS_OBJ_ID_STR_LEN];
895 
896 				(void)bt_ots_obj_id_to_str(cur_object->id, str,
897 							   sizeof(str));
898 				LOG_INF("Read Obj Id %s not selected obj Id %s", t, str);
899 			} else {
900 				LOG_INF("Read Obj Id confirmed correct Obj Id");
901 				cur_object->id = obj_id;
902 
903 				BT_OTS_SET_METADATA_REQ_ID(inst->metadata_read);
904 			}
905 		} else {
906 			LOG_DBG("Invalid length %u (expected %u)", length, BT_OTS_OBJ_ID_SIZE);
907 			err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
908 		}
909 	}
910 
911 	if (err) {
912 		LOG_WRN("err: 0x%02X", err);
913 		if (!inst->metadata_err) {
914 			inst->metadata_err = err;
915 		}
916 	}
917 
918 	read_next_metadata(conn, inst);
919 
920 	return BT_GATT_ITER_STOP;
921 }
922 
read_obj_name_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)923 static uint8_t read_obj_name_cb(struct bt_conn *conn, uint8_t err,
924 				struct bt_gatt_read_params *params,
925 				const void *data, uint16_t length)
926 {
927 	struct bt_otc_internal_instance_t *inst =
928 		lookup_inst_by_handle(params->single.handle);
929 
930 	LOG_DBG("handle %d, length %u", params->single.handle, length);
931 
932 	if (!inst) {
933 		LOG_ERR("Instance not found");
934 		return BT_GATT_ITER_STOP;
935 	}
936 
937 	if (data) {
938 		if (length <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) {
939 			memcpy(inst->otc_inst->cur_object.name_c, data, length);
940 			inst->otc_inst->cur_object.name_c[length] = '\0';
941 		} else {
942 			LOG_WRN("Invalid length %u (expected max %u)", length,
943 				CONFIG_BT_OTS_OBJ_MAX_NAME_LEN);
944 			err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
945 		}
946 	}
947 
948 	if (err) {
949 		LOG_WRN("err: 0x%02X", err);
950 		if (!inst->metadata_err) {
951 			inst->metadata_err = err;
952 		}
953 	}
954 
955 	read_next_metadata(conn, inst);
956 
957 	return BT_GATT_ITER_STOP;
958 }
959 
read_obj_type_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)960 static uint8_t read_obj_type_cb(struct bt_conn *conn, uint8_t err,
961 				struct bt_gatt_read_params *params,
962 				const void *data, uint16_t length)
963 {
964 	struct bt_otc_internal_instance_t *inst =
965 		lookup_inst_by_handle(params->single.handle);
966 
967 	LOG_DBG("handle %d, length %u", params->single.handle, length);
968 
969 	if (!inst) {
970 		LOG_ERR("Instance not found");
971 		return BT_GATT_ITER_STOP;
972 	}
973 
974 	if (data) {
975 		if (length == BT_UUID_SIZE_128 || length == BT_UUID_SIZE_16) {
976 			char uuid_str[BT_UUID_STR_LEN];
977 			struct bt_uuid *uuid =
978 				&inst->otc_inst->cur_object.type.uuid;
979 
980 			if (!bt_uuid_create(uuid, data, length)) {
981 				return BT_GATT_ITER_STOP;
982 			}
983 
984 			bt_uuid_to_str(uuid, uuid_str, sizeof(uuid_str));
985 			LOG_DBG("UUID type read: %s", uuid_str);
986 
987 			BT_OTS_SET_METADATA_REQ_TYPE(inst->metadata_read);
988 		} else {
989 			LOG_WRN("Invalid length %u (expected max %u)", length, OTS_TYPE_MAX_LEN);
990 			err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
991 		}
992 	}
993 
994 	if (err) {
995 		LOG_WRN("err: 0x%02X", err);
996 		if (!inst->metadata_err) {
997 			inst->metadata_err = err;
998 		}
999 	}
1000 
1001 	read_next_metadata(conn, inst);
1002 
1003 	return BT_GATT_ITER_STOP;
1004 }
1005 
1006 
read_obj_created_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)1007 static uint8_t read_obj_created_cb(struct bt_conn *conn, uint8_t err,
1008 				   struct bt_gatt_read_params *params,
1009 				   const void *data, uint16_t length)
1010 {
1011 	struct bt_otc_internal_instance_t *inst =
1012 		lookup_inst_by_handle(params->single.handle);
1013 	struct net_buf_simple net_buf;
1014 
1015 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
1016 
1017 	LOG_DBG("handle %d, length %u", params->single.handle, length);
1018 
1019 	if (!inst) {
1020 		LOG_ERR("Instance not found");
1021 		return BT_GATT_ITER_STOP;
1022 	}
1023 
1024 	if (data) {
1025 		if (length <= BT_OTS_DATE_TIME_FIELD_SIZE) {
1026 			date_time_decode(
1027 				&net_buf,
1028 				&inst->otc_inst->cur_object.first_created);
1029 		} else {
1030 			LOG_WRN("Invalid length %u (expected max %u)", length,
1031 				BT_OTS_DATE_TIME_FIELD_SIZE);
1032 			err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
1033 		}
1034 	}
1035 
1036 	if (err) {
1037 		LOG_WRN("err: 0x%02X", err);
1038 		if (!inst->metadata_err) {
1039 			inst->metadata_err = err;
1040 		}
1041 	}
1042 
1043 	read_next_metadata(conn, inst);
1044 
1045 	return BT_GATT_ITER_STOP;
1046 }
1047 
read_obj_modified_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)1048 static uint8_t read_obj_modified_cb(struct bt_conn *conn, uint8_t err,
1049 				    struct bt_gatt_read_params *params,
1050 				    const void *data, uint16_t length)
1051 {
1052 	struct bt_otc_internal_instance_t *inst =
1053 		lookup_inst_by_handle(params->single.handle);
1054 	struct net_buf_simple net_buf;
1055 
1056 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
1057 
1058 	LOG_DBG("handle %d, length %u", params->single.handle, length);
1059 
1060 	if (!inst) {
1061 		LOG_ERR("Instance not found");
1062 		return BT_GATT_ITER_STOP;
1063 	}
1064 
1065 	if (data) {
1066 		if (length <= BT_OTS_DATE_TIME_FIELD_SIZE) {
1067 			date_time_decode(&net_buf,
1068 					 &inst->otc_inst->cur_object.modified);
1069 		} else {
1070 			LOG_WRN("Invalid length %u (expected max %u)", length,
1071 				BT_OTS_DATE_TIME_FIELD_SIZE);
1072 			err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
1073 		}
1074 	}
1075 
1076 	if (err) {
1077 		LOG_WRN("err: 0x%02X", err);
1078 		if (!inst->metadata_err) {
1079 			inst->metadata_err = err;
1080 		}
1081 	}
1082 
1083 	read_next_metadata(conn, inst);
1084 
1085 	return BT_GATT_ITER_STOP;
1086 }
1087 
read_attr(struct bt_conn * conn,struct bt_otc_internal_instance_t * inst,uint16_t handle,bt_gatt_read_func_t cb)1088 static int read_attr(struct bt_conn *conn,
1089 		     struct bt_otc_internal_instance_t *inst,
1090 		     uint16_t handle, bt_gatt_read_func_t cb)
1091 {
1092 	if (!handle) {
1093 		LOG_DBG("Handle not set");
1094 		return -EINVAL;
1095 	} else if (cb == NULL) {
1096 		LOG_ERR("No callback set");
1097 		return -EINVAL;
1098 	}
1099 
1100 	/* TODO: With EATT we can request multiple metadata to be read at once*/
1101 	inst->otc_inst->read_proc.func = cb;
1102 	inst->otc_inst->read_proc.handle_count = 1;
1103 	inst->otc_inst->read_proc.single.handle = handle;
1104 	inst->otc_inst->read_proc.single.offset = 0;
1105 
1106 	return bt_gatt_read(conn, &inst->otc_inst->read_proc);
1107 }
1108 
read_obj_properties_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)1109 static uint8_t read_obj_properties_cb(struct bt_conn *conn, uint8_t err,
1110 				      struct bt_gatt_read_params *params,
1111 				      const void *data, uint16_t length)
1112 {
1113 	uint8_t cb_err = err;
1114 	struct bt_otc_internal_instance_t *inst =
1115 		lookup_inst_by_handle(params->single.handle);
1116 	struct net_buf_simple net_buf;
1117 
1118 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
1119 
1120 	LOG_INF("handle %d, length %u", params->single.handle, length);
1121 
1122 	if (!inst) {
1123 		LOG_ERR("Instance not found");
1124 		return BT_GATT_ITER_STOP;
1125 	}
1126 
1127 	if (err) {
1128 		LOG_WRN("err: 0x%02X", err);
1129 	} else if (data && length <= OTS_PROPERTIES_LEN) {
1130 		struct bt_ots_obj_metadata *cur_object =
1131 			&inst->otc_inst->cur_object;
1132 
1133 		cur_object->props = net_buf_simple_pull_le32(&net_buf);
1134 
1135 		LOG_INF("Object properties (raw) : 0x%x", cur_object->props);
1136 
1137 		if (!BT_OTS_OBJ_GET_PROP_READ(cur_object->props)) {
1138 			LOG_WRN("Obj properties: Obj read not supported");
1139 		}
1140 
1141 		BT_OTS_SET_METADATA_REQ_PROPS(inst->metadata_read);
1142 	} else {
1143 		LOG_WRN("Invalid length %u (expected %u)", length, OTS_PROPERTIES_LEN);
1144 		cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
1145 	}
1146 
1147 	if (err) {
1148 		LOG_WRN("err: 0x%02X", err);
1149 		if (!inst->metadata_err) {
1150 			inst->metadata_err = err;
1151 		}
1152 	}
1153 
1154 	read_next_metadata(conn, inst);
1155 
1156 	return BT_GATT_ITER_STOP;
1157 }
1158 
write_oacp_cp_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)1159 static void write_oacp_cp_cb(struct bt_conn *conn, uint8_t err,
1160 			     struct bt_gatt_write_params *params)
1161 {
1162 	struct bt_otc_internal_instance_t *inst =
1163 		lookup_inst_by_handle(params->handle);
1164 
1165 	LOG_DBG("Write %s (0x%02X)", err ? "failed" : "successful", err);
1166 
1167 	if (!inst) {
1168 		LOG_ERR("Instance not found");
1169 		return;
1170 	}
1171 
1172 	inst->busy = false;
1173 }
1174 
write_oacp_cp_write_req_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)1175 static void write_oacp_cp_write_req_cb(struct bt_conn *conn, uint8_t err,
1176 				       struct bt_gatt_write_params *params)
1177 {
1178 	struct bt_otc_internal_instance_t *inst =
1179 		lookup_inst_by_handle(params->handle);
1180 	uint32_t len;
1181 
1182 	LOG_DBG("Write Object request %s (0x%02X)", err ? "failed" : "successful", err);
1183 	if (!inst) {
1184 		LOG_ERR("Instance not found");
1185 		return;
1186 	}
1187 
1188 	len = inst->l2cap_ctx.tx.len;
1189 	inst->l2cap_ctx.tx.len = 0;
1190 	err = bt_gatt_ots_l2cap_send(&inst->l2cap_ctx, inst->l2cap_ctx.tx.data, len);
1191 	if (err) {
1192 		LOG_WRN("L2CAP CoC error: %d while trying to execute OACP "
1193 			"Read procedure", err);
1194 	}
1195 
1196 	inst->busy = false;
1197 }
1198 
oacp_read(struct bt_conn * conn,struct bt_otc_internal_instance_t * inst)1199 static int oacp_read(struct bt_conn *conn,
1200 		     struct bt_otc_internal_instance_t *inst)
1201 {
1202 	int err;
1203 	uint32_t offset = 0;
1204 	uint32_t length;
1205 	struct bt_gatt_ots_l2cap *l2cap;
1206 
1207 	if (!inst->otc_inst->oacp_handle) {
1208 		LOG_DBG("Handle not set");
1209 		return -EINVAL;
1210 	} else if (inst->busy) {
1211 		return -EBUSY;
1212 	} else if (cur_inst) {
1213 		return -EBUSY;
1214 	}
1215 
1216 	/* TODO: How do we ensure that the L2CAP is connected in time for the
1217 	 * transfer?
1218 	 */
1219 
1220 	err = bt_gatt_ots_l2cap_connect(conn, &l2cap);
1221 	if (err) {
1222 		LOG_DBG("Could not connect l2cap: %d", err);
1223 		return err;
1224 	}
1225 
1226 	l2cap->tx_done = tx_done;
1227 	l2cap->rx_done = rx_done;
1228 	l2cap->closed  = chan_closed;
1229 
1230 	net_buf_simple_reset(&otc_tx_buf);
1231 
1232 	/* OP Code */
1233 	net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_READ);
1234 
1235 	/* Offset */
1236 	net_buf_simple_add_le32(&otc_tx_buf, offset);
1237 
1238 	/* Len */
1239 	length = inst->otc_inst->cur_object.size.cur - offset;
1240 	net_buf_simple_add_le32(&otc_tx_buf, length);
1241 
1242 	inst->otc_inst->write_params.offset = 0;
1243 	inst->otc_inst->write_params.data = otc_tx_buf.data;
1244 	inst->otc_inst->write_params.length = otc_tx_buf.len;
1245 	inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle;
1246 	inst->otc_inst->write_params.func = write_oacp_cp_cb;
1247 
1248 	err = bt_gatt_write(conn, &inst->otc_inst->write_params);
1249 
1250 	if (!err) {
1251 		inst->busy = true;
1252 	}
1253 
1254 	cur_inst = inst;
1255 	inst->rcvd_size = 0;
1256 
1257 	return err;
1258 }
1259 
oacp_write(struct bt_conn * conn,struct bt_otc_internal_instance_t * inst,const void * buf,uint32_t len,uint32_t offset,enum bt_ots_oacp_write_op_mode mode)1260 static int oacp_write(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
1261 		      const void *buf, uint32_t len, uint32_t offset,
1262 		      enum bt_ots_oacp_write_op_mode mode)
1263 {
1264 	int err;
1265 	struct bt_gatt_ots_l2cap *l2cap;
1266 
1267 	if (!inst->otc_inst->oacp_handle) {
1268 		LOG_DBG("Handle not set");
1269 		return -EINVAL;
1270 	} else if (inst->busy) {
1271 		return -EBUSY;
1272 	} else if (cur_inst) {
1273 		return -EBUSY;
1274 	}
1275 
1276 	err = bt_gatt_ots_l2cap_connect(conn, &l2cap);
1277 	if (err) {
1278 		LOG_DBG("Could not connect l2cap: %d", err);
1279 		return err;
1280 	}
1281 
1282 	l2cap->tx_done = write_obj_tx_done;
1283 	l2cap->rx_done = rx_done;
1284 	l2cap->closed  = chan_closed;
1285 	l2cap->tx.data = (uint8_t *)buf;
1286 	l2cap->tx.len = len;
1287 	net_buf_simple_reset(&otc_tx_buf);
1288 
1289 	/* OP Code */
1290 	net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_WRITE);
1291 
1292 	/* Offset */
1293 	net_buf_simple_add_le32(&otc_tx_buf, offset);
1294 
1295 	/* Len */
1296 	net_buf_simple_add_le32(&otc_tx_buf, len);
1297 
1298 	/* Mode, truncate or not */
1299 	net_buf_simple_add_u8(&otc_tx_buf, mode);
1300 
1301 	inst->otc_inst->write_params.offset = 0;
1302 	inst->otc_inst->write_params.data = otc_tx_buf.data;
1303 	inst->otc_inst->write_params.length = otc_tx_buf.len;
1304 	inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle;
1305 	inst->otc_inst->write_params.func = write_oacp_cp_write_req_cb;
1306 	inst->sent_size = len;
1307 	err = bt_gatt_write(conn, &inst->otc_inst->write_params);
1308 
1309 	if (!err) {
1310 		inst->busy = true;
1311 		cur_inst = inst;
1312 	}
1313 
1314 	inst->rcvd_size = 0;
1315 
1316 	return err;
1317 }
1318 
oacp_checksum(struct bt_conn * conn,struct bt_otc_internal_instance_t * inst,uint32_t offset,uint32_t len)1319 static int oacp_checksum(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
1320 			 uint32_t offset, uint32_t len)
1321 {
1322 	int err;
1323 
1324 	if (!inst->otc_inst->oacp_handle) {
1325 		LOG_DBG("Handle not set");
1326 		return -EINVAL;
1327 	} else if (inst->busy) {
1328 		LOG_DBG("Client is busy");
1329 		return -EBUSY;
1330 	} else if (cur_inst) {
1331 		LOG_DBG("Previous operation is not finished");
1332 		return -EBUSY;
1333 	}
1334 
1335 	net_buf_simple_reset(&otc_tx_buf);
1336 
1337 	/* OP Code */
1338 	net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC);
1339 
1340 	/* Offset */
1341 	net_buf_simple_add_le32(&otc_tx_buf, offset);
1342 
1343 	/* Len */
1344 	net_buf_simple_add_le32(&otc_tx_buf, len);
1345 
1346 	inst->otc_inst->write_params.offset = 0;
1347 	inst->otc_inst->write_params.data = otc_tx_buf.data;
1348 	inst->otc_inst->write_params.length = otc_tx_buf.len;
1349 	inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle;
1350 	inst->otc_inst->write_params.func = write_oacp_cp_cb;
1351 
1352 	err = bt_gatt_write(conn, &inst->otc_inst->write_params);
1353 	if (err != 0) {
1354 		inst->busy = true;
1355 		cur_inst = inst;
1356 	}
1357 
1358 	return err;
1359 }
1360 
bt_ots_client_read_object_data(struct bt_ots_client * otc_inst,struct bt_conn * conn)1361 int bt_ots_client_read_object_data(struct bt_ots_client *otc_inst,
1362 				   struct bt_conn *conn)
1363 {
1364 	struct bt_otc_internal_instance_t *inst;
1365 
1366 	if (!conn) {
1367 		LOG_WRN("Invalid Connection");
1368 		return -ENOTCONN;
1369 	} else if (!otc_inst) {
1370 		LOG_ERR("Invalid OTC instance");
1371 		return -EINVAL;
1372 	}
1373 
1374 	inst = lookup_inst_by_handle(otc_inst->start_handle);
1375 
1376 	if (!inst) {
1377 		LOG_ERR("Invalid OTC instance");
1378 		return -EINVAL;
1379 	}
1380 
1381 	if (otc_inst->cur_object.size.cur == 0) {
1382 		LOG_WRN("Unknown object size");
1383 		return -EINVAL;
1384 	}
1385 
1386 	return oacp_read(conn, inst);
1387 }
1388 
bt_ots_client_write_object_data(struct bt_ots_client * otc_inst,struct bt_conn * conn,const void * buf,size_t len,off_t offset,enum bt_ots_oacp_write_op_mode mode)1389 int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst,
1390 				    struct bt_conn *conn, const void *buf, size_t len,
1391 				    off_t offset, enum bt_ots_oacp_write_op_mode mode)
1392 {
1393 	struct bt_otc_internal_instance_t *inst;
1394 
1395 	CHECKIF(!conn) {
1396 		LOG_WRN("Invalid Connection");
1397 		return -ENOTCONN;
1398 	}
1399 
1400 	CHECKIF(!otc_inst) {
1401 		LOG_ERR("Invalid OTC instance");
1402 		return -EINVAL;
1403 	}
1404 
1405 	CHECKIF((mode != BT_OTS_OACP_WRITE_OP_MODE_NONE) &&
1406 		(mode != BT_OTS_OACP_WRITE_OP_MODE_TRUNCATE)) {
1407 		LOG_ERR("Invalid write object mode parameter %d", mode);
1408 		return -EINVAL;
1409 	}
1410 
1411 	/* OTS_v10.pdf Table 3.9: Object Action Control Point Procedure Requirements
1412 	 *	Offset and Length field are UINT32 Length
1413 	 */
1414 	CHECKIF(len > UINT32_MAX) {
1415 		LOG_ERR("length %zu exceeds UINT32", len);
1416 		return -EINVAL;
1417 	}
1418 
1419 	CHECKIF(len == 0) {
1420 		LOG_ERR("length equals zero");
1421 		return -EINVAL;
1422 	}
1423 
1424 	CHECKIF((sizeof(offset) > sizeof(uint32_t) && (offset > UINT32_MAX)) || (offset < 0)) {
1425 		LOG_ERR("offset %ld exceeds UINT32 and must be >= 0", offset);
1426 		return -EINVAL;
1427 	}
1428 
1429 	CHECKIF(offset > otc_inst->cur_object.size.cur) {
1430 		LOG_ERR("offset %ld exceeds cur size %zu", offset, otc_inst->cur_object.size.cur);
1431 		return -EINVAL;
1432 	}
1433 
1434 	CHECKIF((offset < otc_inst->cur_object.size.cur) &&
1435 		!BT_OTS_OBJ_GET_PROP_PATCH(otc_inst->cur_object.props)) {
1436 		LOG_ERR("Patch is not supported");
1437 		return -EACCES;
1438 	}
1439 
1440 	CHECKIF(((len + offset) > otc_inst->cur_object.size.alloc) &&
1441 		!BT_OTS_OBJ_GET_PROP_APPEND(otc_inst->cur_object.props)) {
1442 		LOG_ERR("APPEND is not supported. Invalid new end of object %lu alloc %zu."
1443 		, (len + offset), otc_inst->cur_object.size.alloc);
1444 		return -EINVAL;
1445 	}
1446 
1447 	inst = lookup_inst_by_handle(otc_inst->start_handle);
1448 
1449 	if (!inst) {
1450 		LOG_ERR("Invalid OTC instance");
1451 		return -EINVAL;
1452 	}
1453 
1454 	return oacp_write(conn, inst, buf, (uint32_t)len, (uint32_t)offset, mode);
1455 }
1456 
bt_ots_client_get_object_checksum(struct bt_ots_client * otc_inst,struct bt_conn * conn,off_t offset,size_t len)1457 int bt_ots_client_get_object_checksum(struct bt_ots_client *otc_inst, struct bt_conn *conn,
1458 				      off_t offset, size_t len)
1459 {
1460 	struct bt_otc_internal_instance_t *inst;
1461 
1462 	CHECKIF(!conn) {
1463 		LOG_DBG("Invalid Connection");
1464 		return -ENOTCONN;
1465 	}
1466 
1467 	CHECKIF(!otc_inst) {
1468 		LOG_DBG("Invalid OTC instance");
1469 		return -EINVAL;
1470 	}
1471 
1472 	/* OTS_v10.pdf Table 3.9: Object Action Control Point Procedure Requirements
1473 	 *	Offset and Length field are UINT32 Length
1474 	 */
1475 	CHECKIF(len > UINT32_MAX) {
1476 		LOG_DBG("length %zu exceeds UINT32", len);
1477 		return -EINVAL;
1478 	}
1479 
1480 	CHECKIF(len == 0) {
1481 		LOG_DBG("length equals zero");
1482 		return -EINVAL;
1483 	}
1484 
1485 	CHECKIF((sizeof(offset) > sizeof(uint32_t) && (offset > UINT32_MAX)) || (offset < 0)) {
1486 		LOG_DBG("offset exceeds %ld UINT32 and must be >= 0", offset);
1487 		return -EINVAL;
1488 	}
1489 
1490 	CHECKIF((len + offset) > otc_inst->cur_object.size.cur) {
1491 		LOG_DBG("The sum of offset (%ld) and length (%zu) exceed the Current Size %lu "
1492 			"alloc %zu.", offset, len, (len + offset), otc_inst->cur_object.size.cur);
1493 		return -EINVAL;
1494 	}
1495 
1496 	inst = lookup_inst_by_handle(otc_inst->start_handle);
1497 	if (!inst) {
1498 		LOG_DBG("Invalid OTC instance");
1499 		return -EINVAL;
1500 	}
1501 
1502 	return oacp_checksum(conn, inst, (uint32_t)offset, (uint32_t)len);
1503 }
1504 
read_next_metadata(struct bt_conn * conn,struct bt_otc_internal_instance_t * inst)1505 static void read_next_metadata(struct bt_conn *conn,
1506 			       struct bt_otc_internal_instance_t *inst)
1507 {
1508 	uint8_t metadata_remaining =
1509 		inst->metadata_to_read ^ inst->metadata_read_attempted;
1510 	int err = 0;
1511 
1512 	LOG_DBG("Attempting to read metadata 0x%02X", metadata_remaining);
1513 
1514 	if (BT_OTS_GET_METADATA_REQ_NAME(metadata_remaining)) {
1515 		BT_OTS_SET_METADATA_REQ_NAME(inst->metadata_read_attempted);
1516 		err = read_attr(conn, inst, inst->otc_inst->obj_name_handle,
1517 				read_obj_name_cb);
1518 	} else if (BT_OTS_GET_METADATA_REQ_TYPE(metadata_remaining)) {
1519 		BT_OTS_SET_METADATA_REQ_TYPE(inst->metadata_read_attempted);
1520 		err = read_attr(conn, inst, inst->otc_inst->obj_type_handle,
1521 				read_obj_type_cb);
1522 	} else if (BT_OTS_GET_METADATA_REQ_SIZE(metadata_remaining)) {
1523 		BT_OTS_SET_METADATA_REQ_SIZE(inst->metadata_read_attempted);
1524 		err = read_attr(conn, inst, inst->otc_inst->obj_size_handle,
1525 				read_object_size_cb);
1526 	} else if (BT_OTS_GET_METADATA_REQ_CREATED(metadata_remaining)) {
1527 		BT_OTS_SET_METADATA_REQ_CREATED(inst->metadata_read_attempted);
1528 		err = read_attr(conn, inst, inst->otc_inst->obj_created_handle,
1529 				read_obj_created_cb);
1530 	} else if (BT_OTS_GET_METADATA_REQ_MODIFIED(metadata_remaining)) {
1531 		BT_OTS_SET_METADATA_REQ_MODIFIED(inst->metadata_read_attempted);
1532 		err = read_attr(conn, inst, inst->otc_inst->obj_modified_handle,
1533 				read_obj_modified_cb);
1534 	} else if (BT_OTS_GET_METADATA_REQ_ID(metadata_remaining)) {
1535 		BT_OTS_SET_METADATA_REQ_ID(inst->metadata_read_attempted);
1536 		err = read_attr(conn, inst, inst->otc_inst->obj_id_handle,
1537 				read_obj_id_cb);
1538 	} else if (BT_OTS_GET_METADATA_REQ_PROPS(metadata_remaining)) {
1539 		BT_OTS_SET_METADATA_REQ_PROPS(inst->metadata_read_attempted);
1540 		err = read_attr(conn, inst,
1541 				inst->otc_inst->obj_properties_handle,
1542 				read_obj_properties_cb);
1543 	} else {
1544 		inst->busy = false;
1545 		if (inst->otc_inst->cb->obj_metadata_read) {
1546 			inst->otc_inst->cb->obj_metadata_read(
1547 				inst->otc_inst, conn, inst->metadata_err,
1548 				inst->metadata_read);
1549 		}
1550 		return;
1551 	}
1552 
1553 	if (err) {
1554 		LOG_DBG("Metadata read failed (%d), trying next", err);
1555 		read_next_metadata(conn, inst);
1556 	}
1557 }
1558 
bt_ots_client_read_object_metadata(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint8_t metadata)1559 int bt_ots_client_read_object_metadata(struct bt_ots_client *otc_inst,
1560 				       struct bt_conn *conn,
1561 				       uint8_t metadata)
1562 {
1563 	struct bt_otc_internal_instance_t *inst;
1564 
1565 	if (!conn) {
1566 		LOG_WRN("Invalid Connection");
1567 		return -ENOTCONN;
1568 	} else if (!otc_inst) {
1569 		LOG_ERR("Invalid OTC instance");
1570 		return -EINVAL;
1571 	} else if (!metadata) {
1572 		LOG_WRN("No metadata to read");
1573 		return -ENOEXEC;
1574 	}
1575 
1576 	inst = lookup_inst_by_handle(otc_inst->start_handle);
1577 
1578 	if (!inst) {
1579 		LOG_ERR("Invalid OTC instance");
1580 		return -EINVAL;
1581 	} else if (inst->busy) {
1582 		return -EBUSY;
1583 	}
1584 
1585 	inst->metadata_read = 0;
1586 	inst->metadata_to_read = metadata & BT_OTS_METADATA_REQ_ALL;
1587 	inst->metadata_read_attempted = 0;
1588 
1589 	inst->busy = true;
1590 	read_next_metadata(conn, inst);
1591 
1592 	return 0;
1593 }
1594 
decode_record(struct net_buf_simple * buf,struct dirlisting_record_t * rec)1595 static int decode_record(struct net_buf_simple *buf,
1596 			 struct dirlisting_record_t *rec)
1597 {
1598 	uint16_t start_len = buf->len;
1599 
1600 	rec->len = net_buf_simple_pull_le16(buf);
1601 
1602 	if (rec->len > buf->len) {
1603 		LOG_WRN("incorrect DirListing record length %u, "
1604 			"longer than remaining size %u",
1605 			rec->len, buf->len);
1606 		return -EINVAL;
1607 	}
1608 
1609 	if ((start_len - buf->len) + BT_OTS_OBJ_ID_SIZE > rec->len) {
1610 		LOG_WRN("incorrect DirListing record, reclen %u too short, "
1611 			"includes only record length",
1612 			rec->len);
1613 		return -EINVAL;
1614 	}
1615 
1616 	rec->metadata.id = net_buf_simple_pull_le48(buf);
1617 
1618 	if (IS_ENABLED(CONFIG_BT_OTS_CLIENT_LOG_LEVEL_DBG)) {
1619 		char t[BT_OTS_OBJ_ID_STR_LEN];
1620 
1621 		(void)bt_ots_obj_id_to_str(rec->metadata.id, t, sizeof(t));
1622 		LOG_DBG("Object ID 0x%s", t);
1623 	}
1624 
1625 	if ((start_len - buf->len) + sizeof(uint8_t) > rec->len) {
1626 		LOG_WRN("incorrect DirListing record, reclen %u too short, "
1627 			"includes only record length + ObjId",
1628 			rec->len);
1629 		return -EINVAL;
1630 	}
1631 
1632 	rec->name_len = net_buf_simple_pull_u8(buf);
1633 
1634 	if (rec->name_len > 0) {
1635 		uint8_t *name;
1636 
1637 		if ((start_len - buf->len) + rec->name_len > rec->len) {
1638 			LOG_WRN("incorrect DirListing record, remaining length "
1639 				"%u shorter than name length %u",
1640 				rec->len - (start_len - buf->len),
1641 				rec->name_len);
1642 			return -EINVAL;
1643 		}
1644 
1645 		if (rec->name_len >= sizeof(rec->metadata.name_c)) {
1646 			LOG_WRN("Name length %u too long, invalid record", rec->name_len);
1647 			return -EINVAL;
1648 		}
1649 
1650 		name = net_buf_simple_pull_mem(buf, rec->name_len);
1651 		memcpy(rec->metadata.name_c, name, rec->name_len);
1652 	}
1653 
1654 	rec->metadata.name_c[rec->name_len] = '\0';
1655 	rec->flags = 0;
1656 
1657 	if ((start_len - buf->len) + sizeof(uint8_t) > rec->len) {
1658 		LOG_WRN("incorrect DirListing record, reclen %u too short, "
1659 			"does not include flags", rec->len);
1660 		return -EINVAL;
1661 	}
1662 
1663 	rec->flags = net_buf_simple_pull_u8(buf);
1664 	LOG_DBG("flags 0x%x", rec->flags);
1665 
1666 	if (BT_OTS_DIR_LIST_GET_FLAG_TYPE_128(rec->flags)) {
1667 		uint8_t *uuid;
1668 
1669 		if ((start_len - buf->len) + BT_UUID_SIZE_128 > rec->len) {
1670 			LOG_WRN("incorrect DirListing record, reclen %u "
1671 				"flags indicates uuid128, too short",
1672 				rec->len);
1673 			LOG_INF("flags 0x%x", rec->flags);
1674 			return -EINVAL;
1675 		}
1676 
1677 		uuid = net_buf_simple_pull_mem(buf, BT_UUID_SIZE_128);
1678 		if (!bt_uuid_create(&rec->metadata.type.uuid, uuid, BT_UUID_SIZE_128)) {
1679 			LOG_DBG("Failed to create UUID");
1680 			return -EINVAL;
1681 		}
1682 	} else {
1683 		if ((start_len - buf->len) + BT_UUID_SIZE_16 > rec->len) {
1684 			LOG_WRN("incorrect DirListing record, reclen %u "
1685 				"flags indicates uuid16, too short",
1686 				rec->len);
1687 			LOG_INF("flags 0x%x", rec->flags);
1688 			return -EINVAL;
1689 		}
1690 
1691 		rec->metadata.type.uuid_16.val =
1692 			net_buf_simple_pull_le16(buf);
1693 	}
1694 
1695 	if (BT_OTS_DIR_LIST_GET_FLAG_CUR_SIZE(rec->flags)) {
1696 		if ((start_len - buf->len) + sizeof(uint32_t) > rec->len) {
1697 			LOG_WRN("incorrect DirListing record, reclen %u "
1698 				"flags indicates cur_size, too short",
1699 				rec->len);
1700 			LOG_INF("flags 0x%x", rec->flags);
1701 			return -EINVAL;
1702 		}
1703 
1704 		rec->metadata.size.cur = net_buf_simple_pull_le32(buf);
1705 	}
1706 
1707 	if (BT_OTS_DIR_LIST_GET_FLAG_ALLOC_SIZE(rec->flags)) {
1708 		if ((start_len - buf->len) + sizeof(uint32_t) > rec->len) {
1709 			LOG_WRN("incorrect DirListing record, reclen %u "
1710 				"flags indicates allocated size, too short",
1711 				rec->len);
1712 			LOG_INF("flags 0x%x", rec->flags);
1713 			return -EINVAL;
1714 		}
1715 
1716 		rec->metadata.size.alloc = net_buf_simple_pull_le32(buf);
1717 	}
1718 
1719 	if (BT_OTS_DIR_LIST_GET_FLAG_FIRST_CREATED(rec->flags)) {
1720 		if ((start_len - buf->len) + BT_OTS_DATE_TIME_FIELD_SIZE > rec->len) {
1721 			LOG_WRN("incorrect DirListing record, reclen %u "
1722 				"too short flags indicates first_created",
1723 				rec->len);
1724 			LOG_INF("flags 0x%x", rec->flags);
1725 			return -EINVAL;
1726 		}
1727 
1728 		date_time_decode(buf, &rec->metadata.first_created);
1729 	}
1730 
1731 	if (BT_OTS_DIR_LIST_GET_FLAG_LAST_MODIFIED(rec->flags)) {
1732 		if ((start_len - buf->len) + BT_OTS_DATE_TIME_FIELD_SIZE > rec->len) {
1733 			LOG_WRN("incorrect DirListing record, reclen %u "
1734 				"flags indicates las_mod, too short",
1735 				rec->len);
1736 			LOG_INF("flags 0x%x", rec->flags);
1737 			return -EINVAL;
1738 		}
1739 
1740 		date_time_decode(buf, &rec->metadata.modified);
1741 	}
1742 
1743 	if (BT_OTS_DIR_LIST_GET_FLAG_PROPERTIES(rec->flags)) {
1744 		if ((start_len - buf->len) + sizeof(uint32_t) > rec->len) {
1745 			LOG_WRN("incorrect DirListing record, reclen %u "
1746 				"flags indicates properties, too short",
1747 				rec->len);
1748 			LOG_INF("flags 0x%x", rec->flags);
1749 			return -EINVAL;
1750 		}
1751 
1752 		rec->metadata.props = net_buf_simple_pull_le32(buf);
1753 	}
1754 
1755 	return rec->len;
1756 }
1757 
bt_ots_client_decode_dirlisting(uint8_t * data,uint16_t length,bt_ots_client_dirlisting_cb cb)1758 int bt_ots_client_decode_dirlisting(uint8_t *data, uint16_t length,
1759 				    bt_ots_client_dirlisting_cb cb)
1760 {
1761 	struct net_buf_simple net_buf;
1762 	uint8_t count = 0;
1763 	struct dirlisting_record_t record;
1764 
1765 	net_buf_simple_init_with_data(&net_buf, (void *)data, length);
1766 
1767 	if (!data || length == 0) {
1768 		return -EINVAL;
1769 	}
1770 
1771 	while (net_buf.len) {
1772 		int ret;
1773 
1774 		count++;
1775 
1776 		if (net_buf.len < sizeof(uint16_t)) {
1777 			LOG_WRN("incorrect DirListing record, len %u too short", net_buf.len);
1778 			return -EINVAL;
1779 		}
1780 
1781 		LOG_DBG("Decoding record %u", count);
1782 		ret = decode_record(&net_buf, &record);
1783 
1784 		if (ret < 0) {
1785 			LOG_WRN("DirListing, record %u invalid", count);
1786 			return ret;
1787 		}
1788 
1789 		ret = cb(&record.metadata);
1790 
1791 		if (ret == BT_OTS_STOP) {
1792 			break;
1793 		}
1794 	}
1795 
1796 	return count;
1797 }
1798 
bt_ots_metadata_display(struct bt_ots_obj_metadata * metadata,uint16_t count)1799 void bt_ots_metadata_display(struct bt_ots_obj_metadata *metadata,
1800 			     uint16_t count)
1801 {
1802 	LOG_INF("--- Displaying %u metadata records ---", count);
1803 
1804 	for (int i = 0; i < count; i++) {
1805 		char t[BT_OTS_OBJ_ID_STR_LEN];
1806 
1807 		(void)bt_ots_obj_id_to_str(metadata->id, t, sizeof(t));
1808 		LOG_INF("Object ID: 0x%s", t);
1809 		LOG_INF("Object name: %s", metadata->name_c);
1810 		LOG_INF("Object Current Size: %u", metadata->size.cur);
1811 		LOG_INF("Object Allocate Size: %u", metadata->size.alloc);
1812 
1813 		if (!bt_uuid_cmp(&metadata->type.uuid,
1814 				 BT_UUID_OTS_TYPE_MPL_ICON)) {
1815 			LOG_INF("Type: Icon Obj Type");
1816 		} else if (!bt_uuid_cmp(&metadata->type.uuid,
1817 					BT_UUID_OTS_TYPE_TRACK_SEGMENT)) {
1818 			LOG_INF("Type: Track Segment Obj Type");
1819 		} else if (!bt_uuid_cmp(&metadata->type.uuid,
1820 					BT_UUID_OTS_TYPE_TRACK)) {
1821 			LOG_INF("Type: Track Obj Type");
1822 		} else if (!bt_uuid_cmp(&metadata->type.uuid,
1823 					BT_UUID_OTS_TYPE_GROUP)) {
1824 			LOG_INF("Type: Group Obj Type");
1825 		} else if (!bt_uuid_cmp(&metadata->type.uuid,
1826 					BT_UUID_OTS_DIRECTORY_LISTING)) {
1827 			LOG_INF("Type: Directory Listing");
1828 		}
1829 
1830 
1831 		LOG_INF("Properties:0x%x", metadata->props);
1832 
1833 		if (BT_OTS_OBJ_GET_PROP_APPEND(metadata->props)) {
1834 			LOG_INF(" - append permitted");
1835 		}
1836 
1837 		if (BT_OTS_OBJ_GET_PROP_DELETE(metadata->props)) {
1838 			LOG_INF(" - delete permitted");
1839 		}
1840 
1841 		if (BT_OTS_OBJ_GET_PROP_EXECUTE(metadata->props)) {
1842 			LOG_INF(" - execute permitted");
1843 		}
1844 
1845 		if (BT_OTS_OBJ_GET_PROP_MARKED(metadata->props)) {
1846 			LOG_INF(" - marked");
1847 		}
1848 
1849 		if (BT_OTS_OBJ_GET_PROP_PATCH(metadata->props)) {
1850 			LOG_INF(" - patch permitted");
1851 		}
1852 
1853 		if (BT_OTS_OBJ_GET_PROP_READ(metadata->props)) {
1854 			LOG_INF(" - read permitted");
1855 		}
1856 
1857 		if (BT_OTS_OBJ_GET_PROP_TRUNCATE(metadata->props)) {
1858 			LOG_INF(" - truncate permitted");
1859 		}
1860 
1861 		if (BT_OTS_OBJ_GET_PROP_WRITE(metadata->props)) {
1862 			LOG_INF(" - write permitted");
1863 		}
1864 	}
1865 }
1866