diff options
author | João Paulo Rechi Vita <jprvita@profusion.mobi> | 2010-05-01 15:15:44 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-05-10 03:28:53 -0400 |
commit | 9b53350d3cf5b330c3261d89b5e62a2dc25c5653 (patch) | |
tree | 085b64bd1e84023ac87b034ffddb3c48876d46fb | |
parent | 18778a63ddc83bc89bda3b119fb02eb121512a66 (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>
-rw-r--r-- | net/bluetooth/l2cap.c | 40 |
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 | ||
3305 | static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) | 3305 | static 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 | ||
3332 | static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) | 3337 | static 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 | |||
3708 | drop: | ||
3709 | kfree_skb(skb); | ||
3710 | return 0; | ||
3679 | } | 3711 | } |
3680 | 3712 | ||
3681 | static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) | 3713 | static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) |