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" 13 RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 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 */ 26 static int 27 speed_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 */ 115 static speed_t 116 baud_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 */ 206 void 207 tty_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 */ 250 void 251 tty_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 347 set: 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