From accf41f8b2b71b03fbd3c7cd5774d44a83874f4a Mon Sep 17 00:00:00 2001
From: Valentin Dornauer <valentin@unimplemented.org>
Date: Tue, 1 Jul 2014 11:54:00 +0200
Subject: [PATCH] Avoid reusing the same TCP port number

Make the initial port number depend on the RTC time. Increase it by 80
for every second, wrapping around after 512 seconds.

* grub-core/net/tcp.c (grub_net_tcp_open): Calculate in_port based
on RTC time to avoid problems with stale open TCP connections on the
remote host.

Original patch by Stefan Fritsch <fritsch@genua.de>.
---
 ChangeLog           |    6 ++++++
 grub-core/net/tcp.c |   21 ++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 5109c5a..61a01d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2014-07-01  Valentin Dornauer  <valentin@unimplemented.org>
+
+	* grub-core/net/tcp.c (grub_net_tcp_open): Calculate in_port based
+	on RTC time to avoid problems with stale open TCP connections on the
+	remote host.
+
 2014-06-26  Colin Watson  <cjwatson@ubuntu.com>
 
 	* docs/grub-dev.texi (Finding your way around): The build system no
diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
index 2077f55..b125e6d 100644
--- a/grub-core/net/tcp.c
+++ b/grub-core/net/tcp.c
@@ -22,6 +22,7 @@
 #include <grub/net/netbuff.h>
 #include <grub/time.h>
 #include <grub/priority_queue.h>
+#include <grub/datetime.h>
 
 #define TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
 #define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES
@@ -553,13 +554,31 @@ grub_net_tcp_open (char *server,
   struct grub_net_network_level_interface *inf;
   grub_net_network_level_address_t gateway;
   grub_net_tcp_socket_t socket;
-  static grub_uint16_t in_port = 21550;
+  static grub_uint16_t in_port = 0;
   struct grub_net_buff *nb;
   struct tcphdr *tcph;
   int i;
   grub_uint8_t *nbd;
   grub_net_link_level_address_t ll_target_addr;
 
+  if (in_port == 0)
+    {
+      struct grub_datetime datetime;
+      unsigned int seconds;
+      in_port = 21550;
+
+      /*
+       * Try to not use the same initial port number on consecutive quick reboots,
+       * in particular avoid collisions within the usual TIME_WAIT time of 120s.
+       * Increase the initial port number by 80 for every RTC second mod 512.
+       * This means the max for in_port is 21550 + 511 * 80 == 62430.
+       */
+      if (grub_get_datetime (&datetime) == 0)
+      {
+	seconds = ((datetime.hour * 60 ) + datetime.minute ) * 60 + datetime.second;
+	in_port += (seconds & 511) * 80;
+      }
+    }
   err = grub_net_resolve_address (server, &addr);
   if (err)
     return NULL;
-- 
1.7.10.4

