Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_sntp.c Source File

lwip_sntp.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * SNTP client module
00004  */
00005 
00006 /*
00007  * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without modification,
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00030  * OF SUCH DAMAGE.
00031  *
00032  * This file is part of the lwIP TCP/IP stack.
00033  *
00034  * Author: Frédéric Bernon, Simon Goldschmidt
00035  */
00036 
00037 
00038 /**
00039  * @defgroup sntp SNTP
00040  * @ingroup apps
00041  *
00042  * This is simple "SNTP" client for the lwIP raw API.
00043  * It is a minimal implementation of SNTPv4 as specified in RFC 4330.
00044  *
00045  * For a list of some public NTP servers, see this link:
00046  * http://support.ntp.org/bin/view/Servers/NTPPoolServers
00047  *
00048  * @todo:
00049  * - complete SNTP_CHECK_RESPONSE checks 3 and 4
00050  */
00051 
00052 #include "lwip/apps/sntp.h"
00053 
00054 #include "lwip/opt.h"
00055 #include "lwip/timeouts.h"
00056 #include "lwip/udp.h"
00057 #include "lwip/dns.h"
00058 #include "lwip/ip_addr.h"
00059 #include "lwip/pbuf.h"
00060 #include "lwip/dhcp.h"
00061 
00062 #include <string.h>
00063 #include <time.h>
00064 
00065 #if LWIP_UDP
00066 
00067 /* Handle support for more than one server via SNTP_MAX_SERVERS */
00068 #if SNTP_MAX_SERVERS > 1
00069 #define SNTP_SUPPORT_MULTIPLE_SERVERS 1
00070 #else /* NTP_MAX_SERVERS > 1 */
00071 #define SNTP_SUPPORT_MULTIPLE_SERVERS 0
00072 #endif /* NTP_MAX_SERVERS > 1 */
00073 
00074 #ifndef SNTP_SUPPRESS_DELAY_CHECK
00075 #if SNTP_UPDATE_DELAY < 15000
00076 #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
00077 #endif
00078 #endif
00079 
00080 /* the various debug levels for this file */
00081 #define SNTP_DEBUG_TRACE        (SNTP_DEBUG | LWIP_DBG_TRACE)
00082 #define SNTP_DEBUG_STATE        (SNTP_DEBUG | LWIP_DBG_STATE)
00083 #define SNTP_DEBUG_WARN         (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
00084 #define SNTP_DEBUG_WARN_STATE   (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
00085 #define SNTP_DEBUG_SERIOUS      (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
00086 
00087 #define SNTP_ERR_KOD                1
00088 
00089 /* SNTP protocol defines */
00090 #define SNTP_MSG_LEN                48
00091 
00092 #define SNTP_OFFSET_LI_VN_MODE      0
00093 #define SNTP_LI_MASK                0xC0
00094 #define SNTP_LI_NO_WARNING          (0x00 << 6)
00095 #define SNTP_LI_LAST_MINUTE_61_SEC  (0x01 << 6)
00096 #define SNTP_LI_LAST_MINUTE_59_SEC  (0x02 << 6)
00097 #define SNTP_LI_ALARM_CONDITION     (0x03 << 6) /* (clock not synchronized) */
00098 
00099 #define SNTP_VERSION_MASK           0x38
00100 #define SNTP_VERSION                (4/* NTP Version 4*/<<3)
00101 
00102 #define SNTP_MODE_MASK              0x07
00103 #define SNTP_MODE_CLIENT            0x03
00104 #define SNTP_MODE_SERVER            0x04
00105 #define SNTP_MODE_BROADCAST         0x05
00106 
00107 #define SNTP_OFFSET_STRATUM         1
00108 #define SNTP_STRATUM_KOD            0x00
00109 
00110 #define SNTP_OFFSET_ORIGINATE_TIME  24
00111 #define SNTP_OFFSET_RECEIVE_TIME    32
00112 #define SNTP_OFFSET_TRANSMIT_TIME   40
00113 
00114 /* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */
00115 #define DIFF_SEC_1970_2036          ((u32_t)2085978496L)
00116 
00117 /** Convert NTP timestamp fraction to microseconds.
00118  */
00119 #ifndef SNTP_FRAC_TO_US
00120 # if LWIP_HAVE_INT64
00121 #  define SNTP_FRAC_TO_US(f)        ((u32_t)(((u64_t)(f) * 1000000UL) >> 32))
00122 # else
00123 #  define SNTP_FRAC_TO_US(f)        ((u32_t)(f) / 4295)
00124 # endif
00125 #endif /* !SNTP_FRAC_TO_US */
00126 
00127 /* Configure behaviour depending on native, microsecond or second precision.
00128  * Treat NTP timestamps as signed two's-complement integers. This way,
00129  * timestamps that have the MSB set simply become negative offsets from
00130  * the epoch (Feb 7, 2036 06:28:16 UTC). Representable dates range from
00131  * 1968 to 2104.
00132  */
00133 #ifndef SNTP_SET_SYSTEM_TIME_NTP
00134 # ifdef SNTP_SET_SYSTEM_TIME_US
00135 #  define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
00136     SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f))
00137 # else
00138 #  define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
00139     SNTP_SET_SYSTEM_TIME((u32_t)((s) + DIFF_SEC_1970_2036))
00140 # endif
00141 #endif /* !SNTP_SET_SYSTEM_TIME_NTP */
00142 
00143 /* Get the system time either natively as NTP timestamp or convert from
00144  * Unix time in seconds and microseconds. Take care to avoid overflow if the
00145  * microsecond value is at the maximum of 999999. Also add 0.5 us fudge to
00146  * avoid special values like 0, and to mask round-off errors that would
00147  * otherwise break round-trip conversion identity.
00148  */
00149 #ifndef SNTP_GET_SYSTEM_TIME_NTP
00150 # define SNTP_GET_SYSTEM_TIME_NTP(s, f) do { \
00151     u32_t sec_, usec_; \
00152     SNTP_GET_SYSTEM_TIME(sec_, usec_); \
00153     (s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \
00154     (f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \
00155   } while (0)
00156 #endif /* !SNTP_GET_SYSTEM_TIME_NTP */
00157 
00158 /* Start offset of the timestamps to extract from the SNTP packet */
00159 #define SNTP_OFFSET_TIMESTAMPS \
00160     (SNTP_OFFSET_TRANSMIT_TIME + 8 - sizeof(struct sntp_timestamps))
00161 
00162 /* Round-trip delay arithmetic helpers */
00163 #if SNTP_COMP_ROUNDTRIP
00164 # if !LWIP_HAVE_INT64
00165 #  error "SNTP round-trip delay compensation requires 64-bit arithmetic"
00166 # endif
00167 # define SNTP_SEC_FRAC_TO_S64(s, f) \
00168     ((s64_t)(((u64_t)(s) << 32) | (u32_t)(f)))
00169 # define SNTP_TIMESTAMP_TO_S64(t) \
00170     SNTP_SEC_FRAC_TO_S64(lwip_ntohl((t).sec), lwip_ntohl((t).frac))
00171 #endif /* SNTP_COMP_ROUNDTRIP */
00172 
00173 /**
00174  * 64-bit NTP timestamp, in network byte order.
00175  */
00176 struct sntp_time {
00177   u32_t sec;
00178   u32_t frac;
00179 };
00180 
00181 /**
00182  * Timestamps to be extracted from the NTP header.
00183  */
00184 struct sntp_timestamps {
00185 #if SNTP_COMP_ROUNDTRIP || SNTP_CHECK_RESPONSE >= 2
00186   struct sntp_time orig;
00187   struct sntp_time recv;
00188 #endif
00189   struct sntp_time xmit;
00190 };
00191 
00192 /**
00193  * SNTP packet format (without optional fields)
00194  * Timestamps are coded as 64 bits:
00195  * - signed 32 bits seconds since Feb 07, 2036, 06:28:16 UTC (epoch 1)
00196  * - unsigned 32 bits seconds fraction (2^32 = 1 second)
00197  */
00198 #ifdef PACK_STRUCT_USE_INCLUDES
00199 #  include "arch/bpstruct.h"
00200 #endif
00201 PACK_STRUCT_BEGIN
00202 struct sntp_msg {
00203   PACK_STRUCT_FLD_8(u8_t  li_vn_mode);
00204   PACK_STRUCT_FLD_8(u8_t  stratum);
00205   PACK_STRUCT_FLD_8(u8_t  poll);
00206   PACK_STRUCT_FLD_8(u8_t  precision);
00207   PACK_STRUCT_FIELD(u32_t root_delay);
00208   PACK_STRUCT_FIELD(u32_t root_dispersion);
00209   PACK_STRUCT_FIELD(u32_t reference_identifier);
00210   PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
00211   PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
00212   PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
00213   PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
00214 } PACK_STRUCT_STRUCT;
00215 PACK_STRUCT_END
00216 #ifdef PACK_STRUCT_USE_INCLUDES
00217 #  include "arch/epstruct.h"
00218 #endif
00219 
00220 /* function prototypes */
00221 static void sntp_request(void *arg);
00222 
00223 /** The operating mode */
00224 static u8_t sntp_opmode;
00225 
00226 /** The UDP pcb used by the SNTP client */
00227 static struct udp_pcb *sntp_pcb;
00228 /** Names/Addresses of servers */
00229 struct sntp_server {
00230 #if SNTP_SERVER_DNS
00231   const char *name;
00232 #endif /* SNTP_SERVER_DNS */
00233   ip_addr_t addr;
00234 #if SNTP_MONITOR_SERVER_REACHABILITY
00235   /** Reachability shift register as described in RFC 5905 */
00236   u8_t reachability;
00237 #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
00238 };
00239 static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
00240 
00241 #if SNTP_GET_SERVERS_FROM_DHCP
00242 static u8_t sntp_set_servers_from_dhcp;
00243 #endif /* SNTP_GET_SERVERS_FROM_DHCP */
00244 #if SNTP_SUPPORT_MULTIPLE_SERVERS
00245 /** The currently used server (initialized to 0) */
00246 static u8_t sntp_current_server;
00247 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
00248 #define sntp_current_server 0
00249 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
00250 
00251 #if SNTP_RETRY_TIMEOUT_EXP
00252 #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
00253 /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
00254 static u32_t sntp_retry_timeout;
00255 #else /* SNTP_RETRY_TIMEOUT_EXP */
00256 #define SNTP_RESET_RETRY_TIMEOUT()
00257 #define sntp_retry_timeout SNTP_RETRY_TIMEOUT
00258 #endif /* SNTP_RETRY_TIMEOUT_EXP */
00259 
00260 #if SNTP_CHECK_RESPONSE >= 1
00261 /** Saves the last server address to compare with response */
00262 static ip_addr_t sntp_last_server_address;
00263 #endif /* SNTP_CHECK_RESPONSE >= 1 */
00264 
00265 #if SNTP_CHECK_RESPONSE >= 2
00266 /** Saves the last timestamp sent (which is sent back by the server)
00267  * to compare against in response. Stored in network byte order. */
00268 static struct sntp_time sntp_last_timestamp_sent;
00269 #endif /* SNTP_CHECK_RESPONSE >= 2 */
00270 
00271 #if defined(LWIP_DEBUG) && !defined(sntp_format_time)
00272 /* Debug print helper. */
00273 static const char *
00274 sntp_format_time(s32_t sec)
00275 {
00276   time_t ut;
00277   ut = (u32_t)((u32_t)sec + DIFF_SEC_1970_2036);
00278   return ctime(&ut);
00279 }
00280 #endif /* LWIP_DEBUG && !sntp_format_time */
00281 
00282 /**
00283  * SNTP processing of received timestamp
00284  */
00285 static void
00286 sntp_process(const struct sntp_timestamps *timestamps)
00287 {
00288   s32_t sec;
00289   u32_t frac;
00290 
00291   sec  = (s32_t)lwip_ntohl(timestamps->xmit.sec);
00292   frac = lwip_ntohl(timestamps->xmit.frac);
00293 
00294 #if SNTP_COMP_ROUNDTRIP
00295 # if SNTP_CHECK_RESPONSE >= 2
00296   if (timestamps->recv.sec != 0 || timestamps->recv.frac != 0)
00297 # endif
00298   {
00299     s32_t dest_sec;
00300     u32_t dest_frac;
00301     u32_t step_sec;
00302 
00303     /* Get the destination time stamp, i.e. the current system time */
00304     SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac);
00305 
00306     step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec)
00307                : ((u32_t)dest_sec - (u32_t)sec);
00308     /* In order to avoid overflows, skip the compensation if the clock step
00309      * is larger than about 34 years. */
00310     if ((step_sec >> 30) == 0) {
00311       s64_t t1, t2, t3, t4;
00312 
00313       t4 = SNTP_SEC_FRAC_TO_S64(dest_sec, dest_frac);
00314       t3 = SNTP_SEC_FRAC_TO_S64(sec, frac);
00315       t1 = SNTP_TIMESTAMP_TO_S64(timestamps->orig);
00316       t2 = SNTP_TIMESTAMP_TO_S64(timestamps->recv);
00317       /* Clock offset calculation according to RFC 4330 */
00318       t4 += ((t2 - t1) + (t3 - t4)) / 2;
00319 
00320       sec  = (s32_t)((u64_t)t4 >> 32);
00321       frac = (u32_t)((u64_t)t4);
00322     }
00323   }
00324 #endif /* SNTP_COMP_ROUNDTRIP */
00325 
00326   SNTP_SET_SYSTEM_TIME_NTP(sec, frac);
00327   LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */
00328   LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %" U32_F " us\n",
00329                                  sntp_format_time(sec), SNTP_FRAC_TO_US(frac)));
00330 }
00331 
00332 /**
00333  * Initialize request struct to be sent to server.
00334  */
00335 static void
00336 sntp_initialize_request(struct sntp_msg *req)
00337 {
00338   memset(req, 0, SNTP_MSG_LEN);
00339   req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
00340 
00341 #if SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP
00342   {
00343     s32_t secs;
00344     u32_t sec, frac;
00345     /* Get the transmit timestamp */
00346     SNTP_GET_SYSTEM_TIME_NTP(secs, frac);
00347     sec  = lwip_htonl((u32_t)secs);
00348     frac = lwip_htonl(frac);
00349 
00350 # if SNTP_CHECK_RESPONSE >= 2
00351     sntp_last_timestamp_sent.sec  = sec;
00352     sntp_last_timestamp_sent.frac = frac;
00353 # endif
00354     req->transmit_timestamp[0] = sec;
00355     req->transmit_timestamp[1] = frac;
00356   }
00357 #endif /* SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP */
00358 }
00359 
00360 /**
00361  * Retry: send a new request (and increase retry timeout).
00362  *
00363  * @param arg is unused (only necessary to conform to sys_timeout)
00364  */
00365 static void
00366 sntp_retry(void *arg)
00367 {
00368   LWIP_UNUSED_ARG(arg);
00369 
00370   LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
00371                                  sntp_retry_timeout));
00372 
00373   /* set up a timer to send a retry and increase the retry delay */
00374   sys_timeout(sntp_retry_timeout, sntp_request, NULL);
00375 
00376 #if SNTP_RETRY_TIMEOUT_EXP
00377   {
00378     u32_t new_retry_timeout;
00379     /* increase the timeout for next retry */
00380     new_retry_timeout = sntp_retry_timeout << 1;
00381     /* limit to maximum timeout and prevent overflow */
00382     if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
00383         (new_retry_timeout > sntp_retry_timeout)) {
00384       sntp_retry_timeout = new_retry_timeout;
00385     }
00386   }
00387 #endif /* SNTP_RETRY_TIMEOUT_EXP */
00388 }
00389 
00390 #if SNTP_SUPPORT_MULTIPLE_SERVERS
00391 /**
00392  * If Kiss-of-Death is received (or another packet parsing error),
00393  * try the next server or retry the current server and increase the retry
00394  * timeout if only one server is available.
00395  * (implicitly, SNTP_MAX_SERVERS > 1)
00396  *
00397  * @param arg is unused (only necessary to conform to sys_timeout)
00398  */
00399 static void
00400 sntp_try_next_server(void *arg)
00401 {
00402   u8_t old_server, i;
00403   LWIP_UNUSED_ARG(arg);
00404 
00405   old_server = sntp_current_server;
00406   for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
00407     sntp_current_server++;
00408     if (sntp_current_server >= SNTP_MAX_SERVERS) {
00409       sntp_current_server = 0;
00410     }
00411     if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
00412 #if SNTP_SERVER_DNS
00413         || (sntp_servers[sntp_current_server].name != NULL)
00414 #endif
00415        ) {
00416       LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
00417                                      (u16_t)sntp_current_server));
00418       /* new server: reset retry timeout */
00419       SNTP_RESET_RETRY_TIMEOUT();
00420       /* instantly send a request to the next server */
00421       sntp_request(NULL);
00422       return;
00423     }
00424   }
00425   /* no other valid server found */
00426   sntp_current_server = old_server;
00427   sntp_retry(NULL);
00428 }
00429 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
00430 /* Always retry on error if only one server is supported */
00431 #define sntp_try_next_server    sntp_retry
00432 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
00433 
00434 /** UDP recv callback for the sntp pcb */
00435 static void
00436 sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
00437 {
00438   struct sntp_timestamps timestamps;
00439   u8_t mode;
00440   u8_t stratum;
00441   err_t err;
00442 
00443   LWIP_UNUSED_ARG(arg);
00444   LWIP_UNUSED_ARG(pcb);
00445 
00446   err = ERR_ARG;
00447 #if SNTP_CHECK_RESPONSE >= 1
00448   /* check server address and port */
00449   if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
00450       (port == SNTP_PORT))
00451 #else /* SNTP_CHECK_RESPONSE >= 1 */
00452   LWIP_UNUSED_ARG(addr);
00453   LWIP_UNUSED_ARG(port);
00454 #endif /* SNTP_CHECK_RESPONSE >= 1 */
00455   {
00456     /* process the response */
00457     if (p->tot_len == SNTP_MSG_LEN) {
00458       mode = pbuf_get_at(p, SNTP_OFFSET_LI_VN_MODE) & SNTP_MODE_MASK;
00459       /* if this is a SNTP response... */
00460       if (((sntp_opmode == SNTP_OPMODE_POLL)       && (mode == SNTP_MODE_SERVER)) ||
00461           ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
00462         stratum = pbuf_get_at(p, SNTP_OFFSET_STRATUM);
00463 
00464         if (stratum == SNTP_STRATUM_KOD) {
00465           /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
00466           err = SNTP_ERR_KOD;
00467           LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
00468         } else {
00469           pbuf_copy_partial(p, &timestamps, sizeof(timestamps), SNTP_OFFSET_TIMESTAMPS);
00470 #if SNTP_CHECK_RESPONSE >= 2
00471           /* check originate_timetamp against sntp_last_timestamp_sent */
00472           if (timestamps.orig.sec != sntp_last_timestamp_sent.sec ||
00473               timestamps.orig.frac != sntp_last_timestamp_sent.frac) {
00474             LWIP_DEBUGF(SNTP_DEBUG_WARN,
00475                         ("sntp_recv: Invalid originate timestamp in response\n"));
00476           } else
00477 #endif /* SNTP_CHECK_RESPONSE >= 2 */
00478             /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
00479           {
00480             /* correct answer */
00481             err = ERR_OK;
00482           }
00483         }
00484       } else {
00485         LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
00486         /* wait for correct response */
00487         err = ERR_TIMEOUT;
00488       }
00489     } else {
00490       LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
00491     }
00492   }
00493 #if SNTP_CHECK_RESPONSE >= 1
00494   else {
00495     /* packet from wrong remote address or port, wait for correct response */
00496     err = ERR_TIMEOUT;
00497   }
00498 #endif /* SNTP_CHECK_RESPONSE >= 1 */
00499 
00500   pbuf_free(p);
00501 
00502   if (err == ERR_OK) {
00503     /* correct packet received: process it it */
00504     sntp_process(&timestamps);
00505 
00506 #if SNTP_MONITOR_SERVER_REACHABILITY
00507     /* indicate that server responded */
00508     sntp_servers[sntp_current_server].reachability |= 1;
00509 #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
00510     /* Set up timeout for next request (only if poll response was received)*/
00511     if (sntp_opmode == SNTP_OPMODE_POLL) {
00512       u32_t sntp_update_delay;
00513       sys_untimeout(sntp_try_next_server, NULL);
00514       sys_untimeout(sntp_request, NULL);
00515 
00516       /* Correct response, reset retry timeout */
00517       SNTP_RESET_RETRY_TIMEOUT();
00518 
00519       sntp_update_delay = (u32_t)SNTP_UPDATE_DELAY;
00520       sys_timeout(sntp_update_delay, sntp_request, NULL);
00521       LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
00522                                      sntp_update_delay));
00523     }
00524   } else if (err == SNTP_ERR_KOD) {
00525     /* KOD errors are only processed in case of an explicit poll response */
00526     if (sntp_opmode == SNTP_OPMODE_POLL) {
00527       /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
00528       sntp_try_next_server(NULL);
00529     }
00530   } else {
00531     /* ignore any broken packet, poll mode: retry after timeout to avoid flooding */
00532   }
00533 }
00534 
00535 /** Actually send an sntp request to a server.
00536  *
00537  * @param server_addr resolved IP address of the SNTP server
00538  */
00539 static void
00540 sntp_send_request(const ip_addr_t *server_addr)
00541 {
00542   struct pbuf *p;
00543 
00544   LWIP_ASSERT("server_addr != NULL", server_addr != NULL);
00545 
00546   p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
00547   if (p != NULL) {
00548     struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
00549     LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
00550     /* initialize request message */
00551     sntp_initialize_request(sntpmsg);
00552     /* send request */
00553     udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
00554     /* free the pbuf after sending it */
00555     pbuf_free(p);
00556 #if SNTP_MONITOR_SERVER_REACHABILITY
00557     /* indicate new packet has been sent */
00558     sntp_servers[sntp_current_server].reachability <<= 1;
00559 #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
00560     /* set up receive timeout: try next server or retry on timeout */
00561     sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
00562 #if SNTP_CHECK_RESPONSE >= 1
00563     /* save server address to verify it in sntp_recv */
00564     ip_addr_copy(sntp_last_server_address, *server_addr);
00565 #endif /* SNTP_CHECK_RESPONSE >= 1 */
00566   } else {
00567     LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
00568                                      (u32_t)SNTP_RETRY_TIMEOUT));
00569     /* out of memory: set up a timer to send a retry */
00570     sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
00571   }
00572 }
00573 
00574 #if SNTP_SERVER_DNS
00575 /**
00576  * DNS found callback when using DNS names as server address.
00577  */
00578 static void
00579 sntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg)
00580 {
00581   LWIP_UNUSED_ARG(hostname);
00582   LWIP_UNUSED_ARG(arg);
00583 
00584   if (ipaddr != NULL) {
00585     /* Address resolved, send request */
00586     LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
00587     sntp_servers[sntp_current_server].addr = *ipaddr;
00588     sntp_send_request(ipaddr);
00589   } else {
00590     /* DNS resolving failed -> try another server */
00591     LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
00592     sntp_try_next_server(NULL);
00593   }
00594 }
00595 #endif /* SNTP_SERVER_DNS */
00596 
00597 /**
00598  * Send out an sntp request.
00599  *
00600  * @param arg is unused (only necessary to conform to sys_timeout)
00601  */
00602 static void
00603 sntp_request(void *arg)
00604 {
00605   ip_addr_t sntp_server_address;
00606   err_t err;
00607 
00608   LWIP_UNUSED_ARG(arg);
00609 
00610   /* initialize SNTP server address */
00611 #if SNTP_SERVER_DNS
00612   if (sntp_servers[sntp_current_server].name) {
00613     /* always resolve the name and rely on dns-internal caching & timeout */
00614     ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
00615     err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
00616                             sntp_dns_found, NULL);
00617     if (err == ERR_INPROGRESS) {
00618       /* DNS request sent, wait for sntp_dns_found being called */
00619       LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
00620       return;
00621     } else if (err == ERR_OK) {
00622       sntp_servers[sntp_current_server].addr = sntp_server_address;
00623     }
00624   } else
00625 #endif /* SNTP_SERVER_DNS */
00626   {
00627     sntp_server_address = sntp_servers[sntp_current_server].addr;
00628     err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
00629   }
00630 
00631   if (err == ERR_OK) {
00632     LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
00633                                    ipaddr_ntoa(&sntp_server_address)));
00634     sntp_send_request(&sntp_server_address);
00635   } else {
00636     /* address conversion failed, try another server */
00637     LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
00638     sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
00639   }
00640 }
00641 
00642 /**
00643  * @ingroup sntp
00644  * Initialize this module.
00645  * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
00646  */
00647 void
00648 sntp_init(void)
00649 {
00650   /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
00651 
00652 #ifdef SNTP_SERVER_ADDRESS
00653 #if SNTP_SERVER_DNS
00654   sntp_setservername(0, SNTP_SERVER_ADDRESS);
00655 #else
00656 #error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
00657 #endif
00658 #endif /* SNTP_SERVER_ADDRESS */
00659 
00660   if (sntp_pcb == NULL) {
00661     sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
00662     LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
00663     if (sntp_pcb != NULL) {
00664       udp_recv(sntp_pcb, sntp_recv, NULL);
00665 
00666       if (sntp_opmode == SNTP_OPMODE_POLL) {
00667         SNTP_RESET_RETRY_TIMEOUT();
00668 #if SNTP_STARTUP_DELAY
00669         sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
00670 #else
00671         sntp_request(NULL);
00672 #endif
00673       } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
00674         ip_set_option(sntp_pcb, SOF_BROADCAST);
00675         udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
00676       }
00677     }
00678   }
00679 }
00680 
00681 /**
00682  * @ingroup sntp
00683  * Stop this module.
00684  */
00685 void
00686 sntp_stop(void)
00687 {
00688   LWIP_ASSERT_CORE_LOCKED();
00689   if (sntp_pcb != NULL) {
00690 #if SNTP_MONITOR_SERVER_REACHABILITY
00691     u8_t i;
00692     for (i = 0; i < SNTP_MAX_SERVERS; i++) {
00693       sntp_servers[i].reachability = 0;
00694     }
00695 #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
00696     sys_untimeout(sntp_request, NULL);
00697     sys_untimeout(sntp_try_next_server, NULL);
00698     udp_remove(sntp_pcb);
00699     sntp_pcb = NULL;
00700   }
00701 }
00702 
00703 /**
00704  * @ingroup sntp
00705  * Get enabled state.
00706  */
00707 u8_t sntp_enabled(void)
00708 {
00709   return (sntp_pcb != NULL) ? 1 : 0;
00710 }
00711 
00712 /**
00713  * @ingroup sntp
00714  * Sets the operating mode.
00715  * @param operating_mode one of the available operating modes
00716  */
00717 void
00718 sntp_setoperatingmode(u8_t operating_mode)
00719 {
00720   LWIP_ASSERT_CORE_LOCKED();
00721   LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
00722   LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
00723   sntp_opmode = operating_mode;
00724 }
00725 
00726 /**
00727  * @ingroup sntp
00728  * Gets the operating mode.
00729  */
00730 u8_t
00731 sntp_getoperatingmode(void)
00732 {
00733   return sntp_opmode;
00734 }
00735 
00736 #if SNTP_MONITOR_SERVER_REACHABILITY
00737 /**
00738  * @ingroup sntp
00739  * Gets the server reachability shift register as described in RFC 5905.
00740  *
00741  * @param idx the index of the NTP server
00742  */
00743 u8_t
00744 sntp_getreachability(u8_t idx)
00745 {
00746   if (idx < SNTP_MAX_SERVERS) {
00747     return sntp_servers[idx].reachability;
00748   }
00749   return 0;
00750 }
00751 #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
00752 
00753 #if SNTP_GET_SERVERS_FROM_DHCP
00754 /**
00755  * Config SNTP server handling by IP address, name, or DHCP; clear table
00756  * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
00757  */
00758 void
00759 sntp_servermode_dhcp(int set_servers_from_dhcp)
00760 {
00761   u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
00762   LWIP_ASSERT_CORE_LOCKED();
00763   if (sntp_set_servers_from_dhcp != new_mode) {
00764     sntp_set_servers_from_dhcp = new_mode;
00765   }
00766 }
00767 #endif /* SNTP_GET_SERVERS_FROM_DHCP */
00768 
00769 /**
00770  * @ingroup sntp
00771  * Initialize one of the NTP servers by IP address
00772  *
00773  * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
00774  * @param server IP address of the NTP server to set
00775  */
00776 void
00777 sntp_setserver(u8_t idx, const ip_addr_t *server)
00778 {
00779   LWIP_ASSERT_CORE_LOCKED();
00780   if (idx < SNTP_MAX_SERVERS) {
00781     if (server != NULL) {
00782       sntp_servers[idx].addr = (*server);
00783     } else {
00784       ip_addr_set_zero(&sntp_servers[idx].addr);
00785     }
00786 #if SNTP_SERVER_DNS
00787     sntp_servers[idx].name = NULL;
00788 #endif
00789   }
00790 }
00791 
00792 #if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
00793 /**
00794  * Initialize one of the NTP servers by IP address, required by DHCP
00795  *
00796  * @param num the index of the NTP server to set must be < SNTP_MAX_SERVERS
00797  * @param server IP address of the NTP server to set
00798  */
00799 void
00800 dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
00801 {
00802   LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
00803                                  (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
00804                                  ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
00805   if (sntp_set_servers_from_dhcp && num) {
00806     u8_t i;
00807     for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
00808       ip_addr_t addr;
00809       ip_addr_copy_from_ip4(addr, server[i]);
00810       sntp_setserver(i, &addr);
00811     }
00812     for (i = num; i < SNTP_MAX_SERVERS; i++) {
00813       sntp_setserver(i, NULL);
00814     }
00815   }
00816 }
00817 #endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
00818 
00819 /**
00820  * @ingroup sntp
00821  * Obtain one of the currently configured by IP address (or DHCP) NTP servers
00822  *
00823  * @param idx the index of the NTP server
00824  * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
00825  *         server has not been configured by address (or at all).
00826  */
00827 const ip_addr_t *
00828 sntp_getserver(u8_t idx)
00829 {
00830   if (idx < SNTP_MAX_SERVERS) {
00831     return &sntp_servers[idx].addr;
00832   }
00833   return IP_ADDR_ANY;
00834 }
00835 
00836 #if SNTP_SERVER_DNS
00837 /**
00838  * Initialize one of the NTP servers by name
00839  *
00840  * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
00841  * @param server DNS name of the NTP server to set, to be resolved at contact time
00842  */
00843 void
00844 sntp_setservername(u8_t idx, const char *server)
00845 {
00846   LWIP_ASSERT_CORE_LOCKED();
00847   if (idx < SNTP_MAX_SERVERS) {
00848     sntp_servers[idx].name = server;
00849   }
00850 }
00851 
00852 /**
00853  * Obtain one of the currently configured by name NTP servers.
00854  *
00855  * @param idx the index of the NTP server
00856  * @return IP address of the indexed NTP server or NULL if the NTP
00857  *         server has not been configured by name (or at all)
00858  */
00859 const char *
00860 sntp_getservername(u8_t idx)
00861 {
00862   if (idx < SNTP_MAX_SERVERS) {
00863     return sntp_servers[idx].name;
00864   }
00865   return NULL;
00866 }
00867 #endif /* SNTP_SERVER_DNS */
00868 
00869 #endif /* LWIP_UDP */