From cf8d6bbd9eb2f5c6cbb0b6e437466c77fc7b6e9b Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Sat, 26 Oct 2013 12:48:49 +0200 Subject: [PATCH] * grub-core/net/tftp.c: Retransmit ack when rereceiving old packet. Try to handle more than 0xFFFF packets. --- ChangeLog | 7 +++++++ grub-core/net/tftp.c | 26 +++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index cc7c43fc1..8ebfb4779 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-10-26 Vladimir Serbinenko + + * grub-core/net/tftp.c: Retransmit ack when rereceiving old packet. + Try to handle more than 0xFFFF packets. + Reported by: Bernhard Übelacker . + He also spotted few overflows in first version of this patch. + 2013-10-26 Vladimir Serbinenko * tests/date_unit_test.c: New test. diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c index b9d9549c8..97217d23d 100644 --- a/grub-core/net/tftp.c +++ b/grub-core/net/tftp.c @@ -102,13 +102,24 @@ typedef struct tftp_data grub_uint64_t file_size; grub_uint64_t block; grub_uint32_t block_size; - grub_uint32_t ack_sent; + grub_uint64_t ack_sent; int have_oack; struct grub_error_saved save_err; grub_net_udp_socket_t sock; grub_priority_queue_t pq; } *tftp_data_t; +static int +cmp_block (grub_uint16_t a, grub_uint16_t b) +{ + grub_int16_t i = (grub_int16_t) (a - b); + if (i > 0) + return +1; + if (i < 0) + return -1; + return 0; +} + static int cmp (const void *a__, const void *b__) { @@ -117,15 +128,11 @@ cmp (const void *a__, const void *b__) struct tftphdr *a = (struct tftphdr *) a_->data; struct tftphdr *b = (struct tftphdr *) b_->data; /* We want the first elements to be on top. */ - if (grub_be_to_cpu16 (a->u.data.block) < grub_be_to_cpu16 (b->u.data.block)) - return +1; - if (grub_be_to_cpu16 (a->u.data.block) > grub_be_to_cpu16 (b->u.data.block)) - return -1; - return 0; + return -cmp_block (grub_be_to_cpu16 (a->u.data.block), grub_be_to_cpu16 (b->u.data.block)); } static grub_err_t -ack (tftp_data_t data, grub_uint16_t block) +ack (tftp_data_t data, grub_uint64_t block) { struct tftphdr *tftph_ack; grub_uint8_t nbdata[512]; @@ -213,12 +220,13 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), return GRUB_ERR_NONE; nb_top = *nb_top_p; tftph = (struct tftphdr *) nb_top->data; - if (grub_be_to_cpu16 (tftph->u.data.block) >= data->block + 1) + if (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) >= 0) break; + ack (data, grub_be_to_cpu16 (tftph->u.data.block)); grub_netbuff_free (nb_top); grub_priority_queue_pop (data->pq); } - if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1) + while (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) == 0) { unsigned size;