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