[BACK]Return to ttymodes.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

File: [local] / src / usr.bin / ssh / ttymodes.c (download)

Revision 1.2, Thu Sep 30 05:03:05 1999 UTC (24 years, 8 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_2_6_BASE, OPENBSD_2_6
Changes since 1.1: +1 -141 lines

cull more ancient garbage from pre-POSIX days

/*

ttymodes.c

Author: Tatu Ylonen <ylo@cs.hut.fi>

Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                   All rights reserved

Created: Tue Mar 21 15:59:15 1995 ylo

Encoding and decoding of terminal modes in a portable way.
Much of the format is defined in ttymodes.h; it is included multiple times
into this file with the appropriate macro definitions to generate the
suitable code.

*/

#include "includes.h"
RCSID("$Id: ttymodes.c,v 1.2 1999/09/30 05:03:05 deraadt Exp $");

#include "packet.h"
#include "ssh.h"

#define TTY_OP_END	0
#define TTY_OP_ISPEED	192 /* int follows */
#define TTY_OP_OSPEED	193 /* int follows */

/* Converts POSIX speed_t to a baud rate.  The values of the constants
   for speed_t are not themselves portable. */

static int speed_to_baud(speed_t speed)
{
  switch (speed)
    {
    case B0:
      return 0;
    case B50:
      return 50;
    case B75:
      return 75;
    case B110:
      return 110;
    case B134:
      return 134;
    case B150:
      return 150;
    case B200:
      return 200;
    case B300:
      return 300;
    case B600:
      return 600;
    case B1200:
      return 1200;
    case B1800:
      return 1800;
    case B2400:
      return 2400;
    case B4800:
      return 4800;
    case B9600:
      return 9600;

#ifdef B19200
    case B19200:
      return 19200;
#else /* B19200 */
#ifdef EXTA
    case EXTA:
      return 19200;
#endif /* EXTA */
#endif /* B19200 */

#ifdef B38400
    case B38400:
      return 38400;
#else /* B38400 */
#ifdef EXTB
    case EXTB:
      return 38400;
#endif /* EXTB */
#endif /* B38400 */

#ifdef B7200
    case B7200:
      return 7200;
#endif /* B7200 */
#ifdef B14400
    case B14400:
      return 14400;
#endif /* B14400 */
#ifdef B28800
    case B28800:
      return 28800;
#endif /* B28800 */
#ifdef B57600
    case B57600:
      return 57600;
#endif /* B57600 */
#ifdef B76800
    case B76800:
      return 76800;
#endif /* B76800 */
#ifdef B115200
    case B115200:
      return 115200;
#endif /* B115200 */
#ifdef B230400
    case B230400:
      return 230400;
#endif /* B230400 */
    default:
      return 9600;
    }
}

/* Converts a numeric baud rate to a POSIX speed_t. */

static speed_t baud_to_speed(int baud)
{
  switch (baud)
    {
    case 0:
      return B0;
    case 50:
      return B50;
    case 75:
      return B75;
    case 110:
      return B110;
    case 134:
      return B134;
    case 150:
      return B150;
    case 200:
      return B200;
    case 300:
      return B300;
    case 600:
      return B600;
    case 1200:
      return B1200;
    case 1800:
      return B1800;
    case 2400:
      return B2400;
    case 4800:
      return B4800;
    case 9600:
      return B9600;

#ifdef B19200
    case 19200:
      return B19200;
#else /* B19200 */
#ifdef EXTA
    case 19200:
      return EXTA;
#endif /* EXTA */
#endif /* B19200 */

#ifdef B38400
    case 38400:
      return B38400;
#else /* B38400 */
#ifdef EXTB
    case 38400:
      return EXTB;
#endif /* EXTB */
#endif /* B38400 */

#ifdef B7200
    case 7200:
      return B7200;
#endif /* B7200 */
#ifdef B14400
    case 14400:
      return B14400;
#endif /* B14400 */
#ifdef B28800
    case 28800:
      return B28800;
#endif /* B28800 */
#ifdef B57600
    case 57600:
      return B57600;
#endif /* B57600 */
#ifdef B76800
    case 76800:
      return B76800;
#endif /* B76800 */
#ifdef B115200
    case 115200:
      return B115200;
#endif /* B115200 */
#ifdef B230400
    case 230400:
      return B230400;
#endif /* B230400 */
    default:
      return B9600;
    }
}

/* Encodes terminal modes for the terminal referenced by fd in a portable
   manner, and appends the modes to a packet being constructed. */

void tty_make_modes(int fd)
{
  struct termios tio;
  int baud;

  /* Get the modes. */
  if (tcgetattr(fd, &tio) < 0)
    {
      packet_put_char(TTY_OP_END);
      log("tcgetattr: %.100s", strerror(errno));
      return;
    }

  /* Store input and output baud rates. */
  baud = speed_to_baud(cfgetospeed(&tio));
  packet_put_char(TTY_OP_OSPEED);
  packet_put_int(baud);
  baud = speed_to_baud(cfgetispeed(&tio));
  packet_put_char(TTY_OP_ISPEED);
  packet_put_int(baud);

  /* Store values of mode flags. */
#define TTYCHAR(NAME, OP) \
  packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
#define TTYMODE(NAME, FIELD, OP) \
  packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0);
#define SGTTYCHAR(NAME, OP)
#define SGTTYMODE(NAME, FIELD, OP)
#define SGTTYMODEN(NAME, FIELD, OP)

#include "ttymodes.h"

#undef TTYCHAR
#undef TTYMODE
#undef SGTTYCHAR
#undef SGTTYMODE
#undef SGTTYMODEN

  /* Mark end of mode data. */
  packet_put_char(TTY_OP_END);
}

/* Decodes terminal modes for the terminal referenced by fd in a portable
   manner from a packet being read. */

void tty_parse_modes(int fd, int *n_bytes_ptr)
{
  struct termios tio;
  int opcode, baud;
  int n_bytes = 0;
  int failure = 0;

  /* Get old attributes for the terminal.  We will modify these flags. 
     I am hoping that if there are any machine-specific modes, they will
     initially have reasonable values. */
  if (tcgetattr(fd, &tio) < 0)
    failure = -1;

  for (;;)
    {
      n_bytes += 1;
      opcode = packet_get_char();
      switch (opcode)
	{
	case TTY_OP_END:
	  goto set;

	case TTY_OP_ISPEED:
	  n_bytes += 4;
	  baud = packet_get_int();
	  if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
	    error("cfsetispeed failed for %d", baud);
	  break;

	case TTY_OP_OSPEED:
	  n_bytes += 4;
	  baud = packet_get_int();
	  if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
	    error("cfsetospeed failed for %d", baud);
	  break;

#define TTYCHAR(NAME, OP) 				\
	case OP:					\
	  n_bytes += 1;					\
	  tio.c_cc[NAME] = packet_get_char();		\
	  break;
#define TTYMODE(NAME, FIELD, OP)		       	\
	case OP:					\
	  n_bytes += 1;					\
	  if (packet_get_char())			\
	    tio.FIELD |= NAME;				\
	  else						\
	    tio.FIELD &= ~NAME;				\
	  break;
#define SGTTYCHAR(NAME, OP)
#define SGTTYMODE(NAME, FIELD, OP)
#define SGTTYMODEN(NAME, FIELD, OP)

#include "ttymodes.h"

#undef TTYCHAR
#undef TTYMODE
#undef SGTTYCHAR
#undef SGTTYMODE
#undef SGTTYMODEN

	default:
	  debug("Ignoring unsupported tty mode opcode %d (0x%x)",
		opcode, opcode);
	  /* Opcodes 0 to 127 are defined to have a one-byte argument. */
	  if (opcode >= 0 && opcode < 128)
	    {
	      n_bytes += 1;
	      (void)packet_get_char();
	      break;
	    }
	  else
	    {
	      /* Opcodes 128 to 159 are defined to have an integer argument. */
	      if (opcode >= 128 && opcode < 160)
		{
		  n_bytes += 4;
		  (void)packet_get_int();
		  break;
		}
	    }
	  /* It is a truly undefined opcode (160 to 255).  We have no idea
	     about its arguments.  So we must stop parsing.  Note that some
	     data may be left in the packet; hopefully there is nothing more
	     coming after the mode data. */
	  log("parse_tty_modes: unknown opcode %d", opcode);
	  packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
	  goto set;
	}
    }

 set:
  if (*n_bytes_ptr != n_bytes)
    {
      *n_bytes_ptr = n_bytes;
      return;			/* Don't process bytes passed */
    }

  if (failure == -1)
    return;			/* Packet parsed ok but tty stuff failed */
  
  /* Set the new modes for the terminal. */
  if (tcsetattr(fd, TCSANOW, &tio) < 0)
    log("Setting tty modes failed: %.100s", strerror(errno));
  return;
}