diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 44c26efa2dad0..63be062050372 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -263,7 +263,13 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, if (buf->len > net_buf_tailroom(conn->rx)) { BT_ERR("Not enough buffer space for L2CAP data"); - bt_conn_reset_rx_state(conn); + + /* Frame is not complete but we still pass it to L2CAP + * so that it may handle error on protocol level + * eg disconnect channel. + */ + bt_l2cap_recv(conn, conn->rx, false); + conn->rx = NULL; net_buf_unref(buf); return; } @@ -308,7 +314,7 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, conn->rx = NULL; BT_DBG("Successfully parsed %u byte L2CAP packet", buf->len); - bt_l2cap_recv(conn, buf); + bt_l2cap_recv(conn, buf, true); } void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index b9b1e48670547..e0128e73503bd 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -2364,13 +2364,23 @@ static void l2cap_chan_recv_queue(struct bt_l2cap_le_chan *chan, } #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ -static void l2cap_chan_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) +static void l2cap_chan_recv(struct bt_l2cap_chan *chan, struct net_buf *buf, + bool complete) { #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan); if (L2CAP_LE_CID_IS_DYN(ch->rx.cid)) { - l2cap_chan_recv_queue(ch, buf); + if (complete) { + l2cap_chan_recv_queue(ch, buf); + } else { + /* if packet was not complete this means peer device + * overflowed our RX and channel shall be disconnected + */ + bt_l2cap_chan_disconnect(chan); + net_buf_unref(buf); + } + return; } #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ @@ -2381,7 +2391,7 @@ static void l2cap_chan_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) net_buf_unref(buf); } -void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) +void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf, bool complete) { struct bt_l2cap_hdr *hdr; struct bt_l2cap_chan *chan; @@ -2411,7 +2421,7 @@ void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) return; } - l2cap_chan_recv(chan, buf); + l2cap_chan_recv(chan, buf, complete); } int bt_l2cap_update_conn_param(struct bt_conn *conn, diff --git a/subsys/bluetooth/host/l2cap_internal.h b/subsys/bluetooth/host/l2cap_internal.h index 03331027bc986..fb0970183a90a 100644 --- a/subsys/bluetooth/host/l2cap_internal.h +++ b/subsys/bluetooth/host/l2cap_internal.h @@ -312,7 +312,7 @@ static inline int bt_l2cap_send(struct bt_conn *conn, uint16_t cid, } /* Receive a new L2CAP PDU from a connection */ -void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf); +void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf, bool complete); /* Perform connection parameter update request */ int bt_l2cap_update_conn_param(struct bt_conn *conn,