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/sys/dlist.h>
12 #include <zephyr/sys/byteorder.h>
13
14 #include <zephyr/bluetooth/services/ots.h>
15 #include "ots_internal.h"
16
17 #include <zephyr/logging/log.h>
18
19 LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
20
21
22 struct bt_gatt_ots_pool_item {
23 sys_dnode_t dnode;
24 struct bt_gatt_ots_object val;
25 bool is_allocated;
26 };
27
28 struct bt_gatt_ots_obj_manager {
29 sys_dlist_t list;
30 struct bt_gatt_ots_pool_item pool[CONFIG_BT_OTS_MAX_OBJ_CNT];
31 bool is_assigned;
32 };
33
obj_id_to_index(uint64_t id)34 static uint64_t obj_id_to_index(uint64_t id)
35 {
36 if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
37 if (id == OTS_OBJ_ID_DIR_LIST) {
38 return id;
39 } else {
40 return id - BT_OTS_OBJ_ID_MIN + 1;
41 }
42 } else {
43 return id - BT_OTS_OBJ_ID_MIN;
44 }
45 }
46
obj_index_to_id(uint64_t index)47 static uint64_t obj_index_to_id(uint64_t index)
48 {
49 if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
50 if (index == 0) {
51 return OTS_OBJ_ID_DIR_LIST;
52 } else {
53 return BT_OTS_OBJ_ID_MIN + index - 1;
54 }
55 } else {
56 return BT_OTS_OBJ_ID_MIN + index;
57 }
58 }
59
bt_gatt_ots_obj_manager_first_obj_get(struct bt_gatt_ots_obj_manager * obj_manager,struct bt_gatt_ots_object ** obj)60 int bt_gatt_ots_obj_manager_first_obj_get(
61 struct bt_gatt_ots_obj_manager *obj_manager,
62 struct bt_gatt_ots_object **obj)
63 {
64 sys_dnode_t *obj_dnode;
65 struct bt_gatt_ots_pool_item *first_item;
66
67 if (sys_dlist_is_empty(&obj_manager->list)) {
68 return -ENOENT;
69 }
70
71 obj_dnode = sys_dlist_peek_head_not_empty(&obj_manager->list);
72 first_item = CONTAINER_OF(obj_dnode, struct bt_gatt_ots_pool_item,
73 dnode);
74 *obj = &first_item->val;
75
76 return 0;
77 }
78
bt_gatt_ots_obj_manager_last_obj_get(struct bt_gatt_ots_obj_manager * obj_manager,struct bt_gatt_ots_object ** obj)79 int bt_gatt_ots_obj_manager_last_obj_get(
80 struct bt_gatt_ots_obj_manager *obj_manager,
81 struct bt_gatt_ots_object **obj)
82 {
83 sys_dnode_t *obj_dnode;
84 struct bt_gatt_ots_pool_item *last_item;
85
86 if (sys_dlist_is_empty(&obj_manager->list)) {
87 return -ENOENT;
88 }
89
90 obj_dnode = sys_dlist_peek_tail(&obj_manager->list);
91 last_item = CONTAINER_OF(obj_dnode, struct bt_gatt_ots_pool_item,
92 dnode);
93 *obj = &last_item->val;
94
95 return 0;
96 }
97
bt_gatt_ots_obj_manager_prev_obj_get(struct bt_gatt_ots_obj_manager * obj_manager,const struct bt_gatt_ots_object * cur_obj,struct bt_gatt_ots_object ** prev_obj)98 int bt_gatt_ots_obj_manager_prev_obj_get(
99 struct bt_gatt_ots_obj_manager *obj_manager,
100 const struct bt_gatt_ots_object *cur_obj,
101 struct bt_gatt_ots_object **prev_obj)
102 {
103 sys_dnode_t *prev_obj_dnode;
104 struct bt_gatt_ots_pool_item *cur_item, *prev_item;
105
106 if (sys_dlist_is_empty(&obj_manager->list)) {
107 return -ENOENT;
108 }
109
110 cur_item = CONTAINER_OF(cur_obj, struct bt_gatt_ots_pool_item, val);
111 prev_obj_dnode = sys_dlist_peek_prev_no_check(&obj_manager->list,
112 &cur_item->dnode);
113 if (!prev_obj_dnode) {
114 return -ENFILE;
115 }
116
117 prev_item = CONTAINER_OF(prev_obj_dnode,
118 struct bt_gatt_ots_pool_item,
119 dnode);
120 *prev_obj = &prev_item->val;
121
122 return 0;
123 }
124
bt_gatt_ots_obj_manager_next_obj_get(struct bt_gatt_ots_obj_manager * obj_manager,const struct bt_gatt_ots_object * cur_obj,struct bt_gatt_ots_object ** next_obj)125 int bt_gatt_ots_obj_manager_next_obj_get(
126 struct bt_gatt_ots_obj_manager *obj_manager,
127 const struct bt_gatt_ots_object *cur_obj,
128 struct bt_gatt_ots_object **next_obj)
129 {
130 sys_dnode_t *next_obj_dnode;
131 struct bt_gatt_ots_pool_item *cur_item, *next_item;
132
133 if (sys_dlist_is_empty(&obj_manager->list)) {
134 return -ENOENT;
135 }
136
137 cur_item = CONTAINER_OF(cur_obj, struct bt_gatt_ots_pool_item, val);
138 next_obj_dnode = sys_dlist_peek_next_no_check(&obj_manager->list,
139 &cur_item->dnode);
140 if (!next_obj_dnode) {
141 return -ENFILE;
142 }
143
144 next_item = CONTAINER_OF(next_obj_dnode,
145 struct bt_gatt_ots_pool_item,
146 dnode);
147 *next_obj = &next_item->val;
148
149 return 0;
150 }
151
bt_gatt_ots_obj_manager_obj_get(struct bt_gatt_ots_obj_manager * obj_manager,uint64_t id,struct bt_gatt_ots_object ** object)152 int bt_gatt_ots_obj_manager_obj_get(
153 struct bt_gatt_ots_obj_manager *obj_manager, uint64_t id,
154 struct bt_gatt_ots_object **object)
155 {
156 uint64_t index;
157
158 if (sys_dlist_is_empty(&obj_manager->list)) {
159 return -ENOENT;
160 }
161
162 if (id == OTS_OBJ_ID_DIR_LIST && !IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
163 return -EINVAL;
164 }
165
166 index = obj_id_to_index(id);
167
168 if (index >= ARRAY_SIZE(obj_manager->pool)) {
169 return -EINVAL;
170 }
171
172 if (!obj_manager->pool[index].is_allocated) {
173 return -EINVAL;
174 }
175
176 *object = &obj_manager->pool[index].val;
177
178 return 0;
179 }
180
bt_gatt_ots_obj_manager_obj_add(struct bt_gatt_ots_obj_manager * obj_manager,struct bt_gatt_ots_object ** object)181 int bt_gatt_ots_obj_manager_obj_add(
182 struct bt_gatt_ots_obj_manager *obj_manager,
183 struct bt_gatt_ots_object **object)
184 {
185 for (uint64_t i = 0; i < ARRAY_SIZE(obj_manager->pool); i++) {
186 struct bt_gatt_ots_pool_item *cur_obj =
187 &obj_manager->pool[i];
188
189 if (!cur_obj->is_allocated) {
190 cur_obj->is_allocated = true;
191 cur_obj->val.id = obj_index_to_id(i);
192 sys_dlist_append(&obj_manager->list, &cur_obj->dnode);
193
194 *object = &cur_obj->val;
195 return 0;
196 }
197 }
198
199 return -ENOMEM;
200 }
201
bt_gatt_ots_obj_manager_obj_delete(struct bt_gatt_ots_object * obj)202 int bt_gatt_ots_obj_manager_obj_delete(struct bt_gatt_ots_object *obj)
203 {
204 struct bt_gatt_ots_pool_item *item;
205
206 item = CONTAINER_OF(obj, struct bt_gatt_ots_pool_item, val);
207
208 if (!item->is_allocated) {
209 return -EINVAL;
210 }
211
212 if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
213 obj->id == OTS_OBJ_ID_DIR_LIST) {
214 return -EINVAL;
215 }
216
217 item->is_allocated = false;
218 sys_dlist_remove(&item->dnode);
219
220 return 0;
221 }
222
223
bt_gatt_ots_obj_manager_obj_contains(struct bt_gatt_ots_obj_manager * obj_manager,struct bt_gatt_ots_object * obj)224 bool bt_gatt_ots_obj_manager_obj_contains(struct bt_gatt_ots_obj_manager *obj_manager,
225 struct bt_gatt_ots_object *obj)
226 {
227 struct bt_gatt_ots_pool_item *item;
228
229 item = CONTAINER_OF(obj, struct bt_gatt_ots_pool_item, val);
230
231 return PART_OF_ARRAY(obj_manager->pool, item);
232 }
233
bt_gatt_ots_obj_manager_assign(void)234 void *bt_gatt_ots_obj_manager_assign(void)
235 {
236 static struct bt_gatt_ots_obj_manager
237 obj_manager[CONFIG_BT_OTS_MAX_INST_CNT];
238 struct bt_gatt_ots_obj_manager *cur_manager;
239
240
241 for (cur_manager = obj_manager;
242 cur_manager != obj_manager + CONFIG_BT_OTS_MAX_INST_CNT;
243 cur_manager++) {
244 if (!cur_manager->is_assigned) {
245 break;
246 }
247 }
248
249 if (cur_manager->is_assigned) {
250 return NULL;
251 }
252
253 cur_manager->is_assigned = true;
254 sys_dlist_init(&cur_manager->list);
255
256 return cur_manager;
257 }
258