aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-07-02 19:33:31 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-02 19:33:31 -0400
commit784771e74b9207b0dd9e1f3b04729e6356c88650 (patch)
tree3f5187519c078bfa265654239854ab0a41597719 /net
parent8a59bd3e9b296b93b905b5509c4ff540ee0e00bf (diff)
parenta0dbd822273ce7660bf35525d61d7a8ac5e679a3 (diff)
Merge branch 'l2tp_seq'
James Chapman says: ==================== L2TP data sequence numbers, if enabled, ensure in-order delivery. A receiver may reorder data packets, or simply drop out-of-sequence packets. If reordering is not enabled, the current implementation does not handle data packet loss correctly, which can result in a stalled L2TP session datapath as soon as the first packet is lost. Most L2TP users either disable sequence numbers or enable data packet reordering when sequence numbers are used to circumvent the issue. This patch series fixes the problem, and makes the L2TP sequence number handling RFC-compliant. v2 incorporates string format changes requested by sergei.shtylyov@cogentembedded.com. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/l2tp/l2tp_core.c114
-rw-r--r--net/l2tp/l2tp_core.h5
2 files changed, 95 insertions, 24 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 6984c3a353cd..feae495a0a30 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,6 +539,84 @@ 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
554/* If packet has sequence numbers, queue it if acceptable. Returns 0 if
555 * acceptable, else non-zero.
556 */
557static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb)
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
570 if (session->reorder_timeout != 0) {
571 /* Packet reordering enabled. Add skb to session's
572 * reorder queue, in order of ns.
573 */
574 l2tp_recv_queue_skb(session, skb);
575 goto out;
576 }
577
578 /* Packet reordering disabled. Discard out-of-sequence packets, while
579 * tracking the number if in-sequence packets after the first OOS packet
580 * is seen. After nr_oos_count_max in-sequence packets, reset the
581 * sequence number to re-enable packet reception.
582 */
583 if (L2TP_SKB_CB(skb)->ns == session->nr) {
584 skb_queue_tail(&session->reorder_q, skb);
585 } else {
586 u32 nr_oos = L2TP_SKB_CB(skb)->ns;
587 u32 nr_next = (session->nr_oos + 1) & session->nr_max;
588
589 if (nr_oos == nr_next)
590 session->nr_oos_count++;
591 else
592 session->nr_oos_count = 0;
593
594 session->nr_oos = nr_oos;
595 if (session->nr_oos_count > session->nr_oos_count_max) {
596 session->reorder_skip = 1;
597 l2tp_dbg(session, L2TP_MSG_SEQ,
598 "%s: %d oos packets received. Resetting sequence numbers\n",
599 session->name, session->nr_oos_count);
600 }
601 if (!session->reorder_skip) {
602 atomic_long_inc(&session->stats.rx_seq_discards);
603 l2tp_dbg(session, L2TP_MSG_SEQ,
604 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n",
605 session->name, L2TP_SKB_CB(skb)->ns,
606 L2TP_SKB_CB(skb)->length, session->nr,
607 skb_queue_len(&session->reorder_q));
608 goto discard;
609 }
610 skb_queue_tail(&session->reorder_q, skb);
611 }
612
613out:
614 return 0;
615
616discard:
617 return 1;
618}
619
545/* Do receive processing of L2TP data frames. We handle both L2TPv2 620/* Do receive processing of L2TP data frames. We handle both L2TPv2
546 * and L2TPv3 data frames here. 621 * and L2TPv3 data frames here.
547 * 622 *
@@ -757,26 +832,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
757 * enabled. Saved L2TP protocol info is stored in skb->sb[]. 832 * enabled. Saved L2TP protocol info is stored in skb->sb[].
758 */ 833 */
759 if (L2TP_SKB_CB(skb)->has_seq) { 834 if (L2TP_SKB_CB(skb)->has_seq) {
760 if (session->reorder_timeout != 0) { 835 if (l2tp_recv_data_seq(session, skb))
761 /* Packet reordering enabled. Add skb to session's 836 goto discard;
762 * reorder queue, in order of ns.
763 */
764 l2tp_recv_queue_skb(session, skb);
765 } else {
766 /* Packet reordering disabled. Discard out-of-sequence
767 * packets
768 */
769 if (L2TP_SKB_CB(skb)->ns != session->nr) {
770 atomic_long_inc(&session->stats.rx_seq_discards);
771 l2tp_dbg(session, L2TP_MSG_SEQ,
772 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n",
773 session->name, L2TP_SKB_CB(skb)->ns,
774 L2TP_SKB_CB(skb)->length, session->nr,
775 skb_queue_len(&session->reorder_q));
776 goto discard;
777 }
778 skb_queue_tail(&session->reorder_q, skb);
779 }
780 } else { 837 } else {
781 /* No sequence numbers. Add the skb to the tail of the 838 /* No sequence numbers. Add the skb to the tail of the
782 * reorder queue. This ensures that it will be 839 * reorder queue. This ensures that it will be
@@ -1812,6 +1869,15 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
1812 session->session_id = session_id; 1869 session->session_id = session_id;
1813 session->peer_session_id = peer_session_id; 1870 session->peer_session_id = peer_session_id;
1814 session->nr = 0; 1871 session->nr = 0;
1872 if (tunnel->version == L2TP_HDR_VER_2)
1873 session->nr_max = 0xffff;
1874 else
1875 session->nr_max = 0xffffff;
1876 session->nr_window_size = session->nr_max / 2;
1877 session->nr_oos_count_max = 4;
1878
1879 /* Use NR of first received packet */
1880 session->reorder_skip = 1;
1815 1881
1816 sprintf(&session->name[0], "sess %u/%u", 1882 sprintf(&session->name[0], "sess %u/%u",
1817 tunnel->tunnel_id, session->session_id); 1883 tunnel->tunnel_id, session->session_id);
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 485a490fd990..66a559b104b6 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -102,6 +102,11 @@ 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 */
107 u32 nr_oos; /* NR of last OOS packet */
108 int nr_oos_count; /* For OOS recovery */
109 int nr_oos_count_max;
105 struct hlist_node hlist; /* Hash list node */ 110 struct hlist_node hlist; /* Hash list node */
106 atomic_t ref_count; 111 atomic_t ref_count;
107 112