From 4aca87515a5083ae0e31ce3177189fd43b6d05ac Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 3 Jan 2015 13:58:15 +0100 Subject: patch to Vanilla Tomato 1.28 --- release/src/router/busybox/networking/slattach.c | 245 +++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 release/src/router/busybox/networking/slattach.c (limited to 'release/src/router/busybox/networking/slattach.c') diff --git a/release/src/router/busybox/networking/slattach.c b/release/src/router/busybox/networking/slattach.c new file mode 100644 index 00000000..d3212bb4 --- /dev/null +++ b/release/src/router/busybox/networking/slattach.c @@ -0,0 +1,245 @@ +/* vi: set sw=4 ts=4: */ +/* + * Stripped down version of net-tools for busybox. + * + * Author: Ignacio Garcia Perez (iggarpe at gmail dot com) + * + * License: GPLv2 or later, see LICENSE file in this tarball. + * + * There are some differences from the standard net-tools slattach: + * + * - The -l option is not supported. + * + * - The -F options allows disabling of RTS/CTS flow control. + */ + +#include "libbb.h" +#include "libiproute/utils.h" /* invarg() */ + +struct globals { + int handle; + int saved_disc; + struct termios saved_state; +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define handle (G.handle ) +#define saved_disc (G.saved_disc ) +#define saved_state (G.saved_state ) +#define INIT_G() do { } while (0) + + +/* + * Save tty state and line discipline + * + * It is fine here to bail out on errors, since we haven modified anything yet + */ +static void save_state(void) +{ + /* Save line status */ + if (tcgetattr(handle, &saved_state) < 0) + bb_perror_msg_and_die("get state"); + + /* Save line discipline */ + xioctl(handle, TIOCGETD, &saved_disc); +} + +static int set_termios_state_or_warn(struct termios *state) +{ + int ret; + + ret = tcsetattr(handle, TCSANOW, state); + if (ret < 0) { + bb_perror_msg("set state"); + return 1; /* used as exitcode */ + } + return 0; +} + +/* + * Restore state and line discipline for ALL managed ttys + * + * Restoring ALL managed ttys is the only way to have a single + * hangup delay. + * + * Go on after errors: we want to restore as many controlled ttys + * as possible. + */ +static void restore_state_and_exit(int exitcode) NORETURN; +static void restore_state_and_exit(int exitcode) +{ + struct termios state; + + /* Restore line discipline */ + if (ioctl_or_warn(handle, TIOCSETD, &saved_disc) < 0) { + exitcode = 1; + } + + /* Hangup */ + memcpy(&state, &saved_state, sizeof(state)); + cfsetispeed(&state, B0); + cfsetospeed(&state, B0); + if (set_termios_state_or_warn(&state)) + exitcode = 1; + sleep(1); + + /* Restore line status */ + if (set_termios_state_or_warn(&saved_state)) + exit(EXIT_FAILURE); + if (ENABLE_FEATURE_CLEAN_UP) + close(handle); + + exit(exitcode); +} + +/* + * Set tty state, line discipline and encapsulation + */ +static void set_state(struct termios *state, int encap) +{ + int disc; + + /* Set line status */ + if (set_termios_state_or_warn(state)) + goto bad; + /* Set line discliple (N_SLIP always) */ + disc = N_SLIP; + if (ioctl_or_warn(handle, TIOCSETD, &disc) < 0) { + goto bad; + } + + /* Set encapsulation (SLIP, CSLIP, etc) */ + if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) { + bad: + restore_state_and_exit(EXIT_FAILURE); + } +} + +static void sig_handler(int signo UNUSED_PARAM) +{ + restore_state_and_exit(EXIT_SUCCESS); +} + +int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int slattach_main(int argc UNUSED_PARAM, char **argv) +{ + /* Line discipline code table */ + static const char proto_names[] ALIGN1 = + "slip\0" /* 0 */ + "cslip\0" /* 1 */ + "slip6\0" /* 2 */ + "cslip6\0" /* 3 */ + "adaptive\0" /* 8 */ + ; + + int i, encap, opt; + struct termios state; + const char *proto = "cslip"; + const char *extcmd; /* Command to execute after hangup */ + const char *baud_str; + int baud_code = -1; /* Line baud rate (system code) */ + + enum { + OPT_p_proto = 1 << 0, + OPT_s_baud = 1 << 1, + OPT_c_extcmd = 1 << 2, + OPT_e_quit = 1 << 3, + OPT_h_watch = 1 << 4, + OPT_m_nonraw = 1 << 5, + OPT_L_local = 1 << 6, + OPT_F_noflow = 1 << 7 + }; + + INIT_G(); + + /* Parse command line options */ + opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd); + /*argc -= optind;*/ + argv += optind; + + if (!*argv) + bb_show_usage(); + + encap = index_in_strings(proto_names, proto); + + if (encap < 0) + invarg(proto, "protocol"); + if (encap > 3) + encap = 8; + + /* We want to know if the baud rate is valid before we start touching the ttys */ + if (opt & OPT_s_baud) { + baud_code = tty_value_to_baud(xatoi(baud_str)); + if (baud_code < 0) + invarg(baud_str, "baud rate"); + } + + /* Trap signals in order to restore tty states upon exit */ + if (!(opt & OPT_e_quit)) { + bb_signals(0 + + (1 << SIGHUP) + + (1 << SIGINT) + + (1 << SIGQUIT) + + (1 << SIGTERM) + , sig_handler); + } + + /* Open tty */ + handle = open(*argv, O_RDWR | O_NDELAY); + if (handle < 0) { + char *buf = concat_path_file("/dev", *argv); + handle = xopen(buf, O_RDWR | O_NDELAY); + /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ + free(buf); + } + + /* Save current tty state */ + save_state(); + + /* Configure tty */ + memcpy(&state, &saved_state, sizeof(state)); + if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ + memset(&state.c_cc, 0, sizeof(state.c_cc)); + state.c_cc[VMIN] = 1; + state.c_iflag = IGNBRK | IGNPAR; + state.c_oflag = 0; + state.c_lflag = 0; + state.c_cflag = CS8 | HUPCL | CREAD + | ((opt & OPT_L_local) ? CLOCAL : 0) + | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); + cfsetispeed(&state, cfgetispeed(&saved_state)); + cfsetospeed(&state, cfgetospeed(&saved_state)); + } + + if (opt & OPT_s_baud) { + cfsetispeed(&state, baud_code); + cfsetospeed(&state, baud_code); + } + + set_state(&state, encap); + + /* Exit now if option -e was passed */ + if (opt & OPT_e_quit) + return 0; + + /* If we're not requested to watch, just keep descriptor open + * until we are killed */ + if (!(opt & OPT_h_watch)) + while (1) + sleep(24*60*60); + + /* Watch line for hangup */ + while (1) { + if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) + goto no_carrier; + sleep(15); + } + + no_carrier: + + /* Execute command on hangup */ + if (opt & OPT_c_extcmd) + system(extcmd); + + /* Restore states and exit */ + restore_state_and_exit(EXIT_SUCCESS); +} -- cgit v1.2.3-54-g00ecf