aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp
diff options
context:
space:
mode:
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_core.c36
-rw-r--r--net/l2tp/l2tp_core.h2
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
542static 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 */
548static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) 557static 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