diff options
Diffstat (limited to 'net/l2tp')
-rw-r--r-- | net/l2tp/l2tp_core.c | 36 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.h | 2 |
2 files changed, 33 insertions, 5 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 5ca29659171d..735cc06971ef 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -414,10 +414,7 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff * | |||
414 | if (L2TP_SKB_CB(skb)->has_seq) { | 414 | if (L2TP_SKB_CB(skb)->has_seq) { |
415 | /* Bump our Nr */ | 415 | /* Bump our Nr */ |
416 | session->nr++; | 416 | session->nr++; |
417 | if (tunnel->version == L2TP_HDR_VER_2) | 417 | session->nr &= session->nr_max; |
418 | session->nr &= 0xffff; | ||
419 | else | ||
420 | session->nr &= 0xffffff; | ||
421 | 418 | ||
422 | l2tp_dbg(session, L2TP_MSG_SEQ, "%s: updated nr to %hu\n", | 419 | l2tp_dbg(session, L2TP_MSG_SEQ, "%s: updated nr to %hu\n", |
423 | session->name, session->nr); | 420 | session->name, session->nr); |
@@ -542,11 +539,34 @@ static inline int l2tp_verify_udp_checksum(struct sock *sk, | |||
542 | return __skb_checksum_complete(skb); | 539 | return __skb_checksum_complete(skb); |
543 | } | 540 | } |
544 | 541 | ||
542 | static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr) | ||
543 | { | ||
544 | u32 nws; | ||
545 | |||
546 | if (nr >= session->nr) | ||
547 | nws = nr - session->nr; | ||
548 | else | ||
549 | nws = (session->nr_max + 1) - (session->nr - nr); | ||
550 | |||
551 | return nws < session->nr_window_size; | ||
552 | } | ||
553 | |||
545 | /* If packet has sequence numbers, queue it if acceptable. Returns 0 if | 554 | /* If packet has sequence numbers, queue it if acceptable. Returns 0 if |
546 | * acceptable, else non-zero. | 555 | * acceptable, else non-zero. |
547 | */ | 556 | */ |
548 | static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) | 557 | static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) |
549 | { | 558 | { |
559 | if (!l2tp_seq_check_rx_window(session, L2TP_SKB_CB(skb)->ns)) { | ||
560 | /* Packet sequence number is outside allowed window. | ||
561 | * Discard it. | ||
562 | */ | ||
563 | l2tp_dbg(session, L2TP_MSG_SEQ, | ||
564 | "%s: pkt %u len %d discarded, outside window, nr=%u\n", | ||
565 | session->name, L2TP_SKB_CB(skb)->ns, | ||
566 | L2TP_SKB_CB(skb)->length, session->nr); | ||
567 | goto discard; | ||
568 | } | ||
569 | |||
550 | if (session->reorder_timeout != 0) { | 570 | if (session->reorder_timeout != 0) { |
551 | /* Packet reordering enabled. Add skb to session's | 571 | /* Packet reordering enabled. Add skb to session's |
552 | * reorder queue, in order of ns. | 572 | * reorder queue, in order of ns. |
@@ -556,7 +576,8 @@ static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) | |||
556 | /* Packet reordering disabled. Discard out-of-sequence | 576 | /* Packet reordering disabled. Discard out-of-sequence |
557 | * packets | 577 | * packets |
558 | */ | 578 | */ |
559 | if (L2TP_SKB_CB(skb)->ns != session->nr) { | 579 | if ((L2TP_SKB_CB(skb)->ns != session->nr) && |
580 | (!session->reorder_skip)) { | ||
560 | atomic_long_inc(&session->stats.rx_seq_discards); | 581 | atomic_long_inc(&session->stats.rx_seq_discards); |
561 | l2tp_dbg(session, L2TP_MSG_SEQ, | 582 | l2tp_dbg(session, L2TP_MSG_SEQ, |
562 | "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", | 583 | "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", |
@@ -1826,6 +1847,11 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1826 | session->session_id = session_id; | 1847 | session->session_id = session_id; |
1827 | session->peer_session_id = peer_session_id; | 1848 | session->peer_session_id = peer_session_id; |
1828 | session->nr = 0; | 1849 | session->nr = 0; |
1850 | if (tunnel->version == L2TP_HDR_VER_2) | ||
1851 | session->nr_max = 0xffff; | ||
1852 | else | ||
1853 | session->nr_max = 0xffffff; | ||
1854 | session->nr_window_size = session->nr_max / 2; | ||
1829 | 1855 | ||
1830 | sprintf(&session->name[0], "sess %u/%u", | 1856 | sprintf(&session->name[0], "sess %u/%u", |
1831 | tunnel->tunnel_id, session->session_id); | 1857 | tunnel->tunnel_id, session->session_id); |
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 485a490fd990..4b9a3b724423 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -102,6 +102,8 @@ struct l2tp_session { | |||
102 | u32 nr; /* session NR state (receive) */ | 102 | u32 nr; /* session NR state (receive) */ |
103 | u32 ns; /* session NR state (send) */ | 103 | u32 ns; /* session NR state (send) */ |
104 | struct sk_buff_head reorder_q; /* receive reorder queue */ | 104 | struct sk_buff_head reorder_q; /* receive reorder queue */ |
105 | u32 nr_max; /* max NR. Depends on tunnel */ | ||
106 | u32 nr_window_size; /* NR window size */ | ||
105 | struct hlist_node hlist; /* Hash list node */ | 107 | struct hlist_node hlist; /* Hash list node */ |
106 | atomic_t ref_count; | 108 | atomic_t ref_count; |
107 | 109 | ||