Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_sntp.c
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, ×tamps, 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(×tamps); 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 */
Generated on Tue Jul 12 2022 13:54:30 by
