From 898c46a8c92394ca2e6141049558f0817f35eb8f Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 1 Aug 2024 14:25:51 +0200 Subject: [PATCH] [nrf fromtree] Bluetooth: Host: Fix `bt_l2cap_chan_ops.recv` `-EINPROGRESS` Fix discrepancy in reference management between calls to `bt_l2cap_chan_ops.recv` when the application returns `-EINPROGRESS`. There are two call sites, `l2cap_chan_le_recv_sdu` and `l2cap_chan_le_recv`, that were inconsistent. `l2cap_chan_le_recv_sdu` moves the reference, and this patch updates `l2cap_chan_le_recv` to do the same. This behavior is also now documented. This bug has existed since the introduction of this feature in 3151d265726fb528d31d8e1ee8b35004e901cfc4. Signed-off-by: Aleksander Wasaznik (cherry picked from commit 200de7c00a0a1beb905ec8565a24fce1d498e13b) --- include/zephyr/bluetooth/l2cap.h | 5 +++++ subsys/bluetooth/host/l2cap.c | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index d3a49f9b3a9..d8812693614 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -350,6 +350,11 @@ struct bt_l2cap_chan_ops { * @kconfig{CONFIG_BT_L2CAP_SEG_RECV} is enabled and seg_recv is * supplied. * + * If the application returns @c -EINPROGRESS, the application takes + * ownership of the reference in @p buf. (I.e. This pointer value can + * simply be given to @ref bt_l2cap_chan_recv_complete without any + * calls @ref net_buf_ref or @ref net_buf_unref.) + * * @return 0 in case of success or negative value in case of error. * @return -EINPROGRESS in case where user has to confirm once the data * has been processed by calling diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index ed185d12fd7..922586aa36b 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -2572,6 +2573,7 @@ static void l2cap_chan_le_recv_seg_direct(struct bt_l2cap_le_chan *chan, struct static void l2cap_chan_le_recv(struct bt_l2cap_le_chan *chan, struct net_buf *buf) { + struct net_buf *owned_ref; uint16_t sdu_len; int err; @@ -2645,7 +2647,13 @@ static void l2cap_chan_le_recv(struct bt_l2cap_le_chan *chan, return; } - err = chan->chan.ops->recv(&chan->chan, buf); + owned_ref = net_buf_ref(buf); + err = chan->chan.ops->recv(&chan->chan, owned_ref); + if (err != -EINPROGRESS) { + net_buf_unref(owned_ref); + owned_ref = NULL; + } + if (err < 0) { if (err != -EINPROGRESS) { LOG_ERR("err %d", err);