- stevesk@cvs.openbsd.org 2001/04/14 16:33:20
     [clientloop.c packet.h session.c ssh.c ttymodes.c ttymodes.h]
     protocol 2 tty modes support; ok markus@
diff --git a/ChangeLog b/ChangeLog
index 727db96..53dd06d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,9 @@
    - markus@cvs.openbsd.org 2001/04/14 16:27:57
      [ssh-add.c]
      use clear_pass instead of xfree()
+   - stevesk@cvs.openbsd.org 2001/04/14 16:33:20
+     [clientloop.c packet.h session.c ssh.c ttymodes.c ttymodes.h]
+     protocol 2 tty modes support; ok markus@
 
 20010414
  - Sync with OpenBSD glob.c, strlcat.c and vis.c changes
@@ -5075,4 +5078,4 @@
  - Wrote replacements for strlcpy and mkdtemp
  - Released 1.0pre1
 
-$Id: ChangeLog,v 1.1113 2001/04/14 23:10:09 mouring Exp $
+$Id: ChangeLog,v 1.1114 2001/04/14 23:13:02 mouring Exp $
diff --git a/clientloop.c b/clientloop.c
index 94d2ec6..24ea0de 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -59,7 +59,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: clientloop.c,v 1.61 2001/04/08 11:27:33 markus Exp $");
+RCSID("$OpenBSD: clientloop.c,v 1.62 2001/04/14 16:33:20 stevesk Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -79,6 +79,7 @@
 #include "clientloop.h"
 #include "authfd.h"
 #include "atomicio.h"
+#include "sshtty.h"
 
 /* import options */
 extern Options options;
@@ -101,15 +102,6 @@
  */
 static volatile int received_window_change_signal = 0;
 
-/* Terminal modes, as saved by enter_raw_mode. */
-static struct termios saved_tio;
-
-/*
- * Flag indicating whether we are in raw mode.  This is used by
- * enter_raw_mode and leave_raw_mode.
- */
-static int in_raw_mode = 0;
-
 /* Flag indicating whether the user\'s terminal is in non-blocking mode. */
 static int in_non_blocking_mode = 0;
 
@@ -136,46 +128,6 @@
 /*XXX*/
 extern Kex *xxx_kex;
 
-/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
-
-void
-leave_raw_mode(void)
-{
-	if (!in_raw_mode)
-		return;
-	in_raw_mode = 0;
-	if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0)
-		perror("tcsetattr");
-
-	fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL);
-}
-
-/* Puts the user\'s terminal in raw mode. */
-
-void
-enter_raw_mode(void)
-{
-	struct termios tio;
-
-	if (tcgetattr(fileno(stdin), &tio) < 0)
-		perror("tcgetattr");
-	saved_tio = tio;
-	tio.c_iflag |= IGNPAR;
-	tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
-	tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
-#ifdef IEXTEN
-	tio.c_lflag &= ~IEXTEN;
-#endif				/* IEXTEN */
-	tio.c_oflag &= ~OPOST;
-	tio.c_cc[VMIN] = 1;
-	tio.c_cc[VTIME] = 0;
-	if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
-		perror("tcsetattr");
-	in_raw_mode = 1;
-
-	fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL);
-}
-
 /* Restores stdin to blocking mode. */
 
 void
@@ -218,7 +170,7 @@
 void
 signal_handler(int sig)
 {
-	if (in_raw_mode)
+	if (in_raw_mode())
 		leave_raw_mode();
 	if (in_non_blocking_mode)
 		leave_non_blocking();
@@ -796,7 +748,7 @@
 		error("client_channel_closed: id %d != session_ident %d",
 		    id, session_ident);
 	session_closed = 1;
-	if (in_raw_mode)
+	if (in_raw_mode())
 		leave_raw_mode();
 }
 
diff --git a/packet.h b/packet.h
index e543271..0f5e710 100644
--- a/packet.h
+++ b/packet.h
@@ -11,7 +11,7 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 
-/* RCSID("$OpenBSD: packet.h,v 1.21 2001/02/28 21:27:47 markus Exp $"); */
+/* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
 
 #ifndef PACKET_H
 #define PACKET_H
@@ -178,8 +178,8 @@
 int     packet_set_maxsize(int s);
 #define packet_get_maxsize() max_packet_size
 
-/* Stores tty modes from the fd into current packet. */
-void    tty_make_modes(int fd);
+/* Stores tty modes from the fd or tiop into current packet. */
+void    tty_make_modes(int fd, struct termios *tiop);
 
 /* Parses tty modes for the fd from the current packet. */
 void    tty_parse_modes(int fd, int *n_bytes_ptr);
diff --git a/session.c b/session.c
index 8da7993..ebefd91 100644
--- a/session.c
+++ b/session.c
@@ -33,7 +33,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.71 2001/04/06 21:00:12 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.72 2001/04/14 16:33:20 stevesk Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -1603,7 +1603,7 @@
 session_pty_req(Session *s)
 {
 	u_int len;
-	char *term_modes;	/* encoded terminal modes */
+	int n_bytes;
 
 	if (no_pty_flag)
 		return 0;
@@ -1614,8 +1614,6 @@
 	s->row = packet_get_int();
 	s->xpixel = packet_get_int();
 	s->ypixel = packet_get_int();
-	term_modes = packet_get_string(&len);
-	packet_done();
 
 	if (strcmp(s->term, "") == 0) {
 		xfree(s->term);
@@ -1628,7 +1626,6 @@
 		s->ptyfd = -1;
 		s->ttyfd = -1;
 		error("session_pty_req: session %d alloc failed", s->self);
-		xfree(term_modes);
 		return 0;
 	}
 	debug("session_pty_req: session %d alloc %s", s->self, s->tty);
@@ -1641,10 +1638,12 @@
 	/* Get window size from the packet. */
 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
 
+	/* Get tty modes from the packet. */
+	tty_parse_modes(s->ttyfd, &n_bytes);
+	packet_done();
+
 	session_proctitle(s);
 
-	/* XXX parse and set terminal modes */
-	xfree(term_modes);
 	return 1;
 }
 
diff --git a/ssh.c b/ssh.c
index 68ce171..bd0d5ba 100644
--- a/ssh.c
+++ b/ssh.c
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.114 2001/04/13 01:26:17 stevesk Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.115 2001/04/14 16:33:20 stevesk Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
@@ -67,6 +67,7 @@
 #include "misc.h"
 #include "kex.h"
 #include "mac.h"
+#include "sshtty.h"
 
 #ifdef HAVE___PROGNAME
 extern char *__progname;
@@ -879,7 +880,7 @@
 		packet_put_int(ws.ws_ypixel);
 
 		/* Store tty modes in the packet. */
-		tty_make_modes(fileno(stdin));
+		tty_make_modes(fileno(stdin), NULL);
 
 		/* Send the packet, and wait for it to leave. */
 		packet_send();
@@ -983,6 +984,7 @@
 {
 	int len;
 	int interactive = 0;
+	struct termios tio;
 
 	debug("client_init id %d arg %ld", id, (long)arg);
 
@@ -1002,7 +1004,8 @@
 		packet_put_int(ws.ws_row);
 		packet_put_int(ws.ws_xpixel);
 		packet_put_int(ws.ws_ypixel);
-		packet_put_cstring("");		/* XXX: encode terminal modes */
+		tio = get_saved_tio();
+		tty_make_modes(/*ignored*/ 0, &tio);
 		packet_send();
 		interactive = 1;
 		/* XXX wait for reply */
diff --git a/ttymodes.c b/ttymodes.c
index 65caf2f..9ce3fbc 100644
--- a/ttymodes.c
+++ b/ttymodes.c
@@ -2,10 +2,6 @@
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
- * Encoding and decoding of terminal modes in a portable way.
- * Much of the format is defined in ttymodes.h; it is included multiple times
- * into this file with the appropriate macro definitions to generate the
- * suitable code.
  *
  * As far as I am concerned, the code I have written for this software
  * can be used freely for any purpose.  Any derived versions of this
@@ -14,16 +10,56 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 
+/*
+ * SSH2 tty modes support by Kevin Steves.
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Encoding and decoding of terminal modes in a portable way.
+ * Much of the format is defined in ttymodes.h; it is included multiple times
+ * into this file with the appropriate macro definitions to generate the
+ * suitable code.
+ */
+
 #include "includes.h"
-RCSID("$OpenBSD: ttymodes.c,v 1.11 2001/03/10 15:02:05 stevesk Exp $");
+RCSID("$OpenBSD: ttymodes.c,v 1.12 2001/04/14 16:33:20 stevesk Exp $");
 
 #include "packet.h"
 #include "log.h"
 #include "ssh1.h"
+#include "compat.h"
+#include "buffer.h"
+#include "bufaux.h"
 
-#define TTY_OP_END	0
-#define TTY_OP_ISPEED	192	/* int follows */
-#define TTY_OP_OSPEED	193	/* int follows */
+#define TTY_OP_END		0
+/*
+ * uint32 (u_int) follows speed in SSH1 and SSH2
+ */
+#define TTY_OP_ISPEED_PROTO1	192
+#define TTY_OP_OSPEED_PROTO1	193
+#define TTY_OP_ISPEED_PROTO2	128
+#define TTY_OP_OSPEED_PROTO2	129
 
 /*
  * Converts POSIX speed_t to a baud rate.  The values of the
@@ -122,7 +158,7 @@
 baud_to_speed(int baud)
 {
 	switch (baud) {
-		case 0:
+	case 0:
 		return B0;
 	case 50:
 		return B50;
@@ -206,41 +242,72 @@
 
 /*
  * Encodes terminal modes for the terminal referenced by fd
- * in a portable manner, and appends the modes to a packet
+ * or tiop in a portable manner, and appends the modes to a packet
  * being constructed.
  */
 void
-tty_make_modes(int fd)
+tty_make_modes(int fd, struct termios *tiop)
 {
 	struct termios tio;
 	int baud;
+	Buffer buf;
+	int tty_op_ospeed, tty_op_ispeed;
+	void (*put_arg)(Buffer *, u_int);
 
-	if (tcgetattr(fd, &tio) < 0) {
-		packet_put_char(TTY_OP_END);
-		log("tcgetattr: %.100s", strerror(errno));
-		return;
+	buffer_init(&buf);
+	if (compat20) {
+		tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
+		tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
+		put_arg = buffer_put_int;
+	} else {
+		tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
+		tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
+		put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
 	}
+
+	if (tiop == NULL) {
+		if (tcgetattr(fd, &tio) == -1) {
+			log("tcgetattr: %.100s", strerror(errno));
+			goto end;
+		}
+	} else
+		tio = *tiop;
+
 	/* Store input and output baud rates. */
 	baud = speed_to_baud(cfgetospeed(&tio));
-	packet_put_char(TTY_OP_OSPEED);
-	packet_put_int(baud);
+	debug2("tty_make_modes: ospeed %d", baud);
+	buffer_put_char(&buf, tty_op_ospeed);
+	buffer_put_int(&buf, baud);
 	baud = speed_to_baud(cfgetispeed(&tio));
-	packet_put_char(TTY_OP_ISPEED);
-	packet_put_int(baud);
+	debug2("tty_make_modes: ispeed %d", baud);
+	buffer_put_char(&buf, tty_op_ispeed);
+	buffer_put_int(&buf, baud);
 
 	/* Store values of mode flags. */
 #define TTYCHAR(NAME, OP) \
-  packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
+	debug2("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \
+	buffer_put_char(&buf, OP); \
+	put_arg(&buf, tio.c_cc[NAME]);
+
 #define TTYMODE(NAME, FIELD, OP) \
-  packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0);
+	debug2("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \
+	buffer_put_char(&buf, OP); \
+	put_arg(&buf, ((tio.FIELD & NAME) != 0));
 
 #include "ttymodes.h"
 
 #undef TTYCHAR
 #undef TTYMODE
 
+end:
 	/* Mark end of mode data. */
-	packet_put_char(TTY_OP_END);
+	buffer_put_char(&buf, TTY_OP_END);
+	if (compat20)
+		packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
+	else
+		packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
+	buffer_free(&buf);
+	return;
 }
 
 /*
@@ -254,14 +321,30 @@
 	int opcode, baud;
 	int n_bytes = 0;
 	int failure = 0;
+	u_int (*get_arg)(void);
+	int arg, arg_size;
+
+	if (compat20) {
+		*n_bytes_ptr = packet_get_int();
+		debug2("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr);
+		if (*n_bytes_ptr == 0)
+			return;
+		get_arg = packet_get_int;
+		arg_size = 4;
+	} else {
+		get_arg = packet_get_char;
+		arg_size = 1;
+	}
 
 	/*
 	 * Get old attributes for the terminal.  We will modify these
 	 * flags. I am hoping that if there are any machine-specific
 	 * modes, they will initially have reasonable values.
 	 */
-	if (tcgetattr(fd, &tio) < 0)
+	if (tcgetattr(fd, &tio) == -1) {
+		log("tcgetattr: %.100s", strerror(errno));
 		failure = -1;
+	}
 
 	for (;;) {
 		n_bytes += 1;
@@ -270,32 +353,40 @@
 		case TTY_OP_END:
 			goto set;
 
-		case TTY_OP_ISPEED:
+		/* XXX: future conflict possible */
+		case TTY_OP_ISPEED_PROTO1:
+		case TTY_OP_ISPEED_PROTO2:
 			n_bytes += 4;
 			baud = packet_get_int();
-			if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
+			debug2("tty_parse_modes: ispeed %d", baud);
+			if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1)
 				error("cfsetispeed failed for %d", baud);
 			break;
 
-		case TTY_OP_OSPEED:
+		/* XXX: future conflict possible */
+		case TTY_OP_OSPEED_PROTO1:
+		case TTY_OP_OSPEED_PROTO2:
 			n_bytes += 4;
 			baud = packet_get_int();
-			if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
+			debug2("tty_parse_modes: ospeed %d", baud);
+			if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1)
 				error("cfsetospeed failed for %d", baud);
 			break;
 
-#define TTYCHAR(NAME, OP) 				\
-	case OP:					\
-	  n_bytes += 1;					\
-	  tio.c_cc[NAME] = packet_get_char();		\
+#define TTYCHAR(NAME, OP) \
+	case OP: \
+	  n_bytes += arg_size; \
+	  tio.c_cc[NAME] = get_arg(); \
+	  debug2("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \
 	  break;
-#define TTYMODE(NAME, FIELD, OP)		       	\
-	case OP:					\
-	  n_bytes += 1;					\
-	  if (packet_get_char())			\
-	    tio.FIELD |= NAME;				\
-	  else						\
-	    tio.FIELD &= ~NAME;				\
+#define TTYMODE(NAME, FIELD, OP) \
+	case OP: \
+	  n_bytes += arg_size; \
+	  if ((arg = get_arg())) \
+	    tio.FIELD |= NAME; \
+	  else \
+	    tio.FIELD &= ~NAME;	\
+	  debug2("tty_parse_modes: %d %d", OP, arg); \
 	  break;
 
 #include "ttymodes.h"
@@ -306,48 +397,66 @@
 		default:
 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
 			      opcode, opcode);
-			/*
-			 * Opcodes 0 to 127 are defined to have
-			 * a one-byte argument.
-			 */
-			if (opcode >= 0 && opcode < 128) {
-				n_bytes += 1;
-				(void) packet_get_char();
-				break;
+			if (!compat20) {
+				/*
+				 * SSH1:
+				 * Opcodes 1 to 127 are defined to have
+				 * a one-byte argument.
+  				 * Opcodes 128 to 159 are defined to have
+  				 * an integer argument.
+  				 */
+				if (opcode > 0 && opcode < 128) {
+					n_bytes += 1;
+					(void) packet_get_char();
+					break;
+				} else if (opcode >= 128 && opcode < 160) {
+  					n_bytes += 4;
+  					(void) packet_get_int();
+  					break;
+				} else {
+					/*
+					 * It is a truly undefined opcode (160 to 255).
+					 * We have no idea about its arguments.  So we
+					 * must stop parsing.  Note that some data may be
+					 * left in the packet; hopefully there is nothing
+					 * more coming after the mode data.
+					 */
+					log("parse_tty_modes: unknown opcode %d", opcode);
+					packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
+					goto set;
+  				}
 			} else {
 				/*
-				 * Opcodes 128 to 159 are defined to have
-				 * an integer argument.
+				 * SSH2:
+				 * Opcodes 0 to 159 are defined to have
+				 * a uint32 argument.
+				 * Opcodes 160 to 255 are undefined and
+				 * cause parsing to stop.
 				 */
-				if (opcode >= 128 && opcode < 160) {
+				if (opcode > 0 && opcode < 160) {
 					n_bytes += 4;
 					(void) packet_get_int();
 					break;
+				} else {
+					log("parse_tty_modes: unknown opcode %d", opcode);
+					goto set;
 				}
-			}
-			/*
-			 * It is a truly undefined opcode (160 to 255).
-			 * We have no idea about its arguments.  So we
-			 * must stop parsing.  Note that some data may be
-			 * left in the packet; hopefully there is nothing
-			 * more coming after the mode data.
-			 */
-			log("parse_tty_modes: unknown opcode %d", opcode);
-			packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
-			goto set;
+  			}
 		}
 	}
 
 set:
 	if (*n_bytes_ptr != n_bytes) {
 		*n_bytes_ptr = n_bytes;
+		log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
+		    *n_bytes_ptr, n_bytes);
 		return;		/* Don't process bytes passed */
 	}
 	if (failure == -1)
 		return;		/* Packet parsed ok but tty stuff failed */
 
 	/* Set the new modes for the terminal. */
-	if (tcsetattr(fd, TCSANOW, &tio) < 0)
+	if (tcsetattr(fd, TCSANOW, &tio) == -1)
 		log("Setting tty modes failed: %.100s", strerror(errno));
 	return;
 }
diff --git a/ttymodes.h b/ttymodes.h
index 860fd0a..ad980e9 100644
--- a/ttymodes.h
+++ b/ttymodes.h
@@ -1,6 +1,6 @@
+/* RCSID("$OpenBSD: ttymodes.h,v 1.11 2001/04/14 16:33:20 stevesk Exp $"); */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * 	SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
  *
@@ -11,14 +11,47 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 
-/* RCSID("$OpenBSD: ttymodes.h,v 1.10 2001/03/10 15:02:05 stevesk Exp $"); */
+/*
+ * SSH2 tty modes support by Kevin Steves.
+ * Copyright (c) 2001 Kevin Steves.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-/* The tty mode description is a stream of bytes.  The stream consists of
+/*
+ * SSH1:
+ * The tty mode description is a stream of bytes.  The stream consists of
  * opcode-arguments pairs.  It is terminated by opcode TTY_OP_END (0).
  * Opcodes 1-127 have one-byte arguments.  Opcodes 128-159 have integer
  * arguments.  Opcodes 160-255 are not yet defined, and cause parsing to
  * stop (they should only be used after any other data).
  *
+ * SSH2:
+ * Differences between SSH1 and SSH2 terminal mode encoding include:
+ * 1. Encoded terminal modes are represented as a string, and a stream
+ *    of bytes within that string.
+ * 2. Opcode arguments are uint32 (1-159); 160-255 remain undefined.
+ * 3. The values for TTY_OP_ISPEED and TTY_OP_OSPEED are different;
+ *    128 and 129 vs. 192 and 193 respectively.
+ *
  * The client puts in the stream any modes it knows about, and the
  * server ignores any modes it does not know about.  This allows some degree
  * of machine-independence, at least between systems that use a posix-like