Commit 38d40b3f authored by James Chapman's avatar James Chapman Committed by David S. Miller

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: default avatarJames Chapman <jchapman@katalix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1070b1b8
...@@ -428,6 +428,7 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) ...@@ -428,6 +428,7 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
session->name, L2TP_SKB_CB(skb)->ns, session->name, L2TP_SKB_CB(skb)->ns,
L2TP_SKB_CB(skb)->length, session->nr, L2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q)); skb_queue_len(&session->reorder_q));
session->reorder_skip = 1;
__skb_unlink(skb, &session->reorder_q); __skb_unlink(skb, &session->reorder_q);
kfree_skb(skb); kfree_skb(skb);
if (session->deref) if (session->deref)
...@@ -436,6 +437,14 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) ...@@ -436,6 +437,14 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
} }
if (L2TP_SKB_CB(skb)->has_seq) { if (L2TP_SKB_CB(skb)->has_seq) {
if (session->reorder_skip) {
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
"%s: advancing nr to next pkt: %u -> %u",
session->name, session->nr,
L2TP_SKB_CB(skb)->ns);
session->reorder_skip = 0;
session->nr = L2TP_SKB_CB(skb)->ns;
}
if (L2TP_SKB_CB(skb)->ns != session->nr) { if (L2TP_SKB_CB(skb)->ns != session->nr) {
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
"%s: holding oos pkt %u len %d, " "%s: holding oos pkt %u len %d, "
......
...@@ -123,6 +123,7 @@ struct l2tp_session { ...@@ -123,6 +123,7 @@ struct l2tp_session {
* categories */ * categories */
int reorder_timeout; /* configured reorder timeout int reorder_timeout; /* configured reorder timeout
* (in jiffies) */ * (in jiffies) */
int reorder_skip; /* set if skip to next nr */
int mtu; int mtu;
int mru; int mru;
enum l2tp_pwtype pwtype; enum l2tp_pwtype pwtype;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment