1 /* $OpenBSD: xmodem.c,v 1.5 2013/07/20 19:27:47 naddy Exp $ */
4 * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
31 #define XMODEM_BLOCK 128
32 #define XMODEM_RETRIES 10
34 #define XMODEM_SOH '\001'
35 #define XMODEM_EOT '\004'
36 #define XMODEM_ACK '\006'
37 #define XMODEM_NAK '\025'
38 #define XMODEM_SUB '\032'
39 #define XMODEM_C '\103'
41 volatile sig_atomic_t xmodem_stop
;
44 xmodem_signal(int sig
__attribute__((unused
)))
50 xmodem_crc16(const u_char
*buf
, size_t len
)
56 for (i
= 0; i
< len
; i
++) {
57 crc
= crc
^ *buf
++ << 8;
58 for (j
= 0; j
< 8; j
++)
60 crc
= crc
<< 1 ^ 0x1021;
68 xmodem_read(u_char
*c
)
71 switch (read(line_fd
, c
, 1)) {
73 if (errno
== EINTR
&& !xmodem_stop
)
86 xmodem_write(const u_char
*buf
, size_t len
)
91 n
= write(line_fd
, buf
, len
);
93 if (errno
== EINTR
&& !xmodem_stop
)
104 xmodem_send(const char *file
)
107 u_char buf
[3 + XMODEM_BLOCK
+ 2], c
;
114 struct sigaction act
, oact
;
116 f
= fopen(file
, "r");
122 memset(&act
, 0, sizeof(act
));
123 sigemptyset(&act
.sa_mask
);
125 act
.sa_handler
= xmodem_signal
;
126 if (sigaction(SIGINT
, &act
, &oact
) != 0)
127 cu_err(1, "sigaction");
130 if (isatty(STDIN_FILENO
)) {
131 memcpy(&tio
, &saved_tio
, sizeof(tio
));
132 tio
.c_lflag
&= ~ECHO
;
133 if (tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tio
) != 0)
134 cu_err(1, "tcsetattr");
137 tcflush(line_fd
, TCIFLUSH
);
138 if (xmodem_read(&c
) != 0)
142 else if (c
== XMODEM_NAK
)
145 cu_warnx("%s: unexpected response \%03hho", file
, c
);
151 pktlen
= 3 + XMODEM_BLOCK
+ (crc_mode
? 2 : 1);
153 len
= fread(buf
+ 3, 1, XMODEM_BLOCK
, f
);
156 memset(buf
+ 3 + len
, XMODEM_SUB
, XMODEM_BLOCK
- len
);
163 crc
= xmodem_crc16(buf
+ 3, XMODEM_BLOCK
);
164 buf
[3 + XMODEM_BLOCK
] = crc
>> 8;
165 buf
[3 + XMODEM_BLOCK
+ 1] = crc
& 0xFF;
167 buf
[3 + XMODEM_BLOCK
] = 0;
168 for (i
= 0; i
< XMODEM_BLOCK
; i
++)
169 buf
[3 + XMODEM_BLOCK
] += buf
[3 + i
];
172 for (i
= 0; i
< XMODEM_RETRIES
; i
++) {
177 cu_warnx("%s: sending block %u (attempt %u)", file
,
179 if (xmodem_write(buf
, pktlen
) != 0)
182 if (xmodem_read(&c
) != 0)
186 if (c
!= XMODEM_NAK
) {
187 cu_warnx("%s: unexpected response \%03hho",
191 if (i
== XMODEM_RETRIES
) {
192 cu_warnx("%s: too many retries", file
);
196 if (len
< XMODEM_BLOCK
)
203 if (xmodem_write(buf
, 1) != 0)
205 cu_warnx("%s: completed %u blocks", file
, num
);
215 sigaction(SIGINT
, &oact
, NULL
);