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) |
