diff options
Diffstat (limited to 'recv_image.c')
-rw-r--r-- | recv_image.c | 229 |
1 files changed, 121 insertions, 108 deletions
diff --git a/recv_image.c b/recv_image.c index d2b8813..f9705f6 100644 --- a/recv_image.c +++ b/recv_image.c @@ -22,33 +22,31 @@ int main(int argc, char **argv) { - struct sockaddr_storage server_addr; - socklen_t server_addrlen = sizeof(server_addr); struct addrinfo *ai; struct addrinfo hints; struct addrinfo *runp; int ret; int sock; - struct image_pkt pktbuf; size_t len; int flfd; struct mtd_info_user meminfo; unsigned char *eb_buf; unsigned char *blockmap = NULL; - unsigned char *subblockmap; int nr_blocks = 0; - int nr_subblocks = 0; + int *pkt_indices; + unsigned char **pkts; + int nr_pkts = 0; int pkts_per_block; int block_nr = -1; uint32_t image_crc; uint32_t blocks_received = 0; - uint32_t block_ofs; loff_t mtdoffset = 0; int *stats; int badcrcs = 0; int duplicates = 0; - int missing = -1; int file_mode = 0; + struct fec_parms *fec; + int i; if (argc != 4) { fprintf(stderr, "usage: %s <host> <port> <mtddev>\n", @@ -84,26 +82,32 @@ int main(int argc, char **argv) pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE; - stats = malloc(pkts_per_block + 1); - if (!stats) { - fprintf(stderr, "No memory for statistics\n"); - exit(1); - } - memset(stats, 0, sizeof(int) * (pkts_per_block + 1)); - eb_buf = malloc(pkts_per_block * PKT_SIZE); if (!eb_buf) { fprintf(stderr, "No memory for eraseblock buffer\n"); exit(1); } - memset(eb_buf, 0, pkts_per_block * PKT_SIZE); - subblockmap = malloc(pkts_per_block + 1); - if (!subblockmap) { - fprintf(stderr, "No memory for subblock map\n"); + pkt_indices = malloc(sizeof(int) * pkts_per_block); + if (!pkt_indices) { + fprintf(stderr, "No memory for packet indices\n"); + exit(1); + } + memset(pkt_indices, 0, sizeof(int) * pkts_per_block); + + pkts = malloc(sizeof(unsigned char *) * pkts_per_block); + if (!pkts) { + fprintf(stderr, "No memory for packet pointers\n"); exit(1); } - memset(subblockmap, 0, pkts_per_block + 1); + for (i=0; i<pkts_per_block; i++) { + pkts[i] = malloc(sizeof(struct image_pkt_hdr) + PKT_SIZE); + if (!pkts[i]) { + printf("No memory for packets\n"); + exit(1); + } + pkts[i] += sizeof(struct image_pkt_hdr); + } memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG; @@ -143,7 +147,7 @@ int main(int argc, char **argv) close(sock); continue; } - } else printf("not multicast?\n"); + } if (bind(sock, runp->ai_addr, runp->ai_addrlen)) { perror("bind"); close(sock); @@ -154,56 +158,85 @@ int main(int argc, char **argv) if (!runp) exit(1); - while ((len = read(sock, &pktbuf, sizeof(pktbuf))) >= 0) { - if (len < sizeof(pktbuf.hdr)) { - fprintf(stderr, "Short read %d bytes\n", len); - continue; + while (1) { + struct image_pkt *thispkt; + + if (nr_pkts < pkts_per_block) + thispkt = (void *)(pkts[nr_pkts] - sizeof(struct image_pkt_hdr)); + else + thispkt = (void *)(pkts[0] - sizeof(struct image_pkt_hdr)); + + len = read(sock, thispkt, sizeof(*thispkt)); + + if (len < 0) { + perror("read socket"); + break; } - if (len != sizeof(pktbuf.hdr) + ntohl(pktbuf.hdr.thislen)) { - fprintf(stderr, "Wrong length %d bytes (expected %d+%d)\n", - len, sizeof(pktbuf.hdr), ntohl(pktbuf.hdr.thislen)); + if (len < sizeof(*thispkt)) { + fprintf(stderr, "Wrong length %d bytes (expected %d)\n", + len, sizeof(*thispkt)); continue; } - /* Holds _data_ length */ - len -= sizeof(pktbuf.hdr); - if (!blockmap) { - image_crc = pktbuf.hdr.totcrc; - if (meminfo.erasesize != ntohl(pktbuf.hdr.blocksize)) { + image_crc = thispkt->hdr.totcrc; + if (meminfo.erasesize != ntohl(thispkt->hdr.blocksize)) { fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n", - ntohl(pktbuf.hdr.blocksize), meminfo.erasesize); + ntohl(thispkt->hdr.blocksize), meminfo.erasesize); exit(1); } - nr_blocks = ntohl(pktbuf.hdr.nr_blocks); - nr_subblocks = pkts_per_block + 2; + nr_blocks = ntohl(thispkt->hdr.nr_blocks); + nr_pkts = 0; + + fec = fec_new(pkts_per_block, ntohs(thispkt->hdr.nr_pkts)); + blockmap = malloc(nr_blocks); if (!blockmap) { fprintf(stderr, "No memory for block map\n"); exit(1); } memset(blockmap, 0, nr_blocks); + stats = malloc(sizeof(int) * (ntohs(thispkt->hdr.nr_pkts) + 1)); + if (!stats) { + fprintf(stderr, "No memory for statistics\n"); + exit(1); + } + memset(stats, 0, sizeof(int) * (ntohs(thispkt->hdr.nr_pkts) + 1)); } - if (image_crc != pktbuf.hdr.totcrc) { + if (image_crc != thispkt->hdr.totcrc) { fprintf(stderr, "Image CRC changed from 0x%x to 0x%x. Aborting\n", - ntohl(image_crc), ntohl(pktbuf.hdr.totcrc)); + ntohl(image_crc), ntohl(thispkt->hdr.totcrc)); exit(1); } - if (ntohl(pktbuf.hdr.block_nr) != block_nr) { + if (ntohl(thispkt->hdr.block_nr) != block_nr) { /* Hm, new block */ - if (nr_subblocks < pkts_per_block && - block_nr != -1) - printf("Lost image block at %08x with only %d/%d packets\n", - block_nr * meminfo.erasesize, nr_subblocks, - pkts_per_block + 1); + if (block_nr != -1) { + if (!blockmap[block_nr]) { + printf("Lost image block %08x with only %d/%d (%d) packets\n", + block_nr * meminfo.erasesize, nr_pkts, pkts_per_block, + ntohs(thispkt->hdr.nr_pkts)); + } + if (blockmap[block_nr] < 2) { + stats[nr_pkts]++; + if (blockmap[block_nr]) { + if (file_mode) + printf(" with %d/%d (%d) packets\n", + nr_pkts, pkts_per_block, + ntohs(thispkt->hdr.nr_pkts)); + blockmap[block_nr] = 2; + } + } + } + /* Put this packet first */ + if (nr_pkts != 0 && nr_pkts < pkts_per_block) { + unsigned char *tmp = pkts[0]; + pkts[0] = pkts[nr_pkts]; + pkts[nr_pkts] = tmp; + } + nr_pkts = 0; - if (nr_subblocks < pkts_per_block + 2) - stats[nr_subblocks]++; + block_nr = ntohl(thispkt->hdr.block_nr); - nr_subblocks = 0; - missing = -1; - memset(subblockmap, 0, pkts_per_block + 1); - block_nr = ntohl(pktbuf.hdr.block_nr); if (block_nr > nr_blocks) { fprintf(stderr, "Erroneous block_nr %d (> %d)\n", block_nr, nr_blocks); @@ -212,84 +245,64 @@ int main(int argc, char **argv) if (blockmap[block_nr]) { printf("Discard chunk at 0x%08x for already-flashed eraseblock (%d to go)\n", block_nr * meminfo.erasesize, nr_blocks - blocks_received); - nr_subblocks = pkts_per_block + 2; continue; } } - if (nr_subblocks == pkts_per_block) { + if (nr_pkts >= pkts_per_block) { /* We have a parity block but we didn't need it */ - nr_subblocks++; + nr_pkts++; continue; } if (blockmap[block_nr]) continue; - block_ofs = ntohl(pktbuf.hdr.block_ofs); - if (block_ofs == meminfo.erasesize) - block_ofs = PKT_SIZE * pkts_per_block; - - if (len != PKT_SIZE && len + block_ofs != meminfo.erasesize) { - fprintf(stderr, "Bogus packet size 0x%x (expected 0x%x)\n", - ntohl(pktbuf.hdr.thislen), - min(PKT_SIZE, meminfo.erasesize - block_ofs)); - exit(1); - } + for (i=0; i < nr_pkts; i++) { + if (pkt_indices[i] == ntohs(thispkt->hdr.pkt_nr)) { + printf("Discarding duplicate packet at %08x pkt %d\n", + block_nr * meminfo.erasesize, pkt_indices[i]); + duplicates++; + break; + } + } /* And if we broke out, skip the packet... */ + if (i < nr_pkts) + continue; - if (crc32(-1, pktbuf.data, len) != ntohl(pktbuf.hdr.thiscrc)) { - printf("Discard chunk %08x with bad CRC (%08x not %08x)\n", - block_nr * meminfo.erasesize + block_ofs, - crc32(-1, pktbuf.data, pktbuf.hdr.thislen), - ntohl(pktbuf.hdr.thiscrc)); + if (crc32(-1, thispkt->data, PKT_SIZE) != ntohl(thispkt->hdr.thiscrc)) { + printf("Discard %08x pkt %d with bad CRC (%08x not %08x)\n", + block_nr * meminfo.erasesize, ntohs(thispkt->hdr.pkt_nr), + crc32(-1, thispkt->data, PKT_SIZE), + ntohl(thispkt->hdr.thiscrc)); badcrcs++; continue; } - if (subblockmap[block_ofs / PKT_SIZE]) { - printf("Discarding duplicate packet at %08x\n", - block_nr * meminfo.erasesize + block_ofs); - duplicates++; - continue; - } - subblockmap[block_ofs / PKT_SIZE] = 1; - nr_subblocks++; - if (block_ofs < meminfo.erasesize) { - /* Normal data packet */ - memcpy(eb_buf + block_ofs, pktbuf.data, len); -// printf("Received data block at %08x\n", block_nr * meminfo.erasesize + block_ofs); - } else { - /* Parity block */ - int i; - /* If we don't have enough to recover, skip */ - if (nr_subblocks < pkts_per_block) - continue; + pkt_indices[nr_pkts] = ntohs(thispkt->hdr.pkt_nr); + nr_pkts++; - for (i = 0; i<pkts_per_block; i++) { - if (subblockmap[i]) { - int j; - for (j=0; j<PKT_SIZE; j++) - pktbuf.data[j] ^= eb_buf[i*PKT_SIZE + j]; - } else - missing = i; - } + if (nr_pkts == pkts_per_block) { - if (missing == -1) { - fprintf(stderr, "dwmw2 is stupid\n"); + if (fec_decode(fec, pkts, pkt_indices, PKT_SIZE)) { + /* Eep. This cannot happen */ + printf("The world is broken. fec_decode() returned error\n"); exit(1); } -// printf("Recover missing packet at %08x from parity\n", -// block_nr * meminfo.erasesize + missing * PKT_SIZE); - memcpy(eb_buf + (missing * PKT_SIZE), pktbuf.data, PKT_SIZE); - } - - if (nr_subblocks == pkts_per_block) { - blockmap[block_nr] = 1; blocks_received++; + /* Put data into order in eb_buf */ + for (i=0; i < pkts_per_block; i++) + memcpy(eb_buf + (i * PKT_SIZE), pkts[i], PKT_SIZE); + + if (crc32(-1, eb_buf, meminfo.erasesize) != ntohl(thispkt->hdr.block_crc)) { + printf("FEC error. CRC %08x != %08x\n", + crc32(-1, eb_buf, meminfo.erasesize), + ntohl(thispkt->hdr.block_crc)); + *(int *)0 = 0; + exit(1); + } if (file_mode) { - printf("Received image block %08x%s (%d/%d)\n", + printf("Received image block %08x (%d/%d)", block_nr * meminfo.erasesize, - (missing==-1)?"":" (parity)", blocks_received, nr_blocks); pwrite(flfd, eb_buf, meminfo.erasesize, block_nr * meminfo.erasesize); } else { @@ -325,16 +338,16 @@ int main(int argc, char **argv) mtdoffset += meminfo.erasesize; goto again; } - printf("Wrote image block %08x (%d/%d) to flash offset %08x%s\n", + printf("Wrote image block %08x (%d/%d) to flash offset %08x\n", block_nr * meminfo.erasesize, blocks_received, nr_blocks, - (uint32_t)mtdoffset, - (missing==-1)?"":" (parity)"); + (uint32_t)mtdoffset); mtdoffset += meminfo.erasesize; } if (!(blocks_received%100) || blocks_received == nr_blocks) { int i, printed = 0; - for (i=0; i <= pkts_per_block + 1; i++) { + printf("\n"); + for (i=0; i <= ntohs(thispkt->hdr.nr_pkts); i++) { if (printed || stats[i]) { printf("Number of blocks with %d packets received: %d\n", i, stats[i]); |