diff options
author | Gustavo F. Padovan <gustavo@las.ic.unicamp.br> | 2009-08-20 21:25:59 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-22 17:55:20 -0400 |
commit | 30afb5b2aa83adf4f69e5090d48e1bb04b64c58a (patch) | |
tree | f47506c5f02b8e1d23123cadee49f518c928afa5 /net/bluetooth/l2cap.c | |
parent | c74e560cd0101455f1889515e1527e4c2e266113 (diff) |
Bluetooth: Initial support for retransmission of packets with REJ frames
When receiving an I-frame with unexpected txSeq, receiver side start the
recovery procedure by sending a REJ S-frame to the transmitter side. So
the transmitter can re-send the lost I-frame.
This patch just adds a basic support for retransmission, it doesn't
mean that ERTM now has full support for packet retransmission.
Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 57 |
1 files changed, 43 insertions, 14 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 167e02532697..35e9f5b80545 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -2951,22 +2951,36 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str | |||
2951 | 2951 | ||
2952 | BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); | 2952 | BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); |
2953 | 2953 | ||
2954 | if (tx_seq != pi->expected_tx_seq) | 2954 | if (tx_seq == pi->expected_tx_seq) { |
2955 | return -EINVAL; | 2955 | if (pi->conn_state & L2CAP_CONN_UNDER_REJ) |
2956 | pi->conn_state &= ~L2CAP_CONN_UNDER_REJ; | ||
2956 | 2957 | ||
2957 | err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); | 2958 | err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); |
2958 | if (err < 0) | 2959 | if (err < 0) |
2959 | return err; | 2960 | return err; |
2961 | |||
2962 | pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; | ||
2963 | pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; | ||
2964 | if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { | ||
2965 | tx_control |= L2CAP_SUPER_RCV_READY; | ||
2966 | tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
2967 | goto send; | ||
2968 | } | ||
2969 | } else { | ||
2970 | /* Unexpected txSeq. Send a REJ S-frame */ | ||
2971 | kfree_skb(skb); | ||
2972 | if (!(pi->conn_state & L2CAP_CONN_UNDER_REJ)) { | ||
2973 | tx_control |= L2CAP_SUPER_REJECT; | ||
2974 | tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
2975 | pi->conn_state |= L2CAP_CONN_UNDER_REJ; | ||
2960 | 2976 | ||
2961 | pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; | 2977 | goto send; |
2962 | pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; | 2978 | } |
2963 | if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { | ||
2964 | tx_control |= L2CAP_CTRL_FRAME_TYPE; | ||
2965 | tx_control |= L2CAP_SUPER_RCV_READY; | ||
2966 | tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
2967 | err = l2cap_send_sframe(pi, tx_control); | ||
2968 | } | 2979 | } |
2969 | return err; | 2980 | return 0; |
2981 | |||
2982 | send: | ||
2983 | return l2cap_send_sframe(pi, tx_control); | ||
2970 | } | 2984 | } |
2971 | 2985 | ||
2972 | static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) | 2986 | static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) |
@@ -2982,8 +2996,18 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str | |||
2982 | l2cap_ertm_send(sk); | 2996 | l2cap_ertm_send(sk); |
2983 | break; | 2997 | break; |
2984 | 2998 | ||
2985 | case L2CAP_SUPER_RCV_NOT_READY: | ||
2986 | case L2CAP_SUPER_REJECT: | 2999 | case L2CAP_SUPER_REJECT: |
3000 | pi->expected_ack_seq = __get_reqseq(rx_control); | ||
3001 | l2cap_drop_acked_frames(sk); | ||
3002 | |||
3003 | sk->sk_send_head = TX_QUEUE(sk)->next; | ||
3004 | pi->next_tx_seq = pi->expected_ack_seq; | ||
3005 | |||
3006 | l2cap_ertm_send(sk); | ||
3007 | |||
3008 | break; | ||
3009 | |||
3010 | case L2CAP_SUPER_RCV_NOT_READY: | ||
2987 | case L2CAP_SUPER_SELECT_REJECT: | 3011 | case L2CAP_SUPER_SELECT_REJECT: |
2988 | break; | 3012 | break; |
2989 | } | 3013 | } |
@@ -3030,6 +3054,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
3030 | if (__is_sar_start(control)) | 3054 | if (__is_sar_start(control)) |
3031 | len -= 2; | 3055 | len -= 2; |
3032 | 3056 | ||
3057 | /* | ||
3058 | * We can just drop the corrupted I-frame here. | ||
3059 | * Receiver will miss it and start proper recovery | ||
3060 | * procedures and ask retransmission. | ||
3061 | */ | ||
3033 | if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) | 3062 | if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) |
3034 | goto drop; | 3063 | goto drop; |
3035 | 3064 | ||