[TCP]: MTU probing

Implementation of packetization layer path mtu discovery for TCP, based on
the internet-draft currently found at
<http://www.ietf.org/internet-drafts/draft-ietf-pmtud-method-05.txt>.

Signed-off-by: John Heffner <jheffner@psc.edu>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index e188095..7c1bde3 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -119,8 +119,10 @@
 /* A write timeout has occurred. Process the after effects. */
 static int tcp_write_timeout(struct sock *sk)
 {
-	const struct inet_connection_sock *icsk = inet_csk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
 	int retry_until;
+	int mss;
 
 	if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
 		if (icsk->icsk_retransmits)
@@ -128,25 +130,19 @@
 		retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
 	} else {
 		if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
-			/* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black
-			   hole detection. :-(
-
-			   It is place to make it. It is not made. I do not want
-			   to make it. It is disgusting. It does not work in any
-			   case. Let me to cite the same draft, which requires for
-			   us to implement this:
-
-   "The one security concern raised by this memo is that ICMP black holes
-   are often caused by over-zealous security administrators who block
-   all ICMP messages.  It is vitally important that those who design and
-   deploy security systems understand the impact of strict filtering on
-   upper-layer protocols.  The safest web site in the world is worthless
-   if most TCP implementations cannot transfer data from it.  It would
-   be far nicer to have all of the black holes fixed rather than fixing
-   all of the TCP implementations."
-
-                           Golden words :-).
-		   */
+			/* Black hole detection */
+			if (sysctl_tcp_mtu_probing) {
+				if (!icsk->icsk_mtup.enabled) {
+					icsk->icsk_mtup.enabled = 1;
+					tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+				} else {
+					mss = min(sysctl_tcp_base_mss,
+					          tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)/2);
+					mss = max(mss, 68 - tp->tcp_header_len);
+					icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
+					tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+				}
+			}
 
 			dst_negative_advice(&sk->sk_dst_cache);
 		}