* grub-core/net/tftp.c: Retransmit ack when rereceiving old packet.
Try to handle more than 0xFFFF packets.
This commit is contained in:
parent
6d1fc99ab5
commit
cf8d6bbd9e
2 changed files with 24 additions and 9 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
2013-10-26 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
* grub-core/net/tftp.c: Retransmit ack when rereceiving old packet.
|
||||||
|
Try to handle more than 0xFFFF packets.
|
||||||
|
Reported by: Bernhard Übelacker <bernhardu>.
|
||||||
|
He also spotted few overflows in first version of this patch.
|
||||||
|
|
||||||
2013-10-26 Vladimir Serbinenko <phcoder@gmail.com>
|
2013-10-26 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* tests/date_unit_test.c: New test.
|
* tests/date_unit_test.c: New test.
|
||||||
|
|
|
@ -102,13 +102,24 @@ typedef struct tftp_data
|
||||||
grub_uint64_t file_size;
|
grub_uint64_t file_size;
|
||||||
grub_uint64_t block;
|
grub_uint64_t block;
|
||||||
grub_uint32_t block_size;
|
grub_uint32_t block_size;
|
||||||
grub_uint32_t ack_sent;
|
grub_uint64_t ack_sent;
|
||||||
int have_oack;
|
int have_oack;
|
||||||
struct grub_error_saved save_err;
|
struct grub_error_saved save_err;
|
||||||
grub_net_udp_socket_t sock;
|
grub_net_udp_socket_t sock;
|
||||||
grub_priority_queue_t pq;
|
grub_priority_queue_t pq;
|
||||||
} *tftp_data_t;
|
} *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
|
static int
|
||||||
cmp (const void *a__, const void *b__)
|
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 *a = (struct tftphdr *) a_->data;
|
||||||
struct tftphdr *b = (struct tftphdr *) b_->data;
|
struct tftphdr *b = (struct tftphdr *) b_->data;
|
||||||
/* We want the first elements to be on top. */
|
/* 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 -cmp_block (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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
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;
|
struct tftphdr *tftph_ack;
|
||||||
grub_uint8_t nbdata[512];
|
grub_uint8_t nbdata[512];
|
||||||
|
@ -213,12 +220,13 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
nb_top = *nb_top_p;
|
nb_top = *nb_top_p;
|
||||||
tftph = (struct tftphdr *) nb_top->data;
|
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;
|
break;
|
||||||
|
ack (data, grub_be_to_cpu16 (tftph->u.data.block));
|
||||||
grub_netbuff_free (nb_top);
|
grub_netbuff_free (nb_top);
|
||||||
grub_priority_queue_pop (data->pq);
|
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;
|
unsigned size;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue