aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2012-05-09 19:43:08 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-10 23:27:34 -0400
commit38d40b3f4e223336422b7e87cb483e758ef87e3a (patch)
tree59a1e49485c3fa596cf7538fd11c1aca589ad5ff /net/l2tp
parent1070b1b831404455d79d15fe94ae9216fb5f8ab4 (diff)
l2tp: fix reorder timeout recovery
When L2TP data packet reordering is enabled, packets are held in a queue while waiting for out-of-sequence packets. If a packet gets lost, packets will be held until the reorder timeout expires, when we are supposed to then advance to the sequence number of the next packet but we don't currently do so. As a result, the data channel is stuck because we are waiting for a packet that will never arrive - all packets age out and none are passed. The fix is to add a flag to the session context, which is set when the reorder timeout expires and tells the receive code to reset the next expected sequence number to that of the next packet in the queue. Tested in a production L2TP network with Starent and Nortel L2TP gear. Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_core.c9
-rw-r--r--net/l2tp/l2tp_core.h1
2 files changed, 10 insertions, 0 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 456b52d8f6d8..d1ab3a236cca 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -428,6 +428,7 @@ start:
428 session->name, L2TP_SKB_CB(skb)->ns, 428 session->name, L2TP_SKB_CB(skb)->ns,
429 L2TP_SKB_CB(skb)->length, session->nr, 429 L2TP_SKB_CB(skb)->length, session->nr,
430 skb_queue_len(&session->reorder_q)); 430 skb_queue_len(&session->reorder_q));
431 session->reorder_skip = 1;
431 __skb_unlink(skb, &session->reorder_q); 432 __skb_unlink(skb, &session->reorder_q);
432 kfree_skb(skb); 433 kfree_skb(skb);
433 if (session->deref) 434 if (session->deref)
@@ -436,6 +437,14 @@ start:
436 } 437 }
437 438
438 if (L2TP_SKB_CB(skb)->has_seq) { 439 if (L2TP_SKB_CB(skb)->has_seq) {
440 if (session->reorder_skip) {
441 PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
442 "%s: advancing nr to next pkt: %u -> %u",
443 session->name, session->nr,
444 L2TP_SKB_CB(skb)->ns);
445 session->reorder_skip = 0;
446 session->nr = L2TP_SKB_CB(skb)->ns;
447 }
439 if (L2TP_SKB_CB(skb)->ns != session->nr) { 448 if (L2TP_SKB_CB(skb)->ns != session->nr) {
440 PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, 449 PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
441 "%s: holding oos pkt %u len %d, " 450 "%s: holding oos pkt %u len %d, "
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 0bf60fc88bb7..90026341a1e5 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -123,6 +123,7 @@ struct l2tp_session {
123 * categories */ 123 * categories */
124 int reorder_timeout; /* configured reorder timeout 124 int reorder_timeout; /* configured reorder timeout
125 * (in jiffies) */ 125 * (in jiffies) */
126 int reorder_skip; /* set if skip to next nr */
126 int mtu; 127 int mtu;
127 int mru; 128 int mru;
128 enum l2tp_pwtype pwtype; 129 enum l2tp_pwtype pwtype;