#ifndef lint static const char rcsid[] = "$Id: zmodemdump.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ; #endif /* variation on serialmon companion program serialdump, which * interprets data as a zmodem dialog */ #include #include #include #include #include #include #include #include #include #include "crctab.h" #define MAXBUF 2048 #define MAXLINE 16 #define MAXHBUF 128 #define OLINELEN (MAXLINE*2) #define CAN 030 #define XON 021 #define ZDLE 030 #define ZPAD '*' #define ZBIN 'A' #define ZHEX 'B' #define ZBIN32 'C' #define ZBINR32 'D' #define ZVBIN 'a' #define ZVHEX 'b' #define ZVBIN32 'c' #define ZVBINR32 'd' #define ZRESC 0177 #define ZRQINIT 0 /* request receive init */ #define ZRINIT 1 /* receive init */ #define ZSINIT 2 /* send init sequence, define Attn */ #define ZACK 3 /* ACK */ #define ZFILE 4 /* file name, from sender */ #define ZSKIP 5 /* skip file command, from receiver */ #define ZNAK 6 /* last packet was garbled */ #define ZABORT 7 /* abort */ #define ZFIN 8 /* finish session */ #define ZRPOS 9 /* resume file from this position, from receiver */ #define ZDATA 10 /* data packets to follow, from sender */ #define ZEOF 11 /* end of file, from sender */ #define ZFERR 12 /* fatal i/o error, from receiver */ #define ZCRC 13 /* request for file crc, from receiver */ #define ZCHALLENGE 14 /* "send this number back to me", from receiver */ #define ZCOMPL 15 /* request is complete */ #define ZCAN 16 /* other end cancelled with CAN-CAN-CAN-CAN-CAN */ #define ZFREECNT 17 /* request for free bytes on filesystem */ #define ZCOMMAND 18 /* command, from sending program */ #define ZSTDERR 19 /* output this message to stderr */ #define ZCRCE 'h' #define ZCRCG 'i' #define ZCRCQ 'j' #define ZCRCW 'k' #define ZRUB0 'l' #define ZRUB1 'm' typedef enum {Idle, Padding, HexHeader, Header16, Header32, InData, InCrc} ZState ; typedef struct { ZState state ; int headertype ; int data[4] ; int crcBytes[4] ; int count ; int zdlePend ; /* ZDLE received */ int crcCmd ; int crclen ; u_long crc ; } Zinfo ; u_char buffer[MAXBUF] ; u_char line[MAXLINE] ; u_char hbuffer[MAXHBUF] ; int linecnt = 0 ; int hbufcnt = 0 ; main( int argc, char **argv ) { int i,j ; int len ; int which ; struct timeval timestamp, oldtime ; struct tm *tm ; Zinfo Ainfo, Binfo ; printf("serial log. 'A' is application, 'B' is serial port\n\n") ; oldtime.tv_sec = 0 ; Ainfo.state = Binfo.state = Idle ; Ainfo.zdlePend = Binfo.zdlePend = 0 ; while( (i=fread((char *)&which, sizeof(which), 1, stdin)) > 0 ) { i = fread((char *)×tamp, sizeof(timestamp), 1, stdin) ; i = fread((char *)&len, sizeof(len), 1, stdin) ; if( timestamp.tv_sec != oldtime.tv_sec || timestamp.tv_usec != oldtime.tv_usec ) { if( linecnt > 0 ) dumpLine() ; tm = localtime(×tamp.tv_sec) ; printf("%c: %2d:%2.2d:%2.2d.%2.2d\n", 'A'+which, tm->tm_hour,tm->tm_min,tm->tm_sec, timestamp.tv_usec/10000 ) ; oldtime = timestamp ; } while( len > 0 ) { i = MAXBUF ; if( len < i ) i = len ; j = fread(buffer, 1, i, stdin) ; assert(j <= MAXBUF) ; len -= j ; parseData(which ? &Binfo : &Ainfo, j) ; } while( len > 0 ) { i = MAXLINE - linecnt ; if( len < i ) i = len ; assert(linecnt+i <= MAXLINE) ; j = fread(line+linecnt, 1, i, stdin) ; assert(linecnt+j <= MAXLINE) ; len -= j ; linecnt += j ; if( linecnt >= MAXLINE ) dumpLine() ; } } if( linecnt > 0 ) dumpLine() ; exit(0) ; } char toprintable(char c) { c &= 0177 ; if( c >= 0x20 && c <= 0x7e ) return c ; else return '.' ; } dumpLine() { int i,j ; if( linecnt <= 0 ) return ; if( linecnt > MAXLINE ) linecnt = MAXLINE ; printf(" ") ; for(i=0; i= 0; ptr++) { assert(ptr >= buffer && ptr < buffer+MAXBUF) ; c = *ptr ; if( c != XON ) switch( info->state ) { case Idle: if( c != ZPAD ) dataChar(c) ; else { info->state = Padding ; info->count = 1 ; hbuffer[0] = c ; } break ; case Padding: if( c == ZDLE ) { info->zdlePend = 1 ; } else if( info->zdlePend ) { info->zdlePend = 0 ; info->count = 0 ; switch(c) { case ZHEX: info->state = HexHeader ; info->crclen=2 ; info->crc = 0 ; break ; case ZBIN: info->state = Header16 ; info->crclen=2 ; info->crc = 0 ; break ; case ZBIN32: info->state = Header32 ; info->crclen=4 ; info->crc = 0xffffffff ; break ; default: cancelHeader(info) ; break ; } } else if( c == ZPAD ) { if( info->count < 2 ) { assert(info->count < MAXHBUF) ; hbuffer[info->count++] = c ; } else dataChar(c) ; } else cancelHeader(info) ; break ; break ; case HexHeader: if( c == ZDLE && !info->zdlePend ) { info->zdlePend = 1 ; break ; } if( info->zdlePend ) { c = zdle(c) ; info->zdlePend = 0 ; } idx = info->count++ ; assert(idx < MAXHBUF) ; hbuffer[idx] = c ; if( info->count >= 16 ) { /* end of header */ info->headertype = hex2(hbuffer+0) ; info->data[0] = hex2(hbuffer+2) ; info->data[1] = hex2(hbuffer+4) ; info->data[2] = hex2(hbuffer+6) ; info->data[3] = hex2(hbuffer+8) ; info->crcBytes[0] = hex2(hbuffer+10) ; info->crcBytes[1] = hex2(hbuffer+12) ; displayHeader(info) ; } break ; case Header16: if( c == ZDLE && !info->zdlePend ) { info->zdlePend = 1 ; break ; } if( info->zdlePend ) { c = zdle(c) ; info->zdlePend = 0 ; } idx = info->count++ ; assert(idx < MAXHBUF) ; hbuffer[idx] = c ; if( info->count >= 7 ) { /* end of header */ info->headertype = hbuffer[0] ; info->data[0] = hbuffer[1] ; info->data[1] = hbuffer[2] ; info->data[2] = hbuffer[3] ; info->data[3] = hbuffer[4] ; info->crcBytes[0] = hbuffer[5] ; info->crcBytes[1] = hbuffer[6] ; displayHeader(info) ; } break ; case Header32: if( c == ZDLE && !info->zdlePend ) { info->zdlePend = 1 ; break ; } if( info->zdlePend ) { c = zdle(c) ; info->zdlePend = 0 ; } idx = info->count++ ; assert(idx < MAXHBUF) ; hbuffer[idx] = c ; if( info->count >= 9 ) { /* end of header */ info->headertype = hbuffer[0] ; info->data[0] = hbuffer[1] ; info->data[1] = hbuffer[2] ; info->data[2] = hbuffer[3] ; info->data[3] = hbuffer[4] ; info->crcBytes[0] = hbuffer[5] ; info->crcBytes[1] = hbuffer[6] ; info->crcBytes[2] = hbuffer[7] ; info->crcBytes[3] = hbuffer[8] ; displayHeader(info) ; } break ; case InData: if( info->zdlePend ) { info->zdlePend = 0 ; switch( c ) { case ZCRCE: case ZCRCW: case ZCRCG: case ZCRCQ: info->crcCmd = c ; dumpLine() ; info->state = InCrc ; info->count = 0 ; break ; default: c = zdle(c) ; dataChar(c) ; break ; } } else if( c == ZDLE ) info->zdlePend = 1 ; else dataChar(c) ; break ; case InCrc: if( info->zdlePend ) { c = zdle(c) ; info->zdlePend = 0 ; } if( c == ZDLE ) info->zdlePend = 1 ; else { dataChar(c) ; if( ++info->count >= info->crclen ) { dumpCrc() ; switch( info->crcCmd ) { case ZCRCE: printf(" ZCRCE: end of frame, header follows\n") ; info->state = Idle ; break ; case ZCRCW: printf(" ZCRCW: end of frame, send ZACK\n") ; info->state = Idle ; break ; case ZCRCG: printf(" ZCRCG: more data follows:\n") ; info->state = InData ; break ; case ZCRCQ: printf(" ZCRCQ: send ZACK, more data follows:\n") ; info->state = InData ; break ; } } } break ; } } } /* handle a character that's not part of the protocol */ dataChar(int c) { assert(linecnt < MAXLINE) ; line[linecnt++] = c ; if( linecnt >= MAXLINE ) dumpLine() ; } /* here if we thought we were in a header, but were wrong */ cancelHeader( Zinfo *info ) { int i ; for(i=0; icount; ++i) { assert(i < MAXHBUF) ; dataChar(hbuffer[i]) ; } info->state = Idle ; } /* here to display a full header. CRC's not currently checked */ displayHeader( Zinfo *info ) { int i ; u_long crc ; int h32 = info->state == Header32 ; static char *names[] = { "ZRQINIT", "ZRINIT", "ZSINIT", "ZACK", "ZFILE", "ZSKIP", "ZNAK", "ZABORT", "ZFIN", "ZRPOS", "ZDATA", "ZEOF", "ZFERR", "ZCRC", "ZCHALLENGE", "ZCOMPL", "ZCAN", "ZFREECNT", "ZCOMMAND", "ZSTDERR",} ; dumpLine() ; printf(" ") ; switch( info->state ) { case HexHeader: printf("hex header") ; break ; case Header16: printf("bin header") ; break ; case Header32: printf("bin32 header") ; break ; } printf(" %d: %s: d=[%x %x %x %x]", info->headertype, info->headertype <= ZSTDERR ? names[info->headertype] : "BAD HEADER", info->data[0], info->data[1], info->data[2], info->data[3]) ; switch( info->state ) { case HexHeader: case Header16: printf(" crc=[%x %x]", info->crcBytes[0], info->crcBytes[1]) ; break ; case Header32: printf(" crc=[%x %x %x %x]", info->crcBytes[0], info->crcBytes[1], info->crcBytes[2], info->crcBytes[3]) ; break ; } switch( info->headertype ) { case ZRQINIT: case ZRINIT: case ZACK: case ZSKIP: case ZNAK: case ZABORT: case ZFIN: case ZRPOS: case ZEOF: case ZFERR: case ZCRC: case ZCHALLENGE: case ZCOMPL: case ZCAN: case ZFREECNT: case ZCOMMAND: printf("\n") ; info->state = Idle ; break ; case ZSINIT: case ZFILE: case ZDATA: case ZSTDERR: printf(", data follows:\n") ; info->state = InData ; info->count = 0 ; break ; } if( !h32 ) { crc = 0 ; crc = updcrc(info->headertype, crc) ; crc = updcrc(info->data[0], crc) ; crc = updcrc(info->data[1], crc) ; crc = updcrc(info->data[2], crc) ; crc = updcrc(info->data[3], crc) ; crc = updcrc(info->crcBytes[0], crc) ; crc = updcrc(info->crcBytes[1], crc) ; if( crc&0xffff != 0 ) printf(" CRC ERROR\n") ; } else { crc = 0xffffffff ; crc = UPDC32(info->headertype, crc) ; crc = UPDC32(info->data[0], crc) ; crc = UPDC32(info->data[1], crc) ; crc = UPDC32(info->data[2], crc) ; crc = UPDC32(info->data[3], crc) ; crc = UPDC32(info->crcBytes[0], crc) ; crc = UPDC32(info->crcBytes[1], crc) ; crc = UPDC32(info->crcBytes[2], crc) ; crc = UPDC32(info->crcBytes[3], crc) ; if( crc != 0xdebb20e3 ) printf(" CRC ERROR\n") ; } } dumpCrc() { int i,j ; if( linecnt <= 0 ) return ; if( linecnt > MAXLINE ) linecnt = MAXLINE ; printf(" crc: ") ; for(i=0; i 9 ) chr -= 'A'-'0'-10 ; if( chr > 15 ) chr -= 'a' - 'A' ; return chr ; } /* apply ZDLE to chr */ int zdle(int chr) { switch( chr ) { case ZRUB0: return 0177 ; case ZRUB1: return 0377 ; default: if( (chr & 0140) == 0100 ) return chr ^ 0100 ; return -1 ; } }