#include #include #include enum { Soh= 0x1, Stx= 0x2, Eot= 0x4, Ack= 0x6, Nak= 0x15, Cancel= 0x18, }; int send(uchar*, int); int notifyf(void*, char*); int debug, progress, onek; void errorout(int ctl, int bytes) { uchar buf[2]; buf[0] = Cancel; write(1, buf, 1); fprint(2, "\nxms: gave up after %d bytes\n", bytes); write(ctl, "rawoff", 6); exits("cancel"); } ushort updcrc(int c, ushort crc) { int count; for (count=8; --count>=0;) { if (crc & 0x8000) { crc <<= 1; crc += (((c<<=1) & 0400) != 0); crc ^= 0x1021; } else { crc <<= 1; crc += (((c<<=1) & 0400) != 0); } } return crc; } void main(int argc, char **argv) { uchar c; uchar buf[1024+5]; uchar seqno; int fd, ctl; long n; int sum; uchar *p; int bytes; int crcmode; ARGBEGIN{ case 'd': debug = 1; break; case 'p': progress = 1; break; case '1': onek = 1; break; }ARGEND if(argc != 1){ fprint(2, "usage: xms filename\n"); exits("usage"); } fd = open(argv[0], OREAD); if(fd < 0){ perror("xms"); exits("open"); } ctl = open("/dev/consctl", OWRITE); if(ctl < 0){ perror("xms"); exits("consctl"); } write(ctl, "rawon", 5); /* give the other side a 30 seconds to signal ready */ atnotify(notifyf, 1); alarm(30*1000); crcmode = 0; for(;;){ if(read(0, &c, 1) != 1){ fprint(2, "xms: timeout\n"); exits("timeout"); } c = c & 0x7f; if(c == Nak) break; if(c == 'C') { if (debug) fprint(2, "crc mode engaged\n"); crcmode = 1; break; } } alarm(0); /* send the file in 128/1024 byte chunks */ for(bytes = 0, seqno = 1; ; bytes += n, seqno++){ n = read(fd, buf+3, onek ? 1024 : 128); if(n < 0) exits("read"); if(n == 0) break; if(n < (onek ? 1024 : 128)) memset(&buf[n+3], 0, (onek ? 1024 : 128)-n); buf[0] = onek ? Stx : Soh; buf[1] = seqno; buf[2] = 255 - seqno; /* calculate checksum and stuff into last byte */ if (crcmode) { unsigned short crc; crc = 0; for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++) crc = updcrc(*p, crc); crc = updcrc(0, crc); crc = updcrc(0, crc); buf[(onek ? 1024 : 128) + 3] = crc >> 8; buf[(onek ? 1024 : 128) + 4] = crc; } else { sum = 0; for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++) sum += *p; buf[(onek ? 1024 : 128) + 3] = sum; } if(send(buf, (onek ? 1024 : 128) + 4 + crcmode) < 0) errorout(ctl, bytes); if (progress && bytes % 10240 == 0) fprint(2, "%dK\n", bytes / 1024); } /* tell other side we're done */ buf[0] = Eot; if(send(buf, 1) < 0) errorout(ctl, bytes); fprint(2, "xms: %d bytes transmitted\n", bytes); write(ctl, "rawoff", 6); exits(0); } /* * send a message till it's acked or we give up */ int send(uchar *buf, int len) { int tries; int n; uchar c; for(tries = 0;; tries++, sleep(2*1000)){ if(tries == 10) return -1; if(write(1, buf, len) != len) return -1; alarm(30*1000); n = read(0, &c, 1); alarm(0); if(debug) switch(c){ case Soh: fprint(2, " Soh"); break; case Eot: fprint(2, " Eot"); break; case Ack: fprint(2, " Ack"); break; case Nak: fprint(2, " Nak"); break; case Cancel: fprint(2, "\nremote Cancel\n"); return -1; default: if(isprint(c)) fprint(2, "%c", c); else fprint(2, " \\0%o", c); } c = c & 0x7f; if(n == 1 && c == Ack) break; } return 0; } int notifyf(void *a, char *msg) { USED(a); if(strcmp(msg, "alarm") == 0) return 1; return 0; }