1 /*
2 * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <assert.h>
8 #include <string.h>
9 #include "host/ble_hs.h"
10 #include "gattc.h"
11
12 static void *peer_svc_mem;
13 static struct os_mempool peer_svc_pool;
14
15 static void *peer_chr_mem;
16 static struct os_mempool peer_chr_pool;
17
18 static void *peer_dsc_mem;
19 static struct os_mempool peer_dsc_pool;
20
21 static void *peer_mem;
22 static struct os_mempool peer_pool;
23 static SLIST_HEAD(, peer) peers;
24
25 static struct peer_svc *
26 peer_svc_find_range(struct peer *peer, uint16_t attr_handle);
27 static struct peer_svc *
28 peer_svc_find(struct peer *peer, uint16_t svc_start_handle,
29 struct peer_svc **out_prev);
30 int
31 peer_svc_is_empty(const struct peer_svc *svc);
32
33 uint16_t
34 chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr);
35 int
36 chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr);
37 static struct peer_chr *
38 peer_chr_find(const struct peer_svc *svc, uint16_t chr_def_handle,
39 struct peer_chr **out_prev);
40 static void
41 peer_disc_chrs(struct peer *peer);
42
43 static int
44 peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
45 uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
46 void *arg);
47
48 struct peer *
peer_find(uint16_t conn_handle)49 peer_find(uint16_t conn_handle)
50 {
51 struct peer *peer;
52
53 SLIST_FOREACH(peer, &peers, next) {
54 if (peer->conn_handle == conn_handle) {
55 return peer;
56 }
57 }
58
59 return NULL;
60 }
61
62 static void
peer_disc_complete(struct peer * peer,int rc)63 peer_disc_complete(struct peer *peer, int rc)
64 {
65 peer->disc_prev_chr_val = 0;
66
67 /* Notify caller that discovery has completed. */
68 if (peer->disc_cb != NULL) {
69 peer->disc_cb(peer, rc, peer->disc_cb_arg);
70 }
71 }
72
73 static struct peer_dsc *
peer_dsc_find_prev(const struct peer_chr * chr,uint16_t dsc_handle)74 peer_dsc_find_prev(const struct peer_chr *chr, uint16_t dsc_handle)
75 {
76 struct peer_dsc *prev;
77 struct peer_dsc *dsc;
78
79 prev = NULL;
80 SLIST_FOREACH(dsc, &chr->dscs, next) {
81 if (dsc->dsc.handle >= dsc_handle) {
82 break;
83 }
84
85 prev = dsc;
86 }
87
88 return prev;
89 }
90
91 static struct peer_dsc *
peer_dsc_find(const struct peer_chr * chr,uint16_t dsc_handle,struct peer_dsc ** out_prev)92 peer_dsc_find(const struct peer_chr *chr, uint16_t dsc_handle,
93 struct peer_dsc **out_prev)
94 {
95 struct peer_dsc *prev;
96 struct peer_dsc *dsc;
97
98 prev = peer_dsc_find_prev(chr, dsc_handle);
99 if (prev == NULL) {
100 dsc = SLIST_FIRST(&chr->dscs);
101 } else {
102 dsc = SLIST_NEXT(prev, next);
103 }
104
105 if (dsc != NULL && dsc->dsc.handle != dsc_handle) {
106 dsc = NULL;
107 }
108
109 if (out_prev != NULL) {
110 *out_prev = prev;
111 }
112 return dsc;
113 }
114
115 static int
peer_dsc_add(struct peer * peer,uint16_t chr_val_handle,const struct ble_gatt_dsc * gatt_dsc)116 peer_dsc_add(struct peer *peer, uint16_t chr_val_handle,
117 const struct ble_gatt_dsc *gatt_dsc)
118 {
119 struct peer_dsc *prev;
120 struct peer_dsc *dsc;
121 struct peer_svc *svc;
122 struct peer_chr *chr;
123
124 svc = peer_svc_find_range(peer, chr_val_handle);
125 if (svc == NULL) {
126 /* Can't find service for discovered descriptor; this shouldn't
127 * happen.
128 */
129 assert(0);
130 return BLE_HS_EUNKNOWN;
131 }
132
133 chr = peer_chr_find(svc, chr_val_handle, NULL);
134 if (chr == NULL) {
135 /* Can't find characteristic for discovered descriptor; this shouldn't
136 * happen.
137 */
138 assert(0);
139 return BLE_HS_EUNKNOWN;
140 }
141
142 dsc = peer_dsc_find(chr, gatt_dsc->handle, &prev);
143 if (dsc != NULL) {
144 /* Descriptor already discovered. */
145 return 0;
146 }
147
148 dsc = os_memblock_get(&peer_dsc_pool);
149 if (dsc == NULL) {
150 /* Out of memory. */
151 return BLE_HS_ENOMEM;
152 }
153 memset(dsc, 0, sizeof * dsc);
154
155 dsc->dsc = *gatt_dsc;
156
157 if (prev == NULL) {
158 SLIST_INSERT_HEAD(&chr->dscs, dsc, next);
159 } else {
160 SLIST_NEXT(prev, next) = dsc;
161 }
162
163 return 0;
164 }
165
166 static void
peer_disc_dscs(struct peer * peer)167 peer_disc_dscs(struct peer *peer)
168 {
169 struct peer_chr *chr;
170 struct peer_svc *svc;
171 int rc;
172
173 /* Search through the list of discovered characteristics for the first
174 * characteristic that contains undiscovered descriptors. Then, discover
175 * all descriptors belonging to that characteristic.
176 */
177 SLIST_FOREACH(svc, &peer->svcs, next) {
178 SLIST_FOREACH(chr, &svc->chrs, next) {
179 if (!chr_is_empty(svc, chr) &&
180 SLIST_EMPTY(&chr->dscs) &&
181 peer->disc_prev_chr_val <= chr->chr.def_handle) {
182
183 rc = ble_gattc_disc_all_dscs(peer->conn_handle,
184 chr->chr.val_handle,
185 chr_end_handle(svc, chr),
186 peer_dsc_disced, peer);
187 if (rc != 0) {
188 peer_disc_complete(peer, rc);
189 }
190
191 peer->disc_prev_chr_val = chr->chr.val_handle;
192 return;
193 }
194 }
195 }
196
197 /* All descriptors discovered. */
198 peer_disc_complete(peer, 0);
199 }
200
201 static int
peer_dsc_disced(uint16_t conn_handle,const struct ble_gatt_error * error,uint16_t chr_val_handle,const struct ble_gatt_dsc * dsc,void * arg)202 peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
203 uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
204 void *arg)
205 {
206 struct peer *peer;
207 int rc;
208
209 peer = arg;
210 assert(peer->conn_handle == conn_handle);
211
212 switch (error->status) {
213 case 0:
214 rc = peer_dsc_add(peer, chr_val_handle, dsc);
215 break;
216
217 case BLE_HS_EDONE:
218 /* All descriptors in this characteristic discovered; start discovering
219 * descriptors in the next characteristic.
220 */
221 if (peer->disc_prev_chr_val > 0) {
222 peer_disc_dscs(peer);
223 }
224 rc = 0;
225 break;
226
227 default:
228 /* Error; abort discovery. */
229 rc = error->status;
230 break;
231 }
232
233 if (rc != 0) {
234 /* Error; abort discovery. */
235 peer_disc_complete(peer, rc);
236 }
237
238 return rc;
239 }
240
241 uint16_t
chr_end_handle(const struct peer_svc * svc,const struct peer_chr * chr)242 chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr)
243 {
244 const struct peer_chr *next_chr;
245
246 next_chr = SLIST_NEXT(chr, next);
247 if (next_chr != NULL) {
248 return next_chr->chr.def_handle - 1;
249 } else {
250 return svc->svc.end_handle;
251 }
252 }
253
254 int
chr_is_empty(const struct peer_svc * svc,const struct peer_chr * chr)255 chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr)
256 {
257 return chr_end_handle(svc, chr) <= chr->chr.val_handle;
258 }
259
260 static struct peer_chr *
peer_chr_find_prev(const struct peer_svc * svc,uint16_t chr_val_handle)261 peer_chr_find_prev(const struct peer_svc *svc, uint16_t chr_val_handle)
262 {
263 struct peer_chr *prev;
264 struct peer_chr *chr;
265
266 prev = NULL;
267 SLIST_FOREACH(chr, &svc->chrs, next) {
268 if (chr->chr.val_handle >= chr_val_handle) {
269 break;
270 }
271
272 prev = chr;
273 }
274
275 return prev;
276 }
277
278 static struct peer_chr *
peer_chr_find(const struct peer_svc * svc,uint16_t chr_val_handle,struct peer_chr ** out_prev)279 peer_chr_find(const struct peer_svc *svc, uint16_t chr_val_handle,
280 struct peer_chr **out_prev)
281 {
282 struct peer_chr *prev;
283 struct peer_chr *chr;
284
285 prev = peer_chr_find_prev(svc, chr_val_handle);
286 if (prev == NULL) {
287 chr = SLIST_FIRST(&svc->chrs);
288 } else {
289 chr = SLIST_NEXT(prev, next);
290 }
291
292 if (chr != NULL && chr->chr.val_handle != chr_val_handle) {
293 chr = NULL;
294 }
295
296 if (out_prev != NULL) {
297 *out_prev = prev;
298 }
299 return chr;
300 }
301
302 static void
peer_chr_delete(struct peer_chr * chr)303 peer_chr_delete(struct peer_chr *chr)
304 {
305 struct peer_dsc *dsc;
306
307 while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) {
308 SLIST_REMOVE_HEAD(&chr->dscs, next);
309 os_memblock_put(&peer_dsc_pool, dsc);
310 }
311
312 os_memblock_put(&peer_chr_pool, chr);
313 }
314
315 static int
peer_chr_add(struct peer * peer,uint16_t svc_start_handle,const struct ble_gatt_chr * gatt_chr)316 peer_chr_add(struct peer *peer, uint16_t svc_start_handle,
317 const struct ble_gatt_chr *gatt_chr)
318 {
319 struct peer_chr *prev;
320 struct peer_chr *chr;
321 struct peer_svc *svc;
322
323 svc = peer_svc_find(peer, svc_start_handle, NULL);
324 if (svc == NULL) {
325 /* Can't find service for discovered characteristic; this shouldn't
326 * happen.
327 */
328 assert(0);
329 return BLE_HS_EUNKNOWN;
330 }
331
332 chr = peer_chr_find(svc, gatt_chr->def_handle, &prev);
333 if (chr != NULL) {
334 /* Characteristic already discovered. */
335 return 0;
336 }
337
338 chr = os_memblock_get(&peer_chr_pool);
339 if (chr == NULL) {
340 /* Out of memory. */
341 return BLE_HS_ENOMEM;
342 }
343 memset(chr, 0, sizeof * chr);
344
345 chr->chr = *gatt_chr;
346
347 if (prev == NULL) {
348 SLIST_INSERT_HEAD(&svc->chrs, chr, next);
349 } else {
350 SLIST_NEXT(prev, next) = chr;
351 }
352
353 return 0;
354 }
355
356 static int
peer_chr_disced(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_chr * chr,void * arg)357 peer_chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
358 const struct ble_gatt_chr *chr, void *arg)
359 {
360 struct peer *peer;
361 int rc;
362
363 peer = arg;
364 assert(peer->conn_handle == conn_handle);
365
366 switch (error->status) {
367 case 0:
368 rc = peer_chr_add(peer, peer->cur_svc->svc.start_handle, chr);
369 break;
370
371 case BLE_HS_EDONE:
372 /* All characteristics in this service discovered; start discovering
373 * characteristics in the next service.
374 */
375 if (peer->disc_prev_chr_val > 0) {
376 peer_disc_chrs(peer);
377 }
378 rc = 0;
379 break;
380
381 default:
382 rc = error->status;
383 break;
384 }
385
386 if (rc != 0) {
387 /* Error; abort discovery. */
388 peer_disc_complete(peer, rc);
389 }
390
391 return rc;
392 }
393
394 static void
peer_disc_chrs(struct peer * peer)395 peer_disc_chrs(struct peer *peer)
396 {
397 struct peer_svc *svc;
398 int rc;
399
400 /* Search through the list of discovered service for the first service that
401 * contains undiscovered characteristics. Then, discover all
402 * characteristics belonging to that service.
403 */
404
405 SLIST_FOREACH(svc, &peer->svcs, next) {
406 if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) {
407 peer->cur_svc = svc;
408 rc = ble_gattc_disc_all_chrs(peer->conn_handle,
409 svc->svc.start_handle,
410 svc->svc.end_handle,
411 peer_chr_disced, peer);
412 if (rc != 0) {
413 peer_disc_complete(peer, rc);
414 }
415 return;
416 }
417 }
418
419 /* All characteristics discovered. */
420 peer_disc_dscs(peer);
421 }
422
423 int
peer_svc_is_empty(const struct peer_svc * svc)424 peer_svc_is_empty(const struct peer_svc *svc)
425 {
426 return svc->svc.end_handle <= svc->svc.start_handle;
427 }
428
429 static struct peer_svc *
peer_svc_find_prev(struct peer * peer,uint16_t svc_start_handle)430 peer_svc_find_prev(struct peer *peer, uint16_t svc_start_handle)
431 {
432 struct peer_svc *prev;
433 struct peer_svc *svc;
434
435 prev = NULL;
436 SLIST_FOREACH(svc, &peer->svcs, next) {
437 if (svc->svc.start_handle >= svc_start_handle) {
438 break;
439 }
440
441 prev = svc;
442 }
443
444 return prev;
445 }
446
447 static struct peer_svc *
peer_svc_find(struct peer * peer,uint16_t svc_start_handle,struct peer_svc ** out_prev)448 peer_svc_find(struct peer *peer, uint16_t svc_start_handle,
449 struct peer_svc **out_prev)
450 {
451 struct peer_svc *prev;
452 struct peer_svc *svc;
453
454 prev = peer_svc_find_prev(peer, svc_start_handle);
455 if (prev == NULL) {
456 svc = SLIST_FIRST(&peer->svcs);
457 } else {
458 svc = SLIST_NEXT(prev, next);
459 }
460
461 if (svc != NULL && svc->svc.start_handle != svc_start_handle) {
462 svc = NULL;
463 }
464
465 if (out_prev != NULL) {
466 *out_prev = prev;
467 }
468 return svc;
469 }
470
471 static struct peer_svc *
peer_svc_find_range(struct peer * peer,uint16_t attr_handle)472 peer_svc_find_range(struct peer *peer, uint16_t attr_handle)
473 {
474 struct peer_svc *svc;
475
476 SLIST_FOREACH(svc, &peer->svcs, next) {
477 if (svc->svc.start_handle <= attr_handle &&
478 svc->svc.end_handle >= attr_handle) {
479
480 return svc;
481 }
482 }
483
484 return NULL;
485 }
486
487 const struct peer_svc *
peer_svc_find_uuid(const struct peer * peer,const ble_uuid_t * uuid)488 peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid)
489 {
490 const struct peer_svc *svc;
491
492 SLIST_FOREACH(svc, &peer->svcs, next) {
493 if ((uuid != NULL) && (ble_uuid_cmp(&(svc->svc.uuid.u), uuid) == 0)) {
494 return svc;
495 }
496 }
497
498 return NULL;
499 }
500
501 const struct peer_chr *
peer_chr_find_uuid(const struct peer * peer,const ble_uuid_t * svc_uuid,const ble_uuid_t * chr_uuid)502 peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
503 const ble_uuid_t *chr_uuid)
504 {
505 const struct peer_svc *svc;
506 const struct peer_chr *chr;
507
508 svc = peer_svc_find_uuid(peer, svc_uuid);
509 if (svc == NULL) {
510 return NULL;
511 }
512
513 SLIST_FOREACH(chr, &svc->chrs, next) {
514 if ((chr_uuid != NULL) && (ble_uuid_cmp(&chr->chr.uuid.u, chr_uuid) == 0)) {
515 return chr;
516 }
517 }
518
519 return NULL;
520 }
521
522 const struct peer_dsc *
peer_dsc_find_uuid(const struct peer * peer,const ble_uuid_t * svc_uuid,const ble_uuid_t * chr_uuid,const ble_uuid_t * dsc_uuid)523 peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
524 const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid)
525 {
526 const struct peer_chr *chr;
527 const struct peer_dsc *dsc;
528
529 chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid);
530 if (chr == NULL) {
531 return NULL;
532 }
533
534 SLIST_FOREACH(dsc, &chr->dscs, next) {
535 if ((dsc_uuid != NULL) && (ble_uuid_cmp(&dsc->dsc.uuid.u, dsc_uuid) == 0)) {
536 return dsc;
537 }
538 }
539
540 return NULL;
541 }
542
543 static int
peer_svc_add(struct peer * peer,const struct ble_gatt_svc * gatt_svc)544 peer_svc_add(struct peer *peer, const struct ble_gatt_svc *gatt_svc)
545 {
546 struct peer_svc *prev;
547 struct peer_svc *svc;
548
549 svc = peer_svc_find(peer, gatt_svc->start_handle, &prev);
550 if (svc != NULL) {
551 /* Service already discovered. */
552 return 0;
553 }
554
555 svc = os_memblock_get(&peer_svc_pool);
556 if (svc == NULL) {
557 /* Out of memory. */
558 return BLE_HS_ENOMEM;
559 }
560 memset(svc, 0, sizeof * svc);
561
562 svc->svc = *gatt_svc;
563 SLIST_INIT(&svc->chrs);
564
565 if (prev == NULL) {
566 SLIST_INSERT_HEAD(&peer->svcs, svc, next);
567 } else {
568 SLIST_INSERT_AFTER(prev, svc, next);
569 }
570
571 return 0;
572 }
573
574 static void
peer_svc_delete(struct peer_svc * svc)575 peer_svc_delete(struct peer_svc *svc)
576 {
577 struct peer_chr *chr;
578
579 while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) {
580 SLIST_REMOVE_HEAD(&svc->chrs, next);
581 peer_chr_delete(chr);
582 }
583
584 os_memblock_put(&peer_svc_pool, svc);
585 }
586
587 static int
peer_svc_disced(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_svc * service,void * arg)588 peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
589 const struct ble_gatt_svc *service, void *arg)
590 {
591 struct peer *peer;
592 int rc;
593
594 peer = arg;
595 assert(peer->conn_handle == conn_handle);
596
597 switch (error->status) {
598 case 0:
599 rc = peer_svc_add(peer, service);
600 break;
601
602 case BLE_HS_EDONE:
603 /* All services discovered; start discovering characteristics. */
604 if (peer->disc_prev_chr_val > 0) {
605 peer_disc_chrs(peer);
606 }
607 rc = 0;
608 break;
609
610 default:
611 rc = error->status;
612 break;
613 }
614
615 if (rc != 0) {
616 /* Error; abort discovery. */
617 peer_disc_complete(peer, rc);
618 }
619
620 return rc;
621 }
622
623 int
peer_disc_all(uint16_t conn_handle,peer_disc_fn * disc_cb,void * disc_cb_arg)624 peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, void *disc_cb_arg)
625 {
626 struct peer_svc *svc;
627 struct peer *peer;
628 int rc;
629
630 peer = peer_find(conn_handle);
631 if (peer == NULL) {
632 return BLE_HS_ENOTCONN;
633 }
634
635 /* Undiscover everything first. */
636 while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
637 SLIST_REMOVE_HEAD(&peer->svcs, next);
638 peer_svc_delete(svc);
639 }
640
641 peer->disc_prev_chr_val = 1;
642 peer->disc_cb = disc_cb;
643 peer->disc_cb_arg = disc_cb_arg;
644
645 rc = ble_gattc_disc_all_svcs(conn_handle, peer_svc_disced, peer);
646 if (rc != 0) {
647 return rc;
648 }
649
650 return 0;
651 }
652
653 int
peer_delete(uint16_t conn_handle)654 peer_delete(uint16_t conn_handle)
655 {
656 struct peer_svc *svc;
657 struct peer *peer;
658 int rc;
659
660 peer = peer_find(conn_handle);
661 if (peer == NULL) {
662 return BLE_HS_ENOTCONN;
663 }
664
665 SLIST_REMOVE(&peers, peer, peer, next);
666
667 while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
668 SLIST_REMOVE_HEAD(&peer->svcs, next);
669 peer_svc_delete(svc);
670 }
671
672 rc = os_memblock_put(&peer_pool, peer);
673 if (rc != 0) {
674 return BLE_HS_EOS;
675 }
676
677 return 0;
678 }
679
680 int
peer_add(uint16_t conn_handle)681 peer_add(uint16_t conn_handle)
682 {
683 struct peer *peer;
684
685 /* Make sure the connection handle is unique. */
686 peer = peer_find(conn_handle);
687 if (peer != NULL) {
688 return BLE_HS_EALREADY;
689 }
690
691 peer = os_memblock_get(&peer_pool);
692 if (peer == NULL) {
693 /* Out of memory. */
694 return BLE_HS_ENOMEM;
695 }
696
697 memset(peer, 0, sizeof * peer);
698 peer->conn_handle = conn_handle;
699
700 SLIST_INSERT_HEAD(&peers, peer, next);
701
702 return 0;
703 }
704
705 static void
peer_free_mem(void)706 peer_free_mem(void)
707 {
708 free(peer_mem);
709 peer_mem = NULL;
710
711 free(peer_svc_mem);
712 peer_svc_mem = NULL;
713
714 free(peer_chr_mem);
715 peer_chr_mem = NULL;
716
717 free(peer_dsc_mem);
718 peer_dsc_mem = NULL;
719 }
720
721 int
peer_init(int max_peers,int max_svcs,int max_chrs,int max_dscs)722 peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
723 {
724 int rc;
725
726 /* Free memory first in case this function gets called more than once. */
727 peer_free_mem();
728
729 peer_mem = malloc(
730 OS_MEMPOOL_BYTES(max_peers, sizeof (struct peer)));
731 if (peer_mem == NULL) {
732 rc = BLE_HS_ENOMEM;
733 goto err;
734 }
735
736 rc = os_mempool_init(&peer_pool, max_peers,
737 sizeof (struct peer), peer_mem,
738 "peer_pool");
739 if (rc != 0) {
740 rc = BLE_HS_EOS;
741 goto err;
742 }
743
744 peer_svc_mem = malloc(
745 OS_MEMPOOL_BYTES(max_svcs, sizeof (struct peer_svc)));
746 if (peer_svc_mem == NULL) {
747 rc = BLE_HS_ENOMEM;
748 goto err;
749 }
750
751 rc = os_mempool_init(&peer_svc_pool, max_svcs,
752 sizeof (struct peer_svc), peer_svc_mem,
753 "peer_svc_pool");
754 if (rc != 0) {
755 rc = BLE_HS_EOS;
756 goto err;
757 }
758
759 peer_chr_mem = malloc(
760 OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr)));
761 if (peer_chr_mem == NULL) {
762 rc = BLE_HS_ENOMEM;
763 goto err;
764 }
765
766 rc = os_mempool_init(&peer_chr_pool, max_chrs,
767 sizeof (struct peer_chr), peer_chr_mem,
768 "peer_chr_pool");
769 if (rc != 0) {
770 rc = BLE_HS_EOS;
771 goto err;
772 }
773
774 peer_dsc_mem = malloc(
775 OS_MEMPOOL_BYTES(max_dscs, sizeof (struct peer_dsc)));
776 if (peer_dsc_mem == NULL) {
777 rc = BLE_HS_ENOMEM;
778 goto err;
779 }
780
781 rc = os_mempool_init(&peer_dsc_pool, max_dscs,
782 sizeof (struct peer_dsc), peer_dsc_mem,
783 "peer_dsc_pool");
784 if (rc != 0) {
785 rc = BLE_HS_EOS;
786 goto err;
787 }
788
789 return 0;
790
791 err:
792 peer_free_mem();
793 ESP_LOGE("ERROR", "Error while allocating mem");
794 return rc;
795 }
796