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 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 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