SNTP IPv6

Andrew Lunn andrew.lunn@ascom.ch
Mon May 19 15:40:00 GMT 2003


Attached is a patch which adds support for IPv6 to the Simple Network
Time Protocol client.

     Andrew


-------------- next part --------------
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/ChangeLog,v
retrieving revision 1.5
diff -u -r1.5 ChangeLog
--- ChangeLog	9 Apr 2003 20:31:45 -0000	1.5
+++ ChangeLog	19 May 2003 15:39:33 -0000
@@ -1,3 +1,7 @@
+2003-05-19  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/sntp.c: Added support for IPv6 multicast NTP packets.
+
 2003-04-09  Michael Checky  <Michael_Checky@Thermoking.com>
 
 	* src/sntp.c: In function sntp_fn() changed 'version' to
Index: doc/sntp.sgml
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/doc/sntp.sgml,v
retrieving revision 1.2
diff -u -r1.2 sntp.sgml
--- doc/sntp.sgml	25 Feb 2003 18:12:19 -0000	1.2
+++ doc/sntp.sgml	19 May 2003 15:39:33 -0000
@@ -35,8 +35,8 @@
 <PARA>
 The SNTP package provides implementation of a client for RFC 2030, the
 Simple Network Time Protocol (SNTP). The client listens for broadcasts
-from an NTP server and uses the information received to set the system
-clock.
+or IPv6 multicasts from an NTP server and uses the information received to
+set the system clock.
 </PARA>
 </PARTINTRO>
 <CHAPTER id="net-sntp">
@@ -45,7 +45,7 @@
 <TITLE>Starting the SNTP client</TITLE>
 <para>
 The sntp client is implemented as a thread which listens for NTP
-broadcasts. This thread is not automatically start by the
+broadcasts and IPv6 multicasts. This thread is not automatically start by the
 system. Instead it must be started by the user application. The header
 file <filename>cyg/sntp/sntp.h</filename> declares the function to be
 called.  The thread is then started by calling the function:
@@ -61,17 +61,19 @@
 <sect1 id="net-sntp-operation">
 <title>What it does</title>
 <para>
-The SNTP client listens for NTP broadcasts from any NTP servers. Such
-broadcasts contain a timestamp indicating the current time. The packet
+The SNTP client listens for NTP IPv4 broadcasts from any NTP servers,
+or IPv6 multicasts using the address fe0x:0X::101, where X can be 1
+(Node Local), 2 (Link Local), 5 (Site-Local) or 0xe (Global). Such
+packets contain a timestamp indicating the current time. The packet
 also contains information about where the server is in the hierarchy
 of time servers. A server at the root of the time server tree normally
 has an atomic clock. Such a server is said to be at stratum 0. A time
 server which is synchronised to a stratum 0 server is said to be at
-stratum 1 etc. The client will accept any NTP broadcast packets from
+stratum 1 etc. The client will accept any NTP packets from
 servers using version 3 or 4 of the protocol. When receiving packets
 from multiple servers, it will use the packets from the server with
 the lowest stratum. However, if there are no packets from this server
-for 10 minute and another server is broadcasting, the client will
+for 10 minute and another server is sending packets, the client will
 change server.
 </para>
 <para>
@@ -88,7 +90,7 @@
 the number of seconds after 00:00 01/01/1900. This 32bit number will
 wrap around at 06:28:16 Feb 7 2036. At this point in time, the eCos
 time will jump back to around 00:00:00 Jan 1 1900 when the next
-broadcast is received. 
+NTP packett is received. 
 </para>
 <para>
 YOU HAVE BEEN WARNED!
@@ -99,19 +101,20 @@
 <para>
 The SNTP package contains a simple test program. Testing an SNTP
 client is not easy, so the test program should be considered as more a
-proof of concept. It shows that a broadcast packet has been received,
-at is accurate to within a few days. 
+proof of concept. It shows that an NTP packet has been received,
+and is accurate to within a few days. 
 </para>
 <para>
 The test program starts the network interfaces using the standard
 call. It then starts the SNTP thread. A loop is then entered printing
 the current system time every second for two minutes. When the client
-receives a broadcast the time will jump from 1970 to hopefully the
+receives an NTP packet the time will jump from 1970 to hopefully the
 present day. Once the two minutes have expired, two simple tests are
 made. If the time is still less than 5 minutes since 00:00:00
-01/01/1970 the test fails. This indicates no broadcast messages have
-been received. Check that the server is actually broadcasting, using
-the correct port (123), and at a sufficiently frequent rate that the
+01/01/1970 the test fails. This indicates no NTP messages have
+been received. Check that the server is actually sending packet, using
+the correct port (123), correct IPv6 multicast address, and at a
+sufficiently frequent rate that the
 target has a chance to receive a message within the 2 minute
 interval. If all this is correct, assume the target is broken. 
 </para>
@@ -119,7 +122,7 @@
 The second test is that the current system time is compared with the
 build time as reported by the CPP macro __DATE__. If the build date is
 in the future relative to the system time, the test fails. If the
-build date is more than 10 days in the past relative to the system
+build date is more than 90 days in the past relative to the system
 time the test also fails. If such failures are seen, use walk-clock
 time to verify the time printed during the test. If this seems correct
 check the build date for the test. This is printed at startup. If all
Index: include/sntp.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/include/sntp.h,v
retrieving revision 1.3
diff -u -r1.3 sntp.h
--- include/sntp.h	25 Feb 2003 19:03:47 -0000	1.3
+++ include/sntp.h	19 May 2003 15:39:33 -0000
@@ -52,6 +52,11 @@
 
 #include <cyg/infra/cyg_type.h>
 
+// Multicast address used by IPv6
+#define IN6ADDR_NTP_MULTICAST \
+	{{{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01 }}}
+
 /* Call this function to start the SNTP Client */
 __externC void 
 cyg_sntp_start(void);
Index: src/sntp.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/src/sntp.c,v
retrieving revision 1.3
diff -u -r1.3 sntp.c
--- src/sntp.c	9 Apr 2003 20:31:45 -0000	1.3
+++ src/sntp.c	19 May 2003 15:39:33 -0000
@@ -65,7 +65,7 @@
 #define MODE_BROADCAST 5
 
 struct sntp_srv_s {
-  struct sockaddr_in addr;
+  struct sockaddr addr;
   int stratum;
   int version;
   cyg_uint32 timestamp;
@@ -95,7 +95,7 @@
    
   time_t last_time, diff;
   
-  if (newer->addr.sin_addr.s_addr == old->addr.sin_addr.s_addr) return 1;
+  if (!memcmp(&newer->addr, &old->addr, newer->addr.sa_len)) return 1;
   if (newer->stratum < old->stratum) return 1;
 
   if (old->timestamp != 0xffffffff) {
@@ -109,6 +109,8 @@
   return 1;
 }
 
+const struct in6_addr in6addr_ntp_multicast = IN6ADDR_NTP_MULTICAST;
+
 static void sntp_fn(cyg_addrword_t data) {
   int fd;
   int ret;
@@ -120,6 +122,13 @@
   int mode;
   int len;
   time_t new_time, current_time, diff;
+  fd_set readfds;
+  int n;
+#ifdef CYGPKG_NET_INET6
+  int fd6 = -1;
+  struct ipv6_mreq mreq;
+  struct sockaddr_in6 local6;
+#endif
 
   memset(&best_srv,0xff,sizeof(best_srv));
 
@@ -131,17 +140,87 @@
 
   memset(&local,0,sizeof(local));
   local.sin_family = AF_INET;
+  local.sin_len = sizeof(local);
   local.sin_port = serv->s_port;
   local.sin_addr.s_addr = INADDR_ANY;
-  
+
   ret=bind(fd,(struct sockaddr *)&local,sizeof(local));
   CYG_ASSERT(0 == ret, "Bind failed");
 
+  n = fd;
+
+#ifdef CYGPKG_NET_INET6
+  fd6 = socket(AF_INET6, SOCK_DGRAM,0);
+  CYG_ASSERT(-1 != fd,"Failed to open socket");
+  mreq.ipv6mr_multiaddr = in6addr_ntp_multicast;
+  mreq.ipv6mr_interface = 0;
+
+  // Node-Local
+  ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+  CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Node-Local");
+
+#ifdef CYGHWR_NET_DRIVER_ETH0
+  // Link-Local
+  mreq.ipv6mr_multiaddr.s6_addr[1]=0x02;
+  mreq.ipv6mr_interface = if_nametoindex("eth0");
+  if (mreq.ipv6mr_interface != 0 ) {
+    ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+    CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Link-Local eth0");
+  }
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+  // Link-Local
+  mreq.ipv6mr_multiaddr.s6_addr[1]=0x02;
+  mreq.ipv6mr_interface = if_nametoindex("eth1");
+  if (mreq.ipv6mr_interface != 0 ) {
+    ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+    CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Link-Local eth1");
+  }
+#endif
+
+  // Site-Local
+  mreq.ipv6mr_multiaddr.s6_addr[1]=0x05;
+  ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+  CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Site-Local");
+
+  // Global
+  mreq.ipv6mr_multiaddr.s6_addr[1]=0x0e;
+  ret = setsockopt(fd6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
+  CYG_ASSERT(0 == ret, "setsockopt(IPV6_JOIN_GROUP) Global");
+  
+  memset(&local6,0,sizeof(local6));
+  local6.sin6_family = AF_INET6;
+  local6.sin6_len = sizeof(local6);
+  local6.sin6_port = serv->s_port;
+  local6.sin6_addr = in6addr_any;
+  
+  ret = bind(fd6, (struct sockaddr *)&local6,sizeof(local6));
+  CYG_ASSERT(0 == ret, "Bind6 failed");
+  
+  n = (n > fd6 ? n : fd6);
+#endif
+
   while (1) {
+    FD_ZERO(&readfds);
+    FD_SET(fd,&readfds);
+#ifdef CYGPKG_NET_INET6
+    FD_SET(fd6,&readfds);
+#endif
+    
+    ret = select(n+1, &readfds,NULL,NULL,NULL);
+    CYG_ASSERT(-1 != ret, "Select");
+
     len = sizeof(new_srv.addr);
-    ret=recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&new_srv.addr,&len);
+    if (FD_ISSET(fd,&readfds)) {
+      ret=recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&new_srv.addr,&len);
+    }
+#ifdef CYGPKG_NET_INET6
+    if (FD_ISSET(fd6,&readfds)) {
+      ret=recvfrom(fd6,buf,sizeof(buf),0,(struct sockaddr *)&new_srv.addr,&len);
+    }
+#endif
     CYG_ASSERT(0 < ret,"recvfrom");
-
+      
     /* We expect at least enough bytes to fill the buffer. There could
        be more if there is a digest, but we ignore that. */
     if (ret < sizeof(buf))
Index: tests/sntp1.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/tests/sntp1.c,v
retrieving revision 1.2
diff -u -r1.2 sntp1.c
--- tests/sntp1.c	25 Feb 2003 18:12:19 -0000	1.2
+++ tests/sntp1.c	19 May 2003 15:39:33 -0000
@@ -82,7 +82,7 @@
 
   cyg_sntp_start();
 
-  for (seconds = 120; seconds > 0; seconds--) {
+  for (seconds = 20; seconds > 0; seconds--) {
     now = time(NULL);
     ctime_r(&now, time_info);
     time_info[strlen(time_info)-1] = '\0';  // Strip \n
@@ -103,7 +103,7 @@
 	break;
     }
     tm.tm_mon = i;
-    tm.tm_mday++;
+    tm.tm_year -= 1900;
 
     build_time = mktime(&tm);
     CYG_ASSERT(-1 != build_time,"mktime returned -1");
@@ -111,7 +111,7 @@
     if (build_time > time(NULL)) {
       CYG_TEST_FAIL_FINISH("Build time is ahead of SNTP time");
     } else {
-      if ((build_time + 60 * 60 * 24 * 90) > time(NULL)) {
+      if ((build_time + 60 * 60 * 24 * 90) < time(NULL)) {
 	CYG_TEST_FAIL_FINISH("Build time is more than 90 days old");
       }
     }


More information about the Ecos-patches mailing list