aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJoão Paulo Rechi Vita <jprvita@profusion.mobi>2010-05-01 15:15:44 -0400
committerMarcel Holtmann <marcel@holtmann.org>2010-05-10 03:28:53 -0400
commit9b53350d3cf5b330c3261d89b5e62a2dc25c5653 (patch)
tree085b64bd1e84023ac87b034ffddb3c48876d46fb /net/bluetooth
parent18778a63ddc83bc89bda3b119fb02eb121512a66 (diff)
Bluetooth: Completes the I-frame tx_seq check logic on RECV
Add checks for invalid tx_seq and fixes the duplicated tx_seq check. Signed-off-by: João Paulo Rechi Vita <jprvita@profusion.mobi> Acked-by: Gustavo F. Padovan <padovan@profusion.mobi> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index cfd672419315..481cec22ef96 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3302,7 +3302,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
3302 } 3302 }
3303} 3303}
3304 3304
3305static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) 3305static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
3306{ 3306{
3307 struct sk_buff *next_skb; 3307 struct sk_buff *next_skb;
3308 3308
@@ -3312,13 +3312,16 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_
3312 next_skb = skb_peek(SREJ_QUEUE(sk)); 3312 next_skb = skb_peek(SREJ_QUEUE(sk));
3313 if (!next_skb) { 3313 if (!next_skb) {
3314 __skb_queue_tail(SREJ_QUEUE(sk), skb); 3314 __skb_queue_tail(SREJ_QUEUE(sk), skb);
3315 return; 3315 return 0;
3316 } 3316 }
3317 3317
3318 do { 3318 do {
3319 if (bt_cb(next_skb)->tx_seq == tx_seq)
3320 return -EINVAL;
3321
3319 if (bt_cb(next_skb)->tx_seq > tx_seq) { 3322 if (bt_cb(next_skb)->tx_seq > tx_seq) {
3320 __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); 3323 __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
3321 return; 3324 return 0;
3322 } 3325 }
3323 3326
3324 if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) 3327 if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb))
@@ -3327,6 +3330,8 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_
3327 } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); 3330 } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb)));
3328 3331
3329 __skb_queue_tail(SREJ_QUEUE(sk), skb); 3332 __skb_queue_tail(SREJ_QUEUE(sk), skb);
3333
3334 return 0;
3330} 3335}
3331 3336
3332static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) 3337static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
@@ -3579,6 +3584,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
3579 u8 tx_seq = __get_txseq(rx_control); 3584 u8 tx_seq = __get_txseq(rx_control);
3580 u8 req_seq = __get_reqseq(rx_control); 3585 u8 req_seq = __get_reqseq(rx_control);
3581 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; 3586 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
3587 u8 tx_seq_offset, expected_tx_seq_offset;
3582 int num_to_ack = (pi->tx_win/6) + 1; 3588 int num_to_ack = (pi->tx_win/6) + 1;
3583 int err = 0; 3589 int err = 0;
3584 3590
@@ -3598,6 +3604,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
3598 if (tx_seq == pi->expected_tx_seq) 3604 if (tx_seq == pi->expected_tx_seq)
3599 goto expected; 3605 goto expected;
3600 3606
3607 tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
3608 if (tx_seq_offset < 0)
3609 tx_seq_offset += 64;
3610
3611 /* invalid tx_seq */
3612 if (tx_seq_offset >= pi->tx_win) {
3613 l2cap_send_disconn_req(pi->conn, sk);
3614 goto drop;
3615 }
3616
3601 if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { 3617 if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
3602 struct srej_list *first; 3618 struct srej_list *first;
3603 3619
@@ -3617,7 +3633,10 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
3617 } 3633 }
3618 } else { 3634 } else {
3619 struct srej_list *l; 3635 struct srej_list *l;
3620 l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); 3636
3637 /* duplicated tx_seq */
3638 if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0)
3639 goto drop;
3621 3640
3622 list_for_each_entry(l, SREJ_LIST(sk), list) { 3641 list_for_each_entry(l, SREJ_LIST(sk), list) {
3623 if (l->tx_seq == tx_seq) { 3642 if (l->tx_seq == tx_seq) {
@@ -3628,6 +3647,15 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
3628 l2cap_send_srejframe(sk, tx_seq); 3647 l2cap_send_srejframe(sk, tx_seq);
3629 } 3648 }
3630 } else { 3649 } else {
3650 expected_tx_seq_offset =
3651 (pi->expected_tx_seq - pi->buffer_seq) % 64;
3652 if (expected_tx_seq_offset < 0)
3653 expected_tx_seq_offset += 64;
3654
3655 /* duplicated tx_seq */
3656 if (tx_seq_offset < expected_tx_seq_offset)
3657 goto drop;
3658
3631 pi->conn_state |= L2CAP_CONN_SREJ_SENT; 3659 pi->conn_state |= L2CAP_CONN_SREJ_SENT;
3632 3660
3633 INIT_LIST_HEAD(SREJ_LIST(sk)); 3661 INIT_LIST_HEAD(SREJ_LIST(sk));
@@ -3676,6 +3704,10 @@ expected:
3676 l2cap_send_ack(pi); 3704 l2cap_send_ack(pi);
3677 3705
3678 return 0; 3706 return 0;
3707
3708drop:
3709 kfree_skb(skb);
3710 return 0;
3679} 3711}
3680 3712
3681static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) 3713static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)