From 450bf1739ef0e1bce97ed28c4ed2b74ae6cdb9ca Mon Sep 17 00:00:00 2001
From: "David J. Fiddes" <D.J@fiddes.net>
Date: Sun, 29 Sep 2019 17:46:17 +0100
Subject: [PATCH] sntp: Don't over-write IPv6 NTP server when processing DHCP
 updates

Currently when a DHCP or DHCPv6 updates containing NTP
server addresses is processed all existing NTP server addresses
are wiped. This can lead to problems when there is intermittent
connectivity to an NTP server over a given IP protocol. This
changes DHCP update processing such that it only overwrites
server addresses for the same protocol. It also does the same
for IPv4 NTP server addresses when processing a DHCPv6 update.

The logging for processing DHCP and DHCPv6 updates are now
a bit more useful.

Tests:
 - On a network with DHCP and DHCPv6 configure diffiering
   numbers (0-3) of NTP servers on each protocol. Ensure that
   as updates are processed the list of 3 LWIP NTP servers is
   updated as expected.
 - On a network with intermittent IPv6 connectivity ensure that
   with both IPv4 and IPv6 servers configured via DHCP that NTP
   updates are requested over IPv4 even if it is not listed first.
---
 src/apps/sntp/sntp.c | 52 ++++++++++++++++++++++++++++----------------
 1 file changed, 33 insertions(+), 19 deletions(-)

diff --git a/src/apps/sntp/sntp.c b/src/apps/sntp/sntp.c
index a6c4ff07..494971ca 100644
--- a/src/apps/sntp/sntp.c
+++ b/src/apps/sntp/sntp.c
@@ -819,20 +819,28 @@ sntp_setserver(u8_t idx, const ip_addr_t *server)
  * @param server IP address of the NTP server to set
  */
 void
-dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
+dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *servers)
 {
-  LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
+  LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u NTP server(s) via DHCP\n",
                                  (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
-                                 ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
+                                 num));
   if (sntp_set_servers_from_dhcp && num) {
-    u8_t i;
-    for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
-      ip_addr_t addr;
-      ip_addr_copy_from_ip4(addr, server[i]);
-      sntp_setserver(i, &addr);
-    }
-    for (i = num; i < SNTP_MAX_SERVERS; i++) {
-      sntp_setserver(i, NULL);
+    u8_t newidx = 0;
+    for (u8_t i = 0; i < SNTP_MAX_SERVERS; i++) {
+      const ip_addr_t* slotIp = sntp_getserver(i);
+      /* If we have an empty or IPv4 slot replace it with a new value from DHCP */
+      if (ip_addr_isany(slotIp) || IP_IS_V4(slotIp)) {
+        if (newidx < num) {
+          ip_addr_t addr;
+          ip_addr_copy_from_ip4(addr, servers[newidx]);
+          LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: Adding server %s to slot %u\n",
+                                        ipaddr_ntoa(&addr), i ));
+          sntp_setserver(i, &addr);
+          newidx++;
+        } else {
+          sntp_setserver(i, NULL);
+        }
+      }
     }
   }
 }
@@ -852,14 +860,20 @@ dhcp6_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs)
                                  (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
                                  num_ntp_servers));
   if (sntp_set_servers_from_dhcp && num_ntp_servers) {
-    u8_t i;
-    for (i = 0; (i < num_ntp_servers) && (i < SNTP_MAX_SERVERS); i++) {
-      LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: NTP server %u: %s\n",
-                                     i, ipaddr_ntoa(&ntp_server_addrs[i])));
-      sntp_setserver(i, &ntp_server_addrs[i]);
-    }
-    for (i = num_ntp_servers; i < SNTP_MAX_SERVERS; i++) {
-      sntp_setserver(i, NULL);
+    u8_t newidx = 0;
+    for (u8_t i = 0; i < SNTP_MAX_SERVERS; i++) {
+      const ip_addr_t* slotIp = sntp_getserver(i);
+      /* If we have an empty or IPv6 slot replace it with a new value from DHCPv6 */
+      if (ip_addr_isany(slotIp) || IP_IS_V6(slotIp)) {
+        if (newidx < num_ntp_servers) {
+          LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: Adding server %s to slot %u\n",
+                                         ipaddr_ntoa(&ntp_server_addrs[newidx]), i));
+          sntp_setserver(i, &ntp_server_addrs[newidx]);
+          newidx++;
+        } else {
+          sntp_setserver(i, NULL);
+        }
+      }
     }
   }
 }
-- 
2.21.0

