aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorGustavo F. Padovan <gustavo@las.ic.unicamp.br>2009-08-20 21:26:04 -0400
committerMarcel Holtmann <marcel@holtmann.org>2009-08-22 18:03:43 -0400
commitef54fd937fbd5ebaeb023818524565bd526a5f36 (patch)
treec664288f00548b8c531ff44a0bc8c7f18542740e /net/bluetooth
parent8f17154f1f70fcc6faa31ac82164fcf7f0599f38 (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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap.c30
1 files changed, 29 insertions, 1 deletions
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: