Re: [PATCH 2/4] Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS
From: Luiz Augusto von Dentz
Date: Wed Feb 25 2026 - 12:24:40 EST
Hi Christian,
On Wed, Feb 25, 2026 at 12:07 PM Christian Eggers <ceggers@xxxxxxx> wrote:
>
> Core 6.0, Vol 3, Part A, 3.4.3:
> "... If the payload size of any K-frame exceeds the receiver's MPS, the
> receiver shall disconnect the channel..."
>
> This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P
> 0x0027 -V le_public -I 100').
>
> Signed-off-by: Christian Eggers <ceggers@xxxxxxx>
> ---
> Maybe the naming of 'mps_orig_le' could be improved...
>
> include/net/bluetooth/l2cap.h | 1 +
> net/bluetooth/l2cap_core.c | 4 +++-
> 2 files changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 010f1a8fd15f..c6744cce75b1 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -552,6 +552,7 @@ struct l2cap_chan {
> __u16 retrans_timeout;
> __u16 monitor_timeout;
> __u16 mps;
> + __u16 mps_orig_le;
Hmm, I wonder if it wouldn't make more sense to have imps/mps_rx and
omps/mps_tx? I guess that is why you need a separate field; otherwise,
the MPS is updated with the remote MPS, causing us to accept the
packets as valid. That said it would need to change quite a few more
places it seems
>
> __u16 tx_credits;
> __u16 rx_credits;
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index ddac5b9270bf..c9555b0a3461 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -568,6 +568,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits)
> chan->tx_credits = tx_credits;
> /* Derive MPS from connection MTU to stop HCI fragmentation */
> chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE);
> + chan->mps_orig_le = chan->mps;
> chan->rx_credits = l2cap_le_rx_credits(chan);
>
> skb_queue_head_init(&chan->tx_q);
> @@ -580,6 +581,7 @@ static void l2cap_ecred_init(struct l2cap_chan *chan, u16 tx_credits)
> /* L2CAP implementations shall support a minimum MPS of 64 octets */
> if (chan->mps < L2CAP_ECRED_MIN_MPS) {
> chan->mps = L2CAP_ECRED_MIN_MPS;
> + chan->mps_orig_le = L2CAP_ECRED_MIN_MPS;
> chan->rx_credits = l2cap_le_rx_credits(chan);
> }
> }
> @@ -6662,7 +6664,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
> return -ENOBUFS;
> }
>
> - if (chan->imtu < skb->len) {
> + if (chan->mps_orig_le < skb->len || chan->imtu < skb->len) {
> BT_ERR("Too big LE L2CAP PDU");
> l2cap_send_disconn_req(chan, ECONNRESET);
> return -ENOBUFS;
> --
> 2.44.4
>
--
Luiz Augusto von Dentz