Bluetooth: Handle incoming REJ frames
authorMat Martineau <mathewm@codeaurora.org>
Fri, 18 May 2012 03:53:47 +0000 (20:53 -0700)
committerJohan Hedberg <johan.hedberg@intel.com>
Tue, 5 Jun 2012 03:34:04 +0000 (06:34 +0300)
REJ frames are sent by the remote device to request that all frames
after a given sequence number be retransmitted.  These are also an
implicit indication that the remote device is not in a busy state and
can receive new iframes.

Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
net/bluetooth/l2cap_core.c

index 36842a29bb479c358e3e95e024ea14db860cc34a..5e4a881a6e19ad3e2feb481fcfd6e30942a8e8ab 100644 (file)
@@ -4613,7 +4613,38 @@ static void l2cap_handle_srej(struct l2cap_chan *chan,
 static void l2cap_handle_rej(struct l2cap_chan *chan,
                             struct l2cap_ctrl *control)
 {
-       /* Placeholder */
+       struct sk_buff *skb;
+
+       BT_DBG("chan %p, control %p", chan, control);
+
+       if (control->reqseq == chan->next_tx_seq) {
+               BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
+       }
+
+       skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
+
+       if (chan->max_tx && skb &&
+           bt_cb(skb)->control.retries >= chan->max_tx) {
+               BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
+       }
+
+       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+
+       l2cap_pass_to_tx(chan, control);
+
+       if (control->final) {
+               if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
+                       l2cap_retransmit_all(chan, control);
+       } else {
+               l2cap_retransmit_all(chan, control);
+               l2cap_ertm_send(chan);
+               if (chan->tx_state == L2CAP_TX_STATE_WAIT_F)
+                       set_bit(CONN_REJ_ACT, &chan->conn_state);
+       }
 }
 
 static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)