xref: /onnv-gate/usr/src/cmd/ssh/libssh/common/ttymodes.c (revision 9354:9559ac454e7e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
30Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
40Sstevel@tonic-gate  *                    All rights reserved
50Sstevel@tonic-gate  *
60Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
70Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
80Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
90Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
100Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
110Sstevel@tonic-gate  */
120Sstevel@tonic-gate 
130Sstevel@tonic-gate /*
140Sstevel@tonic-gate  * SSH2 tty modes support by Kevin Steves.
150Sstevel@tonic-gate  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
160Sstevel@tonic-gate  *
170Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
180Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
190Sstevel@tonic-gate  * are met:
200Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
210Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
220Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
230Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
240Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
270Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
280Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
290Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
300Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
310Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
320Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
330Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
340Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
350Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
360Sstevel@tonic-gate  */
37*9354STim.Marsland@Sun.COM 
380Sstevel@tonic-gate /*
39*9354STim.Marsland@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
400Sstevel@tonic-gate  * Use is subject to license terms.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate  * Encoding and decoding of terminal modes in a portable way.
450Sstevel@tonic-gate  * Much of the format is defined in ttymodes.h; it is included multiple times
460Sstevel@tonic-gate  * into this file with the appropriate macro definitions to generate the
470Sstevel@tonic-gate  * suitable code.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include "includes.h"
510Sstevel@tonic-gate RCSID("$OpenBSD: ttymodes.c,v 1.18 2002/06/19 00:27:55 deraadt Exp $");
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #include "packet.h"
540Sstevel@tonic-gate #include "log.h"
550Sstevel@tonic-gate #include "ssh1.h"
560Sstevel@tonic-gate #include "compat.h"
570Sstevel@tonic-gate #include "buffer.h"
580Sstevel@tonic-gate #include "bufaux.h"
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #define TTY_OP_END		0
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * uint32 (u_int) follows speed in SSH1 and SSH2
630Sstevel@tonic-gate  */
640Sstevel@tonic-gate #define TTY_OP_ISPEED_PROTO1	192
650Sstevel@tonic-gate #define TTY_OP_OSPEED_PROTO1	193
660Sstevel@tonic-gate #define TTY_OP_ISPEED_PROTO2	128
670Sstevel@tonic-gate #define TTY_OP_OSPEED_PROTO2	129
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * Converts POSIX speed_t to a baud rate.  The values of the
710Sstevel@tonic-gate  * constants for speed_t are not themselves portable.
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate static int
speed_to_baud(speed_t speed)740Sstevel@tonic-gate speed_to_baud(speed_t speed)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	switch (speed) {
770Sstevel@tonic-gate 	case B0:
780Sstevel@tonic-gate 		return 0;
790Sstevel@tonic-gate 	case B50:
800Sstevel@tonic-gate 		return 50;
810Sstevel@tonic-gate 	case B75:
820Sstevel@tonic-gate 		return 75;
830Sstevel@tonic-gate 	case B110:
840Sstevel@tonic-gate 		return 110;
850Sstevel@tonic-gate 	case B134:
860Sstevel@tonic-gate 		return 134;
870Sstevel@tonic-gate 	case B150:
880Sstevel@tonic-gate 		return 150;
890Sstevel@tonic-gate 	case B200:
900Sstevel@tonic-gate 		return 200;
910Sstevel@tonic-gate 	case B300:
920Sstevel@tonic-gate 		return 300;
930Sstevel@tonic-gate 	case B600:
940Sstevel@tonic-gate 		return 600;
950Sstevel@tonic-gate 	case B1200:
960Sstevel@tonic-gate 		return 1200;
970Sstevel@tonic-gate 	case B1800:
980Sstevel@tonic-gate 		return 1800;
990Sstevel@tonic-gate 	case B2400:
1000Sstevel@tonic-gate 		return 2400;
1010Sstevel@tonic-gate 	case B4800:
1020Sstevel@tonic-gate 		return 4800;
1030Sstevel@tonic-gate 	case B9600:
1040Sstevel@tonic-gate 		return 9600;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate #ifdef B19200
1070Sstevel@tonic-gate 	case B19200:
1080Sstevel@tonic-gate 		return 19200;
1090Sstevel@tonic-gate #else /* B19200 */
1100Sstevel@tonic-gate #ifdef EXTA
1110Sstevel@tonic-gate 	case EXTA:
1120Sstevel@tonic-gate 		return 19200;
1130Sstevel@tonic-gate #endif /* EXTA */
1140Sstevel@tonic-gate #endif /* B19200 */
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate #ifdef B38400
1170Sstevel@tonic-gate 	case B38400:
1180Sstevel@tonic-gate 		return 38400;
1190Sstevel@tonic-gate #else /* B38400 */
1200Sstevel@tonic-gate #ifdef EXTB
1210Sstevel@tonic-gate 	case EXTB:
1220Sstevel@tonic-gate 		return 38400;
1230Sstevel@tonic-gate #endif /* EXTB */
1240Sstevel@tonic-gate #endif /* B38400 */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate #ifdef B7200
1270Sstevel@tonic-gate 	case B7200:
1280Sstevel@tonic-gate 		return 7200;
1290Sstevel@tonic-gate #endif /* B7200 */
1300Sstevel@tonic-gate #ifdef B14400
1310Sstevel@tonic-gate 	case B14400:
1320Sstevel@tonic-gate 		return 14400;
1330Sstevel@tonic-gate #endif /* B14400 */
1340Sstevel@tonic-gate #ifdef B28800
1350Sstevel@tonic-gate 	case B28800:
1360Sstevel@tonic-gate 		return 28800;
1370Sstevel@tonic-gate #endif /* B28800 */
1380Sstevel@tonic-gate #ifdef B57600
1390Sstevel@tonic-gate 	case B57600:
1400Sstevel@tonic-gate 		return 57600;
1410Sstevel@tonic-gate #endif /* B57600 */
1420Sstevel@tonic-gate #ifdef B76800
1430Sstevel@tonic-gate 	case B76800:
1440Sstevel@tonic-gate 		return 76800;
1450Sstevel@tonic-gate #endif /* B76800 */
1460Sstevel@tonic-gate #ifdef B115200
1470Sstevel@tonic-gate 	case B115200:
1480Sstevel@tonic-gate 		return 115200;
1490Sstevel@tonic-gate #endif /* B115200 */
1500Sstevel@tonic-gate #ifdef B230400
1510Sstevel@tonic-gate 	case B230400:
1520Sstevel@tonic-gate 		return 230400;
1530Sstevel@tonic-gate #endif /* B230400 */
154*9354STim.Marsland@Sun.COM #ifdef B460800
155*9354STim.Marsland@Sun.COM 	case B460800:
156*9354STim.Marsland@Sun.COM 		return 460800;
157*9354STim.Marsland@Sun.COM #endif /* B460800 */
158*9354STim.Marsland@Sun.COM #ifdef B921600
159*9354STim.Marsland@Sun.COM 	case B921600:
160*9354STim.Marsland@Sun.COM 		return 921600;
161*9354STim.Marsland@Sun.COM #endif /* B921600 */
1620Sstevel@tonic-gate 	default:
1630Sstevel@tonic-gate 		return 9600;
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate  * Converts a numeric baud rate to a POSIX speed_t.
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate static speed_t
baud_to_speed(int baud)1710Sstevel@tonic-gate baud_to_speed(int baud)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	switch (baud) {
1740Sstevel@tonic-gate 	case 0:
1750Sstevel@tonic-gate 		return B0;
1760Sstevel@tonic-gate 	case 50:
1770Sstevel@tonic-gate 		return B50;
1780Sstevel@tonic-gate 	case 75:
1790Sstevel@tonic-gate 		return B75;
1800Sstevel@tonic-gate 	case 110:
1810Sstevel@tonic-gate 		return B110;
1820Sstevel@tonic-gate 	case 134:
1830Sstevel@tonic-gate 		return B134;
1840Sstevel@tonic-gate 	case 150:
1850Sstevel@tonic-gate 		return B150;
1860Sstevel@tonic-gate 	case 200:
1870Sstevel@tonic-gate 		return B200;
1880Sstevel@tonic-gate 	case 300:
1890Sstevel@tonic-gate 		return B300;
1900Sstevel@tonic-gate 	case 600:
1910Sstevel@tonic-gate 		return B600;
1920Sstevel@tonic-gate 	case 1200:
1930Sstevel@tonic-gate 		return B1200;
1940Sstevel@tonic-gate 	case 1800:
1950Sstevel@tonic-gate 		return B1800;
1960Sstevel@tonic-gate 	case 2400:
1970Sstevel@tonic-gate 		return B2400;
1980Sstevel@tonic-gate 	case 4800:
1990Sstevel@tonic-gate 		return B4800;
2000Sstevel@tonic-gate 	case 9600:
2010Sstevel@tonic-gate 		return B9600;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate #ifdef B19200
2040Sstevel@tonic-gate 	case 19200:
2050Sstevel@tonic-gate 		return B19200;
2060Sstevel@tonic-gate #else /* B19200 */
2070Sstevel@tonic-gate #ifdef EXTA
2080Sstevel@tonic-gate 	case 19200:
2090Sstevel@tonic-gate 		return EXTA;
2100Sstevel@tonic-gate #endif /* EXTA */
2110Sstevel@tonic-gate #endif /* B19200 */
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate #ifdef B38400
2140Sstevel@tonic-gate 	case 38400:
2150Sstevel@tonic-gate 		return B38400;
2160Sstevel@tonic-gate #else /* B38400 */
2170Sstevel@tonic-gate #ifdef EXTB
2180Sstevel@tonic-gate 	case 38400:
2190Sstevel@tonic-gate 		return EXTB;
2200Sstevel@tonic-gate #endif /* EXTB */
2210Sstevel@tonic-gate #endif /* B38400 */
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate #ifdef B7200
2240Sstevel@tonic-gate 	case 7200:
2250Sstevel@tonic-gate 		return B7200;
2260Sstevel@tonic-gate #endif /* B7200 */
2270Sstevel@tonic-gate #ifdef B14400
2280Sstevel@tonic-gate 	case 14400:
2290Sstevel@tonic-gate 		return B14400;
2300Sstevel@tonic-gate #endif /* B14400 */
2310Sstevel@tonic-gate #ifdef B28800
2320Sstevel@tonic-gate 	case 28800:
2330Sstevel@tonic-gate 		return B28800;
2340Sstevel@tonic-gate #endif /* B28800 */
2350Sstevel@tonic-gate #ifdef B57600
2360Sstevel@tonic-gate 	case 57600:
2370Sstevel@tonic-gate 		return B57600;
2380Sstevel@tonic-gate #endif /* B57600 */
2390Sstevel@tonic-gate #ifdef B76800
2400Sstevel@tonic-gate 	case 76800:
2410Sstevel@tonic-gate 		return B76800;
2420Sstevel@tonic-gate #endif /* B76800 */
2430Sstevel@tonic-gate #ifdef B115200
2440Sstevel@tonic-gate 	case 115200:
2450Sstevel@tonic-gate 		return B115200;
2460Sstevel@tonic-gate #endif /* B115200 */
2470Sstevel@tonic-gate #ifdef B230400
2480Sstevel@tonic-gate 	case 230400:
2490Sstevel@tonic-gate 		return B230400;
2500Sstevel@tonic-gate #endif /* B230400 */
251*9354STim.Marsland@Sun.COM #ifdef B460800
252*9354STim.Marsland@Sun.COM 	case 460800:
253*9354STim.Marsland@Sun.COM 		return B460800;
254*9354STim.Marsland@Sun.COM #endif /* B460800 */
255*9354STim.Marsland@Sun.COM #ifdef B921600
256*9354STim.Marsland@Sun.COM 	case 921600:
257*9354STim.Marsland@Sun.COM 		return B921600;
258*9354STim.Marsland@Sun.COM #endif /* B921600 */
2590Sstevel@tonic-gate 	default:
2600Sstevel@tonic-gate 		return B9600;
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate  * Encodes terminal modes for the terminal referenced by fd
2660Sstevel@tonic-gate  * or tiop in a portable manner, and appends the modes to a packet
2670Sstevel@tonic-gate  * being constructed.
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate void
tty_make_modes(int fd,struct termios * tiop)2700Sstevel@tonic-gate tty_make_modes(int fd, struct termios *tiop)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate 	struct termios tio;
2730Sstevel@tonic-gate 	int baud;
2740Sstevel@tonic-gate 	Buffer buf;
2750Sstevel@tonic-gate 	int tty_op_ospeed, tty_op_ispeed;
2760Sstevel@tonic-gate 	void (*put_arg)(Buffer *, u_int);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	buffer_init(&buf);
2790Sstevel@tonic-gate 	if (compat20) {
2800Sstevel@tonic-gate 		tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
2810Sstevel@tonic-gate 		tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
2820Sstevel@tonic-gate 		put_arg = buffer_put_int;
2830Sstevel@tonic-gate 	} else {
2840Sstevel@tonic-gate 		tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
2850Sstevel@tonic-gate 		tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
2860Sstevel@tonic-gate 		put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	if (tiop == NULL) {
2900Sstevel@tonic-gate 		if (tcgetattr(fd, &tio) == -1) {
2910Sstevel@tonic-gate 			log("tcgetattr: %.100s", strerror(errno));
2920Sstevel@tonic-gate 			goto end;
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 	} else
2950Sstevel@tonic-gate 		tio = *tiop;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/* Store input and output baud rates. */
2980Sstevel@tonic-gate 	baud = speed_to_baud(cfgetospeed(&tio));
2990Sstevel@tonic-gate 	debug3("tty_make_modes: ospeed %d", baud);
3000Sstevel@tonic-gate 	buffer_put_char(&buf, tty_op_ospeed);
3010Sstevel@tonic-gate 	buffer_put_int(&buf, baud);
3020Sstevel@tonic-gate 	baud = speed_to_baud(cfgetispeed(&tio));
3030Sstevel@tonic-gate 	debug3("tty_make_modes: ispeed %d", baud);
3040Sstevel@tonic-gate 	buffer_put_char(&buf, tty_op_ispeed);
3050Sstevel@tonic-gate 	buffer_put_int(&buf, baud);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/* Store values of mode flags. */
3080Sstevel@tonic-gate #define TTYCHAR(NAME, OP) \
3090Sstevel@tonic-gate 	debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \
3100Sstevel@tonic-gate 	buffer_put_char(&buf, OP); \
3110Sstevel@tonic-gate 	put_arg(&buf, tio.c_cc[NAME]);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate #define TTYMODE(NAME, FIELD, OP) \
3140Sstevel@tonic-gate 	debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \
3150Sstevel@tonic-gate 	buffer_put_char(&buf, OP); \
3160Sstevel@tonic-gate 	put_arg(&buf, ((tio.FIELD & NAME) != 0));
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate #include "ttymodes.h"
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate #undef TTYCHAR
3210Sstevel@tonic-gate #undef TTYMODE
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate end:
3240Sstevel@tonic-gate 	/* Mark end of mode data. */
3250Sstevel@tonic-gate 	buffer_put_char(&buf, TTY_OP_END);
3260Sstevel@tonic-gate 	if (compat20)
3270Sstevel@tonic-gate 		packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
3280Sstevel@tonic-gate 	else
3290Sstevel@tonic-gate 		packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
3300Sstevel@tonic-gate 	buffer_free(&buf);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate  * Decodes terminal modes for the terminal referenced by fd in a portable
3350Sstevel@tonic-gate  * manner from a packet being read.
3360Sstevel@tonic-gate  */
3370Sstevel@tonic-gate void
tty_parse_modes(int fd,int * n_bytes_ptr)3380Sstevel@tonic-gate tty_parse_modes(int fd, int *n_bytes_ptr)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	struct termios tio;
3410Sstevel@tonic-gate 	int opcode, baud;
3420Sstevel@tonic-gate 	int n_bytes = 0;
3430Sstevel@tonic-gate 	int failure = 0;
3440Sstevel@tonic-gate 	u_int (*get_arg)(void);
3450Sstevel@tonic-gate 	int arg, arg_size;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if (compat20) {
3480Sstevel@tonic-gate 		*n_bytes_ptr = packet_get_int();
3490Sstevel@tonic-gate 		debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr);
3500Sstevel@tonic-gate 		if (*n_bytes_ptr == 0)
3510Sstevel@tonic-gate 			return;
3520Sstevel@tonic-gate 		get_arg = packet_get_int;
3530Sstevel@tonic-gate 		arg_size = 4;
3540Sstevel@tonic-gate 	} else {
3550Sstevel@tonic-gate 		get_arg = packet_get_char;
3560Sstevel@tonic-gate 		arg_size = 1;
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/*
3600Sstevel@tonic-gate 	 * Get old attributes for the terminal.  We will modify these
3610Sstevel@tonic-gate 	 * flags. I am hoping that if there are any machine-specific
3620Sstevel@tonic-gate 	 * modes, they will initially have reasonable values.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	if (tcgetattr(fd, &tio) == -1) {
3650Sstevel@tonic-gate 		log("tcgetattr: %.100s", strerror(errno));
3660Sstevel@tonic-gate 		failure = -1;
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	for (;;) {
3700Sstevel@tonic-gate 		n_bytes += 1;
3710Sstevel@tonic-gate 		opcode = packet_get_char();
3720Sstevel@tonic-gate 		switch (opcode) {
3730Sstevel@tonic-gate 		case TTY_OP_END:
3740Sstevel@tonic-gate 			goto set;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 		/* XXX: future conflict possible */
3770Sstevel@tonic-gate 		case TTY_OP_ISPEED_PROTO1:
3780Sstevel@tonic-gate 		case TTY_OP_ISPEED_PROTO2:
3790Sstevel@tonic-gate 			n_bytes += 4;
3800Sstevel@tonic-gate 			baud = packet_get_int();
3810Sstevel@tonic-gate 			debug3("tty_parse_modes: ispeed %d", baud);
3820Sstevel@tonic-gate 			if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1)
3830Sstevel@tonic-gate 				error("cfsetispeed failed for %d", baud);
3840Sstevel@tonic-gate 			break;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 		/* XXX: future conflict possible */
3870Sstevel@tonic-gate 		case TTY_OP_OSPEED_PROTO1:
3880Sstevel@tonic-gate 		case TTY_OP_OSPEED_PROTO2:
3890Sstevel@tonic-gate 			n_bytes += 4;
3900Sstevel@tonic-gate 			baud = packet_get_int();
3910Sstevel@tonic-gate 			debug3("tty_parse_modes: ospeed %d", baud);
3920Sstevel@tonic-gate 			if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1)
3930Sstevel@tonic-gate 				error("cfsetospeed failed for %d", baud);
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate #define TTYCHAR(NAME, OP) \
3970Sstevel@tonic-gate 	case OP: \
3980Sstevel@tonic-gate 	  n_bytes += arg_size; \
3990Sstevel@tonic-gate 	  tio.c_cc[NAME] = get_arg(); \
4000Sstevel@tonic-gate 	  debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \
4010Sstevel@tonic-gate 	  break;
4020Sstevel@tonic-gate #define TTYMODE(NAME, FIELD, OP) \
4030Sstevel@tonic-gate 	case OP: \
4040Sstevel@tonic-gate 	  n_bytes += arg_size; \
4050Sstevel@tonic-gate 	  if ((arg = get_arg())) \
4060Sstevel@tonic-gate 	    tio.FIELD |= NAME; \
4070Sstevel@tonic-gate 	  else \
4080Sstevel@tonic-gate 	    tio.FIELD &= ~NAME;	\
4090Sstevel@tonic-gate 	  debug3("tty_parse_modes: %d %d", OP, arg); \
4100Sstevel@tonic-gate 	  break;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate #include "ttymodes.h"
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate #undef TTYCHAR
4150Sstevel@tonic-gate #undef TTYMODE
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 		default:
4180Sstevel@tonic-gate 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
4190Sstevel@tonic-gate 			    opcode, opcode);
4200Sstevel@tonic-gate 			if (!compat20) {
4210Sstevel@tonic-gate 				/*
4220Sstevel@tonic-gate 				 * SSH1:
4230Sstevel@tonic-gate 				 * Opcodes 1 to 127 are defined to have
4240Sstevel@tonic-gate 				 * a one-byte argument.
4250Sstevel@tonic-gate 				 * Opcodes 128 to 159 are defined to have
4260Sstevel@tonic-gate 				 * an integer argument.
4270Sstevel@tonic-gate 				 */
4280Sstevel@tonic-gate 				if (opcode > 0 && opcode < 128) {
4290Sstevel@tonic-gate 					n_bytes += 1;
4300Sstevel@tonic-gate 					(void) packet_get_char();
4310Sstevel@tonic-gate 					break;
4320Sstevel@tonic-gate 				} else if (opcode >= 128 && opcode < 160) {
4330Sstevel@tonic-gate 					n_bytes += 4;
4340Sstevel@tonic-gate 					(void) packet_get_int();
4350Sstevel@tonic-gate 					break;
4360Sstevel@tonic-gate 				} else {
4370Sstevel@tonic-gate 					/*
4380Sstevel@tonic-gate 					 * It is a truly undefined opcode (160 to 255).
4390Sstevel@tonic-gate 					 * We have no idea about its arguments.  So we
4400Sstevel@tonic-gate 					 * must stop parsing.  Note that some data may be
4410Sstevel@tonic-gate 					 * left in the packet; hopefully there is nothing
4420Sstevel@tonic-gate 					 * more coming after the mode data.
4430Sstevel@tonic-gate 					 */
4440Sstevel@tonic-gate 					log("parse_tty_modes: unknown opcode %d", opcode);
4450Sstevel@tonic-gate 					goto set;
4460Sstevel@tonic-gate 				}
4470Sstevel@tonic-gate 			} else {
4480Sstevel@tonic-gate 				/*
4490Sstevel@tonic-gate 				 * SSH2:
4500Sstevel@tonic-gate 				 * Opcodes 1 to 159 are defined to have
4510Sstevel@tonic-gate 				 * a uint32 argument.
4520Sstevel@tonic-gate 				 * Opcodes 160 to 255 are undefined and
4530Sstevel@tonic-gate 				 * cause parsing to stop.
4540Sstevel@tonic-gate 				 */
4550Sstevel@tonic-gate 				if (opcode > 0 && opcode < 160) {
4560Sstevel@tonic-gate 					n_bytes += 4;
4570Sstevel@tonic-gate 					(void) packet_get_int();
4580Sstevel@tonic-gate 					break;
4590Sstevel@tonic-gate 				} else {
4600Sstevel@tonic-gate 					log("parse_tty_modes: unknown opcode %d", opcode);
4610Sstevel@tonic-gate 					goto set;
4620Sstevel@tonic-gate 				}
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate set:
4680Sstevel@tonic-gate 	if (*n_bytes_ptr != n_bytes) {
4690Sstevel@tonic-gate 		*n_bytes_ptr = n_bytes;
4700Sstevel@tonic-gate 		log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
4710Sstevel@tonic-gate 		    *n_bytes_ptr, n_bytes);
4720Sstevel@tonic-gate 		return;		/* Don't process bytes passed */
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 	if (failure == -1)
4750Sstevel@tonic-gate 		return;		/* Packet parsed ok but tcgetattr() failed */
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	/* Set the new modes for the terminal. */
4780Sstevel@tonic-gate 	if (tcsetattr(fd, TCSANOW, &tio) == -1)
4790Sstevel@tonic-gate 		log("Setting tty modes failed: %.100s", strerror(errno));
4800Sstevel@tonic-gate }
481