Remove building with NOCRYPTO option
[minix3.git] / minix / lib / liblwip / dist / src / apps / sntp / sntp.c
blob71b2abedb8fb69fd353e3f928d4cc3c50d42b8be
1 /**
2 * @file
3 * SNTP client module
4 */
6 /*
7 * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
32 * This file is part of the lwIP TCP/IP stack.
34 * Author: Frédéric Bernon, Simon Goldschmidt
38 /**
39 * @defgroup sntp SNTP
40 * @ingroup apps
42 * This is simple "SNTP" client for the lwIP raw API.
43 * It is a minimal implementation of SNTPv4 as specified in RFC 4330.
45 * For a list of some public NTP servers, see this link :
46 * http://support.ntp.org/bin/view/Servers/NTPPoolServers
48 * @todo:
49 * - set/change servers at runtime
50 * - complete SNTP_CHECK_RESPONSE checks 3 and 4
53 #include "lwip/apps/sntp.h"
55 #include "lwip/opt.h"
56 #include "lwip/timeouts.h"
57 #include "lwip/udp.h"
58 #include "lwip/dns.h"
59 #include "lwip/ip_addr.h"
60 #include "lwip/pbuf.h"
61 #include "lwip/dhcp.h"
63 #include <string.h>
64 #include <time.h>
66 #if LWIP_UDP
68 /* Handle support for more than one server via SNTP_MAX_SERVERS */
69 #if SNTP_MAX_SERVERS > 1
70 #define SNTP_SUPPORT_MULTIPLE_SERVERS 1
71 #else /* NTP_MAX_SERVERS > 1 */
72 #define SNTP_SUPPORT_MULTIPLE_SERVERS 0
73 #endif /* NTP_MAX_SERVERS > 1 */
75 #if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
76 #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
77 #endif
79 /* Configure behaviour depending on microsecond or second precision */
80 #ifdef SNTP_SET_SYSTEM_TIME_US
81 #define SNTP_CALC_TIME_US 1
82 #define SNTP_RECEIVE_TIME_SIZE 2
83 #else
84 #define SNTP_SET_SYSTEM_TIME_US(sec, us)
85 #define SNTP_CALC_TIME_US 0
86 #define SNTP_RECEIVE_TIME_SIZE 1
87 #endif
90 /* the various debug levels for this file */
91 #define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
92 #define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
93 #define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
94 #define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
95 #define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
97 #define SNTP_ERR_KOD 1
99 /* SNTP protocol defines */
100 #define SNTP_MSG_LEN 48
102 #define SNTP_OFFSET_LI_VN_MODE 0
103 #define SNTP_LI_MASK 0xC0
104 #define SNTP_LI_NO_WARNING 0x00
105 #define SNTP_LI_LAST_MINUTE_61_SEC 0x01
106 #define SNTP_LI_LAST_MINUTE_59_SEC 0x02
107 #define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
109 #define SNTP_VERSION_MASK 0x38
110 #define SNTP_VERSION (4/* NTP Version 4*/<<3)
112 #define SNTP_MODE_MASK 0x07
113 #define SNTP_MODE_CLIENT 0x03
114 #define SNTP_MODE_SERVER 0x04
115 #define SNTP_MODE_BROADCAST 0x05
117 #define SNTP_OFFSET_STRATUM 1
118 #define SNTP_STRATUM_KOD 0x00
120 #define SNTP_OFFSET_ORIGINATE_TIME 24
121 #define SNTP_OFFSET_RECEIVE_TIME 32
122 #define SNTP_OFFSET_TRANSMIT_TIME 40
124 /* number of seconds between 1900 and 1970 (MSB=1)*/
125 #define DIFF_SEC_1900_1970 (2208988800UL)
126 /* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
127 #define DIFF_SEC_1970_2036 (2085978496UL)
130 * SNTP packet format (without optional fields)
131 * Timestamps are coded as 64 bits:
132 * - 32 bits seconds since Jan 01, 1970, 00:00
133 * - 32 bits seconds fraction (0-padded)
134 * For future use, if the MSB in the seconds part is set, seconds are based
135 * on Feb 07, 2036, 06:28:16.
137 #ifdef PACK_STRUCT_USE_INCLUDES
138 # include "arch/bpstruct.h"
139 #endif
140 PACK_STRUCT_BEGIN
141 struct sntp_msg {
142 PACK_STRUCT_FLD_8(u8_t li_vn_mode);
143 PACK_STRUCT_FLD_8(u8_t stratum);
144 PACK_STRUCT_FLD_8(u8_t poll);
145 PACK_STRUCT_FLD_8(u8_t precision);
146 PACK_STRUCT_FIELD(u32_t root_delay);
147 PACK_STRUCT_FIELD(u32_t root_dispersion);
148 PACK_STRUCT_FIELD(u32_t reference_identifier);
149 PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
150 PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
151 PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
152 PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
153 } PACK_STRUCT_STRUCT;
154 PACK_STRUCT_END
155 #ifdef PACK_STRUCT_USE_INCLUDES
156 # include "arch/epstruct.h"
157 #endif
159 /* function prototypes */
160 static void sntp_request(void *arg);
162 /** The operating mode */
163 static u8_t sntp_opmode;
165 /** The UDP pcb used by the SNTP client */
166 static struct udp_pcb* sntp_pcb;
167 /** Names/Addresses of servers */
168 struct sntp_server {
169 #if SNTP_SERVER_DNS
170 char* name;
171 #endif /* SNTP_SERVER_DNS */
172 ip_addr_t addr;
174 static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
176 #if SNTP_GET_SERVERS_FROM_DHCP
177 static u8_t sntp_set_servers_from_dhcp;
178 #endif /* SNTP_GET_SERVERS_FROM_DHCP */
179 #if SNTP_SUPPORT_MULTIPLE_SERVERS
180 /** The currently used server (initialized to 0) */
181 static u8_t sntp_current_server;
182 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
183 #define sntp_current_server 0
184 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
186 #if SNTP_RETRY_TIMEOUT_EXP
187 #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
188 /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
189 static u32_t sntp_retry_timeout;
190 #else /* SNTP_RETRY_TIMEOUT_EXP */
191 #define SNTP_RESET_RETRY_TIMEOUT()
192 #define sntp_retry_timeout SNTP_RETRY_TIMEOUT
193 #endif /* SNTP_RETRY_TIMEOUT_EXP */
195 #if SNTP_CHECK_RESPONSE >= 1
196 /** Saves the last server address to compare with response */
197 static ip_addr_t sntp_last_server_address;
198 #endif /* SNTP_CHECK_RESPONSE >= 1 */
200 #if SNTP_CHECK_RESPONSE >= 2
201 /** Saves the last timestamp sent (which is sent back by the server)
202 * to compare against in response */
203 static u32_t sntp_last_timestamp_sent[2];
204 #endif /* SNTP_CHECK_RESPONSE >= 2 */
207 * SNTP processing of received timestamp
209 static void
210 sntp_process(u32_t *receive_timestamp)
212 /* convert SNTP time (1900-based) to unix GMT time (1970-based)
213 * if MSB is 0, SNTP time is 2036-based!
215 u32_t rx_secs = lwip_ntohl(receive_timestamp[0]);
216 int is_1900_based = ((rx_secs & 0x80000000) != 0);
217 u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
218 time_t tim = t;
220 #if SNTP_CALC_TIME_US
221 u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295;
222 SNTP_SET_SYSTEM_TIME_US(t, us);
223 /* display local time from GMT time */
224 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
226 #else /* SNTP_CALC_TIME_US */
228 /* change system time and/or the update the RTC clock */
229 SNTP_SET_SYSTEM_TIME(t);
230 /* display local time from GMT time */
231 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
232 #endif /* SNTP_CALC_TIME_US */
233 LWIP_UNUSED_ARG(tim);
237 * Initialize request struct to be sent to server.
239 static void
240 sntp_initialize_request(struct sntp_msg *req)
242 memset(req, 0, SNTP_MSG_LEN);
243 req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
245 #if SNTP_CHECK_RESPONSE >= 2
247 u32_t sntp_time_sec, sntp_time_us;
248 /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
249 SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
250 sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970);
251 req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
252 /* we send/save us instead of fraction to be faster... */
253 sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us);
254 req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
256 #endif /* SNTP_CHECK_RESPONSE >= 2 */
260 * Retry: send a new request (and increase retry timeout).
262 * @param arg is unused (only necessary to conform to sys_timeout)
264 static void
265 sntp_retry(void* arg)
267 LWIP_UNUSED_ARG(arg);
269 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
270 sntp_retry_timeout));
272 /* set up a timer to send a retry and increase the retry delay */
273 sys_timeout(sntp_retry_timeout, sntp_request, NULL);
275 #if SNTP_RETRY_TIMEOUT_EXP
277 u32_t new_retry_timeout;
278 /* increase the timeout for next retry */
279 new_retry_timeout = sntp_retry_timeout << 1;
280 /* limit to maximum timeout and prevent overflow */
281 if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
282 (new_retry_timeout > sntp_retry_timeout)) {
283 sntp_retry_timeout = new_retry_timeout;
286 #endif /* SNTP_RETRY_TIMEOUT_EXP */
289 #if SNTP_SUPPORT_MULTIPLE_SERVERS
291 * If Kiss-of-Death is received (or another packet parsing error),
292 * try the next server or retry the current server and increase the retry
293 * timeout if only one server is available.
294 * (implicitly, SNTP_MAX_SERVERS > 1)
296 * @param arg is unused (only necessary to conform to sys_timeout)
298 static void
299 sntp_try_next_server(void* arg)
301 u8_t old_server, i;
302 LWIP_UNUSED_ARG(arg);
304 old_server = sntp_current_server;
305 for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
306 sntp_current_server++;
307 if (sntp_current_server >= SNTP_MAX_SERVERS) {
308 sntp_current_server = 0;
310 if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
311 #if SNTP_SERVER_DNS
312 || (sntp_servers[sntp_current_server].name != NULL)
313 #endif
315 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
316 (u16_t)sntp_current_server));
317 /* new server: reset retry timeout */
318 SNTP_RESET_RETRY_TIMEOUT();
319 /* instantly send a request to the next server */
320 sntp_request(NULL);
321 return;
324 /* no other valid server found */
325 sntp_current_server = old_server;
326 sntp_retry(NULL);
328 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
329 /* Always retry on error if only one server is supported */
330 #define sntp_try_next_server sntp_retry
331 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
333 /** UDP recv callback for the sntp pcb */
334 static void
335 sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
337 u8_t mode;
338 u8_t stratum;
339 u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
340 err_t err;
342 LWIP_UNUSED_ARG(arg);
343 LWIP_UNUSED_ARG(pcb);
345 /* packet received: stop retry timeout */
346 sys_untimeout(sntp_try_next_server, NULL);
347 sys_untimeout(sntp_request, NULL);
349 err = ERR_ARG;
350 #if SNTP_CHECK_RESPONSE >= 1
351 /* check server address and port */
352 if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
353 (port == SNTP_PORT))
354 #else /* SNTP_CHECK_RESPONSE >= 1 */
355 LWIP_UNUSED_ARG(addr);
356 LWIP_UNUSED_ARG(port);
357 #endif /* SNTP_CHECK_RESPONSE >= 1 */
359 /* process the response */
360 if (p->tot_len == SNTP_MSG_LEN) {
361 pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
362 mode &= SNTP_MODE_MASK;
363 /* if this is a SNTP response... */
364 if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
365 ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
366 pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
367 if (stratum == SNTP_STRATUM_KOD) {
368 /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
369 err = SNTP_ERR_KOD;
370 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
371 } else {
372 #if SNTP_CHECK_RESPONSE >= 2
373 /* check originate_timetamp against sntp_last_timestamp_sent */
374 u32_t originate_timestamp[2];
375 pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
376 if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
377 (originate_timestamp[1] != sntp_last_timestamp_sent[1]))
379 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
380 } else
381 #endif /* SNTP_CHECK_RESPONSE >= 2 */
382 /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
384 /* correct answer */
385 err = ERR_OK;
386 pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
389 } else {
390 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
391 /* wait for correct response */
392 err = ERR_TIMEOUT;
394 } else {
395 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
398 #if SNTP_CHECK_RESPONSE >= 1
399 else {
400 /* packet from wrong remote address or port, wait for correct response */
401 err = ERR_TIMEOUT;
403 #endif /* SNTP_CHECK_RESPONSE >= 1 */
404 pbuf_free(p);
405 if (err == ERR_OK) {
406 sntp_process(receive_timestamp);
408 /* Set up timeout for next request (only if poll response was received)*/
409 if (sntp_opmode == SNTP_OPMODE_POLL) {
410 /* Correct response, reset retry timeout */
411 SNTP_RESET_RETRY_TIMEOUT();
413 sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
414 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
415 (u32_t)SNTP_UPDATE_DELAY));
417 } else if (err != ERR_TIMEOUT) {
418 /* Errors are only processed in case of an explicit poll response */
419 if (sntp_opmode == SNTP_OPMODE_POLL) {
420 if (err == SNTP_ERR_KOD) {
421 /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
422 sntp_try_next_server(NULL);
423 } else {
424 /* another error, try the same server again */
425 sntp_retry(NULL);
431 /** Actually send an sntp request to a server.
433 * @param server_addr resolved IP address of the SNTP server
435 static void
436 sntp_send_request(const ip_addr_t *server_addr)
438 struct pbuf* p;
439 p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
440 if (p != NULL) {
441 struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
442 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
443 /* initialize request message */
444 sntp_initialize_request(sntpmsg);
445 /* send request */
446 udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
447 /* free the pbuf after sending it */
448 pbuf_free(p);
449 /* set up receive timeout: try next server or retry on timeout */
450 sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
451 #if SNTP_CHECK_RESPONSE >= 1
452 /* save server address to verify it in sntp_recv */
453 ip_addr_set(&sntp_last_server_address, server_addr);
454 #endif /* SNTP_CHECK_RESPONSE >= 1 */
455 } else {
456 LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
457 (u32_t)SNTP_RETRY_TIMEOUT));
458 /* out of memory: set up a timer to send a retry */
459 sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
463 #if SNTP_SERVER_DNS
465 * DNS found callback when using DNS names as server address.
467 static void
468 sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
470 LWIP_UNUSED_ARG(hostname);
471 LWIP_UNUSED_ARG(arg);
473 if (ipaddr != NULL) {
474 /* Address resolved, send request */
475 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
476 sntp_send_request(ipaddr);
477 } else {
478 /* DNS resolving failed -> try another server */
479 LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
480 sntp_try_next_server(NULL);
483 #endif /* SNTP_SERVER_DNS */
486 * Send out an sntp request.
488 * @param arg is unused (only necessary to conform to sys_timeout)
490 static void
491 sntp_request(void *arg)
493 ip_addr_t sntp_server_address;
494 err_t err;
496 LWIP_UNUSED_ARG(arg);
498 /* initialize SNTP server address */
499 #if SNTP_SERVER_DNS
500 if (sntp_servers[sntp_current_server].name) {
501 /* always resolve the name and rely on dns-internal caching & timeout */
502 ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
503 err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
504 sntp_dns_found, NULL);
505 if (err == ERR_INPROGRESS) {
506 /* DNS request sent, wait for sntp_dns_found being called */
507 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
508 return;
509 } else if (err == ERR_OK) {
510 sntp_servers[sntp_current_server].addr = sntp_server_address;
512 } else
513 #endif /* SNTP_SERVER_DNS */
515 sntp_server_address = sntp_servers[sntp_current_server].addr;
516 err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
519 if (err == ERR_OK) {
520 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
521 ipaddr_ntoa(&sntp_server_address)));
522 sntp_send_request(&sntp_server_address);
523 } else {
524 /* address conversion failed, try another server */
525 LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
526 sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
531 * @ingroup sntp
532 * Initialize this module.
533 * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
535 void
536 sntp_init(void)
538 #ifdef SNTP_SERVER_ADDRESS
539 #if SNTP_SERVER_DNS
540 sntp_setservername(0, SNTP_SERVER_ADDRESS);
541 #else
542 #error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
543 #endif
544 #endif /* SNTP_SERVER_ADDRESS */
546 if (sntp_pcb == NULL) {
547 sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
548 LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
549 if (sntp_pcb != NULL) {
550 udp_recv(sntp_pcb, sntp_recv, NULL);
552 if (sntp_opmode == SNTP_OPMODE_POLL) {
553 SNTP_RESET_RETRY_TIMEOUT();
554 #if SNTP_STARTUP_DELAY
555 sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
556 #else
557 sntp_request(NULL);
558 #endif
559 } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
560 ip_set_option(sntp_pcb, SOF_BROADCAST);
561 udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
568 * @ingroup sntp
569 * Stop this module.
571 void
572 sntp_stop(void)
574 if (sntp_pcb != NULL) {
575 sys_untimeout(sntp_request, NULL);
576 sys_untimeout(sntp_try_next_server, NULL);
577 udp_remove(sntp_pcb);
578 sntp_pcb = NULL;
583 * @ingroup sntp
584 * Get enabled state.
586 u8_t sntp_enabled(void)
588 return (sntp_pcb != NULL)? 1 : 0;
592 * @ingroup sntp
593 * Sets the operating mode.
594 * @param operating_mode one of the available operating modes
596 void
597 sntp_setoperatingmode(u8_t operating_mode)
599 LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
600 LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
601 sntp_opmode = operating_mode;
605 * @ingroup sntp
606 * Gets the operating mode.
608 u8_t
609 sntp_getoperatingmode(void)
611 return sntp_opmode;
614 #if SNTP_GET_SERVERS_FROM_DHCP
616 * Config SNTP server handling by IP address, name, or DHCP; clear table
617 * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
619 void
620 sntp_servermode_dhcp(int set_servers_from_dhcp)
622 u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
623 if (sntp_set_servers_from_dhcp != new_mode) {
624 sntp_set_servers_from_dhcp = new_mode;
627 #endif /* SNTP_GET_SERVERS_FROM_DHCP */
630 * @ingroup sntp
631 * Initialize one of the NTP servers by IP address
633 * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
634 * @param server IP address of the NTP server to set
636 void
637 sntp_setserver(u8_t idx, const ip_addr_t *server)
639 if (idx < SNTP_MAX_SERVERS) {
640 if (server != NULL) {
641 sntp_servers[idx].addr = (*server);
642 } else {
643 ip_addr_set_zero(&sntp_servers[idx].addr);
645 #if SNTP_SERVER_DNS
646 sntp_servers[idx].name = NULL;
647 #endif
651 #if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
653 * Initialize one of the NTP servers by IP address, required by DHCP
655 * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
656 * @param dnsserver IP address of the NTP server to set
658 void
659 dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
661 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
662 (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
663 ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
664 if (sntp_set_servers_from_dhcp && num) {
665 u8_t i;
666 for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
667 ip_addr_t addr;
668 ip_addr_copy_from_ip4(addr, server[i]);
669 sntp_setserver(i, &addr);
671 for (i = num; i < SNTP_MAX_SERVERS; i++) {
672 sntp_setserver(i, NULL);
676 #endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
679 * @ingroup sntp
680 * Obtain one of the currently configured by IP address (or DHCP) NTP servers
682 * @param idx the index of the NTP server
683 * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
684 * server has not been configured by address (or at all).
686 const ip_addr_t*
687 sntp_getserver(u8_t idx)
689 if (idx < SNTP_MAX_SERVERS) {
690 return &sntp_servers[idx].addr;
692 return IP_ADDR_ANY;
695 #if SNTP_SERVER_DNS
697 * Initialize one of the NTP servers by name
699 * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
700 * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
702 void
703 sntp_setservername(u8_t idx, char *server)
705 if (idx < SNTP_MAX_SERVERS) {
706 sntp_servers[idx].name = server;
711 * Obtain one of the currently configured by name NTP servers.
713 * @param numdns the index of the NTP server
714 * @return IP address of the indexed NTP server or NULL if the NTP
715 * server has not been configured by name (or at all)
717 char *
718 sntp_getservername(u8_t idx)
720 if (idx < SNTP_MAX_SERVERS) {
721 return sntp_servers[idx].name;
723 return NULL;
725 #endif /* SNTP_SERVER_DNS */
727 #endif /* LWIP_UDP */