char* lab_ymodem_receive(int* length, int ymodemg) { int stop; int firstblk; unsigned char gotch; int pktsize; int size = 0; char* rxbuf = NULL; int rbytes; int waitpkts; stop = 0; firstblk = 1; lab_delay(6); rbytes = 0; waitpkts = 16; while (!stop) { if (firstblk) { if (ymodemg) lab_putc(GRC); else lab_putc(CRC); } gotch = getchar(); if (gotch == 0) // timeout { waitpkts--; if (!waitpkts) { printk("WARNING: YMODEM receive timed out!\n"); if (rxbuf) vfree(rxbuf); return NULL; } continue; } switch (gotch) { case SOH: pktsize = 128; goto havesize; case STX: pktsize = 1024; havesize: { unsigned char blk; unsigned char blk255; unsigned char dbytes[1028]; int i; blk = getchar(); blk255 = getchar(); for (i=0; i<pktsize+2; i++) dbytes[i] = getchar(); if (crc16_buf(dbytes, pktsize+2)) { /* CRC failed, try again */ lab_putc(NAK); break; } if (blk255 != (255-blk)) { lab_putc(NAK); break; } if (firstblk) { int i; char* buf; buf = dbytes + strlen(dbytes) + 1; i = 0; size = 0; while (*buf >= '0' && *buf <= '9') { size *= 10; size += *buf - '0'; buf++; } *length = size; size += 1024; rxbuf = vmalloc(size+1024); // a little more safety... // printk(">>> YMODEM: getting file of size %d (buf addr: %08X)\n", size-1024, rxbuf); lab_putc(ACK); if (ymodemg) lab_putc(GRC); else lab_putc(CRC); firstblk = 0; break; } if ((rbytes + pktsize) > size) { lab_putc(CAN); lab_putc(CAN); /* BUFFER OVERRUN!!! */ stop = 1; break; } memcpy(rxbuf+rbytes, dbytes, pktsize); rbytes += pktsize; if (!ymodemg) lab_putc(ACK); break; } case EOT: lab_putc(ACK); lab_delay(1); lab_putc(CRC); lab_delay(1); lab_putc(ACK); lab_delay(1); lab_putc(CAN); lab_putc(CAN); lab_putc(CAN); lab_putc(CAN); lab_puts("\x08\x08\x08\x08 \x08\x08\x08\x08"); eatbytes(); stop = 1; break; case CAN: lab_putc(CAN); lab_putc(CAN); lab_putc(CAN); lab_putc(CAN); lab_puts("\x08\x08\x08\x08 \x08\x08\x08\x08"); stop = 1; lab_delay(1); lab_puts("YMODEM transfer aborted\r\n"); if (rxbuf) vfree(rxbuf); rxbuf = NULL; eatbytes(); break; case 0x03: case 0xFF: /* Control-C. We should NAK it if it was line noise, * but it's more likely to be the user banging on the * keyboard trying to abort a screwup. */ lab_putc(CAN); lab_putc(CAN); lab_putc(CAN); lab_putc(CAN); lab_puts("\x08\x08\x08\x08 \x08\x08\x08\x08"); eatbytes(); if (rxbuf) vfree(rxbuf); rxbuf = NULL; stop=1; break; default: lab_putc(NAK); } } return rxbuf; }
/* Returns 0 on success, 1 on corrupt packet, -1 on error (timeout): */ static int receive_packet(char *data, int *length, int use_crc, int timeout){ int i; unsigned int packet_size, sum; char c; *length = 0; if(receive_byte(&c, timeout) < 0) return -1; switch(c){ case SOH: packet_size = PACKET_SIZE; break; case STX: packet_size = PACKET_1K_SIZE; break; case EOT: return 0; case CAN: if(receive_byte(&c, timeout) == 0 && c == CAN){ *length = -1; return 0; } default: /* This case could be the result of corruption on the first octet * of the packet, but it's more likely that it's the user banging * on the terminal trying to abort a transfer. Technically, the * former case deserves a NAK, but for now we'll just treat this * as an abort case. */ *length = -1; return 0; } *data = c; for(i = 1; i < (packet_size + (use_crc ? PACKET_OVERHEAD_CRC : PACKET_OVERHEAD)); ++i) if(receive_byte(data + i, timeout) < 0) return -1; /* Just a sanity check on the sequence number/complement value. * Caller should check for in-order arrival. */ if(data[PACKET_SEQNO_INDEX] != (data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff) return 1; if(use_crc){ /* It seems odd that the CRC doesn't cover the three preamble bytes. */ if(crc16_buf(data + PACKET_HEADER, packet_size + PACKET_TRAILER_CRC) != 0) return 1; } else { for(i = PACKET_HEADER, sum = 0; i < packet_size + PACKET_HEADER; ++i) sum += data[i]; if((sum & 0xff) != (data[i] & 0xff)) return 1; } *length = packet_size; return 0; }