xref: /freebsd/crypto/openssh/ttymodes.c (revision d4af9e693f15f5155095f38c7650b24fe74ae351)
1d4af9e69SDag-Erling Smørgrav /* $OpenBSD: ttymodes.c,v 1.28 2008/07/07 00:31:41 stevesk Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6b66f2d16SKris Kennaway  *
7b66f2d16SKris Kennaway  * As far as I am concerned, the code I have written for this software
8b66f2d16SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
9b66f2d16SKris Kennaway  * software must be clearly marked as such, and if the derived work is
10b66f2d16SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
11b66f2d16SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
12511b41d2SMark Murray  */
13511b41d2SMark Murray 
141e8db6e2SBrian Feldman /*
151e8db6e2SBrian Feldman  * SSH2 tty modes support by Kevin Steves.
161e8db6e2SBrian Feldman  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
171e8db6e2SBrian Feldman  *
181e8db6e2SBrian Feldman  * Redistribution and use in source and binary forms, with or without
191e8db6e2SBrian Feldman  * modification, are permitted provided that the following conditions
201e8db6e2SBrian Feldman  * are met:
211e8db6e2SBrian Feldman  * 1. Redistributions of source code must retain the above copyright
221e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer.
231e8db6e2SBrian Feldman  * 2. Redistributions in binary form must reproduce the above copyright
241e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer in the
251e8db6e2SBrian Feldman  *    documentation and/or other materials provided with the distribution.
261e8db6e2SBrian Feldman  *
271e8db6e2SBrian Feldman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
281e8db6e2SBrian Feldman  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
291e8db6e2SBrian Feldman  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
301e8db6e2SBrian Feldman  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
311e8db6e2SBrian Feldman  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
321e8db6e2SBrian Feldman  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
331e8db6e2SBrian Feldman  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
341e8db6e2SBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
351e8db6e2SBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
361e8db6e2SBrian Feldman  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
371e8db6e2SBrian Feldman  */
381e8db6e2SBrian Feldman 
391e8db6e2SBrian Feldman /*
401e8db6e2SBrian Feldman  * Encoding and decoding of terminal modes in a portable way.
411e8db6e2SBrian Feldman  * Much of the format is defined in ttymodes.h; it is included multiple times
421e8db6e2SBrian Feldman  * into this file with the appropriate macro definitions to generate the
431e8db6e2SBrian Feldman  * suitable code.
441e8db6e2SBrian Feldman  */
451e8db6e2SBrian Feldman 
46511b41d2SMark Murray #include "includes.h"
47761efaa7SDag-Erling Smørgrav 
48761efaa7SDag-Erling Smørgrav #include <sys/types.h>
49761efaa7SDag-Erling Smørgrav 
50761efaa7SDag-Erling Smørgrav #include <errno.h>
51761efaa7SDag-Erling Smørgrav #include <string.h>
52761efaa7SDag-Erling Smørgrav #include <termios.h>
53761efaa7SDag-Erling Smørgrav #include <stdarg.h>
54511b41d2SMark Murray 
55511b41d2SMark Murray #include "packet.h"
561e8db6e2SBrian Feldman #include "log.h"
571e8db6e2SBrian Feldman #include "ssh1.h"
581e8db6e2SBrian Feldman #include "compat.h"
591e8db6e2SBrian Feldman #include "buffer.h"
60511b41d2SMark Murray 
61511b41d2SMark Murray #define TTY_OP_END		0
621e8db6e2SBrian Feldman /*
631e8db6e2SBrian Feldman  * uint32 (u_int) follows speed in SSH1 and SSH2
641e8db6e2SBrian Feldman  */
651e8db6e2SBrian Feldman #define TTY_OP_ISPEED_PROTO1	192
661e8db6e2SBrian Feldman #define TTY_OP_OSPEED_PROTO1	193
671e8db6e2SBrian Feldman #define TTY_OP_ISPEED_PROTO2	128
681e8db6e2SBrian Feldman #define TTY_OP_OSPEED_PROTO2	129
69511b41d2SMark Murray 
70511b41d2SMark Murray /*
71511b41d2SMark Murray  * Converts POSIX speed_t to a baud rate.  The values of the
72511b41d2SMark Murray  * constants for speed_t are not themselves portable.
73511b41d2SMark Murray  */
74511b41d2SMark Murray static int
75511b41d2SMark Murray speed_to_baud(speed_t speed)
76511b41d2SMark Murray {
77511b41d2SMark Murray 	switch (speed) {
78511b41d2SMark Murray 	case B0:
79511b41d2SMark Murray 		return 0;
80511b41d2SMark Murray 	case B50:
81511b41d2SMark Murray 		return 50;
82511b41d2SMark Murray 	case B75:
83511b41d2SMark Murray 		return 75;
84511b41d2SMark Murray 	case B110:
85511b41d2SMark Murray 		return 110;
86511b41d2SMark Murray 	case B134:
87511b41d2SMark Murray 		return 134;
88511b41d2SMark Murray 	case B150:
89511b41d2SMark Murray 		return 150;
90511b41d2SMark Murray 	case B200:
91511b41d2SMark Murray 		return 200;
92511b41d2SMark Murray 	case B300:
93511b41d2SMark Murray 		return 300;
94511b41d2SMark Murray 	case B600:
95511b41d2SMark Murray 		return 600;
96511b41d2SMark Murray 	case B1200:
97511b41d2SMark Murray 		return 1200;
98511b41d2SMark Murray 	case B1800:
99511b41d2SMark Murray 		return 1800;
100511b41d2SMark Murray 	case B2400:
101511b41d2SMark Murray 		return 2400;
102511b41d2SMark Murray 	case B4800:
103511b41d2SMark Murray 		return 4800;
104511b41d2SMark Murray 	case B9600:
105511b41d2SMark Murray 		return 9600;
106511b41d2SMark Murray 
107511b41d2SMark Murray #ifdef B19200
108511b41d2SMark Murray 	case B19200:
109511b41d2SMark Murray 		return 19200;
110511b41d2SMark Murray #else /* B19200 */
111511b41d2SMark Murray #ifdef EXTA
112511b41d2SMark Murray 	case EXTA:
113511b41d2SMark Murray 		return 19200;
114511b41d2SMark Murray #endif /* EXTA */
115511b41d2SMark Murray #endif /* B19200 */
116511b41d2SMark Murray 
117511b41d2SMark Murray #ifdef B38400
118511b41d2SMark Murray 	case B38400:
119511b41d2SMark Murray 		return 38400;
120511b41d2SMark Murray #else /* B38400 */
121511b41d2SMark Murray #ifdef EXTB
122511b41d2SMark Murray 	case EXTB:
123511b41d2SMark Murray 		return 38400;
124511b41d2SMark Murray #endif /* EXTB */
125511b41d2SMark Murray #endif /* B38400 */
126511b41d2SMark Murray 
127511b41d2SMark Murray #ifdef B7200
128511b41d2SMark Murray 	case B7200:
129511b41d2SMark Murray 		return 7200;
130511b41d2SMark Murray #endif /* B7200 */
131511b41d2SMark Murray #ifdef B14400
132511b41d2SMark Murray 	case B14400:
133511b41d2SMark Murray 		return 14400;
134511b41d2SMark Murray #endif /* B14400 */
135511b41d2SMark Murray #ifdef B28800
136511b41d2SMark Murray 	case B28800:
137511b41d2SMark Murray 		return 28800;
138511b41d2SMark Murray #endif /* B28800 */
139511b41d2SMark Murray #ifdef B57600
140511b41d2SMark Murray 	case B57600:
141511b41d2SMark Murray 		return 57600;
142511b41d2SMark Murray #endif /* B57600 */
143511b41d2SMark Murray #ifdef B76800
144511b41d2SMark Murray 	case B76800:
145511b41d2SMark Murray 		return 76800;
146511b41d2SMark Murray #endif /* B76800 */
147511b41d2SMark Murray #ifdef B115200
148511b41d2SMark Murray 	case B115200:
149511b41d2SMark Murray 		return 115200;
150511b41d2SMark Murray #endif /* B115200 */
151511b41d2SMark Murray #ifdef B230400
152511b41d2SMark Murray 	case B230400:
153511b41d2SMark Murray 		return 230400;
154511b41d2SMark Murray #endif /* B230400 */
155511b41d2SMark Murray 	default:
156511b41d2SMark Murray 		return 9600;
157511b41d2SMark Murray 	}
158511b41d2SMark Murray }
159511b41d2SMark Murray 
160511b41d2SMark Murray /*
161511b41d2SMark Murray  * Converts a numeric baud rate to a POSIX speed_t.
162511b41d2SMark Murray  */
163511b41d2SMark Murray static speed_t
164511b41d2SMark Murray baud_to_speed(int baud)
165511b41d2SMark Murray {
166511b41d2SMark Murray 	switch (baud) {
167511b41d2SMark Murray 	case 0:
168511b41d2SMark Murray 		return B0;
169511b41d2SMark Murray 	case 50:
170511b41d2SMark Murray 		return B50;
171511b41d2SMark Murray 	case 75:
172511b41d2SMark Murray 		return B75;
173511b41d2SMark Murray 	case 110:
174511b41d2SMark Murray 		return B110;
175511b41d2SMark Murray 	case 134:
176511b41d2SMark Murray 		return B134;
177511b41d2SMark Murray 	case 150:
178511b41d2SMark Murray 		return B150;
179511b41d2SMark Murray 	case 200:
180511b41d2SMark Murray 		return B200;
181511b41d2SMark Murray 	case 300:
182511b41d2SMark Murray 		return B300;
183511b41d2SMark Murray 	case 600:
184511b41d2SMark Murray 		return B600;
185511b41d2SMark Murray 	case 1200:
186511b41d2SMark Murray 		return B1200;
187511b41d2SMark Murray 	case 1800:
188511b41d2SMark Murray 		return B1800;
189511b41d2SMark Murray 	case 2400:
190511b41d2SMark Murray 		return B2400;
191511b41d2SMark Murray 	case 4800:
192511b41d2SMark Murray 		return B4800;
193511b41d2SMark Murray 	case 9600:
194511b41d2SMark Murray 		return B9600;
195511b41d2SMark Murray 
196511b41d2SMark Murray #ifdef B19200
197511b41d2SMark Murray 	case 19200:
198511b41d2SMark Murray 		return B19200;
199511b41d2SMark Murray #else /* B19200 */
200511b41d2SMark Murray #ifdef EXTA
201511b41d2SMark Murray 	case 19200:
202511b41d2SMark Murray 		return EXTA;
203511b41d2SMark Murray #endif /* EXTA */
204511b41d2SMark Murray #endif /* B19200 */
205511b41d2SMark Murray 
206511b41d2SMark Murray #ifdef B38400
207511b41d2SMark Murray 	case 38400:
208511b41d2SMark Murray 		return B38400;
209511b41d2SMark Murray #else /* B38400 */
210511b41d2SMark Murray #ifdef EXTB
211511b41d2SMark Murray 	case 38400:
212511b41d2SMark Murray 		return EXTB;
213511b41d2SMark Murray #endif /* EXTB */
214511b41d2SMark Murray #endif /* B38400 */
215511b41d2SMark Murray 
216511b41d2SMark Murray #ifdef B7200
217511b41d2SMark Murray 	case 7200:
218511b41d2SMark Murray 		return B7200;
219511b41d2SMark Murray #endif /* B7200 */
220511b41d2SMark Murray #ifdef B14400
221511b41d2SMark Murray 	case 14400:
222511b41d2SMark Murray 		return B14400;
223511b41d2SMark Murray #endif /* B14400 */
224511b41d2SMark Murray #ifdef B28800
225511b41d2SMark Murray 	case 28800:
226511b41d2SMark Murray 		return B28800;
227511b41d2SMark Murray #endif /* B28800 */
228511b41d2SMark Murray #ifdef B57600
229511b41d2SMark Murray 	case 57600:
230511b41d2SMark Murray 		return B57600;
231511b41d2SMark Murray #endif /* B57600 */
232511b41d2SMark Murray #ifdef B76800
233511b41d2SMark Murray 	case 76800:
234511b41d2SMark Murray 		return B76800;
235511b41d2SMark Murray #endif /* B76800 */
236511b41d2SMark Murray #ifdef B115200
237511b41d2SMark Murray 	case 115200:
238511b41d2SMark Murray 		return B115200;
239511b41d2SMark Murray #endif /* B115200 */
240511b41d2SMark Murray #ifdef B230400
241511b41d2SMark Murray 	case 230400:
242511b41d2SMark Murray 		return B230400;
243511b41d2SMark Murray #endif /* B230400 */
244511b41d2SMark Murray 	default:
245511b41d2SMark Murray 		return B9600;
246511b41d2SMark Murray 	}
247511b41d2SMark Murray }
248511b41d2SMark Murray 
249511b41d2SMark Murray /*
250043840dfSDag-Erling Smørgrav  * Encode a special character into SSH line format.
251043840dfSDag-Erling Smørgrav  */
252043840dfSDag-Erling Smørgrav static u_int
253043840dfSDag-Erling Smørgrav special_char_encode(cc_t c)
254043840dfSDag-Erling Smørgrav {
255043840dfSDag-Erling Smørgrav #ifdef _POSIX_VDISABLE
256043840dfSDag-Erling Smørgrav 	if (c == _POSIX_VDISABLE)
257043840dfSDag-Erling Smørgrav 		return 255;
258043840dfSDag-Erling Smørgrav #endif /* _POSIX_VDISABLE */
259043840dfSDag-Erling Smørgrav 	return c;
260043840dfSDag-Erling Smørgrav }
261043840dfSDag-Erling Smørgrav 
262043840dfSDag-Erling Smørgrav /*
263043840dfSDag-Erling Smørgrav  * Decode a special character from SSH line format.
264043840dfSDag-Erling Smørgrav  */
265043840dfSDag-Erling Smørgrav static cc_t
266043840dfSDag-Erling Smørgrav special_char_decode(u_int c)
267043840dfSDag-Erling Smørgrav {
268043840dfSDag-Erling Smørgrav #ifdef _POSIX_VDISABLE
269043840dfSDag-Erling Smørgrav 	if (c == 255)
270043840dfSDag-Erling Smørgrav 		return _POSIX_VDISABLE;
271043840dfSDag-Erling Smørgrav #endif /* _POSIX_VDISABLE */
272043840dfSDag-Erling Smørgrav 	return c;
273043840dfSDag-Erling Smørgrav }
274043840dfSDag-Erling Smørgrav 
275043840dfSDag-Erling Smørgrav /*
276511b41d2SMark Murray  * Encodes terminal modes for the terminal referenced by fd
2771e8db6e2SBrian Feldman  * or tiop in a portable manner, and appends the modes to a packet
278511b41d2SMark Murray  * being constructed.
279511b41d2SMark Murray  */
280511b41d2SMark Murray void
2811e8db6e2SBrian Feldman tty_make_modes(int fd, struct termios *tiop)
282511b41d2SMark Murray {
283511b41d2SMark Murray 	struct termios tio;
284511b41d2SMark Murray 	int baud;
2851e8db6e2SBrian Feldman 	Buffer buf;
2861e8db6e2SBrian Feldman 	int tty_op_ospeed, tty_op_ispeed;
2871e8db6e2SBrian Feldman 	void (*put_arg)(Buffer *, u_int);
288511b41d2SMark Murray 
2891e8db6e2SBrian Feldman 	buffer_init(&buf);
2901e8db6e2SBrian Feldman 	if (compat20) {
2911e8db6e2SBrian Feldman 		tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
2921e8db6e2SBrian Feldman 		tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
2931e8db6e2SBrian Feldman 		put_arg = buffer_put_int;
2941e8db6e2SBrian Feldman 	} else {
2951e8db6e2SBrian Feldman 		tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
2961e8db6e2SBrian Feldman 		tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
2971e8db6e2SBrian Feldman 		put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
298511b41d2SMark Murray 	}
2991e8db6e2SBrian Feldman 
3001e8db6e2SBrian Feldman 	if (tiop == NULL) {
301d4af9e69SDag-Erling Smørgrav 		if (fd == -1) {
302d4af9e69SDag-Erling Smørgrav 			debug("tty_make_modes: no fd or tio");
303d4af9e69SDag-Erling Smørgrav 			goto end;
304d4af9e69SDag-Erling Smørgrav 		}
3051e8db6e2SBrian Feldman 		if (tcgetattr(fd, &tio) == -1) {
306d95e11bfSDag-Erling Smørgrav 			logit("tcgetattr: %.100s", strerror(errno));
3071e8db6e2SBrian Feldman 			goto end;
3081e8db6e2SBrian Feldman 		}
3091e8db6e2SBrian Feldman 	} else
3101e8db6e2SBrian Feldman 		tio = *tiop;
3111e8db6e2SBrian Feldman 
312511b41d2SMark Murray 	/* Store input and output baud rates. */
313511b41d2SMark Murray 	baud = speed_to_baud(cfgetospeed(&tio));
314ae1f160dSDag-Erling Smørgrav 	debug3("tty_make_modes: ospeed %d", baud);
3151e8db6e2SBrian Feldman 	buffer_put_char(&buf, tty_op_ospeed);
3161e8db6e2SBrian Feldman 	buffer_put_int(&buf, baud);
317511b41d2SMark Murray 	baud = speed_to_baud(cfgetispeed(&tio));
318ae1f160dSDag-Erling Smørgrav 	debug3("tty_make_modes: ispeed %d", baud);
3191e8db6e2SBrian Feldman 	buffer_put_char(&buf, tty_op_ispeed);
3201e8db6e2SBrian Feldman 	buffer_put_int(&buf, baud);
321511b41d2SMark Murray 
322511b41d2SMark Murray 	/* Store values of mode flags. */
323511b41d2SMark Murray #define TTYCHAR(NAME, OP) \
3241e8db6e2SBrian Feldman 	buffer_put_char(&buf, OP); \
325043840dfSDag-Erling Smørgrav 	put_arg(&buf, special_char_encode(tio.c_cc[NAME]));
3261e8db6e2SBrian Feldman 
327511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \
3281e8db6e2SBrian Feldman 	buffer_put_char(&buf, OP); \
3291e8db6e2SBrian Feldman 	put_arg(&buf, ((tio.FIELD & NAME) != 0));
330511b41d2SMark Murray 
331511b41d2SMark Murray #include "ttymodes.h"
332511b41d2SMark Murray 
333511b41d2SMark Murray #undef TTYCHAR
334511b41d2SMark Murray #undef TTYMODE
335511b41d2SMark Murray 
3361e8db6e2SBrian Feldman end:
337511b41d2SMark Murray 	/* Mark end of mode data. */
3381e8db6e2SBrian Feldman 	buffer_put_char(&buf, TTY_OP_END);
3391e8db6e2SBrian Feldman 	if (compat20)
3401e8db6e2SBrian Feldman 		packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
3411e8db6e2SBrian Feldman 	else
3421e8db6e2SBrian Feldman 		packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
3431e8db6e2SBrian Feldman 	buffer_free(&buf);
344511b41d2SMark Murray }
345511b41d2SMark Murray 
346511b41d2SMark Murray /*
347511b41d2SMark Murray  * Decodes terminal modes for the terminal referenced by fd in a portable
348511b41d2SMark Murray  * manner from a packet being read.
349511b41d2SMark Murray  */
350511b41d2SMark Murray void
351511b41d2SMark Murray tty_parse_modes(int fd, int *n_bytes_ptr)
352511b41d2SMark Murray {
353511b41d2SMark Murray 	struct termios tio;
354511b41d2SMark Murray 	int opcode, baud;
355511b41d2SMark Murray 	int n_bytes = 0;
356511b41d2SMark Murray 	int failure = 0;
3571e8db6e2SBrian Feldman 	u_int (*get_arg)(void);
358d4af9e69SDag-Erling Smørgrav 	int arg_size;
3591e8db6e2SBrian Feldman 
3601e8db6e2SBrian Feldman 	if (compat20) {
3611e8db6e2SBrian Feldman 		*n_bytes_ptr = packet_get_int();
362ae1f160dSDag-Erling Smørgrav 		debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr);
3631e8db6e2SBrian Feldman 		if (*n_bytes_ptr == 0)
3641e8db6e2SBrian Feldman 			return;
3651e8db6e2SBrian Feldman 		get_arg = packet_get_int;
3661e8db6e2SBrian Feldman 		arg_size = 4;
3671e8db6e2SBrian Feldman 	} else {
3681e8db6e2SBrian Feldman 		get_arg = packet_get_char;
3691e8db6e2SBrian Feldman 		arg_size = 1;
3701e8db6e2SBrian Feldman 	}
371511b41d2SMark Murray 
372511b41d2SMark Murray 	/*
373511b41d2SMark Murray 	 * Get old attributes for the terminal.  We will modify these
374511b41d2SMark Murray 	 * flags. I am hoping that if there are any machine-specific
375511b41d2SMark Murray 	 * modes, they will initially have reasonable values.
376511b41d2SMark Murray 	 */
3771e8db6e2SBrian Feldman 	if (tcgetattr(fd, &tio) == -1) {
378d95e11bfSDag-Erling Smørgrav 		logit("tcgetattr: %.100s", strerror(errno));
379511b41d2SMark Murray 		failure = -1;
3801e8db6e2SBrian Feldman 	}
381511b41d2SMark Murray 
382511b41d2SMark Murray 	for (;;) {
383511b41d2SMark Murray 		n_bytes += 1;
384511b41d2SMark Murray 		opcode = packet_get_char();
385511b41d2SMark Murray 		switch (opcode) {
386511b41d2SMark Murray 		case TTY_OP_END:
387511b41d2SMark Murray 			goto set;
388511b41d2SMark Murray 
3891e8db6e2SBrian Feldman 		/* XXX: future conflict possible */
3901e8db6e2SBrian Feldman 		case TTY_OP_ISPEED_PROTO1:
3911e8db6e2SBrian Feldman 		case TTY_OP_ISPEED_PROTO2:
392511b41d2SMark Murray 			n_bytes += 4;
393511b41d2SMark Murray 			baud = packet_get_int();
394ae1f160dSDag-Erling Smørgrav 			debug3("tty_parse_modes: ispeed %d", baud);
395761efaa7SDag-Erling Smørgrav 			if (failure != -1 &&
396761efaa7SDag-Erling Smørgrav 			    cfsetispeed(&tio, baud_to_speed(baud)) == -1)
397511b41d2SMark Murray 				error("cfsetispeed failed for %d", baud);
398511b41d2SMark Murray 			break;
399511b41d2SMark Murray 
4001e8db6e2SBrian Feldman 		/* XXX: future conflict possible */
4011e8db6e2SBrian Feldman 		case TTY_OP_OSPEED_PROTO1:
4021e8db6e2SBrian Feldman 		case TTY_OP_OSPEED_PROTO2:
403511b41d2SMark Murray 			n_bytes += 4;
404511b41d2SMark Murray 			baud = packet_get_int();
405ae1f160dSDag-Erling Smørgrav 			debug3("tty_parse_modes: ospeed %d", baud);
406761efaa7SDag-Erling Smørgrav 			if (failure != -1 &&
407761efaa7SDag-Erling Smørgrav 			    cfsetospeed(&tio, baud_to_speed(baud)) == -1)
408511b41d2SMark Murray 				error("cfsetospeed failed for %d", baud);
409511b41d2SMark Murray 			break;
410511b41d2SMark Murray 
411511b41d2SMark Murray #define TTYCHAR(NAME, OP) \
412511b41d2SMark Murray 	case OP: \
4131e8db6e2SBrian Feldman 	  n_bytes += arg_size; \
414043840dfSDag-Erling Smørgrav 	  tio.c_cc[NAME] = special_char_decode(get_arg()); \
415511b41d2SMark Murray 	  break;
416511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \
417511b41d2SMark Murray 	case OP: \
4181e8db6e2SBrian Feldman 	  n_bytes += arg_size; \
419d4af9e69SDag-Erling Smørgrav 	  if (get_arg()) \
420511b41d2SMark Murray 	    tio.FIELD |= NAME; \
421511b41d2SMark Murray 	  else \
422511b41d2SMark Murray 	    tio.FIELD &= ~NAME;	\
423511b41d2SMark Murray 	  break;
424511b41d2SMark Murray 
425511b41d2SMark Murray #include "ttymodes.h"
426511b41d2SMark Murray 
427511b41d2SMark Murray #undef TTYCHAR
428511b41d2SMark Murray #undef TTYMODE
429511b41d2SMark Murray 
430511b41d2SMark Murray 		default:
431511b41d2SMark Murray 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
432511b41d2SMark Murray 			    opcode, opcode);
4331e8db6e2SBrian Feldman 			if (!compat20) {
434511b41d2SMark Murray 				/*
4351e8db6e2SBrian Feldman 				 * SSH1:
4361e8db6e2SBrian Feldman 				 * Opcodes 1 to 127 are defined to have
437511b41d2SMark Murray 				 * a one-byte argument.
438511b41d2SMark Murray 				 * Opcodes 128 to 159 are defined to have
439511b41d2SMark Murray 				 * an integer argument.
440511b41d2SMark Murray 				 */
4411e8db6e2SBrian Feldman 				if (opcode > 0 && opcode < 128) {
4421e8db6e2SBrian Feldman 					n_bytes += 1;
4431e8db6e2SBrian Feldman 					(void) packet_get_char();
4441e8db6e2SBrian Feldman 					break;
4451e8db6e2SBrian Feldman 				} else if (opcode >= 128 && opcode < 160) {
446511b41d2SMark Murray 					n_bytes += 4;
447511b41d2SMark Murray 					(void) packet_get_int();
448511b41d2SMark Murray 					break;
4491e8db6e2SBrian Feldman 				} else {
450511b41d2SMark Murray 					/*
451511b41d2SMark Murray 					 * It is a truly undefined opcode (160 to 255).
452511b41d2SMark Murray 					 * We have no idea about its arguments.  So we
453761efaa7SDag-Erling Smørgrav 					 * must stop parsing.  Note that some data
454761efaa7SDag-Erling Smørgrav 					 * may be left in the packet; hopefully there
455761efaa7SDag-Erling Smørgrav 					 * is nothing more coming after the mode data.
456511b41d2SMark Murray 					 */
457761efaa7SDag-Erling Smørgrav 					logit("parse_tty_modes: unknown opcode %d",
458761efaa7SDag-Erling Smørgrav 					    opcode);
459511b41d2SMark Murray 					goto set;
460511b41d2SMark Murray 				}
4611e8db6e2SBrian Feldman 			} else {
4621e8db6e2SBrian Feldman 				/*
4631e8db6e2SBrian Feldman 				 * SSH2:
4641e8db6e2SBrian Feldman 				 * Opcodes 1 to 159 are defined to have
4651e8db6e2SBrian Feldman 				 * a uint32 argument.
4661e8db6e2SBrian Feldman 				 * Opcodes 160 to 255 are undefined and
4671e8db6e2SBrian Feldman 				 * cause parsing to stop.
4681e8db6e2SBrian Feldman 				 */
4691e8db6e2SBrian Feldman 				if (opcode > 0 && opcode < 160) {
4701e8db6e2SBrian Feldman 					n_bytes += 4;
4711e8db6e2SBrian Feldman 					(void) packet_get_int();
4721e8db6e2SBrian Feldman 					break;
4731e8db6e2SBrian Feldman 				} else {
474761efaa7SDag-Erling Smørgrav 					logit("parse_tty_modes: unknown opcode %d",
475761efaa7SDag-Erling Smørgrav 					    opcode);
4761e8db6e2SBrian Feldman 					goto set;
4771e8db6e2SBrian Feldman 				}
4781e8db6e2SBrian Feldman 			}
4791e8db6e2SBrian Feldman 		}
480511b41d2SMark Murray 	}
481511b41d2SMark Murray 
482511b41d2SMark Murray set:
483511b41d2SMark Murray 	if (*n_bytes_ptr != n_bytes) {
484511b41d2SMark Murray 		*n_bytes_ptr = n_bytes;
485d95e11bfSDag-Erling Smørgrav 		logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
4861e8db6e2SBrian Feldman 		    *n_bytes_ptr, n_bytes);
487511b41d2SMark Murray 		return;		/* Don't process bytes passed */
488511b41d2SMark Murray 	}
489511b41d2SMark Murray 	if (failure == -1)
4901e8db6e2SBrian Feldman 		return;		/* Packet parsed ok but tcgetattr() failed */
491511b41d2SMark Murray 
492511b41d2SMark Murray 	/* Set the new modes for the terminal. */
4931e8db6e2SBrian Feldman 	if (tcsetattr(fd, TCSANOW, &tio) == -1)
494d95e11bfSDag-Erling Smørgrav 		logit("Setting tty modes failed: %.100s", strerror(errno));
495511b41d2SMark Murray }
496