Bluetooth: Fix disconnecting L2CAP when a credits overflow occurs
authorJohan Hedberg <johan.hedberg@intel.com>
Mon, 27 Jan 2014 23:11:35 +0000 (15:11 -0800)
committerJohan Hedberg <johan.hedberg@intel.com>
Thu, 13 Feb 2014 07:51:38 +0000 (09:51 +0200)
The L2CAP specification requires us to disconnect an L2CAP channel if
the remote side gives us credits beyond 65535. This patch makes sure we
disconnect the channel in such a situation.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/l2cap_core.c

index fbc9709abccf6a7f1b922e7cd32c304ab41ff1e8..d2ef49b54aa212736e0fff65c9baf2f8797329d6 100644 (file)
@@ -42,6 +42,8 @@
 #include "amp.h"
 #include "6lowpan.h"
 
+#define LE_FLOWCTL_MAX_CREDITS 65535
+
 bool disable_ertm;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
@@ -5473,7 +5475,7 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
 {
        struct l2cap_le_credits *pkt;
        struct l2cap_chan *chan;
-       u16 cid, credits;
+       u16 cid, credits, max_credits;
 
        if (cmd_len != sizeof(*pkt))
                return -EPROTO;
@@ -5488,6 +5490,17 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
        if (!chan)
                return -EBADSLT;
 
+       max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits;
+       if (credits > max_credits) {
+               BT_ERR("LE credits overflow");
+               l2cap_send_disconn_req(chan, ECONNRESET);
+
+               /* Return 0 so that we don't trigger an unnecessary
+                * command reject packet.
+                */
+               return 0;
+       }
+
        chan->tx_credits += credits;
 
        while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {