1 /*-
2 * Copyright (c) 2006 M. Warner Losh. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * This software is derived from software provide by Kwikbyte who specifically
25 * disclaimed copyright on the code. This version of xmodem has been nearly
26 * completely rewritten, but the CRC is from the original.
27 *
28 * $FreeBSD$
29 */
30
31 #include "lib.h"
32
33 #define PACKET_SIZE 128
34
35 /* Line control codes */
36 #define SOH 0x01 /* start of header */
37 #define ACK 0x06 /* Acknowledge */
38 #define NAK 0x15 /* Negative acknowledge */
39 #define CAN 0x18 /* Cancel */
40 #define EOT 0x04 /* end of text */
41
42 #define TO 10
43 /*
44 * int GetRecord(char , char *)
45 * This private function receives a x-modem record to the pointer and
46 * returns non-zero on success.
47 */
48 static int
GetRecord(char blocknum,char * dest)49 GetRecord(char blocknum, char *dest)
50 {
51 int size;
52 int ch;
53 unsigned chk, j;
54
55 chk = 0;
56
57 if ((ch = getc(TO)) == -1)
58 goto err;
59 if (ch != blocknum)
60 goto err;
61 if ((ch = getc(TO)) == -1)
62 goto err;
63 if (ch != (~blocknum & 0xff))
64 goto err;
65
66 for (size = 0; size < PACKET_SIZE; ++size) {
67 if ((ch = getc(TO)) == -1)
68 goto err;
69 chk = chk ^ ch << 8;
70 for (j = 0; j < 8; ++j) {
71 if (chk & 0x8000)
72 chk = chk << 1 ^ 0x1021;
73 else
74 chk = chk << 1;
75 }
76 *dest++ = ch;
77 }
78
79 chk &= 0xFFFF;
80
81 if (((ch = getc(TO)) == -1) || ((ch & 0xff) != ((chk >> 8) & 0xFF)))
82 goto err;
83 if (((ch = getc(TO)) == -1) || ((ch & 0xff) != (chk & 0xFF)))
84 goto err;
85 putchar(ACK);
86
87 return (1);
88 err:;
89 putchar(CAN);
90 // We should allow for resend, but we don't.
91 return (0);
92 }
93
94 /*
95 * int xmodem_rx(char *)
96 * This global function receives a x-modem transmission consisting of
97 * (potentially) several blocks. Returns the number of bytes received or
98 * -1 on error.
99 */
100 int
xmodem_rx(char * dest)101 xmodem_rx(char *dest)
102 {
103 int starting, ch;
104 char packetNumber, *startAddress = dest;
105
106 packetNumber = 1;
107 starting = 1;
108
109 while (1) {
110 if (starting)
111 putchar('C');
112 if (((ch = getc(1)) == -1) || (ch != SOH && ch != EOT))
113 continue;
114 if (ch == EOT) {
115 putchar(ACK);
116 return (dest - startAddress);
117 }
118 starting = 0;
119 // Xmodem packets: SOH PKT# ~PKT# 128-bytes CRC16
120 if (!GetRecord(packetNumber, dest))
121 return (-1);
122 dest += PACKET_SIZE;
123 packetNumber++;
124 }
125
126 // the loop above should return in all cases
127 return (-1);
128 }
129