aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2009-05-29 15:02:29 -0700
committerDavid S. Miller <davem@davemloft.net>2009-05-29 15:02:29 -0700
commit2df9001edc382c331f338f45d259feeaa740c418 (patch)
treeeb92c3ef77973295469743a1087c551acf7ece67 /net/ipv4
parent5d4e039b2cb1ca4de9774344ea7b61ad7fa1b0a1 (diff)
downloadkernel_samsung_tuna-2df9001edc382c331f338f45d259feeaa740c418.zip
kernel_samsung_tuna-2df9001edc382c331f338f45d259feeaa740c418.tar.gz
kernel_samsung_tuna-2df9001edc382c331f338f45d259feeaa740c418.tar.bz2
tcp: fix loop in ofo handling code and reduce its complexity
Somewhat luckily, I was looking into these parts with very fine comb because I've made somewhat similar changes on the same area (conflicts that arose weren't that lucky though). The loop was very much overengineered recently in commit 915219441d566 (tcp: Use SKB queue and list helpers instead of doing it by-hand), while it basically just wants to know if there are skbs after 'skb'. Also it got broken because skb1 = skb->next got translated into skb1 = skb1->next (though abstracted) improperly. Note that 'skb1' is pointing to previous sk_buff than skb or NULL if at head. Two things went wrong: - We'll kfree 'skb' on the first iteration instead of the skbuff following 'skb' (it would require required SACK reneging to recover I think). - The list head case where 'skb1' is NULL is checked too early and the loop won't execute whereas it previously did. Conclusion, mostly revert the recent changes which makes the cset very messy looking but using proper accessor in the previous-like version. The effective changes against the original can be viewed with: git-diff 915219441d566f1da0caa0e262be49b666159e17^ \ net/ipv4/tcp_input.c | sed -n -e '57,70 p' Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp_input.c28
1 files changed, 11 insertions, 17 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ba34a23..2bdb0da 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4481,26 +4481,20 @@ drop:
__skb_queue_after(&tp->out_of_order_queue, skb1, skb);
/* And clean segments covered by new one as whole. */
- if (skb1 && !skb_queue_is_last(&tp->out_of_order_queue, skb1)) {
- struct sk_buff *n;
+ while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) {
+ skb1 = skb_queue_next(&tp->out_of_order_queue, skb);
- skb1 = skb_queue_next(&tp->out_of_order_queue, skb1);
- skb_queue_walk_from_safe(&tp->out_of_order_queue,
- skb1, n) {
- if (!after(end_seq, TCP_SKB_CB(skb1)->seq))
- break;
- if (before(end_seq,
- TCP_SKB_CB(skb1)->end_seq)) {
- tcp_dsack_extend(sk,
- TCP_SKB_CB(skb1)->seq,
- end_seq);
- break;
- }
- __skb_unlink(skb1, &tp->out_of_order_queue);
+ if (!after(end_seq, TCP_SKB_CB(skb1)->seq))
+ break;
+ if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
- TCP_SKB_CB(skb1)->end_seq);
- __kfree_skb(skb1);
+ end_seq);
+ break;
}
+ __skb_unlink(skb1, &tp->out_of_order_queue);
+ tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
+ TCP_SKB_CB(skb1)->end_seq);
+ __kfree_skb(skb1);
}
add_sack: