• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }