1 /*
2 * Copyright (c) 2021 WinnerMicro Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdbool.h>
20
21 #include "ohos_bt_gatt_server.h"
22
23 #include "wm_mem.h"
24 #include "wm_ble.h"
25 #include "wm_bt_def.h"
26 #include "list.h"
27 #include "ble_util.h"
28
29 #include "host/ble_hs.h"
30 #include "host/util/util.h"
31
32 /*
33 * STRUCTURE DEFINITIONS
34 ****************************************************************************************
35 */
36
37 typedef struct {
38 struct dl_list list;
39 BleAttribType attr_type;
40 uint16_t attr_handle;
41 ble_uuid_any_t uuid;
42 BleGattOperateFunc func;
43 struct ble_npl_mutex service_mutex;
44 } service_elem_t;
45
46 typedef struct {
47 struct dl_list list;
48 uint16_t server_id;
49 uint8_t srvc_count;
50 void *priv_data;
51 service_elem_t srvc_list;
52 struct ble_npl_mutex server_mutex;
53 } server_elem_t;
54
55 typedef struct {
56 struct dl_list list;
57 struct ble_gatt_svc_def *svc;
58 } nim_service_t;
59
60 /*
61 * GLOBAL VARIABLE DEFINITIONS
62 ****************************************************************************************
63 */
64
65 static uint16_t g_server_id;
66 static server_elem_t server_list;
67 static nim_service_t nim_service_list;
68
69 /*
70 * LOCAL FUNCTION DEFINITIONS
71 ****************************************************************************************
72 */
73
ble_server_gap_event(struct ble_gap_event * event,void * arg)74 void ble_server_gap_event(struct ble_gap_event *event, void *arg)
75 {
76 BdAddr bdaddr;
77 struct ble_gap_conn_desc desc;
78 server_elem_t *svr_item = NULL;
79 BtGattServerCallbacks *gatts_struct_func_ptr_cb = (BtGattServerCallbacks *)arg;
80
81 switch (event->type) {
82 case BLE_GAP_EVENT_CONNECT:
83 if (event->connect.status == 0) {
84 int rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
85 assert(rc == 0);
86 memcpy(bdaddr.addr, desc.peer_id_addr.val, 6); // 6:size
87
88 if (gatts_struct_func_ptr_cb && gatts_struct_func_ptr_cb->connectServerCb) {
89 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
90 gatts_struct_func_ptr_cb->connectServerCb(event->connect.conn_handle, \
91 svr_item->server_id, &bdaddr);
92 }
93 }
94 break;
95 case BLE_GAP_EVENT_DISCONNECT:
96 memcpy(bdaddr.addr, event->disconnect.conn.peer_id_addr.val, 6); // 6:size
97 if (gatts_struct_func_ptr_cb && gatts_struct_func_ptr_cb->disconnectServerCb) {
98 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
99 gatts_struct_func_ptr_cb->disconnectServerCb(event->disconnect.conn.conn_handle, \
100 svr_item->server_id, &bdaddr);
101 }
102 break;
103 default:
104 break;
105 }
106 }
107
ble_server_retrieve_id_by_uuid(ble_uuid_t * uuid,uint16_t * server_id)108 void ble_server_retrieve_id_by_uuid(ble_uuid_t *uuid, uint16_t *server_id)
109 {
110 server_elem_t *svr_item = NULL;
111 service_elem_t *svc_item = NULL;
112 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
113 {
114 svc_item = dl_list_first(&svr_item->srvc_list.list, service_elem_t, list);
115 if (ble_uuid_cmp(uuid, &svc_item->uuid) == 0) {
116 *server_id = svr_item->server_id;
117 }
118 }
119 }
120
ble_server_retrieve_id_by_service_id(uint16_t svc_handle,uint16_t * server_id)121 void ble_server_retrieve_id_by_service_id(uint16_t svc_handle, uint16_t *server_id)
122 {
123 server_elem_t *svr_item = NULL;
124 service_elem_t *svc_item = NULL;
125 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
126 {
127 svc_item = dl_list_first(&svr_item->srvc_list.list, service_elem_t, list);
128 if (svc_item->attr_handle == svc_handle) {
129 *server_id = svr_item->server_id;
130 }
131 }
132 }
ble_server_retrieve_service_handle_by_server_id(uint16_t server_id,uint16_t * service_handle)133 void ble_server_retrieve_service_handle_by_server_id(uint16_t server_id, uint16_t *service_handle)
134 {
135 server_elem_t *svr_item = NULL;
136 service_elem_t *svc_item = NULL;
137 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
138 {
139 if (svr_item->server_id == server_id) {
140 svc_item = dl_list_first(&svr_item->srvc_list.list, service_elem_t, list);
141 if (svc_item) {
142 *service_handle = svc_item->attr_handle;
143 }
144 }
145 }
146 }
147
ble_server_update_svc_handle(ble_uuid_t * uuid,uint16_t attr_handle)148 void ble_server_update_svc_handle(ble_uuid_t *uuid, uint16_t attr_handle)
149 {
150 server_elem_t *svr_item = NULL;
151 service_elem_t *svc_item = NULL;
152 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
153 {
154 svc_item = dl_list_first(&svr_item->srvc_list.list, service_elem_t, list);
155 if (ble_uuid_cmp(uuid, &svc_item->uuid) == 0) {
156 svc_item->attr_handle = attr_handle;
157 }
158 }
159 }
160
ble_server_func_by_attr_handle(uint16_t attr_handle,uint8_t op,uint8_t * data,int * len)161 void ble_server_func_by_attr_handle(uint16_t attr_handle, uint8_t op, uint8_t *data, int *len)
162 {
163 server_elem_t *svr_item = NULL;
164 service_elem_t *svc_item = NULL;
165
166 /* match the attr_handle and do the callback */
167 dl_list_for_each(svr_item, &server_list.list, server_elem_t, list)
168 {
169 dl_list_for_each(svc_item, &svr_item->srvc_list.list, service_elem_t, list)
170 {
171 if (svc_item->attr_handle == attr_handle) {
172 switch (op) {
173 case BLE_GATT_ACCESS_OP_WRITE_CHR:
174 if (svc_item->func.write) {
175 #if BLE_IF_DBG
176 #endif
177 svc_item->func.write(data, (int)*len);
178 }
179 break;
180 case BLE_GATT_ACCESS_OP_READ_CHR:
181 if (svc_item->func.read) {
182 svc_item->func.read(data, len);
183 #if BLE_IF_DBG
184 tls_bt_dump_hexstring("To Remote:", data, *len);
185 #endif
186 }
187 break;
188 default:
189 break;
190 }
191 }
192 }
193 }
194 }
195
196 static uint8_t cache_buffer[512];
197
ble_server_gatt_svc_access_func(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)198 static int ble_server_gatt_svc_access_func(uint16_t conn_handle, uint16_t attr_handle,
199 struct ble_gatt_access_ctxt *ctxt, void *arg)
200 {
201 int length = 0;
202 int offset = 0;
203 struct os_mbuf *om = ctxt->om;
204
205 BLE_IF_DEBUG("%s, op=%d,attr_handle=%d\r\n", __FUNCTION__, ctxt->op, attr_handle);
206 switch (ctxt->op) {
207 case BLE_GATT_ACCESS_OP_WRITE_CHR:
208 {
209 while (om) {
210 length = om->om_len;
211 memcpy_s(cache_buffer+offset, sizeof(cache_buffer+offset), om->om_data, length);
212 offset += length;
213 assert(offset <= sizeof(cache_buffer));
214 om = SLIST_NEXT(om, om_next);
215 }
216 if (offset > 0)
217 ble_server_func_by_attr_handle(attr_handle, ctxt->op, cache_buffer, &offset);
218 return 0;
219 }
220 case BLE_GATT_ACCESS_OP_READ_CHR:
221 {
222 ble_server_func_by_attr_handle(attr_handle, ctxt->op, cache_buffer, &length);
223 if (length > 0) {
224 int rc = os_mbuf_append(ctxt->om, &cache_buffer[0], length);
225 return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
226 }
227 return 0;
228 }
229 default:
230 return BLE_ATT_ERR_UNLIKELY;
231 }
232 }
233
ble_server_uuid_init_from_buf(ble_uuid_any_t * uuid,const void * buf,size_t len)234 int ble_server_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len)
235 {
236 switch (len) {
237 case OHOS_UUID_TYPE_16_BIT:
238 uuid->u.type = BLE_UUID_TYPE_16;
239 uuid->u16.value = get_le16(buf);
240 return 0;
241 case OHOS_UUID_TYPE_32_BIT:
242 uuid->u.type = BLE_UUID_TYPE_32;
243 uuid->u32.value = get_le32(buf);
244 return 0;
245 case OHOS_UUID_TYPE_128_BIT:
246 uuid->u.type = BLE_UUID_TYPE_128;
247 memcpy_s(uuid->u128.value, sizeof(uuid->u128.value), buf, 16); // 16:size
248 return 0;
249 default:
250 return 0;
251 }
252
253 return BLE_HS_EINVAL;
254 }
255
256 /*
257 * EXPORTED FUNCTION DEFINITIONS
258 ****************************************************************************************
259 */
260
ble_server_alloc(BleGattService * srvcinfo)261 int ble_server_alloc(BleGattService *srvcinfo)
262 {
263 int i = 0;
264
265 uint8_t srvc_counter = 0;
266 uint8_t char_counter = 0;
267 uint8_t desc_counter = 0;
268
269 service_elem_t *srvc_elem = NULL;
270 service_elem_t *srvc_sub_elem = NULL;
271
272 struct ble_gatt_svc_def *gatt_svc_array = NULL;
273 struct ble_gatt_chr_def *gatt_chr_array = NULL;
274 struct ble_gatt_dsc_def *gatt_dsc_array = NULL;
275
276 assert(srvcinfo != NULL);
277
278 server_elem_t *serv_elem = (server_elem_t *)tls_mem_alloc(sizeof(server_elem_t));
279 assert(serv_elem != NULL);
280 memset_s(serv_elem, sizeof(serv_elem), 0, sizeof(server_elem_t));
281 /* init the service list attached to the server element */
282 dl_list_init(&serv_elem->srvc_list.list);
283
284 serv_elem->server_id = g_server_id++;
285 serv_elem->srvc_count = 0;
286
287 // presearch to get the counter of character and descriptor;
288 for (i = 0; i < srvcinfo->attrNum; i++) {
289 if (srvcinfo->attrList[i].attrType == OHOS_BLE_ATTRIB_TYPE_SERVICE) {
290 srvc_counter++;
291 } else if (srvcinfo->attrList[i].attrType == OHOS_BLE_ATTRIB_TYPE_CHAR) {
292 char_counter++;
293 BLE_IF_DEBUG("CHAR PROP=0x%02x, PERM=0x%02x\r\n", srvcinfo->attrList[i].properties, \
294 srvcinfo->attrList[i].permission);
295 } else if (srvcinfo->attrList[i].attrType == OHOS_BLE_ATTRIB_TYPE_CHAR_USER_DESCR) {
296 desc_counter++;
297 BLE_IF_DEBUG("DESC PROP=0x%02x, PERM=0x%02x\r\n", srvcinfo->attrList[i].properties, \
298 srvcinfo->attrList[i].permission);
299 }
300 }
301 assert(srvc_counter == 1);
302 assert(char_counter >= 1);
303
304 BLE_IF_DEBUG("Adding service srvc=%d, char=%d, dsc=%d\r\n", srvc_counter, char_counter, desc_counter);
305
306 /* alloc service array */
307 gatt_svc_array = (struct ble_gatt_svc_def *)tls_mem_alloc(2 * sizeof(struct ble_gatt_svc_def)); // 2:byte alignment
308 assert(gatt_svc_array != NULL);
309 memset_s(gatt_svc_array, sizeof(gatt_svc_array), 0, 2 * sizeof(struct ble_gatt_svc_def)); // 2:byte alignment
310
311 /* prealloc charactertistic array */
312 gatt_chr_array = (struct ble_gatt_chr_def *)tls_mem_alloc((1 + char_counter) * sizeof(struct ble_gatt_chr_def));
313 assert(gatt_chr_array != NULL);
314 memset_s(gatt_chr_array, sizeof(gatt_chr_array), 0, (1 + char_counter) * sizeof(struct ble_gatt_chr_def));
315
316 /* preappending to character array */
317 gatt_svc_array[0].characteristics = gatt_chr_array;
318
319 /* create a service item and appending it to the servcie array */
320 nim_service_t *nim_service = (nim_service_t *)tls_mem_alloc(sizeof(nim_service_t));
321 assert(nim_service != NULL);
322 memset_s(nim_service, sizeof(nim_service), 0, sizeof(nim_service_t));
323 nim_service->svc = gatt_svc_array;
324 dl_list_add_tail(&nim_service_list.list, &nim_service->list);
325
326 for (i = 0; i<srvcinfo->attrNum; i++) {
327 if (srvcinfo->attrList[i].attrType == OHOS_BLE_ATTRIB_TYPE_SERVICE) {
328 srvc_elem = (service_elem_t *)tls_mem_alloc(sizeof(service_elem_t));
329 assert(srvc_elem != NULL);
330 srvc_elem->attr_type = srvcinfo->attrList[i].attrType;
331 ble_server_uuid_init_from_buf(&srvc_elem->uuid, srvcinfo->attrList[i].uuid, srvcinfo->attrList[i].uuidType);
332 srvc_elem->attr_handle = 0xFFFF;
333 dl_list_add_tail(&serv_elem->srvc_list.list, &srvc_elem->list);
334 // first fill with element used for nimble stack;
335 gatt_svc_array[0].type = BLE_GATT_SVC_TYPE_PRIMARY;
336 gatt_svc_array[0].uuid = &srvc_elem->uuid;
337 } else if (srvcinfo->attrList[i].attrType == OHOS_BLE_ATTRIB_TYPE_CHAR) {
338 srvc_sub_elem = (service_elem_t *)tls_mem_alloc(sizeof(service_elem_t));
339 assert(srvc_sub_elem != NULL);
340 srvc_sub_elem->attr_type = srvcinfo->attrList[i].attrType;
341 ble_server_uuid_init_from_buf(&srvc_sub_elem->uuid,srvcinfo->attrList[i].uuid, \
342 srvcinfo->attrList[i].uuidType);
343 srvc_sub_elem->func = srvcinfo->attrList[i].func;
344 dl_list_add_tail(&serv_elem->srvc_list.list, &srvc_sub_elem->list);
345
346 /* process stack env */
347 gatt_chr_array[serv_elem->srvc_count].uuid = &srvc_sub_elem->uuid;
348 gatt_chr_array[serv_elem->srvc_count].access_cb = ble_server_gatt_svc_access_func;
349 gatt_chr_array[serv_elem->srvc_count].flags = srvcinfo->attrList[i].properties;
350 gatt_chr_array[serv_elem->srvc_count].min_key_size = 16; // 16:byte alignment
351 gatt_chr_array[serv_elem->srvc_count].val_handle = &srvc_sub_elem->attr_handle;
352 gatt_chr_array[serv_elem->srvc_count].arg = (void*)&srvc_elem->attr_handle; \
353 // give the service handle as arg, char added callback will handle it;
354 serv_elem->srvc_count++;
355 } else if (srvcinfo->attrList[i].attrType == OHOS_BLE_ATTRIB_TYPE_CHAR_USER_DESCR) {
356 // stack will handle the cccd
357 serv_elem->srvc_count--; // fill with descriptor attached to this character
358
359 srvc_sub_elem = (service_elem_t *)tls_mem_alloc(sizeof(service_elem_t));
360 assert(srvc_sub_elem != NULL);
361 srvc_sub_elem->attr_type = srvcinfo->attrList[i].attrType;
362 ble_server_uuid_init_from_buf(&srvc_sub_elem->uuid,srvcinfo->attrList[i].uuid, \
363 srvcinfo->attrList[i].uuidType);
364 srvc_sub_elem->func = srvcinfo->attrList[i].func;
365 dl_list_add_tail(&serv_elem->srvc_list.list, &srvc_sub_elem->list);
366
367 if ((gatt_chr_array[serv_elem->srvc_count].flags & BLE_GATT_CHR_F_NOTIFY) || \
368 (gatt_chr_array[serv_elem->srvc_count].flags & BLE_GATT_CHR_F_INDICATE)) {
369 // NimBLE stack will auto add the cccd.
370 } else {
371 gatt_dsc_array =
372 (struct ble_gatt_dsc_def *)tls_mem_alloc(2 * sizeof(struct ble_gatt_dsc_def)); // 2:byte alignment
373 memset_s(gatt_dsc_array, sizeof(gatt_dsc_array), 0,
374 2 * sizeof(struct ble_gatt_dsc_def)); // 2:byte alignment
375 gatt_dsc_array[0].uuid = &srvc_sub_elem->uuid;
376 gatt_dsc_array[0].access_cb = ble_server_gatt_svc_access_func;
377 gatt_dsc_array[0].att_flags =
378 srvcinfo->attrList[i].properties |srvcinfo->attrList[i].permission << 8; // 8:byte alignment
379 gatt_dsc_array[0].min_key_size = 16; // 16:byte alignment
380 gatt_dsc_array[0].arg = (void*)&srvc_elem->attr_handle;
381 // give the service handle as arg, char added callback will handle it;
382 gatt_chr_array[serv_elem->srvc_count].descriptors = gatt_dsc_array;
383 }
384
385 serv_elem->srvc_count++; // restore it;
386 }
387 }
388
389 serv_elem->priv_data = (void*)nim_service;
390
391 // appending the server elem to the server list;
392 dl_list_add_tail(&server_list.list, &serv_elem->list);
393
394 return serv_elem->server_id;
395 }
396
ble_server_free(int server_id)397 int ble_server_free(int server_id)
398 {
399 int d = 0;
400 nim_service_t *nim_service_item = NULL;
401 server_elem_t *svr_item = NULL;
402 server_elem_t *svr_item_next = NULL;
403 service_elem_t *svc_item = NULL;
404 service_elem_t *svc_item_next = NULL;
405 struct ble_gatt_svc_def *svc_array = NULL;
406 struct ble_gatt_chr_def *chr_array = NULL;
407
408 // free list entry for application level
409 dl_list_for_each_safe(svr_item, svr_item_next, &server_list.list, server_elem_t, list)
410 {
411 if (svr_item->server_id == server_id) {
412 nim_service_item = (nim_service_t *)svr_item->priv_data; // the svc_array to be freed;
413
414 dl_list_for_each_safe(svc_item, svc_item_next, &svr_item->srvc_list.list, service_elem_t, list)
415 {
416 dl_list_del(&svc_item->list);
417 tls_mem_free(svc_item);
418 }
419
420 dl_list_del(&svr_item->list);
421 tls_mem_free(svr_item);
422 break;
423 }
424 }
425
426 // free servcie array used for nimble stack;
427 if (nim_service_item) {
428 svc_array = nim_service_item->svc;
429 if (svc_array) {
430 if (svc_array->characteristics != NULL) {
431 for (int c = 0; svc_array->characteristics[c].uuid != NULL; c++) {
432 chr_array = svc_array->characteristics + c;
433
434 if (chr_array->descriptors != NULL) {
435 tls_mem_free(chr_array->descriptors);
436 }
437 }
438
439 tls_mem_free(svc_array->characteristics);
440 }
441
442 tls_mem_free(svc_array);
443 }
444
445 dl_list_del(&nim_service_item->list);
446 tls_mem_free(nim_service_item);
447 }
448 }
449
ble_server_start_service(void)450 void ble_server_start_service(void)
451 {
452 nim_service_t *svc_item = NULL;
453
454 if (!dl_list_empty(&nim_service_list.list)) {
455 int rc;
456 dl_list_for_each(svc_item, &nim_service_list.list, nim_service_t, list)
457 {
458 if (svc_item == NULL) {
459 BLE_IF_PRINTF("ERROR, LIST ERROR\r\n");
460 return;
461 }
462 rc = ble_gatts_count_cfg(svc_item->svc);
463 assert(rc == 0);
464
465 rc = ble_gatts_add_svcs(svc_item->svc);
466 assert(rc == 0);
467 }
468
469 rc = ble_gatts_start();
470 assert(rc == 0);
471 }
472 }
473
ble_server_init(void)474 void ble_server_init(void)
475 {
476 memset_s(&server_list, sizeof(&server_list), 0, sizeof(server_elem_t));
477 dl_list_init(&server_list.list);
478 dl_list_init(&nim_service_list.list);
479 }