New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bluetooth: l2cap do not recover when faced with long packets and run out of buffers #20640
Comments
It looks like we are not generating a -EAGAIN in case we run out of memory, that would indeed stop us from resuming so the following patch should fix it:
|
@Vudentz I thought so too, but was not successful. I will test it again, maybe I missed something |
@Vudentz As I mentioned above it is not enough. l2cap debug logging level is to noisy, I switch to info and changed few lines: diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c
index 24d4b5f261..52a70031c7 100644
--- a/subsys/bluetooth/host/l2cap.c
+++ b/subsys/bluetooth/host/l2cap.c
@@ -1181,7 +1181,8 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, struct net_buf *buf,
seg = l2cap_chan_create_seg(ch, buf, sdu_hdr_len);
if (!seg) {
- return -ENOMEM;
+ BT_INFO("l2cap_chan_create_seg() failed");
+ return -EAGAIN;
}
/* Channel may have been disconnected while waiting for a buffer */
@@ -1259,6 +1260,7 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
ret = l2cap_chan_le_send(ch, frag, 0);
if (ret < 0) {
+ BT_INFO("l2cap_chan_le_send() failed %d", ret);
if (ret == -EAGAIN) {
/* Store sent data into user_data */
memcpy(net_buf_user_data(frag), &sent,
@@ -1299,10 +1301,11 @@ static void l2cap_chan_le_send_resume(struct bt_l2cap_le_chan *ch)
while ((buf = l2cap_chan_le_get_tx_buf(ch))) {
int sent = *((int *)net_buf_user_data(buf));
- BT_DBG("buf %p sent %u", buf, sent);
+ BT_INFO("buf %p sent %u", buf, sent);
sent = l2cap_chan_le_send_sdu(ch, &buf, sent);
if (sent < 0) {
+ BT_INFO("l2cap_chan_le_send_sdu() failed %d", sent);
if (sent == -EAGAIN) {
ch->tx_buf = buf;
}
@@ -1328,7 +1331,7 @@ static void le_credits(struct bt_l2cap *l2cap, u8_t ident,
cid = sys_le16_to_cpu(ev->cid);
credits = sys_le16_to_cpu(ev->credits);
- BT_DBG("cid 0x%04x credits %u", cid, credits);
+ BT_INFO("cid 0x%04x credits %u", cid, credits);
chan = bt_l2cap_le_lookup_tx_cid(conn, cid);
if (!chan) {
@@ -1892,6 +1895,7 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
if (err < 0) {
if (err == -EAGAIN) {
/* Queue buffer to be sent later */
+ BT_INFO("Queue buffer, l2cap_chan_le_send_sdu() failed %d", err);
net_buf_put(&(BT_L2CAP_LE_CHAN(chan))->tx_queue, buf);
return *((int *)net_buf_user_data(buf));
}
console:
|
When a segment could not be allocated it should be possible to resume sending it later once previous segments complete, the only exception is when there is no previous activity and we are unable to alocate even the very first segment which should indicate to the caller that it would block since that only happens on syswq the caller might need to defer to another thread or resubmit the work. Fixes zephyrproject-rtos#20640 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
When a segment could not be allocated it should be possible to resume sending it later once previous segments complete, the only exception is when there is no previous activity and we are unable to alocate even the very first segment which should indicate to the caller that it would block since that only happens on syswq the caller might need to defer to another thread or resubmit the work. Fixes #20640 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Describe the bug
l2cap do not recover when faced with long packets and runs out of buffers. Discovered while testing hci_usb with IPSP sample. After ping with long payload or short intervals the IPSP device remains unresponsive (does not recover / not respond anymore).
If the l2cap_chan_le_send_sdu returns EAGAIN and the buffer is queued and then in l2cap_chan_le_send_resume the same situation happens again because the l2cap_chan_le_send_sdu() and subsequent calls of
l2cap_chan_le_send()->
l2cap_chan_create_seg()->
l2cap_alloc_seg()->
bt_l2cap_create_pdu() fail (with bt_conn: Unable to allocate buffer), the device remains unresponsive or not recover even if the host stops sending data. l2cap also do not try l2cap_chan_le_send_resume() again.
To Reproduce
Build, flash, connect to IPSP sample, try
ping -i 0,3 -s 512 2001:db8::1
orping -i 1 -s 1024 2001:db8::1
Expected behavior
The device should recover after ping flood, even if it does not have enough buffer for the data.
console output
The text was updated successfully, but these errors were encountered: