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