Bluetooth: Implement RejActioned flag
authorGustavo F. Padovan <gustavo@las.ic.unicamp.br>
Sat, 3 Oct 2009 05:34:39 +0000 (02:34 -0300)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 3 Dec 2009 18:34:24 +0000 (19:34 +0100)
RejActioned is used to prevent retransmission when a entity is on the
WAIT_F state, i.e., waiting for a frame with F-bit set due local busy
condition or a expired retransmission timer. (When these two events raise
they send a frame with the Poll bit set and enters in the WAIT_F state to
wait for a frame with the Final bit set.)
The local entity doesn't send I-frames(the data frames) until the receipt
of a frame with F-bit set. When that happens it also set RejActioned to false.
RejActioned is a mandatory feature of ERTM spec.

Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/l2cap.h
net/bluetooth/l2cap.c

index 327eb57..17a689f 100644 (file)
@@ -374,6 +374,7 @@ struct l2cap_pinfo {
 #define L2CAP_CONN_SEND_PBIT       0x10
 #define L2CAP_CONN_REMOTE_BUSY     0x20
 #define L2CAP_CONN_LOCAL_BUSY      0x40
+#define L2CAP_CONN_REJ_ACT         0x80
 
 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
                jiffies +  msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
index 78ab881..73bda0a 100644 (file)
@@ -3362,6 +3362,16 @@ expected:
                return 0;
        }
 
+       if (rx_control & L2CAP_CTRL_FINAL) {
+               if (pi->conn_state & L2CAP_CONN_REJ_ACT)
+                       pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+               else {
+                       sk->sk_send_head = TX_QUEUE(sk)->next;
+                       pi->next_tx_seq = pi->expected_ack_seq;
+                       l2cap_ertm_send(sk);
+               }
+       }
+
        pi->buffer_seq = (pi->buffer_seq + 1) % 64;
 
        err = l2cap_sar_reassembly_sdu(sk, skb, rx_control);
@@ -3398,6 +3408,14 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
                        pi->expected_ack_seq = tx_seq;
                        l2cap_drop_acked_frames(sk);
 
+                       if (pi->conn_state & L2CAP_CONN_REJ_ACT)
+                               pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+                       else {
+                               sk->sk_send_head = TX_QUEUE(sk)->next;
+                               pi->next_tx_seq = pi->expected_ack_seq;
+                               l2cap_ertm_send(sk);
+                       }
+
                        if (!(pi->conn_state & L2CAP_CONN_WAIT_F))
                                break;
 
@@ -3425,10 +3443,24 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
                pi->expected_ack_seq = __get_reqseq(rx_control);
                l2cap_drop_acked_frames(sk);
 
-               sk->sk_send_head = TX_QUEUE(sk)->next;
-               pi->next_tx_seq = pi->expected_ack_seq;
+               if (rx_control & L2CAP_CTRL_FINAL) {
+                       if (pi->conn_state & L2CAP_CONN_REJ_ACT)
+                               pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+                       else {
+                               sk->sk_send_head = TX_QUEUE(sk)->next;
+                               pi->next_tx_seq = pi->expected_ack_seq;
+                               l2cap_ertm_send(sk);
+                       }
+               } else {
+                       sk->sk_send_head = TX_QUEUE(sk)->next;
+                       pi->next_tx_seq = pi->expected_ack_seq;
+                       l2cap_ertm_send(sk);
 
-               l2cap_ertm_send(sk);
+                       if (pi->conn_state & L2CAP_CONN_WAIT_F) {
+                               pi->srej_save_reqseq = tx_seq;
+                               pi->conn_state |= L2CAP_CONN_REJ_ACT;
+                       }
+               }
 
                break;