Index: net/sntp/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/ChangeLog,v retrieving revision 1.7 diff -u -r1.7 ChangeLog --- net/sntp/current/ChangeLog 2 Oct 2003 22:43:41 -0000 1.7 +++ net/sntp/current/ChangeLog 21 Oct 2003 17:12:21 -0000 @@ -1,3 +1,12 @@ +2003-10-15 Dan Jakubiec + Andrew Lunn + + * src/sntp.c: Added DHCP support for SNTP unicast mode. + * src/sntp.cdl: Added DHCP support for SNTP unicast mode. + * src/sntp.h: Removed UDP port constant. + * src/sntp1.c: Added test code for SNTP unicast mode. + * src/sntp.sgml: Added documentation for SNTP unicast mode. + 2003-09-29 Dan Jakubiec * src/sntp.c: Added support for SNTP unicast mode. Index: net/sntp/current/cdl/sntp.cdl =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/cdl/sntp.cdl,v retrieving revision 1.3 diff -u -r1.3 sntp.cdl --- net/sntp/current/cdl/sntp.cdl 2 Oct 2003 22:43:41 -0000 1.3 +++ net/sntp/current/cdl/sntp.cdl 21 Oct 2003 17:12:22 -0000 @@ -62,21 +62,34 @@ requires CYGSEM_LIBC_TIME_SETTIME_WORKING compile sntp.c + cdl_component CYGPKG_NET_SNTP_UNICAST { + display "Enable SNTP client unicast support" + flavor bool + default_value 0 + description " + This option enables SNTP unicast mode in + for the SNTP client. This mode will send + SNTP requests to NTP/SNTP servers in + addition to listening for SNTP broadcasts." + + cdl_option CYGNUM_NET_SNTP_UNICAST_MAXDHCP { + display "Maximum number of NTP servers to use from DHCP" + flavor booldata + requires CYGPKG_NET_DHCP + legal_values 1 to 8 + default_value 2 + description " + This option specifies the maximum number of + NTP servers to get from DHCP. These servers + are used to configure the unicast SNTP client. + Disabling this option disables DHCP usage." + } + } + cdl_component CYGPKG_NET_SNTP_OPTIONS { display "SNTP support build options" flavor none no_define - - cdl_option CYGPKG_NET_SNTP_UNICAST { - display "Enable SNTP client unicast support" - flavor bool - default_value 0 - description " - This option enables SNTP unicast mode in - for the SNTP client. This mode will send - SNTP requests to NTP/SNTP servers in - addition to listening for SNTP broadcasts." - } cdl_option CYGPKG_NET_SNTP_CFLAGS_ADD { display "Additional compiler flags" Index: net/sntp/current/doc/sntp.sgml =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/doc/sntp.sgml,v retrieving revision 1.3 diff -u -r1.3 sntp.sgml --- net/sntp/current/doc/sntp.sgml 21 May 2003 14:03:36 -0000 1.3 +++ net/sntp/current/doc/sntp.sgml 21 Oct 2003 17:12:22 -0000 @@ -36,7 +36,8 @@ The SNTP package provides implementation of a client for RFC 2030, the Simple Network Time Protocol (SNTP). The client listens for broadcasts or IPv6 multicasts from an NTP server and uses the information received to -set the system clock. +set the system clock. It can also be configured to send SNTP time +requests to specific NTP servers using SNTP's unicast mode. @@ -45,16 +46,20 @@ Starting the SNTP client The sntp client is implemented as a thread which listens for NTP -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 cyg/sntp/sntp.h declares the function to be +broadcasts and IPv6 multicasts, and optionally sends SNTP unicast +requests to specific NTP servers. This thread may be automatically +started by the system if it receives a list of (S)NTP servers from the +DHCP server and unicast mode is enabled. Otherwise it must be started +by the user application. The header file +cyg/sntp/sntp.h declares the function to be called. The thread is then started by calling the function: void cyg_sntp_start(void); -Once started, the thread will run forever. +It is safe to call this function multiple times. Once started, the +thread will run forever. @@ -62,8 +67,8 @@ What it does 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 +or IPv6 multicasts using the address fe0x:0X::101, where X can be +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 @@ -73,8 +78,19 @@ 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 sending packets, the client will -change server. +for 10 minutes and another server is sending packets, the client will +change servers. + + +If SNTP unicast mode is enabled via the CYGPKG_NET_SNTP_UNICAST +option, the SNTP client can additionally be configured with a list +of specific NTP servers to query. The general algorithm is as follows: if +the system clock has not yet been set via an NTP time update, then +the client will send out NTP requests every 30 seconds to all +configured NTP servers. Once an NTP time update has been received, +the client will send out additional NTP requests every 30 minutes +in order to update the system clock. These requests are resent +every 30 seconds until a response is received. The system clock in eCos is accurate to 1 second. The SNTP client will @@ -83,6 +99,53 @@ + +Configuring the unicast list of NTP servers + +If SNTP unicast mode is enabled via the CYGPKG_NET_SNTP_UNICAST +option, the SNTP client can be configured with a list of +NTP servers to contact for time updates. + + +By default, this list is configured with NTP server information +received from DHCP. The number of NTP servers that are extracted +from DHCP can be configured with the CYGOPT_NET_SNTP_UNICAST_MAXDHCP +option. This option can also be used to disable DHCP usage entirely. + + +The list of NTP servers can be manually configured with the following +API function. Note that manual configuration will override any +servers that were automatically configured by DHCP. But later +reconfigurations by DHCP will override manual configurations. Hence it +is not recommended to manually configure servers when +CYGOPT_NET_SNTP_UNICAST is enabled. + + +#include <cyg/sntp/sntp.h> + +void cyg_sntp_set_servers(struct sockaddr *server_list, cyg_uint32 num_servers); + + +This function takes an array of sockaddr structures specifying the +IP address and UDP port of each NTP server to query. Currently, +both IPv4 and IPv6 sockaddr structures are supported. The +num_servers argument specifies how many sockaddr's are contained +in the array. The server_list array must be maintained by the caller. +Once the array is registered with this function, it must not be +modified by the caller until it is replaced or unregistered +by another call to this function. + + +Calling this function with a server_list of NULL and a num_servers +value of 0 unregisters any previously configured server_list array. + + +Finally, note that if this function is called with a non-empty server +list, it will implicitly start the SNTP client if it has not already +been started (i.e. it will call cyg_sntp_start()). + + + Warning: timestamp wrap around @@ -90,7 +153,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 -NTP packett is received. +NTP packet is received. YOU HAVE BEEN WARNED! @@ -129,6 +192,16 @@ else fails check that the computer used to build the test has the correct time. + +If SNTP unicast mode is enabled, the above tests are run twice. The +first time, the SNTP client is configured with NTP server addresses +from DHCP. The second time, unicast mode is disabled and only +multicasts are listened for. Note that the unicast test is partially +bogus in the sense that any multicast packet received will also make +the unicast test pass. To reduce the chance of this happening the +test will wait for a sorter time for replies. This is not ideal, but +it is the best that can be done with an automated test. + - \ No newline at end of file + Index: net/sntp/current/include/sntp.h =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/include/sntp.h,v retrieving revision 1.5 diff -u -r1.5 sntp.h --- net/sntp/current/include/sntp.h 2 Oct 2003 22:43:42 -0000 1.5 +++ net/sntp/current/include/sntp.h 21 Oct 2003 17:12:23 -0000 @@ -53,9 +53,6 @@ #include #include -/* General Definitions */ -#define NTP_UDP_PORT 123 - // Multicast address used by IPv6 #define IN6ADDR_NTP_MULTICAST \ {{{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ Index: net/sntp/current/src/sntp.c =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/src/sntp.c,v retrieving revision 1.5 diff -u -r1.5 sntp.c --- net/sntp/current/src/sntp.c 2 Oct 2003 22:43:42 -0000 1.5 +++ net/sntp/current/src/sntp.c 21 Oct 2003 17:12:24 -0000 @@ -480,7 +480,6 @@ } #ifdef CYGPKG_NET_SNTP_UNICAST - /* * FUNCTION cyg_sntp_set_servers * @@ -497,8 +496,10 @@ * array can be unregistered by calling this * function again with different parameters. * - * NOTE: This function must be called AFTER - * cyg_sntp_start(). + * NOTE: If cyg_sntp_start() has not been called + * already, and this function is called with a + * list of 1 or more servers, then cyg_sntp_start() + * will be called by this function to start the client. * * PARAMETERS * server_list - Array of IPv4 and/or IPv6 sockaddr's @@ -510,9 +511,21 @@ void cyg_sntp_set_servers(struct sockaddr *server_list, cyg_uint32 num_servers) { - /* Get the server list mutex */ + /* If we haven't already started the SNTP client, then + * start it now. + */ if (!sntp_initialized) - return; + { + /* If we haven't started already and we don't + * have a list of servers, then don't start + * anything up. + */ + if (num_servers == 0) + return; + cyg_sntp_start(); + } + + /* Get the server list mutex */ cyg_mutex_lock(&sntp_mutex); /* Record the new server list */ @@ -525,4 +538,7 @@ cyg_mutex_unlock(&sntp_mutex); } #endif /* CYGPKG_NET_SNTP_UNICAST */ + + + Index: net/sntp/current/tests/sntp1.c =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/sntp/current/tests/sntp1.c,v retrieving revision 1.3 diff -u -r1.3 sntp1.c --- net/sntp/current/tests/sntp1.c 21 May 2003 14:03:37 -0000 1.3 +++ net/sntp/current/tests/sntp1.c 21 Oct 2003 17:12:24 -0000 @@ -66,7 +66,7 @@ int seconds; time_t now, build_time; struct tm tm={ 0,0,0,0,0,0,0,0,0 }; - int i; + int i, loop, waittime; char month[4]; char months[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -82,39 +82,78 @@ cyg_sntp_start(); - for (seconds = 20; seconds > 0; seconds--) { - now = time(NULL); - ctime_r(&now, time_info); - time_info[strlen(time_info)-1] = '\0'; // Strip \n - CYG_TEST_INFO(time_info); - cyg_thread_delay(100); - } + /* The SNTP client will try to obtain NTP time updates by + * listening for multicasts. It can also be configured + * to send unicast requests to specific NTP servers. By + * default, unicast NTP servers are obtained from DHCP. + * + * If unicast mode is enabled, the run the test loop twice. + * The first time, unicast requests will be sent. The + * second time, the unicast list will be unconfigured and + * the client will listen only for multicasts. + * + * Note that this test is somewhat bogus since multicast + * NTP packets will actually allow both test loops to + * pass. But it is the best we can do for the automated + * test, so consider this more of a usage example. + */ +#ifdef CYGPKG_NET_SNTP_UNICAST + loop = 2; +#else + loop = 1; +#endif + while (loop-- > 0) + { + if (loop == 1) { + CYG_TEST_INFO("Testing SNTP unicast mode."); + waittime=14; + } else { + CYG_TEST_INFO("Testing SNTP multicast mode."); + waittime=20; + } + for (seconds = waittime; seconds > 0; seconds--) { + now = time(NULL); + ctime_r(&now, time_info); + time_info[strlen(time_info)-1] = '\0'; // Strip \n + CYG_TEST_INFO(time_info); + cyg_thread_delay(100); + } - now = time(NULL); + now = time(NULL); - if ( now < (5 * 60)) { - CYG_TEST_FAIL_FINISH("Nothing recieved from the SNTP server"); - } else { + if ( now < (5 * 60)) { + CYG_TEST_FAIL_FINISH("Nothing recieved from the SNTP server"); + } else { - i=sscanf(__DATE__, "%s %d %d",month,&tm.tm_mday,&tm.tm_year); - CYG_ASSERT(3==i,"sscanf did not return enough results"); - for (i=0; i < 12; i++) { - if (!strcmp(month,months[i])) - break; - } - tm.tm_mon = i; - tm.tm_year -= 1900; + i=sscanf(__DATE__, "%s %d %d",month,&tm.tm_mday,&tm.tm_year); + CYG_ASSERT(3==i,"sscanf did not return enough results"); + for (i=0; i < 12; i++) { + if (!strcmp(month,months[i])) + break; + } + tm.tm_mon = i; + tm.tm_year -= 1900; - build_time = mktime(&tm); - CYG_ASSERT(-1 != build_time,"mktime returned -1"); + build_time = mktime(&tm); + CYG_ASSERT(-1 != build_time,"mktime returned -1"); - 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)) { - CYG_TEST_FAIL_FINISH("Build time is more than 90 days old"); + 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)) { + CYG_TEST_FAIL_FINISH("Build time is more than 90 days old"); + } } } + +#ifdef CYGPKG_NET_SNTP_UNICAST + /* For the second pass of the test, we set the time + * back to epoch and unconfigure the list of SNTP + * unicast servers. This will test non-unicast mode. + */ + cyg_sntp_set_servers(NULL, 0); + cyg_libc_time_settime(0); +#endif } CYG_TEST_PASS_FINISH("sntp1 test is complete"); } Index: net/common//current/src/bootp_support.c =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/bootp_support.c,v retrieving revision 1.3 diff -u -r1.3 bootp_support.c --- net/common//current/src/bootp_support.c 12 Jan 2003 04:53:28 -0000 1.3 +++ net/common//current/src/bootp_support.c 21 Oct 2003 17:12:26 -0000 @@ -68,6 +68,9 @@ #ifdef CYGINT_ISO_DNS #include #endif +#ifdef CYGPKG_NET_SNTP +#include +#endif #ifndef CYGPKG_LIBC_STDIO #define perror(s) diag_printf(#s ": %s\n", strerror(errno)) @@ -361,7 +364,15 @@ diag_printf(" %d",op[i]); diag_printf("\n"); break; - + case TAG_NTP_SERVER: + diag_printf(" NTP servers: "); + for ( i = 0 ; i < op[1]/4 ; i++) { + diag_printf("%d.%d.%d.%d ", + op[1+i*4+1], op[1+i*4+2], + op[1+i*4+3], op[1+i*4+4]); + } + diag_printf("\n"); + break; default: diag_printf("Unknown option: %x/%d.%d:", *op, *op, *(op+1)); for ( i = 2; i < 2 + op[1]; i++ ) @@ -536,6 +547,47 @@ } } #endif + +#ifdef CYGNUM_NET_SNTP_UNICAST_MAXDHCP + { + struct in_addr dhcp_addrs[CYGNUM_NET_SNTP_UNICAST_MAXDHCP]; + + /* Removed any previously registered addresses */ + cyg_sntp_set_servers(NULL, 0); + + /* See if we received any NTP servers from DHCP */ + length = sizeof(dhcp_addrs); + if (get_bootp_option(bp, TAG_NTP_SERVER, &dhcp_addrs[0], &length)) + { + static struct sockaddr ntp_servers[CYGNUM_NET_SNTP_UNICAST_MAXDHCP]; + struct servent *service; + cyg_uint32 num; + + /* See how many addresses we got. The length should always + * be a multiple of 4, but cut off any extra bytes and + * use what we got. + */ + length /= sizeof(struct in_addr); + + /* Fill out a sockaddr array for the NTP client */ + service = getservbyname("ntp", "udp"); + CYG_CHECK_DATA_PTR(service, "NTP service not found."); + memset(&ntp_servers[0], 0, sizeof(ntp_servers)); + for (num = 0; num < length; num++) + { + struct sockaddr_in *saddr = (struct sockaddr_in *)&ntp_servers[num]; + + saddr->sin_len = sizeof(*saddr); + saddr->sin_family = AF_INET; + saddr->sin_port = service->s_port; /* Already network-endian */ + saddr->sin_addr = dhcp_addrs[num]; /* Already network-endian */ + } + + /* Configure the client with the array */ + cyg_sntp_set_servers(&ntp_servers[0], num); + } + } +#endif /* CYGNUM_NET_SNTP_UNICAST_MAXDHCP */ return true; } Index: net/common//current/src/dhcp_prot.c =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/dhcp_prot.c,v retrieving revision 1.12 diff -u -r1.12 dhcp_prot.c --- net/common//current/src/dhcp_prot.c 16 Oct 2003 08:13:46 -0000 1.12 +++ net/common//current/src/dhcp_prot.c 21 Oct 2003 17:12:30 -0000 @@ -56,6 +56,10 @@ #ifdef CYGPKG_NET_DHCP +#ifdef CYGPKG_NET_SNTP +#include +#endif /* CYGPKG_NET_SNTP */ + #if 0 #define perror( txt ) // nothing #endif @@ -543,6 +547,9 @@ TAG_DOMAIN_SERVER , // domain server: 10.16.19.66 TAG_DOMAIN_NAME , // domain name: hmt10.cambridge.redhat.com TAG_IP_BROADCAST , // IP broadcast: 10.16.19.255 +#endif +#ifdef CYGNUM_NET_SNTP_UNICAST_MAXDHCP + TAG_NTP_SERVER , // NTP Server Addresses(es) #endif #ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL ,