diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-05-01 15:15:36 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-05-10 03:28:46 -0400 |
commit | d5392c8f1e9faef089bb7cb66c3314da8bddd1fe (patch) | |
tree | 4a935a46f0bfe2b9eb6d94f1d18fa079d2e1d095 /net/bluetooth/l2cap.c | |
parent | e8235c6bdd1c7ffbaa7eb8dcdbb46c51f1e5d72e (diff) |
Bluetooth: Implement 'Send IorRRorRNR' event
After receive a RR with P bit set ERTM shall use this funcion to choose
what type of frame to reply with F bit = 1.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index a9c152a09f0b..06687e264703 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -1383,6 +1383,10 @@ static int l2cap_ertm_send(struct sock *sk) | |||
1383 | bt_cb(skb)->retries++; | 1383 | bt_cb(skb)->retries++; |
1384 | 1384 | ||
1385 | control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); | 1385 | control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); |
1386 | if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { | ||
1387 | control |= L2CAP_CTRL_FINAL; | ||
1388 | pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; | ||
1389 | } | ||
1386 | control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | 1390 | control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) |
1387 | | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); | 1391 | | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); |
1388 | put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); | 1392 | put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); |
@@ -1404,6 +1408,7 @@ static int l2cap_ertm_send(struct sock *sk) | |||
1404 | pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; | 1408 | pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; |
1405 | 1409 | ||
1406 | pi->unacked_frames++; | 1410 | pi->unacked_frames++; |
1411 | pi->frames_sent++; | ||
1407 | 1412 | ||
1408 | if (skb_queue_is_last(TX_QUEUE(sk), skb)) | 1413 | if (skb_queue_is_last(TX_QUEUE(sk), skb)) |
1409 | sk->sk_send_head = NULL; | 1414 | sk->sk_send_head = NULL; |
@@ -2191,6 +2196,7 @@ static inline void l2cap_ertm_init(struct sock *sk) | |||
2191 | l2cap_pi(sk)->unacked_frames = 0; | 2196 | l2cap_pi(sk)->unacked_frames = 0; |
2192 | l2cap_pi(sk)->buffer_seq = 0; | 2197 | l2cap_pi(sk)->buffer_seq = 0; |
2193 | l2cap_pi(sk)->num_to_ack = 0; | 2198 | l2cap_pi(sk)->num_to_ack = 0; |
2199 | l2cap_pi(sk)->frames_sent = 0; | ||
2194 | 2200 | ||
2195 | setup_timer(&l2cap_pi(sk)->retrans_timer, | 2201 | setup_timer(&l2cap_pi(sk)->retrans_timer, |
2196 | l2cap_retrans_timeout, (unsigned long) sk); | 2202 | l2cap_retrans_timeout, (unsigned long) sk); |
@@ -3148,6 +3154,38 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) | |||
3148 | return 0; | 3154 | return 0; |
3149 | } | 3155 | } |
3150 | 3156 | ||
3157 | static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) | ||
3158 | { | ||
3159 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
3160 | u16 control = 0; | ||
3161 | |||
3162 | pi->frames_sent = 0; | ||
3163 | pi->conn_state |= L2CAP_CONN_SEND_FBIT; | ||
3164 | |||
3165 | control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
3166 | |||
3167 | if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { | ||
3168 | control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL; | ||
3169 | l2cap_send_sframe(pi, control); | ||
3170 | pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; | ||
3171 | } | ||
3172 | |||
3173 | if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0) | ||
3174 | __mod_retrans_timer(); | ||
3175 | |||
3176 | l2cap_ertm_send(sk); | ||
3177 | |||
3178 | if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && | ||
3179 | pi->frames_sent == 0) { | ||
3180 | control |= L2CAP_SUPER_RCV_READY; | ||
3181 | if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { | ||
3182 | control |= L2CAP_CTRL_FINAL; | ||
3183 | pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; | ||
3184 | } | ||
3185 | l2cap_send_sframe(pi, control); | ||
3186 | } | ||
3187 | } | ||
3188 | |||
3151 | static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) | 3189 | static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) |
3152 | { | 3190 | { |
3153 | struct sk_buff *next_skb; | 3191 | struct sk_buff *next_skb; |
@@ -3418,10 +3456,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str | |||
3418 | switch (rx_control & L2CAP_CTRL_SUPERVISE) { | 3456 | switch (rx_control & L2CAP_CTRL_SUPERVISE) { |
3419 | case L2CAP_SUPER_RCV_READY: | 3457 | case L2CAP_SUPER_RCV_READY: |
3420 | if (rx_control & L2CAP_CTRL_POLL) { | 3458 | if (rx_control & L2CAP_CTRL_POLL) { |
3421 | u16 control = L2CAP_CTRL_FINAL; | 3459 | l2cap_send_i_or_rr_or_rnr(sk); |
3422 | control |= L2CAP_SUPER_RCV_READY | | ||
3423 | (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT); | ||
3424 | l2cap_send_sframe(l2cap_pi(sk), control); | ||
3425 | pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; | 3460 | pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; |
3426 | 3461 | ||
3427 | } else if (rx_control & L2CAP_CTRL_FINAL) { | 3462 | } else if (rx_control & L2CAP_CTRL_FINAL) { |