diff -ru openssh-2.5.2p2/clientloop.c new/clientloop.c
--- openssh-2.5.2p2/clientloop.c	Tue Mar  6 03:34:40 2001
+++ new/clientloop.c	Fri Jun 29 00:55:42 2001
@@ -320,10 +320,14 @@
  * one of the file descriptors).
  */
 
-void
+int
 client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
     int *maxfdp, int rekeying)
 {
+        struct timeval tv, *tvp;
+	int n;
+	extern Options options;
+
 	/* Add any selections by the channel mechanism. */
 	channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
 
@@ -362,7 +366,21 @@
 	 * SSH_MSG_IGNORE packet when the timeout expires.
 	 */
 
-	if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
+	/*
+	 * We don't do the 'random' bit, but we want periodic ignored
+	 * message anyway, so as to notice when the other ends TCP
+	 * has given up during an outage.
+	 */
+
+	if(options.protocolkeepalives > 0) {
+	        tvp = &tv;
+		tv.tv_sec = options.protocolkeepalives;
+		tv.tv_usec = 0;
+	} else
+	        tvp = 0;
+
+	n = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
+	if (n < 0) {
 		char buf[100];
 
 		/*
@@ -374,12 +392,13 @@
 		memset(*writesetp, 0, *maxfdp);
 
 		if (errno == EINTR)
-			return;
+			return 0;
 		/* Note: we might still have data in the buffers. */
 		snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
 		buffer_append(&stderr_buffer, buf, strlen(buf));
 		quit_pending = 1;
 	}
+	return n == 0;
 }
 
 void
@@ -768,6 +787,7 @@
 {
 	fd_set *readset = NULL, *writeset = NULL;
 	double start_time, total_time;
+	int timed_out;
 	int max_fd = 0, len, rekeying = 0;
 	char buf[100];
 
@@ -875,11 +895,24 @@
 		 * Wait until we have something to do (something becomes
 		 * available on one of the descriptors).
 		 */
-		client_wait_until_can_do_something(&readset, &writeset,
-		    &max_fd, rekeying);
+		timed_out = client_wait_until_can_do_something(&readset, 
+		    &writeset, &max_fd, rekeying);
 
 		if (quit_pending)
 			break;
+ 
+ 		if(timed_out) {
+ 		        /*
+ 			 * Nothing is happening, so synthesize some
+ 			 * bogus activity
+ 			 */
+ 		        packet_start(SSH_MSG_IGNORE);
+ 			packet_put_cstring("");
+ 			packet_send();
+ 			if (FD_ISSET(connection_out, writeset))
+ 			        packet_write_poll();
+ 			continue;
+ 		}
 
 		/* Do channel operations unless rekeying in progress. */
 		if (!rekeying) {
diff -ru openssh-2.5.2p2/readconf.c new/readconf.c
--- openssh-2.5.2p2/readconf.c	Mon Mar 19 22:15:57 2001
+++ new/readconf.c	Fri Jun 29 00:55:42 2001
@@ -83,6 +83,8 @@
      UseRsh no
      StrictHostKeyChecking yes
      KeepAlives no
+     ProtocolKeepAlives 0
+     BannerTimeOut 0
      IdentityFile ~/.ssh/identity
      Port 22
      EscapeChar ~
@@ -111,7 +113,7 @@
 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
-	oHostKeyAlgorithms
+	oHostKeyAlgorithms, oProtocolKeepAlives, oBannerTimeOut
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -177,6 +179,8 @@
 	{ "dynamicforward", oDynamicForward },
 	{ "preferredauthentications", oPreferredAuthentications },
 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
+	{ "protocolkeepalives", oProtocolKeepAlives },
+	{ "bannertimeout", oBannerTimeOut },
 	{ NULL, 0 }
 };
 
@@ -394,6 +398,14 @@
 		intptr = &options->keepalives;
 		goto parse_flag;
 
+	case oProtocolKeepAlives:
+	        intptr = &options->protocolkeepalives;
+		goto parse_int;
+
+	case oBannerTimeOut:
+	        intptr = &options->bannertimeout;
+		goto parse_int;
+
 	case oNumberOfPasswordPrompts:
 		intptr = &options->number_of_password_prompts;
 		goto parse_int;
@@ -738,6 +750,8 @@
 	options->strict_host_key_checking = -1;
 	options->compression = -1;
 	options->keepalives = -1;
+	options->protocolkeepalives = -1;
+	options->bannertimeout = -1;
 	options->compression_level = -1;
 	options->port = -1;
 	options->connection_attempts = -1;
@@ -825,6 +839,14 @@
 		options->compression = 0;
 	if (options->keepalives == -1)
 		options->keepalives = 1;
+	if (options->protocolkeepalives == -1){
+	  if (options->batch_mode == 1) /*in batch mode, default is 5mins */
+	        options->protocolkeepalives = 300;
+	  else  options->protocolkeepalives = 0;}
+	if (options->bannertimeout == -1){
+	  if (options->batch_mode == 1) /*in batch mode, default is 5mins */
+	        options->bannertimeout = 300;
+	  else  options->bannertimeout = 0;}
 	if (options->compression_level == -1)
 		options->compression_level = 6;
 	if (options->port == -1)
diff -ru openssh-2.5.2p2/readconf.h new/readconf.h
--- openssh-2.5.2p2/readconf.h	Sun Mar 11 01:49:20 2001
+++ new/readconf.h	Fri Jun 29 00:55:42 2001
@@ -61,6 +61,8 @@
 	int     compression_level;	/* Compression level 1 (fast) to 9
 					 * (best). */
 	int     keepalives;	/* Set SO_KEEPALIVE. */
+        int     protocolkeepalives; /* ssh-level keepalives */
+        int     bannertimeout; /* timeout in the protocol banner exchange */
 	LogLevel log_level;	/* Level for logging. */
 
 	int     port;		/* Port to connect. */
diff -ru openssh-2.5.2p2/ssh.1 new/ssh.1
--- openssh-2.5.2p2/ssh.1	Mon Mar 19 12:59:11 2001
+++ new/ssh.1	Fri Jun 29 00:55:42 2001
@@ -655,12 +655,30 @@
 or
 .Dq no .
 This option applies to protocol version 1 only.
+.It Cm BannerTimeOut
+Normally,
+.Nm ssh
+blocks indefinitly whilst waiting to receive the ssh banner from the
+server, at the beginning of the protocol negotiation. This can cause
+.Nm ssh
+to hang under certain circumstances. If this option is set,
+.Nm ssh
+will wait the specified number of seconds to receive the banner before
+giving up. The argument must be an integer. The default is 0
+(disabled), or 300 if
+.Cm BatchMode
+is set.
 .It Cm BatchMode
 If set to
 .Dq yes ,
-passphrase/password querying will be disabled.
+passphrase/password querying will be disabled. In addition, the 
+.Cm ProtocolKeepAlives 
+and
+.Cm BannerTimeOut
+options will both be set to 300 seconds.
 This option is useful in scripts and other batch jobs where you have no
-user to supply the password.
+user to supply the password, and where it is desirable to detect a
+broken network swiftly.
 The argument must be
 .Dq yes
 or
@@ -830,7 +848,12 @@
 Specifies whether the system should send keepalive messages to the
 other side.
 If they are sent, death of the connection or crash of one
-of the machines will be properly noticed.
+of the machines will be properly noticed. This option only uses TCP
+keepalives (as opposed to using ssh level keepalives), so takes a long
+time to notice when the connection dies. As such, you probably want
+the 
+.Cm ProtocolKeepAlives 
+option as well.
 However, this means that
 connections will die if the route is down temporarily, and some people
 find it annoying.
@@ -921,6 +944,13 @@
 .Nm
 tries version 2 and falls back to version 1
 if version 2 is not available.
+.It Cm ProtocolKeepAlives
+Specifies the interval at which SSH_MSG_IGNORE packets will be sent to
+the server during dile periods. Use this option in scripts to detect
+when the network fails. The argument must be an integer. The default
+is 0 (disabled), or 300 if the 
+.Cm BtchMode
+option is set.
 .It Cm ProxyCommand
 Specifies the command to use to connect to the server.
 The command
diff -ru openssh-2.5.2p2/sshconnect.c new/sshconnect.c
--- openssh-2.5.2p2/sshconnect.c	Tue Mar 13 04:57:59 2001
+++ new/sshconnect.c	Fri Jun 29 01:00:24 2001
@@ -41,6 +41,12 @@
 /* AF_UNSPEC or AF_INET or AF_INET6 */
 extern int IPv4or6;
 
+void alarm_catch (int signum)
+{
+        if(signum!=SIGALRM) return;
+	else fatal("ssh_exchange_identification: Timeout waiting for version information.");
+}
+
 /*
  * Connect to the given ssh server using a proxy command.
  */
@@ -329,8 +335,21 @@
 	int connection_in = packet_get_connection_in();
 	int connection_out = packet_get_connection_out();
 	int minor1 = PROTOCOL_MINOR_1;
+	struct sigaction sa, osa;
 
-	/* Read other side\'s version identification. */
+	/* Read other side's version identification.
+	 * If BannerTimeOut has been set, give up after
+	 * the specified amount of time
+	 */
+	if(options.bannertimeout > 0){
+        	memset(&sa,0,sizeof(sa));
+		sa.sa_restorer=NULL;
+		sa.sa_handler=alarm_catch;
+		/*throw away any pending alarms, since we'd block otherwise*/
+		alarm(0);
+		sigaction(SIGALRM,&sa,&osa);
+		alarm(options.bannertimeout);
+	}
 	for (;;) {
 		for (i = 0; i < sizeof(buf) - 1; i++) {
 			int len = atomicio(read, connection_in, &buf[i], 1);
@@ -354,6 +373,14 @@
 		debug("ssh_exchange_identification: %s", buf);
 	}
 	server_version_string = xstrdup(buf);
+
+	/* If BannerTimeOut has been set, unset the alarm now, and
+	 * put the correct handler for SIGALRM back.
+	 */
+	if(options.bannertimeout > 0){
+	        alarm(0);
+		sigaction(SIGALRM,&osa,NULL);
+	}
 
 	/*
 	 * Check that the versions match.  In future this might accept
