1 |
/* vi: set sw=4 ts=4: */ |
/* vi: set sw=4 ts=4: */ |
2 |
/*------------------------------------------------------------------------- |
/* |
|
* Filename: xmodem.c |
|
3 |
* Copyright: Copyright (C) 2001, Hewlett-Packard Company |
* Copyright: Copyright (C) 2001, Hewlett-Packard Company |
4 |
* Author: Christopher Hoover <ch@hpl.hp.com> |
* Author: Christopher Hoover <ch@hpl.hp.com> |
5 |
* Description: xmodem functionality for uploading of kernels |
* Description: xmodem functionality for uploading of kernels |
6 |
* and the like |
* and the like |
7 |
* Created at: Thu Dec 20 01:58:08 PST 2001 |
* Created at: Thu Dec 20 01:58:08 PST 2001 |
8 |
*-----------------------------------------------------------------------*/ |
* |
9 |
/* |
* xmodem functionality for uploading of kernels and the like |
|
* xmodem.c: xmodem functionality for uploading of kernels and |
|
|
* the like |
|
10 |
* |
* |
11 |
* Copyright (C) 2001 Hewlett-Packard Laboratories |
* Copyright (C) 2001 Hewlett-Packard Laboratories |
12 |
* |
* |
23 |
#define ACK 0x06 |
#define ACK 0x06 |
24 |
#define NAK 0x15 |
#define NAK 0x15 |
25 |
#define BS 0x08 |
#define BS 0x08 |
26 |
|
#define PAD 0x1A |
27 |
|
|
28 |
/* |
/* |
29 |
Cf: |
Cf: |
42 |
|
|
43 |
static int read_byte(unsigned timeout) |
static int read_byte(unsigned timeout) |
44 |
{ |
{ |
45 |
char buf[1]; |
unsigned char buf; |
46 |
int n; |
int n; |
47 |
|
|
48 |
alarm(timeout); |
alarm(timeout); |
49 |
/* NOT safe_read! We want ALRM to interrupt us */ |
/* NOT safe_read! We want ALRM to interrupt us */ |
50 |
n = read(read_fd, buf, 1); |
n = read(read_fd, &buf, 1); |
51 |
alarm(0); |
alarm(0); |
52 |
if (n == 1) |
if (n == 1) |
53 |
return (unsigned char)buf[0]; |
return buf; |
54 |
return -1; |
return -1; |
55 |
} |
} |
56 |
|
|
57 |
static int receive(/*int read_fd, */int file_fd) |
static int receive(/*int read_fd, */int file_fd) |
58 |
{ |
{ |
59 |
unsigned char blockBuf[1024]; |
unsigned char blockBuf[1024]; |
60 |
|
unsigned blockLength = 0; |
61 |
unsigned errors = 0; |
unsigned errors = 0; |
62 |
unsigned wantBlockNo = 1; |
unsigned wantBlockNo = 1; |
63 |
unsigned length = 0; |
unsigned length = 0; |
64 |
int do_crc = 1; |
int do_crc = 1; |
65 |
char nak = 'C'; |
char reply_char; |
66 |
unsigned timeout = TIMEOUT_LONG; |
unsigned timeout = TIMEOUT_LONG; |
67 |
|
|
68 |
/* Flush pending input */ |
/* Flush pending input */ |
69 |
tcflush(read_fd, TCIFLUSH); |
tcflush(read_fd, TCIFLUSH); |
70 |
|
|
71 |
/* Ask for CRC; if we get errors, we will go with checksum */ |
/* Ask for CRC; if we get errors, we will go with checksum */ |
72 |
full_write(write_fd, &nak, 1); |
reply_char = 'C'; |
73 |
|
full_write(write_fd, &reply_char, 1); |
74 |
|
|
75 |
for (;;) { |
for (;;) { |
76 |
int blockBegin; |
int blockBegin; |
77 |
int blockNo, blockNoOnesCompl; |
int blockNo, blockNoOnesCompl; |
78 |
int blockLength; |
int cksum_or_crc; |
|
int cksum_crc; /* cksum OR crc */ |
|
79 |
int expected; |
int expected; |
80 |
int i,j; |
int i, j; |
81 |
|
|
82 |
blockBegin = read_byte(timeout); |
blockBegin = read_byte(timeout); |
83 |
if (blockBegin < 0) |
if (blockBegin < 0) |
84 |
goto timeout; |
goto timeout; |
85 |
|
|
86 |
|
/* If last block, remove padding */ |
87 |
|
if (blockBegin == EOT) { |
88 |
|
/* Data blocks can be padded with ^Z characters */ |
89 |
|
/* This code tries to detect and remove them */ |
90 |
|
if (blockLength >= 3 |
91 |
|
&& blockBuf[blockLength - 1] == PAD |
92 |
|
&& blockBuf[blockLength - 2] == PAD |
93 |
|
&& blockBuf[blockLength - 3] == PAD |
94 |
|
) { |
95 |
|
while (blockLength |
96 |
|
&& blockBuf[blockLength - 1] == PAD |
97 |
|
) { |
98 |
|
blockLength--; |
99 |
|
} |
100 |
|
} |
101 |
|
} |
102 |
|
/* Write previously received block */ |
103 |
|
if (blockLength) { |
104 |
|
errno = 0; |
105 |
|
if (full_write(file_fd, blockBuf, blockLength) != blockLength) { |
106 |
|
bb_perror_msg("can't write to file"); |
107 |
|
goto fatal; |
108 |
|
} |
109 |
|
} |
110 |
|
|
111 |
timeout = TIMEOUT; |
timeout = TIMEOUT; |
112 |
nak = NAK; |
reply_char = NAK; |
113 |
|
|
114 |
switch (blockBegin) { |
switch (blockBegin) { |
115 |
case SOH: |
case SOH: |
116 |
case STX: |
case STX: |
117 |
break; |
break; |
|
|
|
118 |
case EOT: |
case EOT: |
119 |
nak = ACK; |
reply_char = ACK; |
120 |
full_write(write_fd, &nak, 1); |
full_write(write_fd, &reply_char, 1); |
121 |
return length; |
return length; |
|
|
|
122 |
default: |
default: |
123 |
goto error; |
goto error; |
124 |
} |
} |
125 |
|
|
126 |
/* block no */ |
/* Block no */ |
127 |
blockNo = read_byte(TIMEOUT); |
blockNo = read_byte(TIMEOUT); |
128 |
if (blockNo < 0) |
if (blockNo < 0) |
129 |
goto timeout; |
goto timeout; |
130 |
|
|
131 |
/* block no one's compliment */ |
/* Block no, in one's complement form */ |
132 |
blockNoOnesCompl = read_byte(TIMEOUT); |
blockNoOnesCompl = read_byte(TIMEOUT); |
133 |
if (blockNoOnesCompl < 0) |
if (blockNoOnesCompl < 0) |
134 |
goto timeout; |
goto timeout; |
148 |
} |
} |
149 |
|
|
150 |
if (do_crc) { |
if (do_crc) { |
151 |
cksum_crc = read_byte(TIMEOUT); |
cksum_or_crc = read_byte(TIMEOUT); |
152 |
if (cksum_crc < 0) |
if (cksum_or_crc < 0) |
153 |
goto timeout; |
goto timeout; |
154 |
cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT); |
cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT); |
155 |
if (cksum_crc < 0) |
if (cksum_or_crc < 0) |
156 |
goto timeout; |
goto timeout; |
157 |
} else { |
} else { |
158 |
cksum_crc = read_byte(TIMEOUT); |
cksum_or_crc = read_byte(TIMEOUT); |
159 |
if (cksum_crc < 0) |
if (cksum_or_crc < 0) |
160 |
goto timeout; |
goto timeout; |
161 |
} |
} |
162 |
|
|
177 |
expected = expected ^ blockBuf[i] << 8; |
expected = expected ^ blockBuf[i] << 8; |
178 |
for (j = 0; j < 8; j++) { |
for (j = 0; j < 8; j++) { |
179 |
if (expected & 0x8000) |
if (expected & 0x8000) |
180 |
expected = expected << 1 ^ 0x1021; |
expected = (expected << 1) ^ 0x1021; |
181 |
else |
else |
182 |
expected = expected << 1; |
expected = (expected << 1); |
183 |
} |
} |
184 |
} |
} |
185 |
expected &= 0xffff; |
expected &= 0xffff; |
188 |
expected += blockBuf[i]; |
expected += blockBuf[i]; |
189 |
expected &= 0xff; |
expected &= 0xff; |
190 |
} |
} |
191 |
if (cksum_crc != expected) { |
if (cksum_or_crc != expected) { |
192 |
bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x" |
bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x" |
193 |
: "checksum error, expected 0x%02x, got 0x%02x", |
: "checksum error, expected 0x%02x, got 0x%02x", |
194 |
expected, cksum_crc); |
expected, cksum_or_crc); |
195 |
goto error; |
goto error; |
196 |
} |
} |
197 |
|
|
198 |
wantBlockNo++; |
wantBlockNo++; |
199 |
length += blockLength; |
length += blockLength; |
|
|
|
|
errno = 0; |
|
|
if (full_write(file_fd, blockBuf, blockLength) != blockLength) { |
|
|
bb_perror_msg("can't write to file"); |
|
|
goto fatal; |
|
|
} |
|
200 |
next: |
next: |
201 |
errors = 0; |
errors = 0; |
202 |
nak = ACK; |
reply_char = ACK; |
203 |
full_write(write_fd, &nak, 1); |
full_write(write_fd, &reply_char, 1); |
204 |
continue; |
continue; |
205 |
error: |
error: |
206 |
timeout: |
timeout: |
208 |
if (errors == MAXERRORS) { |
if (errors == MAXERRORS) { |
209 |
/* Abort */ |
/* Abort */ |
210 |
|
|
211 |
/* if were asking for crc, try again w/o crc */ |
/* If were asking for crc, try again w/o crc */ |
212 |
if (nak == 'C') { |
if (reply_char == 'C') { |
213 |
nak = NAK; |
reply_char = NAK; |
214 |
errors = 0; |
errors = 0; |
215 |
do_crc = 0; |
do_crc = 0; |
216 |
goto timeout; |
goto timeout; |
225 |
/* Flush pending input */ |
/* Flush pending input */ |
226 |
tcflush(read_fd, TCIFLUSH); |
tcflush(read_fd, TCIFLUSH); |
227 |
|
|
228 |
full_write(write_fd, &nak, 1); |
full_write(write_fd, &reply_char, 1); |
229 |
} /* for (;;) */ |
} /* for (;;) */ |
230 |
} |
} |
231 |
|
|
234 |
} |
} |
235 |
|
|
236 |
int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
237 |
int rx_main(int argc, char **argv) |
int rx_main(int argc UNUSED_PARAM, char **argv) |
238 |
{ |
{ |
239 |
struct termios tty, orig_tty; |
struct termios tty, orig_tty; |
240 |
int termios_err; |
int termios_err; |
241 |
int file_fd; |
int file_fd; |
242 |
int n; |
int n; |
243 |
|
|
|
if (argc != 2) |
|
|
bb_show_usage(); |
|
|
|
|
244 |
/* Disabled by vda: |
/* Disabled by vda: |
245 |
* why we can't receive from stdin? Why we *require* |
* why we can't receive from stdin? Why we *require* |
246 |
* controlling tty?? */ |
* controlling tty?? */ |
247 |
/*read_fd = xopen(CURRENT_TTY, O_RDWR);*/ |
/*read_fd = xopen(CURRENT_TTY, O_RDWR);*/ |
248 |
file_fd = xopen(argv[1], O_RDWR|O_CREAT|O_TRUNC); |
file_fd = xopen(single_argv(argv), O_RDWR|O_CREAT|O_TRUNC); |
249 |
|
|
250 |
termios_err = tcgetattr(read_fd, &tty); |
termios_err = tcgetattr(read_fd, &tty); |
251 |
if (termios_err == 0) { |
if (termios_err == 0) { |