peer.c 18 KB

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