aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap.c
diff options
context:
space:
mode:
authorAndrei Emeltchenko <andrei.emeltchenko@nokia.com>2010-09-15 07:28:44 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2010-10-12 11:44:52 -0400
commit8979481328dc2e14cea9f99b3562ffcf8655998e (patch)
tree3d312fddecc45fc7a510011218f7af25d533466d /net/bluetooth/l2cap.c
parent3cd01976e702ccaffb907727caff4f8789353599 (diff)
Bluetooth: check L2CAP length in first ACL fragment
Current Bluetooth code assembles fragments of big L2CAP packets in l2cap_recv_acldata and then checks allowed L2CAP size in assemled L2CAP packet (pi->imtu < skb->len). The patch moves allowed L2CAP size check to the early stage when we receive the first fragment of L2CAP packet. We do not need to reserve and keep L2CAP fragments for bad packets. Updated version after comments from Mat Martineau <mathewm@codeaurora.org> and Gustavo Padovan <padovan@profusion.mobi>. Trace below is received when using stress tools sending big fragmented L2CAP packets. ... [ 1712.798492] swapper: page allocation failure. order:4, mode:0x4020 [ 1712.804809] [<c0031870>] (unwind_backtrace+0x0/0xdc) from [<c00a1f70>] (__alloc_pages_nodemask+0x4) [ 1712.814666] [<c00a1f70>] (__alloc_pages_nodemask+0x47c/0x4d4) from [<c00a1fd8>] (__get_free_pages+) [ 1712.824645] [<c00a1fd8>] (__get_free_pages+0x10/0x3c) from [<c026eb5c>] (__alloc_skb+0x4c/0xfc) [ 1712.833465] [<c026eb5c>] (__alloc_skb+0x4c/0xfc) from [<bf28c738>] (l2cap_recv_acldata+0xf0/0x1f8 ) [ 1712.843322] [<bf28c738>] (l2cap_recv_acldata+0xf0/0x1f8 [l2cap]) from [<bf0094ac>] (hci_rx_task+0x) ... Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r--net/bluetooth/l2cap.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index a9e7470d3cea..5441083ff1ca 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -4663,6 +4663,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
4663 4663
4664 if (flags & ACL_START) { 4664 if (flags & ACL_START) {
4665 struct l2cap_hdr *hdr; 4665 struct l2cap_hdr *hdr;
4666 struct sock *sk;
4667 u16 cid;
4666 int len; 4668 int len;
4667 4669
4668 if (conn->rx_len) { 4670 if (conn->rx_len) {
@@ -4681,6 +4683,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
4681 4683
4682 hdr = (struct l2cap_hdr *) skb->data; 4684 hdr = (struct l2cap_hdr *) skb->data;
4683 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; 4685 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
4686 cid = __le16_to_cpu(hdr->cid);
4684 4687
4685 if (len == skb->len) { 4688 if (len == skb->len) {
4686 /* Complete frame received */ 4689 /* Complete frame received */
@@ -4697,6 +4700,19 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
4697 goto drop; 4700 goto drop;
4698 } 4701 }
4699 4702
4703 sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
4704
4705 if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
4706 BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)",
4707 len, l2cap_pi(sk)->imtu);
4708 bh_unlock_sock(sk);
4709 l2cap_conn_unreliable(conn, ECOMM);
4710 goto drop;
4711 }
4712
4713 if (sk)
4714 bh_unlock_sock(sk);
4715
4700 /* Allocate skb for the complete frame (with header) */ 4716 /* Allocate skb for the complete frame (with header) */
4701 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); 4717 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4702 if (!conn->rx_skb) 4718 if (!conn->rx_skb)