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