1157873Simp/*- 2157873Simp * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3157873Simp * 4157873Simp * Redistribution and use in source and binary forms, with or without 5157873Simp * modification, are permitted provided that the following conditions 6157873Simp * are met: 7157873Simp * 1. Redistributions of source code must retain the above copyright 8157873Simp * notice, this list of conditions and the following disclaimer. 9157873Simp * 2. Redistributions in binary form must reproduce the above copyright 10157873Simp * notice, this list of conditions and the following disclaimer in the 11157873Simp * documentation and/or other materials provided with the distribution. 12157873Simp * 13157873Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14157873Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15157873Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16157873Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17157873Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18157873Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19157873Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20157873Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21157873Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22157873Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23157873Simp * 24157873Simp * This software is derived from software provide by Kwikbyte who specifically 25157873Simp * disclaimed copyright on the code. This version of xmodem has been nearly 26157873Simp * completely rewritten, but the CRC is from the original. 27157873Simp * 28157873Simp * $FreeBSD$ 29157873Simp */ 30157873Simp 31157873Simp#include "lib.h" 32157873Simp 33157873Simp#define PACKET_SIZE 128 34157873Simp 35157873Simp/* Line control codes */ 36157873Simp#define SOH 0x01 /* start of header */ 37157873Simp#define ACK 0x06 /* Acknowledge */ 38157873Simp#define NAK 0x15 /* Negative acknowledge */ 39157873Simp#define CAN 0x18 /* Cancel */ 40157873Simp#define EOT 0x04 /* end of text */ 41157873Simp 42161190Simp#define TO 10 43157873Simp/* 44157873Simp * int GetRecord(char , char *) 45157873Simp * This private function receives a x-modem record to the pointer and 46157873Simp * returns non-zero on success. 47157873Simp */ 48157873Simpstatic int 49157873SimpGetRecord(char blocknum, char *dest) 50157873Simp{ 51157873Simp int size; 52157873Simp int ch; 53157873Simp unsigned chk, j; 54157873Simp 55157873Simp chk = 0; 56157873Simp 57161190Simp if ((ch = getc(TO)) == -1) 58157873Simp goto err; 59161190Simp if (ch != blocknum) 60157873Simp goto err; 61161190Simp if ((ch = getc(TO)) == -1) 62157873Simp goto err; 63157873Simp if (ch != (~blocknum & 0xff)) 64157873Simp goto err; 65157873Simp 66157873Simp for (size = 0; size < PACKET_SIZE; ++size) { 67161190Simp if ((ch = getc(TO)) == -1) 68157873Simp goto err; 69157873Simp chk = chk ^ ch << 8; 70157873Simp for (j = 0; j < 8; ++j) { 71157873Simp if (chk & 0x8000) 72157873Simp chk = chk << 1 ^ 0x1021; 73157873Simp else 74157873Simp chk = chk << 1; 75157873Simp } 76157873Simp *dest++ = ch; 77157873Simp } 78157873Simp 79157873Simp chk &= 0xFFFF; 80157873Simp 81161190Simp if (((ch = getc(TO)) == -1) || ((ch & 0xff) != ((chk >> 8) & 0xFF))) 82161190Simp goto err; 83161190Simp if (((ch = getc(TO)) == -1) || ((ch & 0xff) != (chk & 0xFF))) 84161190Simp goto err; 85157873Simp putchar(ACK); 86157873Simp 87157873Simp return (1); 88157873Simperr:; 89157873Simp putchar(CAN); 90157873Simp // We should allow for resend, but we don't. 91157873Simp return (0); 92157873Simp} 93157873Simp 94157873Simp/* 95157873Simp * int xmodem_rx(char *) 96157873Simp * This global function receives a x-modem transmission consisting of 97157873Simp * (potentially) several blocks. Returns the number of bytes received or 98157873Simp * -1 on error. 99157873Simp */ 100157873Simpint 101157873Simpxmodem_rx(char *dest) 102157873Simp{ 103157873Simp int starting, ch; 104157873Simp char packetNumber, *startAddress = dest; 105157873Simp 106157873Simp packetNumber = 1; 107157873Simp starting = 1; 108157873Simp 109157873Simp while (1) { 110157873Simp if (starting) 111157873Simp putchar('C'); 112157873Simp if (((ch = getc(1)) == -1) || (ch != SOH && ch != EOT)) 113157873Simp continue; 114157873Simp if (ch == EOT) { 115157873Simp putchar(ACK); 116157873Simp return (dest - startAddress); 117157873Simp } 118157873Simp starting = 0; 119157873Simp // Xmodem packets: SOH PKT# ~PKT# 128-bytes CRC16 120157873Simp if (!GetRecord(packetNumber, dest)) 121157873Simp return (-1); 122157873Simp dest += PACKET_SIZE; 123157873Simp packetNumber++; 124157873Simp } 125157873Simp 126157873Simp // the loop above should return in all cases 127157873Simp return (-1); 128157873Simp} 129