From d65f6713c8514b016629b87d44d5154d70776f7b Mon Sep 17 00:00:00 2001 From: pali <7141871+pali@users.noreply.github.com> Date: Sat, 5 Jun 2021 03:43:24 +0200 Subject: [PATCH] pppd: Add support for arbitrary baud rates via BOTHER on Linux (#278) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Most Linux architectures and drivers support arbitrary baud rate BOTHER values via TCGETS2 and TCSETS2 ioctls in struct termios2. This patch implements support for BOTHER and struct termios2 which allows pppd to use any baud rate on Linux systems where architecture and drivers have support for it. By default standard values are used. Support for BOTHER is enabled during compilation when header files have appropriate definitions of TCGETS2 and TCSETS2 ioctls. Because there is no glibc support for BOTHER and struct termios2 yet, pppd defines own BOTHER macro and struct termios2. Signed-off-by: Pali Rohár --- pppd/pppd.8 | 4 +-- pppd/sys-linux.c | 75 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/pppd/pppd.8 b/pppd/pppd.8 index 95051bf..cd4b9eb 100644 --- a/pppd/pppd.8 +++ b/pppd/pppd.8 @@ -55,8 +55,8 @@ non-privileged user. .I speed An option that is a decimal number is taken as the desired baud rate for the serial device. On systems such as -4.4BSD and NetBSD, any speed can be specified. Other systems -(e.g. Linux, SunOS) only support the commonly-used baud rates. +Linux, 4.4BSD and NetBSD, any speed can be specified. Other systems +(e.g. SunOS) only support the commonly-used baud rates. .TP .B asyncmap \fImap This option sets the Async-Control-Character-Map (ACCM) for this end diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index b0ad508..c05047c 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -104,6 +104,7 @@ #if !defined(__GLIBC__) || __GLIBC__ >= 2 #include /* glibc 2 conflicts with linux/types.h */ +#include #include #include #include @@ -158,6 +159,20 @@ #include #endif +#ifndef BOTHER +#define BOTHER 0010000 +#endif +struct termios2 { + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_cflag; + unsigned int c_lflag; + unsigned char c_line; + unsigned char c_cc[19]; + unsigned int c_ispeed; + unsigned int c_ospeed; +}; + #ifdef INET6 #ifndef _LINUX_IN6_H /* @@ -898,6 +913,12 @@ struct speed { #ifdef B460800 { 460800, B460800 }, #endif +#ifdef B500000 + { 500000, B500000 }, +#endif +#ifdef B576000 + { 576000, B576000 }, +#endif #ifdef B921600 { 921600, B921600 }, #endif @@ -942,7 +963,6 @@ static int translate_speed (int bps) if (bps == speedp->speed_int) return speedp->speed_val; } - warn("speed %d not supported", bps); } return 0; } @@ -1021,26 +1041,57 @@ void set_up_tty(int tty_fd, int local) if (stop_bits >= 2) tios.c_cflag |= CSTOPB; - speed = translate_speed(inspeed); - if (speed) { - cfsetospeed (&tios, speed); - cfsetispeed (&tios, speed); + if (inspeed) { + speed = translate_speed(inspeed); + if (speed) { + cfsetospeed (&tios, speed); + cfsetispeed (&tios, speed); + speed = cfgetospeed(&tios); + } + baud_rate = baud_rate_of(speed); } -/* - * We can't proceed if the serial port speed is B0, - * since that implies that the serial port is disabled. - */ else { speed = cfgetospeed(&tios); - if (speed == B0) - fatal("Baud rate for %s is 0; need explicit baud rate", devnam); + baud_rate = baud_rate_of(speed); } while (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0 && !ok_error(errno)) if (errno != EINTR) fatal("tcsetattr: %m (line %d)", __LINE__); - baud_rate = baud_rate_of(speed); +/* Most Linux architectures and drivers support arbitrary baud rate values via BOTHER */ +#ifdef TCGETS2 + if (!baud_rate) { + struct termios2 tios2; + if (ioctl(tty_fd, TCGETS2, &tios2) == 0) { + if (inspeed) { + tios2.c_cflag &= ~CBAUD; + tios2.c_cflag |= BOTHER; + tios2.c_ispeed = inspeed; + tios2.c_ospeed = inspeed; +#ifdef TCSETS2 + if (ioctl(tty_fd, TCSETS2, &tios2) == 0) + baud_rate = inspeed; +#endif + } else { + if ((tios2.c_cflag & CBAUD) == BOTHER && tios2.c_ospeed) + baud_rate = tios2.c_ospeed; + } + } + } +#endif + +/* + * We can't proceed if the serial port baud rate is unknown, + * since that implies that the serial port is disabled. + */ + if (!baud_rate) { + if (inspeed) + fatal("speed %d not supported", inspeed); + else + fatal("Baud rate for %s is 0; need explicit baud rate", devnam); + } + restore_term = 1; } -- 2.39.2