1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/types.h>
8 #include <stddef.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <zephyr/init.h>
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/kernel.h>
15 
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/l2cap.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/uuid.h>
20 #include <zephyr/bluetooth/gatt.h>
21 
22 #include <zephyr/sys/check.h>
23 
24 #include <zephyr/bluetooth/services/ots.h>
25 #include "ots_internal.h"
26 #include "ots_obj_manager_internal.h"
27 #include "ots_dir_list_internal.h"
28 
29 #include <zephyr/logging/log.h>
30 
31 LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
32 
33 #if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT)
34 #define OACP_FEAT_BIT_CREATE BIT(BT_OTS_OACP_FEAT_CREATE)
35 #else
36 #define OACP_FEAT_BIT_CREATE 0
37 #endif
38 
39 #if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT)
40 #define OACP_FEAT_BIT_DELETE BIT(BT_OTS_OACP_FEAT_DELETE)
41 #else
42 #define OACP_FEAT_BIT_DELETE 0
43 #endif
44 
45 #if defined(BT_OTS_OACP_CHECKSUM_SUPPORT)
46 #define OACP_FEAT_BIT_CRC BIT(BT_OTS_OACP_FEAT_CHECKSUM)
47 #else
48 #define OACP_FEAT_BIT_CRC 0
49 #endif
50 
51 #if defined(CONFIG_BT_OTS_OACP_READ_SUPPORT)
52 #define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ)
53 #else
54 #define OACP_FEAT_BIT_READ 0
55 #endif
56 
57 #if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT)
58 #define OACP_FEAT_BIT_WRITE BIT(BT_OTS_OACP_FEAT_WRITE)
59 #else
60 #define OACP_FEAT_BIT_WRITE 0
61 #endif
62 
63 #if defined(CONFIG_BT_OTS_OACP_PATCH_SUPPORT)
64 #define OACP_FEAT_BIT_PATCH BIT(BT_OTS_OACP_FEAT_PATCH)
65 #else
66 #define OACP_FEAT_BIT_PATCH 0
67 #endif
68 
69 /* OACP features supported by Kconfig */
70 #define OACP_FEAT (		\
71 	OACP_FEAT_BIT_CREATE |	\
72 	OACP_FEAT_BIT_DELETE |	\
73 	OACP_FEAT_BIT_CRC |     \
74 	OACP_FEAT_BIT_READ |	\
75 	OACP_FEAT_BIT_WRITE |	\
76 	OACP_FEAT_BIT_PATCH)
77 
78 #if defined(CONFIG_BT_OTS_OLCP_GO_TO_SUPPORT)
79 #define OLCP_FEAT_BIT_GOTO BIT(BT_OTS_OLCP_FEAT_GO_TO)
80 #else
81 #define OLCP_FEAT_BIT_GOTO 0
82 #endif
83 
84 /* OLCP features supported by Kconfig */
85 #define OLCP_FEAT OLCP_FEAT_BIT_GOTO
86 
ots_obj_validate_prop_against_oacp(uint32_t prop,uint32_t oacp)87 static bool ots_obj_validate_prop_against_oacp(uint32_t prop, uint32_t oacp)
88 {
89 	if (BT_OTS_OBJ_GET_PROP_DELETE(prop) > 0 && BT_OTS_OACP_GET_FEAT_DELETE(oacp) == 0) {
90 		return false;
91 	}
92 
93 	if (BT_OTS_OBJ_GET_PROP_EXECUTE(prop) > 0 && BT_OTS_OACP_GET_FEAT_EXECUTE(oacp) == 0) {
94 		return false;
95 	}
96 
97 	if (BT_OTS_OBJ_GET_PROP_READ(prop) > 0 && BT_OTS_OACP_GET_FEAT_READ(oacp) == 0) {
98 		return false;
99 	}
100 
101 	if (BT_OTS_OBJ_GET_PROP_WRITE(prop) > 0 && BT_OTS_OACP_GET_FEAT_WRITE(oacp) == 0) {
102 		return false;
103 	}
104 
105 	if (BT_OTS_OBJ_GET_PROP_APPEND(prop) > 0 && BT_OTS_OACP_GET_FEAT_APPEND(oacp) == 0) {
106 		return false;
107 	}
108 
109 	if (BT_OTS_OBJ_GET_PROP_TRUNCATE(prop) > 0 && BT_OTS_OACP_GET_FEAT_TRUNCATE(oacp) == 0) {
110 		return false;
111 	}
112 
113 	if (BT_OTS_OBJ_GET_PROP_PATCH(prop) > 0 && BT_OTS_OACP_GET_FEAT_PATCH(oacp) == 0) {
114 		return false;
115 	}
116 
117 	return true;
118 }
119 
ots_feature_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)120 static ssize_t ots_feature_read(struct bt_conn *conn,
121 				const struct bt_gatt_attr *attr, void *buf,
122 				uint16_t len, uint16_t offset)
123 {
124 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
125 
126 	LOG_DBG("OTS Feature GATT Read Operation");
127 
128 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &ots->features,
129 		sizeof(ots->features));
130 }
131 
ots_obj_name_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)132 static ssize_t ots_obj_name_read(struct bt_conn *conn,
133 				 const struct bt_gatt_attr *attr, void *buf,
134 				 uint16_t len, uint16_t offset)
135 {
136 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
137 
138 	LOG_DBG("OTS Object Name GATT Read Operation");
139 
140 	if (!ots->cur_obj) {
141 		LOG_DBG("No Current Object selected in OTS!");
142 		return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
143 	}
144 
145 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
146 				 ots->cur_obj->metadata.name,
147 				 strlen(ots->cur_obj->metadata.name));
148 }
149 
150 #if defined(CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT)
ots_obj_name_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)151 ssize_t ots_obj_name_write(struct bt_conn *conn,
152 			   const struct bt_gatt_attr *attr,
153 			   const void *buf, uint16_t len,
154 			   uint16_t offset, uint8_t flags)
155 {
156 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
157 	struct bt_gatt_ots_object *obj = NULL;
158 	int rc = 0;
159 	char name[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1];
160 
161 	LOG_DBG("OTS Object Name GATT Write Operation");
162 
163 	if (!ots->cur_obj) {
164 		LOG_DBG("No Current Object selected in OTS!");
165 		return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
166 	}
167 
168 	if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
169 	    ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) {
170 		LOG_DBG("Rejecting name write for the directory list object.");
171 		return BT_GATT_ERR(BT_GATT_OTS_WRITE_REQUEST_REJECTED);
172 	}
173 
174 	if (offset > 0) {
175 		LOG_DBG("Rejecting a long write, offset must be 0!");
176 		return BT_GATT_ERR(BT_GATT_OTS_WRITE_REQUEST_REJECTED);
177 	}
178 
179 	if (len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) {
180 		LOG_DBG("Object name is too long!");
181 		return BT_GATT_ERR(BT_GATT_OTS_WRITE_REQUEST_REJECTED);
182 	}
183 
184 	/* Construct a temporary name for duplication detection */
185 	memcpy(name, buf, len);
186 	name[len] = '\0';
187 
188 	rc = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, &obj);
189 	while (rc == 0) {
190 		if (obj != ots->cur_obj && strcmp(name, obj->metadata.name) == 0) {
191 			LOG_DBG("Object name is duplicated!");
192 			return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NAME_ALREADY_EXISTS);
193 		}
194 		rc = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, obj, &obj);
195 	}
196 
197 	/* No duplicate detected, notify application and update real object name */
198 	if (ots->cb->obj_name_written) {
199 		ots->cb->obj_name_written(ots, conn, ots->cur_obj->id,
200 					  ots->cur_obj->metadata.name, name);
201 	}
202 
203 	strcpy(ots->cur_obj->metadata.name, name);
204 
205 	return len;
206 }
207 #endif
208 
ots_obj_type_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)209 static ssize_t ots_obj_type_read(struct bt_conn *conn,
210 				 const struct bt_gatt_attr *attr, void *buf,
211 				 uint16_t len, uint16_t offset)
212 {
213 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
214 	struct bt_ots_obj_metadata *obj_meta;
215 
216 	LOG_DBG("OTS Object Type GATT Read Operation");
217 
218 	if (!ots->cur_obj) {
219 		LOG_DBG("No Current Object selected in OTS!");
220 		return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
221 	}
222 
223 	obj_meta = &ots->cur_obj->metadata;
224 	switch (obj_meta->type.uuid.type) {
225 	case BT_UUID_TYPE_16:
226 		return bt_gatt_attr_read(conn, attr, buf, len, offset,
227 					 &obj_meta->type.uuid_16.val,
228 					 sizeof(obj_meta->type.uuid_16.val));
229 	case BT_UUID_TYPE_128:
230 		return bt_gatt_attr_read(conn, attr, buf, len, offset,
231 					 obj_meta->type.uuid_128.val,
232 					 sizeof(obj_meta->type.uuid_128.val));
233 	default:
234 		return -EINVAL;
235 	}
236 }
237 
ots_obj_size_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)238 static ssize_t ots_obj_size_read(struct bt_conn *conn,
239 				 const struct bt_gatt_attr *attr, void *buf,
240 				 uint16_t len, uint16_t offset)
241 {
242 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
243 
244 	LOG_DBG("OTS Object Size GATT Read Operation");
245 
246 	if (!ots->cur_obj) {
247 		LOG_DBG("No Current Object selected in OTS!");
248 		return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
249 	}
250 
251 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
252 				 &ots->cur_obj->metadata.size,
253 				 sizeof(ots->cur_obj->metadata.size));
254 }
255 
ots_obj_id_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)256 static ssize_t ots_obj_id_read(struct bt_conn *conn,
257 			       const struct bt_gatt_attr *attr, void *buf,
258 			       uint16_t len, uint16_t offset)
259 {
260 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
261 	uint8_t id[BT_OTS_OBJ_ID_SIZE];
262 	char id_str[BT_OTS_OBJ_ID_STR_LEN];
263 
264 	LOG_DBG("OTS Object ID GATT Read Operation");
265 
266 	if (!ots->cur_obj) {
267 		LOG_DBG("No Current Object selected in OTS!");
268 		return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
269 	}
270 
271 	sys_put_le48(ots->cur_obj->id, id);
272 
273 	bt_ots_obj_id_to_str(ots->cur_obj->id, id_str,
274 				      sizeof(id_str));
275 	LOG_DBG("Current Object ID: %s", id_str);
276 
277 	return bt_gatt_attr_read(conn, attr, buf, len, offset, id, sizeof(id));
278 }
279 
ots_obj_prop_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)280 static ssize_t ots_obj_prop_read(struct bt_conn *conn,
281 				 const struct bt_gatt_attr *attr, void *buf,
282 				 uint16_t len, uint16_t offset)
283 {
284 	struct bt_ots *ots = (struct bt_ots *) attr->user_data;
285 
286 	LOG_DBG("OTS Object Properties GATT Read Operation");
287 
288 	if (!ots->cur_obj) {
289 		LOG_DBG("No Current Object selected in OTS!");
290 		return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
291 	}
292 
293 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
294 				 &ots->cur_obj->metadata.props,
295 				 sizeof(ots->cur_obj->metadata.props));
296 }
297 
bt_ots_obj_add_internal(struct bt_ots * ots,struct bt_conn * conn,const struct bt_ots_obj_add_param * param,struct bt_gatt_ots_object ** obj)298 int bt_ots_obj_add_internal(struct bt_ots *ots, struct bt_conn *conn,
299 			    const struct bt_ots_obj_add_param *param,
300 			    struct bt_gatt_ots_object **obj)
301 {
302 	int err;
303 	struct bt_gatt_ots_object *new_obj;
304 	struct bt_ots_obj_created_desc created_desc;
305 
306 	if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list &&
307 	    !bt_ots_dir_list_is_idle(ots->dir_list)) {
308 		LOG_DBG("Directory Listing Object is being read");
309 		return -EBUSY;
310 	}
311 
312 	err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &new_obj);
313 	if (err) {
314 		LOG_ERR("No space available in the object manager");
315 		return err;
316 	}
317 
318 	(void)memset(&created_desc, 0, sizeof(created_desc));
319 
320 	if (ots->cb->obj_created) {
321 		err = ots->cb->obj_created(ots, NULL, new_obj->id, param, &created_desc);
322 
323 		if (err) {
324 			(void)bt_gatt_ots_obj_manager_obj_delete(new_obj);
325 
326 			return err;
327 		}
328 
329 		if (!ots_obj_validate_prop_against_oacp(created_desc.props, ots->features.oacp)) {
330 			LOG_ERR("Object properties (0x%04X) are not a subset of OACP (0x%04X)",
331 				created_desc.props, ots->features.oacp);
332 
333 			(void)bt_ots_obj_delete(ots, new_obj->id);
334 			return -ECANCELED;
335 		}
336 
337 		if (created_desc.name == NULL) {
338 			LOG_ERR("Object name must be set by application after object creation.");
339 
340 			(void)bt_ots_obj_delete(ots, new_obj->id);
341 			return -ECANCELED;
342 		}
343 
344 		if (created_desc.size.alloc < param->size) {
345 			LOG_ERR("Object allocated size must >= requested size.");
346 
347 			(void)bt_ots_obj_delete(ots, new_obj->id);
348 			return -ECANCELED;
349 		}
350 	}
351 
352 	new_obj->metadata.type = param->type;
353 	new_obj->metadata.name = created_desc.name;
354 	new_obj->metadata.size = created_desc.size;
355 	new_obj->metadata.props = created_desc.props;
356 
357 	if (obj) {
358 		*obj = new_obj;
359 	}
360 
361 	return 0;
362 }
363 
bt_ots_obj_add(struct bt_ots * ots,const struct bt_ots_obj_add_param * param)364 int bt_ots_obj_add(struct bt_ots *ots, const struct bt_ots_obj_add_param *param)
365 {
366 	int err;
367 	size_t name_len;
368 	struct bt_gatt_ots_object *obj;
369 
370 	err = bt_ots_obj_add_internal(ots, NULL, param, &obj);
371 	if (err) {
372 		return err;
373 	}
374 
375 	name_len = strlen(obj->metadata.name);
376 	if (name_len == 0 || name_len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) {
377 		LOG_ERR("Invalid name length %zu", name_len);
378 
379 		(void)bt_ots_obj_delete(ots, obj->id);
380 		return -ECANCELED;
381 	}
382 
383 	if (obj->metadata.size.cur > param->size) {
384 		LOG_ERR("Object current size must be less than or equal to requested size.");
385 
386 		(void)bt_ots_obj_delete(ots, obj->id);
387 		return -ECANCELED;
388 	}
389 
390 	return obj->id;
391 }
392 
bt_ots_obj_delete(struct bt_ots * ots,uint64_t id)393 int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
394 {
395 	int err;
396 	struct bt_gatt_ots_object *obj;
397 
398 	CHECKIF(!BT_OTS_VALID_OBJ_ID(id)) {
399 		LOG_DBG("Invalid object ID 0x%016llx", id);
400 
401 		return -EINVAL;
402 	}
403 
404 	err = bt_gatt_ots_obj_manager_obj_get(ots->obj_manager, id, &obj);
405 	if (err) {
406 		return err;
407 	}
408 
409 	if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
410 		return -EBUSY;
411 	}
412 
413 	if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list &&
414 	    !bt_ots_dir_list_is_idle(ots->dir_list)) {
415 		LOG_DBG("Directory Listing Object is being read");
416 		return -EBUSY;
417 	}
418 
419 	if (ots->cb->obj_deleted) {
420 		err = ots->cb->obj_deleted(ots, NULL, obj->id);
421 		if (err) {
422 			return err;
423 		}
424 	}
425 
426 	err = bt_gatt_ots_obj_manager_obj_delete(obj);
427 	if (err) {
428 		return err;
429 	}
430 
431 	if (ots->cur_obj == obj) {
432 		ots->cur_obj = NULL;
433 	}
434 
435 	return 0;
436 }
437 
438 #if defined(CONFIG_BT_OTS_SECONDARY_SVC)
bt_ots_svc_decl_get(struct bt_ots * ots)439 void *bt_ots_svc_decl_get(struct bt_ots *ots)
440 {
441 	return ots->service->attrs;
442 }
443 #endif
444 
bt_ots_init(struct bt_ots * ots,struct bt_ots_init_param * ots_init)445 int bt_ots_init(struct bt_ots *ots,
446 		     struct bt_ots_init_param *ots_init)
447 {
448 	int err;
449 
450 	if (!ots || !ots_init || !ots_init->cb) {
451 		return -EINVAL;
452 	}
453 
454 	__ASSERT(ots_init->cb->obj_created,
455 		 "Callback for object creation is not set");
456 	__ASSERT(ots_init->cb->obj_deleted ||
457 		 !BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp),
458 		 "Callback for object deletion is not set and object creation is enabled");
459 #if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT)
460 	__ASSERT(ots_init->cb->obj_cal_checksum,
461 		 "Callback for object calculate checksum is not set");
462 #endif
463 	__ASSERT(ots_init->cb->obj_read ||
464 		 !BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp),
465 		 "Callback for object reading is not set");
466 	__ASSERT(ots_init->cb->obj_write ||
467 		 !BT_OTS_OACP_GET_FEAT_WRITE(ots_init->features.oacp),
468 		 "Callback for object write is not set");
469 
470 	/* Set callback structure. */
471 	ots->cb = ots_init->cb;
472 
473 	/* Check OACP supported features against Kconfig. */
474 	if (ots_init->features.oacp & (~((uint32_t) OACP_FEAT))) {
475 		return -ENOTSUP;
476 	}
477 
478 	__ASSERT(!BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp) ||
479 		 BT_OTS_OACP_GET_FEAT_WRITE(ots_init->features.oacp),
480 		 "Object creation requires object write to be supported");
481 
482 	ots->features.oacp = ots_init->features.oacp;
483 	LOG_DBG("OACP features: 0x%04X", ots->features.oacp);
484 
485 	/* Check OLCP supported features against Kconfig. */
486 	if (ots_init->features.olcp & (~((uint32_t) OLCP_FEAT))) {
487 		return -ENOTSUP;
488 	}
489 	ots->features.olcp = ots_init->features.olcp;
490 	LOG_DBG("OLCP features: 0x%04X", ots->features.olcp);
491 
492 	/* Register L2CAP context. */
493 	err = bt_gatt_ots_l2cap_register(&ots->l2cap);
494 	if (err) {
495 		return err;
496 	}
497 
498 	err = bt_gatt_service_register(ots->service);
499 	if (err) {
500 		bt_gatt_ots_l2cap_unregister(&ots->l2cap);
501 
502 		return err;
503 	}
504 
505 	if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
506 		bt_ots_dir_list_init(&ots->dir_list, ots->obj_manager);
507 	}
508 
509 	LOG_DBG("Initialized OTS");
510 
511 	return 0;
512 }
513 
514 #if defined(CONFIG_BT_OTS_SECONDARY_SVC)
515 	#define BT_GATT_OTS_SERVICE	BT_GATT_SECONDARY_SERVICE
516 #else
517 	#define BT_GATT_OTS_SERVICE	BT_GATT_PRIMARY_SERVICE
518 #endif
519 
520 #if defined(CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT)
521 	#define BT_OTS_OBJ_NAME_GATT_CHRC  (BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE)
522 	#define BT_OTS_OBJ_NAME_GATT_PERM  (BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
523 	#define BT_OTS_OBJ_NAME_GATT_WRITE (ots_obj_name_write)
524 #else
525 	#define BT_OTS_OBJ_NAME_GATT_CHRC  (BT_GATT_CHRC_READ)
526 	#define BT_OTS_OBJ_NAME_GATT_PERM  (BT_GATT_PERM_READ)
527 	#define BT_OTS_OBJ_NAME_GATT_WRITE (NULL)
528 #endif
529 
530 #define BT_GATT_OTS_ATTRS(_ots) {					\
531 	BT_GATT_OTS_SERVICE(BT_UUID_OTS),				\
532 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_FEATURE,			\
533 		BT_GATT_CHRC_READ, BT_GATT_PERM_READ,			\
534 		ots_feature_read, NULL, &_ots),				\
535 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_NAME,			\
536 		BT_OTS_OBJ_NAME_GATT_CHRC, BT_OTS_OBJ_NAME_GATT_PERM,	\
537 		ots_obj_name_read, BT_OTS_OBJ_NAME_GATT_WRITE, &_ots),	\
538 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_TYPE,			\
539 		BT_GATT_CHRC_READ, BT_GATT_PERM_READ,			\
540 		ots_obj_type_read, NULL, &_ots),			\
541 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_SIZE,			\
542 		BT_GATT_CHRC_READ, BT_GATT_PERM_READ,			\
543 		ots_obj_size_read, NULL, &_ots),			\
544 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_ID,				\
545 		BT_GATT_CHRC_READ, BT_GATT_PERM_READ,			\
546 		ots_obj_id_read, NULL, &_ots),				\
547 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_PROPERTIES,			\
548 		BT_GATT_CHRC_READ, BT_GATT_PERM_READ,			\
549 		ots_obj_prop_read, NULL, &_ots),			\
550 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_ACTION_CP,			\
551 		BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE,		\
552 		BT_GATT_PERM_WRITE, NULL,				\
553 		bt_gatt_ots_oacp_write, &_ots),				\
554 	BT_GATT_CCC_MANAGED(&_ots.oacp_ind.ccc,				\
555 		BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),		\
556 	BT_GATT_CHARACTERISTIC(BT_UUID_OTS_LIST_CP,			\
557 		BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE,		\
558 		BT_GATT_PERM_WRITE, NULL,				\
559 		bt_gatt_ots_olcp_write, &_ots),				\
560 	BT_GATT_CCC_MANAGED(&_ots.olcp_ind.ccc,				\
561 		BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)			\
562 }
563 
564 #define BT_GATT_OTS_INSTANCE_LIST_SIZE	(ARRAY_SIZE(ots_instances))
565 #define BT_GATT_OTS_INSTANCE_LIST_START	ots_instances
566 #define BT_GATT_OTS_INSTANCE_LIST_END	\
567 	(&ots_instances[BT_GATT_OTS_INSTANCE_LIST_SIZE])
568 
569 #define BT_GATT_OTS_SERVICE_LIST_START	ots_service_list
570 
571 static struct bt_ots ots_instances[CONFIG_BT_OTS_MAX_INST_CNT];
572 static uint32_t instance_cnt;
573 BT_GATT_SERVICE_INSTANCE_DEFINE(ots_service_list, ots_instances,
574 				CONFIG_BT_OTS_MAX_INST_CNT,
575 				BT_GATT_OTS_ATTRS);
576 
ots_delete_empty_name_objects(struct bt_ots * ots,struct bt_conn * conn)577 static void ots_delete_empty_name_objects(struct bt_ots *ots, struct bt_conn *conn)
578 {
579 	char id_str[BT_OTS_OBJ_ID_STR_LEN];
580 	struct bt_gatt_ots_object *obj;
581 	struct bt_gatt_ots_object *next_obj;
582 	int err;
583 
584 	err = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, &next_obj);
585 	while (!err) {
586 		obj = next_obj;
587 
588 		/* Get the next object before we potentially delete the current object and
589 		 * no longer can get the next object
590 		 */
591 		err = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, obj, &next_obj);
592 
593 		if (strlen(obj->metadata.name) == 0) {
594 			bt_ots_obj_id_to_str(obj->id, id_str, sizeof(id_str));
595 			LOG_DBG("Deleting object with %s ID due to empty name", id_str);
596 
597 			if (ots->cb && ots->cb->obj_deleted) {
598 				ots->cb->obj_deleted(ots, conn, obj->id);
599 			}
600 
601 			if (bt_gatt_ots_obj_manager_obj_delete(obj)) {
602 				LOG_ERR("Failed to remove object with %s ID from object manager",
603 					id_str);
604 			}
605 		}
606 	}
607 }
608 
ots_conn_disconnected(struct bt_conn * conn,uint8_t reason)609 static void ots_conn_disconnected(struct bt_conn *conn, uint8_t reason)
610 {
611 	uint32_t index;
612 	struct bt_ots *instance;
613 
614 	for (instance = BT_GATT_OTS_INSTANCE_LIST_START, index = 0;
615 	     index < instance_cnt;
616 	     instance++, index++) {
617 
618 		LOG_DBG("Processing disconnect for OTS instance %u", index);
619 
620 		if (instance->cur_obj != NULL) {
621 			__ASSERT(instance->cur_obj->state.type == BT_GATT_OTS_OBJECT_IDLE_STATE,
622 				"The current object is expected to be in idle state as part "
623 				"of cleanup of the L2CAP channel connection close.");
624 			instance->cur_obj = NULL;
625 		}
626 
627 		ots_delete_empty_name_objects(instance, conn);
628 	}
629 }
630 
631 BT_CONN_CB_DEFINE(conn_callbacks) = {
632 	.disconnected = ots_conn_disconnected,
633 };
634 
bt_ots_free_instance_get(void)635 struct bt_ots *bt_ots_free_instance_get(void)
636 {
637 	if (instance_cnt >= BT_GATT_OTS_INSTANCE_LIST_SIZE) {
638 		return NULL;
639 	}
640 
641 	return &BT_GATT_OTS_INSTANCE_LIST_START[instance_cnt++];
642 }
643 
bt_gatt_ots_instances_prepare(void)644 static int bt_gatt_ots_instances_prepare(void)
645 {
646 	uint32_t index;
647 	struct bt_ots *instance;
648 
649 	for (instance = BT_GATT_OTS_INSTANCE_LIST_START, index = 0;
650 	     instance != BT_GATT_OTS_INSTANCE_LIST_END;
651 	     instance++, index++) {
652 		/* Assign an object pool to the OTS instance. */
653 		instance->obj_manager = bt_gatt_ots_obj_manager_assign();
654 
655 		if (!instance->obj_manager) {
656 			LOG_ERR("OTS Object manager instance not available");
657 			return -ENOMEM;
658 		}
659 
660 		/* Assign pointer to the service descriptor. */
661 		instance->service = &BT_GATT_OTS_SERVICE_LIST_START[index];
662 
663 		/* Initialize CCC descriptors for characteristics with
664 		 * indication properties.
665 		 */
666 		instance->oacp_ind.ccc.cfg_changed =
667 			bt_gatt_ots_oacp_cfg_changed;
668 		instance->olcp_ind.ccc.cfg_changed =
669 			bt_gatt_ots_olcp_cfg_changed;
670 	}
671 
672 	return 0;
673 }
674 
675 SYS_INIT(bt_gatt_ots_instances_prepare, APPLICATION,
676 	 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
677