]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
* grub-core/net/tftp.c: Retransmit ack when rereceiving old packet.
authorVladimir Serbinenko <phcoder@gmail.com>
Sat, 26 Oct 2013 10:48:49 +0000 (12:48 +0200)
committerVladimir Serbinenko <phcoder@gmail.com>
Sun, 27 Oct 2013 18:15:37 +0000 (19:15 +0100)
Try to handle more than 0xFFFF packets.

ChangeLog
grub-core/net/tftp.c

index cc7c43fc17289aebbd081cd88643293ebfbb82e8..8ebfb47798375aa2b64f46cfafefff51a219d886 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
        * tests/date_unit_test.c: New test.
index b9d9549c8adab3ffdbeb77a92848ab74e7200ff8..97217d23daffeaa0c3c347f2cb4951ef791952e8 100644 (file)
@@ -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;