Annotation of src/usr.bin/cu/xmodem.c, Revision 1.5
1.5 ! naddy 1: /* $OpenBSD: xmodem.c,v 1.4 2013/01/17 21:10:24 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
5: *
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.
9: *
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.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <errno.h>
22: #include <signal.h>
23: #include <stdio.h>
24: #include <string.h>
25: #include <termios.h>
26: #include <unistd.h>
27:
28: #include "cu.h"
29:
30: #define XMODEM_BLOCK 128
31: #define XMODEM_RETRIES 10
32:
33: #define XMODEM_SOH '\001'
34: #define XMODEM_EOT '\004'
35: #define XMODEM_ACK '\006'
36: #define XMODEM_NAK '\025'
37: #define XMODEM_SUB '\032'
1.5 ! naddy 38: #define XMODEM_C '\103'
1.1 nicm 39:
40: volatile sig_atomic_t xmodem_stop;
41:
42: void
43: xmodem_signal(int sig)
44: {
45: xmodem_stop = 1;
46: }
47:
1.5 ! naddy 48: uint16_t
! 49: xmodem_crc16(const u_char *buf, size_t len)
! 50: {
! 51: uint16_t crc;
! 52: u_int i, j;
! 53:
! 54: crc = 0;
! 55: for (i = 0; i < len; i++) {
! 56: crc = crc ^ *buf++ << 8;
! 57: for (j = 0; j < 8; j++)
! 58: if (crc & 0x8000)
! 59: crc = crc << 1 ^ 0x1021;
! 60: else
! 61: crc = crc << 1;
! 62: }
! 63: return (crc);
! 64: }
! 65:
1.1 nicm 66: int
67: xmodem_read(char *c)
68: {
69: for (;;) {
70: switch (read(line_fd, c, 1)) {
71: case -1:
72: if (errno == EINTR && !xmodem_stop)
73: continue;
74: return (-1);
75: case 0:
76: errno = EPIPE;
77: return (-1);
78: case 1:
79: return (0);
80: }
81: }
82: }
83:
84: int
85: xmodem_write(const u_char *buf, size_t len)
86: {
87: ssize_t n;
88:
89: while (len > 0) {
90: n = write(line_fd, buf, len);
91: if (n == -1) {
92: if (errno == EINTR && !xmodem_stop)
93: continue;
94: return (-1);
95: }
96: buf += n;
97: len -= n;
98: }
99: return (0);
100: }
101:
102: void
103: xmodem_send(const char *file)
104: {
105: FILE *f;
1.5 ! naddy 106: u_char buf[3 + XMODEM_BLOCK + 2], c;
! 107: size_t len, pktlen;
1.1 nicm 108: uint8_t num;
1.5 ! naddy 109: uint16_t crc;
! 110: int crc_mode;
1.2 nicm 111: u_int i, total;
1.1 nicm 112: struct termios tio;
113: struct sigaction act, oact;
114:
115: f = fopen(file, "r");
116: if (f == NULL) {
117: cu_warn("%s", file);
118: return;
119: }
120:
121: memset(&act, 0, sizeof(act));
122: sigemptyset(&act.sa_mask);
123: act.sa_flags = 0;
124: act.sa_handler = xmodem_signal;
125: if (sigaction(SIGINT, &act, &oact) != 0)
126: cu_err(1, "sigaction");
127: xmodem_stop = 0;
128:
129: if (isatty(STDIN_FILENO)) {
130: memcpy(&tio, &saved_tio, sizeof(tio));
131: tio.c_lflag &= ~ECHO;
132: if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0)
133: cu_err(1, "tcsetattr");
134: }
135:
1.5 ! naddy 136: tcflush(line_fd, TCIFLUSH);
! 137: if (xmodem_read(&c) != 0)
! 138: goto fail;
! 139: if (c == XMODEM_C)
! 140: crc_mode = 1;
! 141: else if (c == XMODEM_NAK)
! 142: crc_mode = 0;
! 143: else {
! 144: cu_warnx("%s: unexpected response \%03hho", file, c);
! 145: goto fail;
! 146: }
! 147:
1.1 nicm 148: num = 1;
1.2 nicm 149: total = 1;
1.5 ! naddy 150: pktlen = 3 + XMODEM_BLOCK + (crc_mode ? 2 : 1);
1.1 nicm 151: for (;;) {
152: len = fread(buf + 3, 1, XMODEM_BLOCK, f);
153: if (len == 0)
154: break;
155: memset(buf + 3 + len, XMODEM_SUB, XMODEM_BLOCK - len);
156:
157: buf[0] = XMODEM_SOH;
158: buf[1] = num;
159: buf[2] = 255 - num;
160:
1.5 ! naddy 161: if (crc_mode) {
! 162: crc = xmodem_crc16(buf + 3, XMODEM_BLOCK);
! 163: buf[3 + XMODEM_BLOCK] = crc >> 8;
! 164: buf[3 + XMODEM_BLOCK + 1] = crc & 0xFF;
! 165: } else {
! 166: buf[3 + XMODEM_BLOCK] = 0;
! 167: for (i = 0; i < XMODEM_BLOCK; i++)
! 168: buf[3 + XMODEM_BLOCK] += buf[3 + i];
! 169: }
1.1 nicm 170:
171: for (i = 0; i < XMODEM_RETRIES; i++) {
172: if (xmodem_stop) {
173: errno = EINTR;
174: goto fail;
175: }
176: cu_warnx("%s: sending block %u (attempt %u)", file,
1.2 nicm 177: total, 1 + i);
1.5 ! naddy 178: if (xmodem_write(buf, pktlen) != 0)
1.1 nicm 179: goto fail;
180:
181: if (xmodem_read(&c) != 0)
182: goto fail;
183: if (c == XMODEM_ACK)
184: break;
185: if (c != XMODEM_NAK) {
186: cu_warnx("%s: unexpected response \%03hho",
187: file, c);
188: }
189: }
190: if (i == XMODEM_RETRIES) {
191: cu_warnx("%s: too many retries", file);
192: goto out;
1.4 nicm 193: }
1.1 nicm 194:
195: if (len < XMODEM_BLOCK)
196: break;
197: num++;
1.2 nicm 198: total++;
1.1 nicm 199: }
200:
201: buf[0] = XMODEM_EOT;
202: if (xmodem_write(buf, 1) != 0)
203: goto fail;
204: cu_warnx("%s: completed %u blocks", file, num);
205:
206: goto out;
207:
208: fail:
209: cu_warn("%s", file);
210:
211: out:
212: set_termios();
213:
214: sigaction(SIGINT, &oact, NULL);
215:
1.4 nicm 216: fclose(f);
1.1 nicm 217: }