From 9b36a6a347254fc298fca8af806668b0a1a4db3a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 13 May 2026 11:11:28 +0200 Subject: [PATCH] transport/common/hci_h4: propagate OOM instead of asserting When hci_h4_sm_w4_header() or hci_h4_sm_w4_payload() returns -1 because the underlying allocator returned NULL (transport ACL pool exhausted), hci_h4_sm_rx() currently asserts via two `assert(rc >= 0)` checks. This turns a recoverable pool-pressure event into a fatal crash. The condition is reachable in practice on host-side transports such as SiFli SF32LB52: the H4 RX task allocates ACL mbufs from mpool_acl and queues them on ble_hs_rx_q for the host event loop to drain. If the host is parked (e.g. blocked while serving GATT notifications into a downstream buffer that drains slowly) the queue grows until the pool is empty; the next allocation returns NULL and the assert fires. Remove both `assert(rc >= 0)` so -1 propagates through hci_h4_sm_rx() to the transport. Callers can then back off (e.g. block until a buffer is returned to the pool via the put callback) and retry with the same input. The existing `assert(rc < 0)` at the bottom of hci_h4_sm_rx() still enforces the legitimate "consumed nothing => rc indicates error" invariant. Note that when the input source is destructive, callers must retry with the same buffer rather than drop bytes on -1, otherwise the H4 framing desyncs. The state machine already preserves partial state across calls so retry is safe. Signed-off-by: Gerard Marull-Paretas --- nimble/transport/common/hci_h4/src/hci_h4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nimble/transport/common/hci_h4/src/hci_h4.c b/nimble/transport/common/hci_h4/src/hci_h4.c index fd89154a34..c52241ca83 100644 --- a/nimble/transport/common/hci_h4/src/hci_h4.c +++ b/nimble/transport/common/hci_h4/src/hci_h4.c @@ -289,15 +289,16 @@ hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len) /* no break */ case HCI_H4_SM_W4_HEADER: rc = hci_h4_sm_w4_header(h4sm, &ib); - assert(rc >= 0); if (rc) { + /* rc == 1: need more data; rc < 0: alloc failed, propagate + * to caller so it can back off and retry instead of crashing. + */ break; } h4sm->state = HCI_H4_SM_W4_PAYLOAD; /* no break */ case HCI_H4_SM_W4_PAYLOAD: rc = hci_h4_sm_w4_payload(h4sm, &ib); - assert(rc >= 0); if (rc) { break; }