Mercurial > ecos
changeset 2067:5841ca1d8824
TFTP ACK/NAK fixes, from Andrew Dyer
| author | gthomas |
|---|---|
| date | Fri, 09 Sep 2005 13:26:01 +0000 |
| parents | 5d5572c64422 |
| children | c051df3f1083 |
| files | packages/redboot/current/ChangeLog packages/redboot/current/include/net/tftp_support.h packages/redboot/current/src/load.c packages/redboot/current/src/net/tftp_client.c |
| diffstat | 4 files changed, 67 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog +++ b/packages/redboot/current/ChangeLog @@ -1,3 +1,16 @@ +2005-09-09 Andrew Dyer <adyer@righthandtech.com> + + * src/load.c: add calls to redboot_getc_terminate before exiting + load_elf_image() in various error scenarios, change the final call + to redboot_getc_terminate to have the error flag set. This will + cause a tftp nak and close down the connection since for ELF files + we don't read the whole content but end the connection when the + runnable parts are in. + + * src/net/tftp_client.c: add tftp_error() to send an error back to + the server. define tftp_stream_terminate() and pass it into the + redboot interface. + 2005-09-08 Gary Thomas <gary@mlbassoc.com> * src/io.c:
--- a/packages/redboot/current/include/net/tftp_support.h +++ b/packages/redboot/current/include/net/tftp_support.h @@ -87,6 +87,7 @@ extern int tftp_stream_open(connection_info_t *info, int *err); extern int tftp_stream_read(char *buf, int len, int *err); extern void tftp_stream_close(int *err); +extern void tftp_stream_terminate(bool abort, int (*getc)(void)); extern char *tftp_error(int err); #define TFTP_TIMEOUT_PERIOD 5
--- a/packages/redboot/current/src/load.c +++ b/packages/redboot/current/src/load.c @@ -307,6 +307,7 @@ load_elf_image(getc_t getc, unsigned lon // Read the header if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) { diag_printf("Can't read ELF header\n"); + redboot_getc_terminate(true); return 0; } offset += sizeof(ehdr); @@ -318,15 +319,18 @@ load_elf_image(getc_t getc, unsigned lon #endif if (ehdr.e_type != ET_EXEC) { diag_printf("Only absolute ELF images supported\n"); + redboot_getc_terminate(true); return 0; } if (ehdr.e_phnum > MAX_PHDR) { diag_printf("Too many program headers\n"); + redboot_getc_terminate(true); return 0; } while (offset < ehdr.e_phoff) { if ((*getc)() < 0) { diag_printf(SHORT_DATA); + redboot_getc_terminate(true); return 0; } offset++; @@ -334,6 +338,7 @@ load_elf_image(getc_t getc, unsigned lon for (phx = 0; phx < ehdr.e_phnum; phx++) { if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) { diag_printf("Can't read ELF program header\n"); + redboot_getc_terminate(true); return 0; } #if 0 // DEBUG @@ -376,6 +381,7 @@ load_elf_image(getc_t getc, unsigned lon if (offset > phdr[phx].p_offset) { if ((phdr[phx].p_offset + len) < offset) { diag_printf("Can't load ELF file - program headers out of order\n"); + redboot_getc_terminate(true); return 0; } addr += offset - phdr[phx].p_offset; @@ -383,6 +389,7 @@ load_elf_image(getc_t getc, unsigned lon while (offset < phdr[phx].p_offset) { if ((*getc)() < 0) { diag_printf(SHORT_DATA); + redboot_getc_terminate(true); return 0; } offset++; @@ -400,6 +407,7 @@ load_elf_image(getc_t getc, unsigned lon #endif if ((ch = (*getc)()) < 0) { diag_printf(SHORT_DATA); + redboot_getc_terminate(true); return 0; } *addr++ = ch; @@ -422,7 +430,10 @@ load_elf_image(getc_t getc, unsigned lon entry_address = ehdr.e_entry; } - redboot_getc_terminate(false); + // nak everything to stop the transfer, since redboot + // usually doesn't read all the way to the end of the + // elf files. + redboot_getc_terminate(true); if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset); diag_printf("Entry point: %p, address range: %p-%p\n", (void*)entry_address, (void *)load_address, (void *)load_address_end);
--- a/packages/redboot/current/src/net/tftp_client.c +++ b/packages/redboot/current/src/net/tftp_client.c @@ -158,10 +158,49 @@ tftp_ack(int *err) return 0; } +static int +tftp_error_ack(int *err, short code, char *msg) +{ + struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data; + + if (strlen(msg) > (SEGSIZE-1)) { + *(msg + SEGSIZE) = NULL; + } + + if (tftp_stream.packets_received > 0) { + hdr->th_opcode = htons(ERROR); + hdr->th_code = code; + strcpy(&hdr->th_data, msg); + if (__udp_sendto(tftp_stream.data, (5 + strlen(msg)), + &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) { + // Problem sending ACK + *err = TFTP_NETERR; + return -1; + } + } + return 0; +} + void tftp_stream_close(int *err) { - tftp_ack(err); + if (tftp_stream.open == true) { + tftp_ack(err); + tftp_stream.open = false; + } +} + +void +tftp_stream_terminate(bool abort, + int (*getc)(void)) +{ + int err; + + if (abort) + tftp_error_ack(&err, EUNDEF, "redboot tftp_stream_terminate"); + else + tftp_ack(&err); + tftp_stream.open = false; } @@ -274,6 +313,6 @@ tftp_error(int err) // RedBoot interface // GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close, - 0, tftp_stream_read, tftp_error); + tftp_stream_terminate, tftp_stream_read, tftp_error); RedBoot_load(tftp, tftp_io, true, true, 0);
