ttymodes.c revision 60573
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *                    All rights reserved
5 * Created: Tue Mar 21 15:59:15 1995 ylo
6 * Encoding and decoding of terminal modes in a portable way.
7 * Much of the format is defined in ttymodes.h; it is included multiple times
8 * into this file with the appropriate macro definitions to generate the
9 * suitable code.
10 */
11
12#include "includes.h"
13RCSID("$Id: ttymodes.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
14
15#include "packet.h"
16#include "ssh.h"
17
18#define TTY_OP_END	0
19#define TTY_OP_ISPEED	192	/* int follows */
20#define TTY_OP_OSPEED	193	/* int follows */
21
22/*
23 * Converts POSIX speed_t to a baud rate.  The values of the
24 * constants for speed_t are not themselves portable.
25 */
26static int
27speed_to_baud(speed_t speed)
28{
29	switch (speed) {
30	case B0:
31		return 0;
32	case B50:
33		return 50;
34	case B75:
35		return 75;
36	case B110:
37		return 110;
38	case B134:
39		return 134;
40	case B150:
41		return 150;
42	case B200:
43		return 200;
44	case B300:
45		return 300;
46	case B600:
47		return 600;
48	case B1200:
49		return 1200;
50	case B1800:
51		return 1800;
52	case B2400:
53		return 2400;
54	case B4800:
55		return 4800;
56	case B9600:
57		return 9600;
58
59#ifdef B19200
60	case B19200:
61		return 19200;
62#else /* B19200 */
63#ifdef EXTA
64	case EXTA:
65		return 19200;
66#endif /* EXTA */
67#endif /* B19200 */
68
69#ifdef B38400
70	case B38400:
71		return 38400;
72#else /* B38400 */
73#ifdef EXTB
74	case EXTB:
75		return 38400;
76#endif /* EXTB */
77#endif /* B38400 */
78
79#ifdef B7200
80	case B7200:
81		return 7200;
82#endif /* B7200 */
83#ifdef B14400
84	case B14400:
85		return 14400;
86#endif /* B14400 */
87#ifdef B28800
88	case B28800:
89		return 28800;
90#endif /* B28800 */
91#ifdef B57600
92	case B57600:
93		return 57600;
94#endif /* B57600 */
95#ifdef B76800
96	case B76800:
97		return 76800;
98#endif /* B76800 */
99#ifdef B115200
100	case B115200:
101		return 115200;
102#endif /* B115200 */
103#ifdef B230400
104	case B230400:
105		return 230400;
106#endif /* B230400 */
107	default:
108		return 9600;
109	}
110}
111
112/*
113 * Converts a numeric baud rate to a POSIX speed_t.
114 */
115static speed_t
116baud_to_speed(int baud)
117{
118	switch (baud) {
119		case 0:
120		return B0;
121	case 50:
122		return B50;
123	case 75:
124		return B75;
125	case 110:
126		return B110;
127	case 134:
128		return B134;
129	case 150:
130		return B150;
131	case 200:
132		return B200;
133	case 300:
134		return B300;
135	case 600:
136		return B600;
137	case 1200:
138		return B1200;
139	case 1800:
140		return B1800;
141	case 2400:
142		return B2400;
143	case 4800:
144		return B4800;
145	case 9600:
146		return B9600;
147
148#ifdef B19200
149	case 19200:
150		return B19200;
151#else /* B19200 */
152#ifdef EXTA
153	case 19200:
154		return EXTA;
155#endif /* EXTA */
156#endif /* B19200 */
157
158#ifdef B38400
159	case 38400:
160		return B38400;
161#else /* B38400 */
162#ifdef EXTB
163	case 38400:
164		return EXTB;
165#endif /* EXTB */
166#endif /* B38400 */
167
168#ifdef B7200
169	case 7200:
170		return B7200;
171#endif /* B7200 */
172#ifdef B14400
173	case 14400:
174		return B14400;
175#endif /* B14400 */
176#ifdef B28800
177	case 28800:
178		return B28800;
179#endif /* B28800 */
180#ifdef B57600
181	case 57600:
182		return B57600;
183#endif /* B57600 */
184#ifdef B76800
185	case 76800:
186		return B76800;
187#endif /* B76800 */
188#ifdef B115200
189	case 115200:
190		return B115200;
191#endif /* B115200 */
192#ifdef B230400
193	case 230400:
194		return B230400;
195#endif /* B230400 */
196	default:
197		return B9600;
198	}
199}
200
201/*
202 * Encodes terminal modes for the terminal referenced by fd
203 * in a portable manner, and appends the modes to a packet
204 * being constructed.
205 */
206void
207tty_make_modes(int fd)
208{
209	struct termios tio;
210	int baud;
211
212	if (tcgetattr(fd, &tio) < 0) {
213		packet_put_char(TTY_OP_END);
214		log("tcgetattr: %.100s", strerror(errno));
215		return;
216	}
217	/* Store input and output baud rates. */
218	baud = speed_to_baud(cfgetospeed(&tio));
219	packet_put_char(TTY_OP_OSPEED);
220	packet_put_int(baud);
221	baud = speed_to_baud(cfgetispeed(&tio));
222	packet_put_char(TTY_OP_ISPEED);
223	packet_put_int(baud);
224
225	/* Store values of mode flags. */
226#define TTYCHAR(NAME, OP) \
227  packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
228#define TTYMODE(NAME, FIELD, OP) \
229  packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0);
230#define SGTTYCHAR(NAME, OP)
231#define SGTTYMODE(NAME, FIELD, OP)
232#define SGTTYMODEN(NAME, FIELD, OP)
233
234#include "ttymodes.h"
235
236#undef TTYCHAR
237#undef TTYMODE
238#undef SGTTYCHAR
239#undef SGTTYMODE
240#undef SGTTYMODEN
241
242	/* Mark end of mode data. */
243	packet_put_char(TTY_OP_END);
244}
245
246/*
247 * Decodes terminal modes for the terminal referenced by fd in a portable
248 * manner from a packet being read.
249 */
250void
251tty_parse_modes(int fd, int *n_bytes_ptr)
252{
253	struct termios tio;
254	int opcode, baud;
255	int n_bytes = 0;
256	int failure = 0;
257
258	/*
259	 * Get old attributes for the terminal.  We will modify these
260	 * flags. I am hoping that if there are any machine-specific
261	 * modes, they will initially have reasonable values.
262	 */
263	if (tcgetattr(fd, &tio) < 0)
264		failure = -1;
265
266	for (;;) {
267		n_bytes += 1;
268		opcode = packet_get_char();
269		switch (opcode) {
270		case TTY_OP_END:
271			goto set;
272
273		case TTY_OP_ISPEED:
274			n_bytes += 4;
275			baud = packet_get_int();
276			if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
277				error("cfsetispeed failed for %d", baud);
278			break;
279
280		case TTY_OP_OSPEED:
281			n_bytes += 4;
282			baud = packet_get_int();
283			if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
284				error("cfsetospeed failed for %d", baud);
285			break;
286
287#define TTYCHAR(NAME, OP) 				\
288	case OP:					\
289	  n_bytes += 1;					\
290	  tio.c_cc[NAME] = packet_get_char();		\
291	  break;
292#define TTYMODE(NAME, FIELD, OP)		       	\
293	case OP:					\
294	  n_bytes += 1;					\
295	  if (packet_get_char())			\
296	    tio.FIELD |= NAME;				\
297	  else						\
298	    tio.FIELD &= ~NAME;				\
299	  break;
300#define SGTTYCHAR(NAME, OP)
301#define SGTTYMODE(NAME, FIELD, OP)
302#define SGTTYMODEN(NAME, FIELD, OP)
303
304#include "ttymodes.h"
305
306#undef TTYCHAR
307#undef TTYMODE
308#undef SGTTYCHAR
309#undef SGTTYMODE
310#undef SGTTYMODEN
311
312		default:
313			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
314			      opcode, opcode);
315			/*
316			 * Opcodes 0 to 127 are defined to have
317			 * a one-byte argument.
318			 */
319			if (opcode >= 0 && opcode < 128) {
320				n_bytes += 1;
321				(void) packet_get_char();
322				break;
323			} else {
324				/*
325				 * Opcodes 128 to 159 are defined to have
326				 * an integer argument.
327				 */
328				if (opcode >= 128 && opcode < 160) {
329					n_bytes += 4;
330					(void) packet_get_int();
331					break;
332				}
333			}
334			/*
335			 * It is a truly undefined opcode (160 to 255).
336			 * We have no idea about its arguments.  So we
337			 * must stop parsing.  Note that some data may be
338			 * left in the packet; hopefully there is nothing
339			 * more coming after the mode data.
340			 */
341			log("parse_tty_modes: unknown opcode %d", opcode);
342			packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
343			goto set;
344		}
345	}
346
347set:
348	if (*n_bytes_ptr != n_bytes) {
349		*n_bytes_ptr = n_bytes;
350		return;		/* Don't process bytes passed */
351	}
352	if (failure == -1)
353		return;		/* Packet parsed ok but tty stuff failed */
354
355	/* Set the new modes for the terminal. */
356	if (tcsetattr(fd, TCSANOW, &tio) < 0)
357		log("Setting tty modes failed: %.100s", strerror(errno));
358	return;
359}
360