Skip to content

Commit 931e1fa

Browse files
Damian-Nordicnordicjm
authored andcommitted
bluetooth: rpc: reclaim GATT buffer on bt_disable
bt_enable() fails after a few bt_enable() -> bt_disable() cycles because: 1. bt_enable() registers static services on the host device 2. on the host, the service data is allocated from shared GATT memory buffer and the memory used by a service is never released. 3. eventually, the GATT memory buffer is exhausted and 1 fails. Fix the most common scenario where only static services are used, or all dynamic services are registered at once by implementing the following changes: 1. in bt_disable(), unregister all static services 2. on the host, reset the GATT memory buffer if the last registered service has just been unregistered. Signed-off-by: Damian Krolik <[email protected]>
1 parent b8d4242 commit 931e1fa

File tree

4 files changed

+59
-14
lines changed

4 files changed

+59
-14
lines changed

subsys/bluetooth/rpc/client/bt_rpc_gap_client.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ int bt_disable(void)
150150
nrf_rpc_cbor_cmd_no_err(&bt_rpc_grp, BT_DISABLE_RPC_CMD, &ctx, nrf_rpc_rsp_decode_i32,
151151
&result);
152152

153+
if (IS_ENABLED(CONFIG_BT_CONN) && (result == 0)) {
154+
result = bt_rpc_gatt_uninit();
155+
}
156+
153157
return result;
154158
}
155159

subsys/bluetooth/rpc/client/bt_rpc_gatt_client.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -683,38 +683,58 @@ int bt_rpc_gatt_init(void)
683683
return 0;
684684
}
685685

686-
#if defined(CONFIG_BT_GATT_DYNAMIC_DB)
687-
int bt_gatt_service_register(struct bt_gatt_service *svc)
688-
{
689-
return send_service(svc);
690-
}
691-
692-
int bt_gatt_service_unregister(struct bt_gatt_service *svc)
686+
static int remove_service(const struct bt_gatt_service *svc)
693687
{
694688
struct nrf_rpc_cbor_ctx ctx;
695689
int result;
696690
size_t buffer_size_max = 3;
697691
uint16_t svc_index;
698692
int err;
699693

700-
NRF_RPC_CBOR_ALLOC(&bt_rpc_grp, ctx, buffer_size_max);
701-
702694
err = bt_rpc_gatt_service_to_index(svc, &svc_index);
703695
if (err) {
704696
return err;
705697
}
706698

699+
NRF_RPC_CBOR_ALLOC(&bt_rpc_grp, ctx, buffer_size_max);
707700
nrf_rpc_encode_uint(&ctx, svc_index);
708-
709-
nrf_rpc_cbor_cmd_no_err(&bt_rpc_grp, BT_RPC_GATT_SERVICE_UNREGISTER_RPC_CMD,
710-
&ctx, nrf_rpc_rsp_decode_i32, &result);
701+
nrf_rpc_cbor_cmd_no_err(&bt_rpc_grp, BT_RPC_GATT_SERVICE_UNREGISTER_RPC_CMD, &ctx,
702+
nrf_rpc_rsp_decode_i32, &result);
711703

712704
if (result) {
713705
return result;
714706
}
715707

716708
return bt_rpc_gatt_remove_service(svc);
717709
}
710+
711+
int bt_rpc_gatt_uninit(void)
712+
{
713+
int err = 0;
714+
715+
STRUCT_SECTION_FOREACH(bt_gatt_service_static, svc)
716+
{
717+
int rc = remove_service((const struct bt_gatt_service *)svc);
718+
719+
/* Continue removing services even if removing one fails. */
720+
if (err == 0) {
721+
err = rc;
722+
}
723+
}
724+
725+
return err;
726+
}
727+
728+
#if defined(CONFIG_BT_GATT_DYNAMIC_DB)
729+
int bt_gatt_service_register(struct bt_gatt_service *svc)
730+
{
731+
return send_service(svc);
732+
}
733+
734+
int bt_gatt_service_unregister(struct bt_gatt_service *svc)
735+
{
736+
return remove_service(svc);
737+
}
718738
#endif /* defined(CONFIG_BT_GATT_DYNAMIC_DB) */
719739

720740
static size_t bt_gatt_notify_params_buf_size(const struct bt_gatt_notify_params *data)

subsys/bluetooth/rpc/client/bt_rpc_gatt_client.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,25 @@ extern "C" {
2020

2121
/** @brief Initialize GATT functionality over RPC.
2222
*
23-
* This function registers all GATT static services and its attribute on a host.
24-
* Serives are registered as dynamic services on a host.
23+
* This function registers all GATT static services and its attributes on the host.
24+
*
25+
* @note On the host, the client's static services are represented as dynamic services.
2526
*
2627
* @retval 0 If the operation was successful.
2728
* Otherwise, a (negative) error code is returned.
2829
*/
2930
int bt_rpc_gatt_init(void);
3031

32+
/** @brief Uninitialize GATT functionality over RPC.
33+
*
34+
* This function reverses the operations performed by :c:func:`bt_rpc_gatt_init`.
35+
* Specifically, it unregisters all GATT static services on the host.
36+
*
37+
* @retval 0 If the operation was successful.
38+
* Otherwise, a (negative) error code is returned.
39+
*/
40+
int bt_rpc_gatt_uninit(void);
41+
3142
#ifdef __cplusplus
3243
}
3344
#endif

subsys/bluetooth/rpc/host/bt_rpc_gatt_host.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,16 @@ static void bt_rpc_gatt_service_unregister_rpc_handler(const struct nrf_rpc_grou
740740
result = bt_rpc_gatt_remove_service(svc);
741741
}
742742

743+
if (!result && (bt_rpc_gatt_get_service_by_index(0) == NULL)) {
744+
/*
745+
* The last service has been unregistered, so we can reclaim the entire GATT buffer.
746+
* Ideally, each dynamic service would use a separate buffer so that unregistering
747+
* a single service releases all its resources right away, but this requires
748+
* rewriting the GATT attribute memory management.
749+
*/
750+
net_buf_simple_reset(&gatt_buffer);
751+
}
752+
743753
nrf_rpc_rsp_send_int(group, result);
744754
return;
745755
decoding_error:

0 commit comments

Comments
 (0)