Skip to content

Commit

Permalink
Bluetooth: Fix a redundant and problematic incoming MTU check
Browse files Browse the repository at this point in the history
The L2CAP MTU for incoming data is verified differently depending on
the L2CAP mode, so the check is best performed in a mode-specific
context.  Checking the incoming MTU before HCI fragment reassembly is
a layer violation and assumes all bytes after the standard L2CAP
header are L2CAP data.

This approach causes issues with unsegmented ERTM or streaming mode
frames, where there are additional enhanced or extended headers before
the data payload and possible FCS bytes after the data payload.  A
valid frame could be as many as 10 bytes larger than the MTU.

Removing this code is the best fix, because the MTU is checked later
on for all L2CAP data frames (connectionless, basic, ERTM, and
streaming).  This also gets rid of outdated locking (socket instead of
l2cap_chan) and an extra lookup of the channel ID.

Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Reviewed-by: Ulisses Furquim <ulisses@profusion.mobi>
Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
  • Loading branch information
Mat Martineau authored and Gustavo Padovan committed May 16, 2012
1 parent 85d5972 commit 35c84d7
Showing 1 changed file with 0 additions and 20 deletions.
20 changes: 0 additions & 20 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5000,8 +5000,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)

if (!(flags & ACL_CONT)) {
struct l2cap_hdr *hdr;
struct l2cap_chan *chan;
u16 cid;
int len;

if (conn->rx_len) {
Expand All @@ -5021,7 +5019,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)

hdr = (struct l2cap_hdr *) skb->data;
len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
cid = __le16_to_cpu(hdr->cid);

if (len == skb->len) {
/* Complete frame received */
Expand All @@ -5038,23 +5035,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
goto drop;
}

chan = l2cap_get_chan_by_scid(conn, cid);

if (chan && chan->sk) {
struct sock *sk = chan->sk;
lock_sock(sk);

if (chan->imtu < len - L2CAP_HDR_SIZE) {
BT_ERR("Frame exceeding recv MTU (len %d, "
"MTU %d)", len,
chan->imtu);
release_sock(sk);
l2cap_conn_unreliable(conn, ECOMM);
goto drop;
}
release_sock(sk);
}

/* Allocate skb for the complete frame (with header) */
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!conn->rx_skb)
Expand Down

0 comments on commit 35c84d7

Please sign in to comment.