X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fsys-linux.c;h=513fc3dc009ef3010f434328121e8dde4b918137;hb=b21711c71f2bf9537f5985339cf6e224738315ef;hp=2ede95f7566906a31f748e74d7021a12a7329005;hpb=ad60737852c22a3c19c379bd94ecc76b80386f4f;p=ppp.git diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 2ede95f..513fc3d 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -69,6 +69,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -85,12 +89,13 @@ #include #include #include +#ifdef HAVE_UTMP_H #include +#endif #include #include #include #include -#include #include /* This is in netdevice.h. However, this compile will fail miserably if @@ -104,7 +109,6 @@ #if !defined(__GLIBC__) || __GLIBC__ >= 2 #include /* glibc 2 conflicts with linux/types.h */ -#include #include #include #include @@ -159,19 +163,11 @@ #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; -}; +/* + * Instead of system header file 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 @@ -691,11 +687,11 @@ static int make_ppp_unit(void) if (x == 0 && req_ifname[0] != '\0') { struct ifreq ifr; - char t[MAXIFNAMELEN]; + char t[IFNAMSIZ]; memset(&ifr, 0, sizeof(struct ifreq)); slprintf(t, sizeof(t), "%s%d", PPP_DRV_NAME, ifunit); - strlcpy(ifr.ifr_name, t, IF_NAMESIZE); - strlcpy(ifr.ifr_newname, req_ifname, IF_NAMESIZE); + strlcpy(ifr.ifr_name, t, IFNAMSIZ); + strlcpy(ifr.ifr_newname, req_ifname, IFNAMSIZ); x = ioctl(sock_fd, SIOCSIFNAME, &ifr); if (x < 0) error("Couldn't rename interface %s to %s: %m", t, req_ifname); @@ -1047,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, @@ -1092,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; } /******************************************************************** @@ -3007,7 +3000,14 @@ static int sif6addr_rtnetlink(unsigned int iface, eui64_t our_eui64, eui64_t his /* error == 0 indicates success, negative value is errno code */ if (nlresp.nlerr.error != 0) { - error("sif6addr_rtnetlink: %s (line %d)", strerror(-nlresp.nlerr.error), __LINE__); + /* + * Linux kernel versions prior 3.11 do not support setting IPv6 peer + * addresses and error response is expected. On older kernel versions + * do not show this error message. On error pppd tries to fallback to + * the old IOCTL method. + */ + if (kernel_version >= KVERSION(3,11,0)) + error("sif6addr_rtnetlink: %s (line %d)", strerror(-nlresp.nlerr.error), __LINE__); return 0; } @@ -3023,6 +3023,7 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) struct in6_ifreq ifr6; struct ifreq ifr; struct in6_rtmsg rt6; + int ret; if (sock6_fd < 0) { errno = -sock6_fd; @@ -3038,8 +3039,16 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) if (kernel_version >= KVERSION(2,1,16)) { /* Set both local address and remote peer address (with route for it) via rtnetlink */ - return sif6addr_rtnetlink(ifr.ifr_ifindex, our_eui64, his_eui64); + ret = sif6addr_rtnetlink(ifr.ifr_ifindex, our_eui64, his_eui64); } else { + ret = 0; + } + + /* + * Linux kernel versions prior 3.11 do not support setting IPv6 peer address + * via rtnetlink. So if sif6addr_rtnetlink() fails then try old IOCTL method. + */ + if (!ret) { /* Local interface */ memset(&ifr6, 0, sizeof(ifr6)); IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);