1 /* 2 * Z M . C 3 * ZMODEM protocol primitives 4 * 05-09-88 Chuck Forsberg Omen Technology Inc 5 * 6 * Entry point Functions: 7 * zsbhdr(type, hdr) send binary header 8 * zshhdr(type, hdr) send hex header 9 * zgethdr(hdr, eflag) receive header - binary or hex 10 * zsdata(buf, len, frameend) send data 11 * zrdata(buf, len) receive data 12 * stohdr(pos) store position data in Txhdr 13 * long rclhdr(hdr) recover position offset from header 14 */ 15 16 #ifndef CANFDX 17 #include "zmodem.h" 18 #endif 19 int Rxtimeout = 100; /* Tenths of seconds to wait for something */ 20 21 #ifndef UNSL 22 #define UNSL 23 #endif 24 25 26 /* Globals used by ZMODEM functions */ 27 int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ 28 int Rxtype; /* Type of header received */ 29 int Rxcount; /* Count of data bytes received */ 30 char Rxhdr[4]; /* Received header */ 31 char Txhdr[4]; /* Transmitted header */ 32 long Rxpos; /* Received file position */ 33 long Txpos; /* Transmitted file position */ 34 int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ 35 int Crc32t; /* Display flag indicating 32 bit CRC being sent */ 36 int Crc32; /* Display flag indicating 32 bit CRC being received */ 37 int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ 38 char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ 39 40 static int lastsent; /* Last char we sent */ 41 static int Not8bit; /* Seven bits seen on header */ 42 43 static char *frametypes[] = { 44 "Carrier Lost", /* -3 */ 45 "TIMEOUT", /* -2 */ 46 "ERROR", /* -1 */ 47 #define FTOFFSET 3 48 "ZRQINIT", 49 "ZRINIT", 50 "ZSINIT", 51 "ZACK", 52 "ZFILE", 53 "ZSKIP", 54 "ZNAK", 55 "ZABORT", 56 "ZFIN", 57 "ZRPOS", 58 "ZDATA", 59 "ZEOF", 60 "ZFERR", 61 "ZCRC", 62 "ZCHALLENGE", 63 "ZCOMPL", 64 "ZCAN", 65 "ZFREECNT", 66 "ZCOMMAND", 67 "ZSTDERR", 68 "xxxxx" 69 #define FRTYPES 22 /* Total number of frame types in this array */ 70 /* not including psuedo negative entries */ 71 }; 72 73 static char badcrc[] = "Bad CRC"; 74 75 /* Send ZMODEM binary header hdr of type type */ 76 void zsbhdr(int type, char *hdr) 77 { 78 register int n; 79 register unsigned short crc; 80 81 vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr)); 82 if (type == ZDATA) 83 for (n = Znulls; --n >=0; ) 84 xsendline(0); 85 86 xsendline(ZPAD); xsendline(ZDLE); 87 88 if ((Crc32t=Txfcs32)) 89 zsbh32(hdr, type); 90 else { 91 xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0); 92 93 for (n=4; --n >= 0; ++hdr) { 94 zsendline(*hdr); 95 crc = updcrc((0377& *hdr), crc); 96 } 97 crc = updcrc(0,updcrc(0,crc)); 98 zsendline(crc>>8); 99 zsendline(crc); 100 } 101 if (type != ZDATA) 102 flushmo(); 103 } 104 105 106 /* Send ZMODEM binary header hdr of type type */ 107 void zsbh32(char *hdr, int type) 108 { 109 register int n; 110 register UNSL long crc; 111 112 xsendline(ZBIN32); zsendline(type); 113 crc = 0xFFFFFFFFL; crc = UPDC32(type, crc); 114 115 for (n=4; --n >= 0; ++hdr) { 116 crc = UPDC32((0377 & *hdr), crc); 117 zsendline(*hdr); 118 } 119 crc = ~crc; 120 for (n=4; --n >= 0;) { 121 zsendline((int)crc); 122 crc >>= 8; 123 } 124 } 125 126 /* Send ZMODEM HEX header hdr of type type */ 127 void zshhdr(int type, char *hdr) 128 { 129 register int n; 130 register unsigned short crc; 131 132 vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr)); 133 sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX); 134 zputhex(type); 135 Crc32t = 0; 136 137 crc = updcrc(type, 0); 138 for (n=4; --n >= 0; ++hdr) { 139 zputhex(*hdr); crc = updcrc((0377 & *hdr), crc); 140 } 141 crc = updcrc(0,updcrc(0,crc)); 142 zputhex(crc>>8); zputhex(crc); 143 144 /* Make it printable on remote machine */ 145 sendline(015); sendline(0212); 146 /* 147 * Uncork the remote in case a fake XOFF has stopped data flow 148 */ 149 if (type != ZFIN && type != ZACK) 150 sendline(021); 151 flushmo(); 152 } 153 154 /* 155 * Send binary array buf of length length, with ending ZDLE sequence frameend 156 */ 157 static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; 158 159 void zsdata(char *buf, int length, int frameend) 160 { 161 register unsigned short crc; 162 163 vfile("zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]); 164 if (Crc32t) 165 zsda32(buf, length, frameend); 166 else { 167 crc = 0; 168 for (;--length >= 0; ++buf) { 169 zsendline(*buf); crc = updcrc((0377 & *buf), crc); 170 } 171 xsendline(ZDLE); xsendline(frameend); 172 crc = updcrc(frameend, crc); 173 174 crc = updcrc(0,updcrc(0,crc)); 175 zsendline(crc>>8); zsendline(crc); 176 } 177 if (frameend == ZCRCW) { 178 xsendline(XON); flushmo(); 179 } 180 } 181 182 void zsda32(char *buf, int length, int frameend) 183 { 184 register int c; 185 register UNSL long crc; 186 187 crc = 0xFFFFFFFFL; 188 for (;--length >= 0; ++buf) { 189 c = *buf & 0377; 190 if (c & 0140) 191 xsendline(lastsent = c); 192 else 193 zsendline(c); 194 crc = UPDC32(c, crc); 195 } 196 xsendline(ZDLE); xsendline(frameend); 197 crc = UPDC32(frameend, crc); 198 199 crc = ~crc; 200 for (length=4; --length >= 0;) { 201 zsendline((int)crc); crc >>= 8; 202 } 203 } 204 205 /* 206 * Receive array buf of max length with ending ZDLE sequence 207 * and CRC. Returns the ending character or error code. 208 * NB: On errors may store length+1 bytes! 209 */ 210 int zrdata(char *buf, int length) 211 { 212 register int c; 213 register unsigned short crc; 214 register char *end; 215 register int d; 216 217 if (Rxframeind == ZBIN32) 218 return zrdat32(buf, length); 219 220 crc = Rxcount = 0; end = buf + length; 221 while (buf <= end) { 222 if ((c = zdlread()) & ~0377) { 223 crcfoo: 224 switch (c) { 225 case GOTCRCE: 226 case GOTCRCG: 227 case GOTCRCQ: 228 case GOTCRCW: 229 crc = updcrc((((d=c))&0377), crc); 230 if ((c = zdlread()) & ~0377) 231 goto crcfoo; 232 crc = updcrc(c, crc); 233 if ((c = zdlread()) & ~0377) 234 goto crcfoo; 235 crc = updcrc(c, crc); 236 if (crc & 0xFFFF) { 237 zperr(badcrc); 238 return ERROR; 239 } 240 Rxcount = length - (end - buf); 241 vfile("zrdata: %d %s", Rxcount, 242 Zendnames[(d-GOTCRCE)&3]); 243 return d; 244 case GOTCAN: 245 zperr("Sender Canceled"); 246 return ZCAN; 247 case TIMEOUT: 248 zperr("TIMEOUT"); 249 return c; 250 default: 251 zperr("Bad data subpacket"); 252 return c; 253 } 254 } 255 *buf++ = c; 256 crc = updcrc(c, crc); 257 } 258 zperr("Data subpacket too long"); 259 return ERROR; 260 } 261 262 int zrdat32(char *buf, int length) 263 { 264 register int c; 265 register UNSL long crc; 266 register char *end; 267 register int d; 268 269 crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; 270 while (buf <= end) { 271 if ((c = zdlread()) & ~0377) { 272 crcfoo: 273 switch (c) { 274 case GOTCRCE: 275 case GOTCRCG: 276 case GOTCRCQ: 277 case GOTCRCW: 278 d = c; c &= 0377; 279 crc = UPDC32(c, crc); 280 if ((c = zdlread()) & ~0377) 281 goto crcfoo; 282 crc = UPDC32(c, crc); 283 if ((c = zdlread()) & ~0377) 284 goto crcfoo; 285 crc = UPDC32(c, crc); 286 if ((c = zdlread()) & ~0377) 287 goto crcfoo; 288 crc = UPDC32(c, crc); 289 if ((c = zdlread()) & ~0377) 290 goto crcfoo; 291 crc = UPDC32(c, crc); 292 if (crc != 0xDEBB20E3) { 293 zperr(badcrc); 294 return ERROR; 295 } 296 Rxcount = length - (end - buf); 297 vfile("zrdat32: %d %s", Rxcount, 298 Zendnames[(d-GOTCRCE)&3]); 299 return d; 300 case GOTCAN: 301 zperr("Sender Canceled"); 302 return ZCAN; 303 case TIMEOUT: 304 zperr("TIMEOUT"); 305 return c; 306 default: 307 zperr("Bad data subpacket"); 308 return c; 309 } 310 } 311 *buf++ = c; 312 crc = UPDC32(c, crc); 313 } 314 zperr("Data subpacket too long"); 315 return ERROR; 316 } 317 318 319 /* 320 * Read a ZMODEM header to hdr, either binary or hex. 321 * eflag controls local display of non zmodem characters: 322 * 0: no display 323 * 1: display printing characters only 324 * 2: display all non ZMODEM characters 325 * On success, set Zmodem to 1, set Rxpos and return type of header. 326 * Otherwise return negative on error. 327 * Return ERROR instantly if ZCRCW sequence, for fast error recovery. 328 */ 329 int zgethdr(char *hdr, int eflag) 330 { 331 register int c, n, cancount; 332 333 n = Zrwindow + Baudrate; /* Max bytes before start of frame */ 334 Rxframeind = Rxtype = 0; 335 336 startover: 337 cancount = 5; 338 again: 339 /* Return immediate ERROR if ZCRCW sequence seen */ 340 switch (c = readline(Rxtimeout)) { 341 case RCDO: 342 case TIMEOUT: 343 goto fifi; 344 case CAN: 345 gotcan: 346 if (--cancount <= 0) { 347 c = ZCAN; goto fifi; 348 } 349 switch (c = readline(1)) { 350 case TIMEOUT: 351 goto again; 352 case ZCRCW: 353 c = ERROR; 354 /* **** FALL THRU TO **** */ 355 case RCDO: 356 goto fifi; 357 default: 358 break; 359 case CAN: 360 if (--cancount <= 0) { 361 c = ZCAN; goto fifi; 362 } 363 goto again; 364 } 365 /* **** FALL THRU TO **** */ 366 default: 367 agn2: 368 if ( --n == 0) { 369 zperr("Garbage count exceeded"); 370 return(ERROR); 371 } 372 if (eflag && ((c &= 0177) & 0140)) 373 bttyout(c); 374 else if (eflag > 1) 375 bttyout(c); 376 #ifdef UNIX 377 fflush(stderr); 378 #endif 379 goto startover; 380 case ZPAD|0200: /* This is what we want. */ 381 Not8bit = c; 382 case ZPAD: /* This is what we want. */ 383 break; 384 } 385 cancount = 5; 386 splat: 387 switch (c = noxrd7()) { 388 case ZPAD: 389 goto splat; 390 case RCDO: 391 case TIMEOUT: 392 goto fifi; 393 default: 394 goto agn2; 395 case ZDLE: /* This is what we want. */ 396 break; 397 } 398 399 switch (c = noxrd7()) { 400 case RCDO: 401 case TIMEOUT: 402 goto fifi; 403 case ZBIN: 404 Rxframeind = ZBIN; Crc32 = FALSE; 405 c = zrbhdr(hdr); 406 break; 407 case ZBIN32: 408 Crc32 = Rxframeind = ZBIN32; 409 c = zrbhdr32(hdr); 410 break; 411 case ZHEX: 412 Rxframeind = ZHEX; Crc32 = FALSE; 413 c = zrhhdr(hdr); 414 break; 415 case CAN: 416 goto gotcan; 417 default: 418 goto agn2; 419 } 420 Rxpos = hdr[ZP3] & 0377; 421 Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377); 422 Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377); 423 Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377); 424 fifi: 425 switch (c) { 426 case GOTCAN: 427 c = ZCAN; 428 /* **** FALL THRU TO **** */ 429 case ZNAK: 430 case ZCAN: 431 case ERROR: 432 case TIMEOUT: 433 case RCDO: 434 zperr("Got %s", frametypes[c+FTOFFSET]); 435 /* **** FALL THRU TO **** */ 436 default: 437 if (c >= -3 && c <= FRTYPES) 438 vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos); 439 else 440 vfile("zgethdr: %d %lx", c, Rxpos); 441 } 442 return c; 443 } 444 445 /* Receive a binary style header (type and position) */ 446 int zrbhdr(char *hdr) 447 { 448 register int c, n; 449 register unsigned short crc; 450 451 if ((c = zdlread()) & ~0377) 452 return c; 453 Rxtype = c; 454 crc = updcrc(c, 0); 455 456 for (n=4; --n >= 0; ++hdr) { 457 if ((c = zdlread()) & ~0377) 458 return c; 459 crc = updcrc(c, crc); 460 *hdr = c; 461 } 462 if ((c = zdlread()) & ~0377) 463 return c; 464 crc = updcrc(c, crc); 465 if ((c = zdlread()) & ~0377) 466 return c; 467 crc = updcrc(c, crc); 468 if (crc & 0xFFFF) { 469 zperr(badcrc); 470 return ERROR; 471 } 472 #ifdef ZMODEM 473 Protocol = ZMODEM; 474 #endif 475 Zmodem = 1; 476 return Rxtype; 477 } 478 479 /* Receive a binary style header (type and position) with 32 bit FCS */ 480 int zrbhdr32(char *hdr) 481 { 482 register int c, n; 483 register UNSL long crc; 484 485 if ((c = zdlread()) & ~0377) 486 return c; 487 Rxtype = c; 488 crc = 0xFFFFFFFFL; crc = UPDC32(c, crc); 489 #ifdef DEBUGZ 490 vfile("zrbhdr32 c=%X crc=%lX", c, crc); 491 #endif 492 493 for (n=4; --n >= 0; ++hdr) { 494 if ((c = zdlread()) & ~0377) 495 return c; 496 crc = UPDC32(c, crc); 497 *hdr = c; 498 #ifdef DEBUGZ 499 vfile("zrbhdr32 c=%X crc=%lX", c, crc); 500 #endif 501 } 502 for (n=4; --n >= 0;) { 503 if ((c = zdlread()) & ~0377) 504 return c; 505 crc = UPDC32(c, crc); 506 #ifdef DEBUGZ 507 vfile("zrbhdr32 c=%X crc=%lX", c, crc); 508 #endif 509 } 510 if (crc != 0xDEBB20E3) { 511 zperr(badcrc); 512 return ERROR; 513 } 514 #ifdef ZMODEM 515 Protocol = ZMODEM; 516 #endif 517 Zmodem = 1; 518 return Rxtype; 519 } 520 521 522 /* Receive a hex style header (type and position) */ 523 int zrhhdr(char *hdr) 524 { 525 register int c; 526 register unsigned short crc; 527 register int n; 528 529 if ((c = zgethex()) < 0) 530 return c; 531 Rxtype = c; 532 crc = updcrc(c, 0); 533 534 for (n=4; --n >= 0; ++hdr) { 535 if ((c = zgethex()) < 0) 536 return c; 537 crc = updcrc(c, crc); 538 *hdr = c; 539 } 540 if ((c = zgethex()) < 0) 541 return c; 542 crc = updcrc(c, crc); 543 if ((c = zgethex()) < 0) 544 return c; 545 crc = updcrc(c, crc); 546 if (crc & 0xFFFF) { 547 zperr(badcrc); return ERROR; 548 } 549 switch ( c = readline(1)) { 550 case 0215: 551 Not8bit = c; 552 /* **** FALL THRU TO **** */ 553 case 015: 554 /* Throw away possible cr/lf */ 555 switch (c = readline(1)) { 556 case 012: 557 Not8bit |= c; 558 } 559 } 560 #ifdef ZMODEM 561 Protocol = ZMODEM; 562 #endif 563 Zmodem = 1; return Rxtype; 564 } 565 566 /* Send a byte as two hex digits */ 567 void zputhex(int c) 568 { 569 static char digits[] = "0123456789abcdef"; 570 571 if (Verbose>8) 572 vfile("zputhex: %02X", c); 573 sendline(digits[(c&0xF0)>>4]); 574 sendline(digits[(c)&0xF]); 575 } 576 577 /* 578 * Send character c with ZMODEM escape sequence encoding. 579 * Escape XON, XOFF. Escape CR following @ (Telenet net escape) 580 */ 581 void zsendline(int c) 582 { 583 584 /* Quick check for non control characters */ 585 if (c & 0140) 586 xsendline(lastsent = c); 587 else { 588 switch (c &= 0377) { 589 case ZDLE: 590 xsendline(ZDLE); 591 xsendline (lastsent = (c ^= 0100)); 592 break; 593 case 015: 594 case 0215: 595 if (!Zctlesc && (lastsent & 0177) != '@') 596 goto sendit; 597 /* **** FALL THRU TO **** */ 598 case 020: 599 case 021: 600 case 023: 601 case 0220: 602 case 0221: 603 case 0223: 604 xsendline(ZDLE); 605 c ^= 0100; 606 sendit: 607 xsendline(lastsent = c); 608 break; 609 default: 610 if (Zctlesc && ! (c & 0140)) { 611 xsendline(ZDLE); 612 c ^= 0100; 613 } 614 xsendline(lastsent = c); 615 } 616 } 617 } 618 619 /* Decode two lower case hex digits into an 8 bit byte value */ 620 int zgethex() 621 { 622 register int c; 623 624 c = zgeth1(); 625 if (Verbose>8) 626 vfile("zgethex: %02X", c); 627 return c; 628 } 629 int zgeth1() 630 { 631 register int c, n; 632 633 if ((c = noxrd7()) < 0) 634 return c; 635 n = c - '0'; 636 if (n > 9) 637 n -= ('a' - ':'); 638 if (n & ~0xF) 639 return ERROR; 640 if ((c = noxrd7()) < 0) 641 return c; 642 c -= '0'; 643 if (c > 9) 644 c -= ('a' - ':'); 645 if (c & ~0xF) 646 return ERROR; 647 c += (n<<4); 648 return c; 649 } 650 651 /* 652 * Read a byte, checking for ZMODEM escape encoding 653 * including CAN*5 which represents a quick abort 654 */ 655 int zdlread() 656 { 657 register int c; 658 659 again: 660 /* Quick check for non control characters */ 661 if ((c = readline(Rxtimeout)) & 0140) 662 return c; 663 switch (c) { 664 case ZDLE: 665 break; 666 case 023: 667 case 0223: 668 case 021: 669 case 0221: 670 goto again; 671 default: 672 if (Zctlesc && !(c & 0140)) { 673 goto again; 674 } 675 return c; 676 } 677 again2: 678 if ((c = readline(Rxtimeout)) < 0) 679 return c; 680 if (c == CAN && (c = readline(Rxtimeout)) < 0) 681 return c; 682 if (c == CAN && (c = readline(Rxtimeout)) < 0) 683 return c; 684 if (c == CAN && (c = readline(Rxtimeout)) < 0) 685 return c; 686 switch (c) { 687 case CAN: 688 return GOTCAN; 689 case ZCRCE: 690 case ZCRCG: 691 case ZCRCQ: 692 case ZCRCW: 693 return (c | GOTOR); 694 case ZRUB0: 695 return 0177; 696 case ZRUB1: 697 return 0377; 698 case 023: 699 case 0223: 700 case 021: 701 case 0221: 702 goto again2; 703 default: 704 if (Zctlesc && ! (c & 0140)) { 705 goto again2; 706 } 707 if ((c & 0140) == 0100) 708 return (c ^ 0100); 709 break; 710 } 711 if (Verbose>1) 712 zperr("Bad escape sequence %x", c); 713 return ERROR; 714 } 715 716 /* 717 * Read a character from the modem line with timeout. 718 * Eat parity, XON and XOFF characters. 719 */ 720 int noxrd7() 721 { 722 register int c; 723 724 for (;;) { 725 if ((c = readline(Rxtimeout)) < 0) 726 return c; 727 switch (c &= 0177) { 728 case XON: 729 case XOFF: 730 continue; 731 default: 732 if (Zctlesc && !(c & 0140)) 733 continue; 734 case '\r': 735 case '\n': 736 case ZDLE: 737 return c; 738 } 739 } 740 } 741 742 /* Store long integer pos in Txhdr */ 743 void stohdr(long pos) 744 { 745 Txhdr[ZP0] = pos; 746 Txhdr[ZP1] = pos>>8; 747 Txhdr[ZP2] = pos>>16; 748 Txhdr[ZP3] = pos>>24; 749 } 750 751 /* Recover a long integer from a header */ 752 long 753 rclhdr(char *hdr) 754 { 755 register long l; 756 757 l = (hdr[ZP3] & 0377); 758 l = (l << 8) | (hdr[ZP2] & 0377); 759 l = (l << 8) | (hdr[ZP1] & 0377); 760 l = (l << 8) | (hdr[ZP0] & 0377); 761 return l; 762 } 763 764 /* End of zm.c */ 765