diff options
author | Gustavo F. Padovan <gustavo@las.ic.unicamp.br> | 2009-08-20 21:26:04 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-22 18:03:43 -0400 |
commit | ef54fd937fbd5ebaeb023818524565bd526a5f36 (patch) | |
tree | c664288f00548b8c531ff44a0bc8c7f18542740e | |
parent | 8f17154f1f70fcc6faa31ac82164fcf7f0599f38 (diff) |
Bluetooth: Full support for receiving L2CAP SREJ frames
Support for receiving of SREJ frames as specified by the state table.
Signed-off-by: Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 3 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 30 |
2 files changed, 32 insertions, 1 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9f2126a4f6f5..7ca614ac5d43 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -328,6 +328,7 @@ struct l2cap_pinfo { | |||
328 | __u8 expected_tx_seq; | 328 | __u8 expected_tx_seq; |
329 | __u8 buffer_seq; | 329 | __u8 buffer_seq; |
330 | __u8 buffer_seq_srej; | 330 | __u8 buffer_seq_srej; |
331 | __u8 srej_save_reqseq; | ||
331 | __u8 unacked_frames; | 332 | __u8 unacked_frames; |
332 | __u8 retry_count; | 333 | __u8 retry_count; |
333 | __u8 num_to_ack; | 334 | __u8 num_to_ack; |
@@ -370,6 +371,8 @@ struct l2cap_pinfo { | |||
370 | #define L2CAP_CONN_SAR_SDU 0x01 | 371 | #define L2CAP_CONN_SAR_SDU 0x01 |
371 | #define L2CAP_CONN_SREJ_SENT 0x02 | 372 | #define L2CAP_CONN_SREJ_SENT 0x02 |
372 | #define L2CAP_CONN_WAIT_F 0x04 | 373 | #define L2CAP_CONN_WAIT_F 0x04 |
374 | #define L2CAP_CONN_SREJ_ACT 0x08 | ||
375 | #define L2CAP_CONN_SEND_PBIT 0x10 | ||
373 | 376 | ||
374 | #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ | 377 | #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ |
375 | jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); | 378 | jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); |
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 70aff921db8c..c04526f3df2e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -3241,6 +3241,10 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) | |||
3241 | while (tx_seq != pi->expected_tx_seq) { | 3241 | while (tx_seq != pi->expected_tx_seq) { |
3242 | control = L2CAP_SUPER_SELECT_REJECT; | 3242 | control = L2CAP_SUPER_SELECT_REJECT; |
3243 | control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; | 3243 | control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; |
3244 | if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { | ||
3245 | control |= L2CAP_CTRL_POLL; | ||
3246 | pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; | ||
3247 | } | ||
3244 | l2cap_send_sframe(pi, control); | 3248 | l2cap_send_sframe(pi, control); |
3245 | 3249 | ||
3246 | new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); | 3250 | new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); |
@@ -3300,6 +3304,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str | |||
3300 | __skb_queue_head_init(SREJ_QUEUE(sk)); | 3304 | __skb_queue_head_init(SREJ_QUEUE(sk)); |
3301 | l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); | 3305 | l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); |
3302 | 3306 | ||
3307 | pi->conn_state |= L2CAP_CONN_SEND_PBIT; | ||
3308 | |||
3303 | l2cap_send_srejframe(sk, tx_seq); | 3309 | l2cap_send_srejframe(sk, tx_seq); |
3304 | } | 3310 | } |
3305 | return 0; | 3311 | return 0; |
@@ -3370,7 +3376,29 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str | |||
3370 | break; | 3376 | break; |
3371 | 3377 | ||
3372 | case L2CAP_SUPER_SELECT_REJECT: | 3378 | case L2CAP_SUPER_SELECT_REJECT: |
3373 | l2cap_retransmit_frame(sk, tx_seq); | 3379 | if (rx_control & L2CAP_CTRL_POLL) { |
3380 | l2cap_retransmit_frame(sk, tx_seq); | ||
3381 | pi->expected_ack_seq = tx_seq; | ||
3382 | l2cap_drop_acked_frames(sk); | ||
3383 | l2cap_ertm_send(sk); | ||
3384 | if (pi->conn_state & L2CAP_CONN_WAIT_F) { | ||
3385 | pi->srej_save_reqseq = tx_seq; | ||
3386 | pi->conn_state |= L2CAP_CONN_SREJ_ACT; | ||
3387 | } | ||
3388 | } else if (rx_control & L2CAP_CTRL_FINAL) { | ||
3389 | if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && | ||
3390 | pi->srej_save_reqseq == tx_seq) | ||
3391 | pi->srej_save_reqseq &= ~L2CAP_CONN_SREJ_ACT; | ||
3392 | else | ||
3393 | l2cap_retransmit_frame(sk, tx_seq); | ||
3394 | } | ||
3395 | else { | ||
3396 | l2cap_retransmit_frame(sk, tx_seq); | ||
3397 | if (pi->conn_state & L2CAP_CONN_WAIT_F) { | ||
3398 | pi->srej_save_reqseq = tx_seq; | ||
3399 | pi->conn_state |= L2CAP_CONN_SREJ_ACT; | ||
3400 | } | ||
3401 | } | ||
3374 | break; | 3402 | break; |
3375 | 3403 | ||
3376 | case L2CAP_SUPER_RCV_NOT_READY: | 3404 | case L2CAP_SUPER_RCV_NOT_READY: |