1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include "libbb.h"
41#include "common_bufsiz.h"
42#include "libiproute/utils.h"
43
44struct globals {
45 int saved_disc;
46 struct termios saved_state;
47} FIX_ALIASING;
48#define G (*(struct globals*)bb_common_bufsiz1)
49#define INIT_G() do { setup_common_bufsiz(); } while (0)
50
51#define serial_fd 3
52
53static int tcsetattr_serial_or_warn(struct termios *state)
54{
55 int ret;
56
57 ret = tcsetattr(serial_fd, TCSANOW, state);
58 if (ret != 0) {
59 bb_perror_msg("tcsetattr");
60 return 1;
61 }
62 return ret;
63}
64
65static void restore_state_and_exit(int exitcode) NORETURN;
66static void restore_state_and_exit(int exitcode)
67{
68 struct termios state;
69
70
71 if (ioctl_or_warn(serial_fd, TIOCSETD, &G.saved_disc)) {
72 exitcode = 1;
73 }
74
75
76 memcpy(&state, &G.saved_state, sizeof(state));
77 cfsetispeed(&state, B0);
78 cfsetospeed(&state, B0);
79 exitcode |= tcsetattr_serial_or_warn(&state);
80 sleep(1);
81
82
83 if (tcsetattr_serial_or_warn(&G.saved_state))
84 exit(EXIT_FAILURE);
85
86 if (ENABLE_FEATURE_CLEAN_UP)
87 close(serial_fd);
88
89 exit(exitcode);
90}
91
92static void sig_handler(int signo UNUSED_PARAM)
93{
94 restore_state_and_exit(EXIT_SUCCESS);
95}
96
97int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
98int slattach_main(int argc UNUSED_PARAM, char **argv)
99{
100
101 static const char proto_names[] ALIGN1 =
102 "slip\0"
103 "cslip\0"
104 "slip6\0"
105 "cslip6\0"
106 "adaptive\0"
107 ;
108 static const int int_N_SLIP = N_SLIP;
109
110 int encap, opt, fd;
111 struct termios state;
112 const char *proto = "cslip";
113 const char *extcmd;
114 const char *baud_str;
115 int baud_code = baud_code;
116
117 enum {
118 OPT_p_proto = 1 << 0,
119 OPT_s_baud = 1 << 1,
120 OPT_c_extcmd = 1 << 2,
121 OPT_e_quit = 1 << 3,
122 OPT_h_watch = 1 << 4,
123 OPT_m_nonraw = 1 << 5,
124 OPT_L_local = 1 << 6,
125 OPT_F_noflow = 1 << 7
126 };
127
128 INIT_G();
129
130
131 opt = getopt32(argv, "^" "p:s:c:ehmLF" "\0" "=1",
132 &proto, &baud_str, &extcmd
133 );
134
135 argv += optind;
136
137 encap = index_in_strings(proto_names, proto);
138 if (encap < 0)
139 invarg_1_to_2(proto, "protocol");
140 if (encap > 3)
141 encap = 8;
142
143
144 if (opt & OPT_s_baud) {
145 baud_code = tty_value_to_baud(xatoi(baud_str));
146 if (baud_code < 0)
147 invarg_1_to_2(baud_str, "baud rate");
148 }
149
150
151 fd = open(*argv, O_RDWR | O_NDELAY);
152 if (fd < 0) {
153 char *buf = concat_path_file("/dev", *argv);
154 fd = xopen(buf, O_RDWR | O_NDELAY);
155
156 free(buf);
157 }
158 xmove_fd(fd, serial_fd);
159
160
161 if (tcgetattr(serial_fd, &G.saved_state) != 0)
162 bb_perror_msg_and_die("tcgetattr");
163
164 xioctl(serial_fd, TIOCGETD, &G.saved_disc);
165
166
167 if (!(opt & OPT_e_quit)) {
168 bb_signals(0
169 + (1 << SIGHUP)
170 + (1 << SIGINT)
171 + (1 << SIGQUIT)
172 + (1 << SIGTERM)
173 , sig_handler);
174 }
175
176
177 memcpy(&state, &G.saved_state, sizeof(state));
178 if (!(opt & OPT_m_nonraw)) {
179 memset(&state.c_cc, 0, sizeof(state.c_cc));
180 state.c_cc[VMIN] = 1;
181 state.c_iflag = IGNBRK | IGNPAR;
182
183
184 state.c_cflag = CS8 | HUPCL | CREAD
185 | ((opt & OPT_L_local) ? CLOCAL : 0)
186 | ((opt & OPT_F_noflow) ? 0 : CRTSCTS);
187 cfsetispeed(&state, cfgetispeed(&G.saved_state));
188 cfsetospeed(&state, cfgetospeed(&G.saved_state));
189 }
190 if (opt & OPT_s_baud) {
191 cfsetispeed(&state, baud_code);
192 cfsetospeed(&state, baud_code);
193 }
194
195 if (tcsetattr_serial_or_warn(&state))
196 goto bad;
197
198 if (ioctl_or_warn(serial_fd, TIOCSETD, (void*)&int_N_SLIP))
199 goto bad;
200
201 if (ioctl_or_warn(serial_fd, SIOCSIFENCAP, &encap))
202 goto bad;
203
204
205 if (opt & OPT_e_quit)
206 return EXIT_SUCCESS;
207
208
209
210 if (!(opt & OPT_h_watch))
211 while (1)
212 sleep(24*60*60);
213
214
215 while (1) {
216 int modem_stat;
217 if (ioctl(serial_fd, TIOCMGET, &modem_stat))
218 break;
219 if (!(modem_stat & TIOCM_CAR))
220 break;
221 sleep(15);
222 }
223
224
225 if (opt & OPT_c_extcmd)
226 system(extcmd);
227
228
229 restore_state_and_exit(EXIT_SUCCESS);
230 bad:
231 restore_state_and_exit(EXIT_FAILURE);
232}
233