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#include "libbb.h"
36
37#define SOH 0x01
38#define STX 0x02
39#define EOT 0x04
40#define ACK 0x06
41#define NAK 0x15
42#define BS 0x08
43#define PAD 0x1A
44
45
46
47
48
49
50
51
52
53#define TIMEOUT 1
54#define TIMEOUT_LONG 10
55#define MAXERRORS 10
56
57#define read_fd STDIN_FILENO
58#define write_fd STDOUT_FILENO
59
60static int read_byte(unsigned timeout)
61{
62 unsigned char buf;
63 int n;
64
65 alarm(timeout);
66
67 n = read(read_fd, &buf, 1);
68 alarm(0);
69 if (n == 1)
70 return buf;
71 return -1;
72}
73
74static int receive(int file_fd)
75{
76 unsigned char blockBuf[1024];
77 unsigned blockLength = 0;
78 unsigned errors = 0;
79 unsigned wantBlockNo = 1;
80 unsigned length = 0;
81 int do_crc = 1;
82 char reply_char;
83 unsigned timeout = TIMEOUT_LONG;
84
85
86 tcflush(read_fd, TCIFLUSH);
87
88
89 reply_char = 'C';
90 full_write(write_fd, &reply_char, 1);
91
92 for (;;) {
93 int blockBegin;
94 int blockNo, blockNoOnesCompl;
95 int cksum_or_crc;
96 unsigned expected;
97 int i, j;
98
99 blockBegin = read_byte(timeout);
100 if (blockBegin < 0)
101 goto timeout;
102
103
104 if (blockBegin == EOT) {
105
106
107 if (blockLength >= 3
108 && blockBuf[blockLength - 1] == PAD
109 && blockBuf[blockLength - 2] == PAD
110 && blockBuf[blockLength - 3] == PAD
111 ) {
112 while (blockLength
113 && blockBuf[blockLength - 1] == PAD
114 ) {
115 blockLength--;
116 }
117 }
118 }
119
120 errno = 0;
121 if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
122 bb_simple_perror_msg(bb_msg_write_error);
123 goto fatal;
124 }
125
126 timeout = TIMEOUT;
127 reply_char = NAK;
128
129 switch (blockBegin) {
130 case SOH:
131 case STX:
132 break;
133 case EOT:
134 reply_char = ACK;
135 full_write(write_fd, &reply_char, 1);
136 return length;
137 default:
138 goto error;
139 }
140
141
142 blockNo = read_byte(TIMEOUT);
143 if (blockNo < 0)
144 goto timeout;
145
146
147 blockNoOnesCompl = read_byte(TIMEOUT);
148 if (blockNoOnesCompl < 0)
149 goto timeout;
150
151 if (blockNo != (255 - blockNoOnesCompl)) {
152 bb_simple_error_msg("bad block ones compl");
153 goto error;
154 }
155
156 blockLength = (blockBegin == SOH) ? 128 : 1024;
157
158 for (i = 0; i < blockLength; i++) {
159 int cc = read_byte(TIMEOUT);
160 if (cc < 0)
161 goto timeout;
162 blockBuf[i] = cc;
163 }
164
165 cksum_or_crc = read_byte(TIMEOUT);
166 if (cksum_or_crc < 0)
167 goto timeout;
168 if (do_crc) {
169 cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT);
170 if (cksum_or_crc < 0)
171 goto timeout;
172 }
173
174 if (blockNo == ((wantBlockNo - 1) & 0xff)) {
175
176
177
178 blockLength = 0;
179 goto next;
180 }
181 if (blockNo != (wantBlockNo & 0xff)) {
182 bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
183 goto error;
184 }
185
186 expected = 0;
187 if (do_crc) {
188 for (i = 0; i < blockLength; i++) {
189 expected = expected ^ blockBuf[i] << 8;
190 for (j = 0; j < 8; j++) {
191 if (expected & 0x8000)
192 expected = (expected << 1) ^ 0x1021;
193 else
194 expected = (expected << 1);
195 }
196 }
197 expected &= 0xffff;
198 } else {
199 for (i = 0; i < blockLength; i++)
200 expected += blockBuf[i];
201 expected &= 0xff;
202 }
203 if (cksum_or_crc != expected) {
204 bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
205 : "checksum error, expected 0x%02x, got 0x%02x",
206 expected, cksum_or_crc);
207 goto error;
208 }
209
210 wantBlockNo++;
211 length += blockLength;
212 next:
213 errors = 0;
214 reply_char = ACK;
215 full_write(write_fd, &reply_char, 1);
216 continue;
217 error:
218 timeout:
219 blockLength = 0;
220 errors++;
221 if (errors == MAXERRORS) {
222
223
224
225 if (reply_char == 'C') {
226 reply_char = NAK;
227 errors = 0;
228 do_crc = 0;
229 goto timeout;
230 }
231 bb_simple_error_msg("too many errors; giving up");
232 fatal:
233
234 safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10);
235 return -1;
236 }
237
238
239 tcflush(read_fd, TCIFLUSH);
240
241 full_write(write_fd, &reply_char, 1);
242 }
243}
244
245static void sigalrm_handler(int UNUSED_PARAM signum)
246{
247}
248
249int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
250int rx_main(int argc UNUSED_PARAM, char **argv)
251{
252 struct termios tty, orig_tty;
253 int termios_err;
254 int file_fd;
255 int n;
256
257
258
259
260
261 file_fd = xopen(single_argv(argv), O_RDWR|O_CREAT|O_TRUNC);
262
263 termios_err = tcgetattr(read_fd, &tty);
264 if (termios_err == 0) {
265
266 orig_tty = tty;
267 cfmakeraw(&tty);
268 tcsetattr(read_fd, TCSAFLUSH, &tty);
269 }
270
271
272 signal_no_SA_RESTART_empty_mask(SIGALRM, sigalrm_handler);
273
274 n = receive(file_fd);
275
276 if (termios_err == 0)
277 tcsetattr(read_fd, TCSAFLUSH, &orig_tty);
278 if (ENABLE_FEATURE_CLEAN_UP)
279 close(file_fd);
280 fflush_stdout_and_exit(n >= 0);
281}
282