[TCP]: Prevent sending past receiver window with TSO (at last skb)

With TSO it was possible to send past the receiver window when the skb
to be sent was the last in the write queue while the receiver window
is the limiting factor. One can notice that there's a loophole in the
tcp_mss_split_point that lacked a receiver window check for the
tcp_write_queue_tail() if also cwnd was smaller than the full skb.

Noticed by Thomas Gleixner <tglx@linutronix.de> in form of "Treason
uncloaked! Peer ... shrinks window .... Repaired." messages (the peer
didn't actually shrink its window as the message suggests, we had just
sent something past it without a permission to do so).

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Tested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Ilpo Järvinen and committed by David S. Miller 5ea3a748 445815d7

+10 -2
+10 -2
net/ipv4/tcp_output.c
··· 1035 1035 * introducing MSS oddities to segment boundaries. In rare cases where 1036 1036 * mss_now != mss_cache, we will request caller to create a small skb 1037 1037 * per input skb which could be mostly avoided here (if desired). 1038 + * 1039 + * We explicitly want to create a request for splitting write queue tail 1040 + * to a small skb for Nagle purposes while avoiding unnecessary modulos, 1041 + * thus all the complexity (cwnd_len is always MSS multiple which we 1042 + * return whenever allowed by the other factors). Basically we need the 1043 + * modulo only when the receiver window alone is the limiting factor or 1044 + * when we would be allowed to send the split-due-to-Nagle skb fully. 1038 1045 */ 1039 1046 static unsigned int tcp_mss_split_point(struct sock *sk, struct sk_buff *skb, 1040 1047 unsigned int mss_now, unsigned int cwnd) ··· 1055 1048 if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk))) 1056 1049 return cwnd_len; 1057 1050 1058 - if (skb == tcp_write_queue_tail(sk) && cwnd_len <= skb->len) 1051 + needed = min(skb->len, window); 1052 + 1053 + if (skb == tcp_write_queue_tail(sk) && cwnd_len <= needed) 1059 1054 return cwnd_len; 1060 1055 1061 - needed = min(skb->len, window); 1062 1056 return needed - needed % mss_now; 1063 1057 } 1064 1058