]> git.ozlabs.org Git - ppp.git/commitdiff
Merge branch 'fix-compiler-warnings-2' of https://github.com/enaess/ppp
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 27 Sep 2021 07:12:00 +0000 (17:12 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Mon, 27 Sep 2021 07:12:00 +0000 (17:12 +1000)
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pppd/Makefile.am
pppd/sys-linux.c
pppd/termios_linux.h [new file with mode: 0644]

index 22445072f78b8e3add93bd7aefb8dd6ed6b47e4e..03c6fd448171eb9c80c9dccc0a79d71de55b963a 100644 (file)
@@ -72,7 +72,7 @@ pppd_LDFLAGS =
 pppd_LIBS =
 
 if LINUX
-pppd_SOURCES += sys-linux.c
+pppd_SOURCES += sys-linux.c termios_linux.h
 pppd_LIBS += $(CRYPT_LIBS) $(UTIL_LIBS)
 endif
 
index 4c04e7e5c2d005bf0a37994b1dbc21cda4e4b488..1e00366ba2914f5c1fba36fabd98e17edecaef72 100644 (file)
@@ -96,7 +96,6 @@
 #include <signal.h>
 #include <fcntl.h>
 #include <ctype.h>
-#include <termios.h>
 #include <unistd.h>
 
 /* This is in netdevice.h. However, this compile will fail miserably if
 
 #if !defined(__GLIBC__) || __GLIBC__ >= 2
 #include <asm/types.h>         /* glibc 2 conflicts with linux/types.h */
-#include <asm/ioctls.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/route.h>
 #include <sys/locks.h>
 #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;
-};
+/*
+ * Instead of system header file <termios.h> use local "termios_linux.h" header
+ * file as it provides additional support for arbitrary baud rates via BOTHER.
+ */
+#include "termios_linux.h"
 
 #ifdef INET6
 #ifndef _LINUX_IN6_H
@@ -1053,40 +1043,32 @@ void set_up_tty(int tty_fd, int local)
            cfsetospeed (&tios, speed);
            cfsetispeed (&tios, speed);
            speed = cfgetospeed(&tios);
+           baud_rate = baud_rate_of(speed);
+       } else {
+#ifdef BOTHER
+           tios.c_cflag &= ~CBAUD;
+           tios.c_cflag |= BOTHER;
+           tios.c_ospeed = inspeed;
+#ifdef IBSHIFT
+           /* B0 sets input baudrate to the output baudrate */
+           tios.c_cflag &= ~(CBAUD << IBSHIFT);
+           tios.c_cflag |= B0 << IBSHIFT;
+           tios.c_ispeed = inspeed;
+#endif
+           baud_rate = inspeed;
+#else
+           baud_rate = 0;
+#endif
        }
-       baud_rate = baud_rate_of(speed);
     }
     else {
        speed = cfgetospeed(&tios);
        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__);
-    restore_term = 1;
-
-/* 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;
+#ifdef BOTHER
+       if (!baud_rate)
+           baud_rate = tios.c_ospeed;
 #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,
@@ -1098,6 +1080,11 @@ void set_up_tty(int tty_fd, int local)
        else
            fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
     }
+
+    while (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0 && !ok_error(errno))
+       if (errno != EINTR)
+           fatal("tcsetattr: %m (line %d)", __LINE__);
+    restore_term = 1;
 }
 
 /********************************************************************
diff --git a/pppd/termios_linux.h b/pppd/termios_linux.h
new file mode 100644 (file)
index 0000000..9c79d16
--- /dev/null
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-4-Clause OR BSD-3-Clause OR BSD-2-Clause */
+/*
+ * termios fuctions to support arbitrary baudrates (on Linux)
+ *
+ * Copyright (c) 2021 Pali Rohár <pali@kernel.org>
+ * Copyright (c) 2021 Marek Behún <kabel@kernel.org>
+ */
+
+#ifndef _TERMIOS_LINUX_H_
+#define _TERMIOS_LINUX_H_
+
+/*
+ * We need to use raw TCGETS2/TCSETS2 or TCGETS/TCSETS ioctls with the BOTHER
+ * flag in struct termios2/termios, defined in Linux headers <asm/ioctls.h>
+ * and <asm/termbits.h>. Since these headers conflict with glibc's header file
+ * <termios.h>, it is not possible to use libc's termios functions and we need
+ * to reimplement them via ioctl() calls.
+ *
+ * An arbitrary baudrate is supported when the macro BOTHER is defined. The
+ * baudrate value itself is then stored into the c_ospeed and c_ispeed members.
+ * If ioctls TCGETS2/TCSETS2 are defined and supported then these fields are
+ * present in struct termios2, otherwise these fields are present in struct
+ * termios.
+ *
+ * Note that the Bnnn constants from <termios.h> need not be compatible with
+ * Bnnn constants from <asm/termbits.h>.
+ */
+
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <asm/ioctls.h>
+#include <asm/termbits.h>
+
+#if defined(BOTHER) && defined(TCGETS2)
+#define termios termios2
+#endif
+
+static inline int tcgetattr(int fd, struct termios *t)
+{
+#if defined(BOTHER) && defined(TCGETS2)
+       return ioctl(fd, TCGETS2, t);
+#else
+       return ioctl(fd, TCGETS, t);
+#endif
+}
+
+static inline int tcsetattr(int fd, int a, const struct termios *t)
+{
+       int cmd;
+
+       switch (a) {
+#if defined(BOTHER) && defined(TCGETS2)
+       case TCSANOW:
+               cmd = TCSETS2;
+               break;
+       case TCSADRAIN:
+               cmd = TCSETSW2;
+               break;
+       case TCSAFLUSH:
+               cmd = TCSETSF2;
+               break;
+#else
+       case TCSANOW:
+               cmd = TCSETS;
+               break;
+       case TCSADRAIN:
+               cmd = TCSETSW;
+               break;
+       case TCSAFLUSH:
+               cmd = TCSETSF;
+               break;
+#endif
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       return ioctl(fd, cmd, t);
+}
+
+static inline int tcdrain(int fd)
+{
+       return ioctl(fd, TCSBRK, 1);
+}
+
+static inline int tcflush(int fd, int q)
+{
+       return ioctl(fd, TCFLSH, q);
+}
+
+static inline int tcsendbreak(int fd, int d)
+{
+#ifdef TCSBRKP
+       return ioctl(fd, TCSBRKP, d);
+#else
+       return ioctl(fd, TCSBRK, 0);
+#endif
+}
+
+static inline int tcflow(int fd, int a)
+{
+       return ioctl(fd, TCXONC, a);
+}
+
+static inline pid_t tcgetsid(int fd)
+{
+       pid_t sid;
+
+       if (ioctl(fd, TIOCGSID, &sid) < 0)
+               return (pid_t)-1;
+
+       return sid;
+}
+
+static inline speed_t cfgetospeed(const struct termios *t)
+{
+       return t->c_cflag & CBAUD;
+}
+
+static inline int cfsetospeed(struct termios *t, speed_t s)
+{
+       if (s & ~CBAUD) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       t->c_cflag &= ~CBAUD;
+       t->c_cflag |= s;
+
+       return 0;
+}
+
+#ifdef IBSHIFT
+static inline speed_t cfgetispeed(const struct termios *t)
+{
+       speed_t s = (t->c_cflag >> IBSHIFT) & CBAUD;
+
+       if (s == B0)
+               return cfgetospeed(t);
+       else
+               return s;
+}
+
+static inline int cfsetispeed(struct termios *t, speed_t s)
+{
+       if (s == 0)
+               s = B0;
+
+       if (s & ~CBAUD) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       t->c_cflag &= ~(CBAUD << IBSHIFT);
+       t->c_cflag |= s << IBSHIFT;
+
+       return 0;
+}
+#else /* !IBSHIFT */
+static inline speed_t cfgetispeed(const struct termios *t)
+{
+       return cfgetospeed(t);
+}
+
+static inline int cfsetispeed(struct termios *t, speed_t s)
+{
+       return cfsetospeed(t, s);
+}
+#endif /* !IBSHIFT */
+
+static inline int cfsetspeed(struct termios *t, speed_t s)
+{
+       if (cfsetospeed(t, s))
+               return -1;
+#ifdef IBSHIFT
+       if (cfsetispeed(t, s))
+               return -1;
+#endif
+
+       return 0;
+}
+
+static void cfmakeraw(struct termios *t)
+{
+       t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR |
+                       ICRNL | IXON);
+       t->c_oflag &= ~OPOST;
+       t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+       t->c_cflag &= ~(CSIZE | PARENB);
+       t->c_cflag |= CS8;
+}
+
+#endif /* _TERMIOS_LINUX_H_ */