[457] | 1 | /**
|
---|
| 2 | * @file
|
---|
| 3 | * SNTP client module
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
| 7 | * Copyright (c) 2007-2009 Fr辿d辿ric Bernon, Simon Goldschmidt
|
---|
| 8 | * All rights reserved.
|
---|
| 9 | *
|
---|
| 10 | * Redistribution and use in source and binary forms, with or without modification,
|
---|
| 11 | * are permitted provided that the following conditions are met:
|
---|
| 12 | *
|
---|
| 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.
|
---|
| 20 | *
|
---|
| 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.
|
---|
| 31 | *
|
---|
| 32 | * This file is part of the lwIP TCP/IP stack.
|
---|
| 33 | *
|
---|
| 34 | * Author: Fr辿d辿ric Bernon, Simon Goldschmidt
|
---|
| 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
| 38 | /**
|
---|
| 39 | * @defgroup sntp SNTP
|
---|
| 40 | * @ingroup apps
|
---|
| 41 | *
|
---|
| 42 | * This is simple "SNTP" client for the lwIP raw API.
|
---|
| 43 | * It is a minimal implementation of SNTPv4 as specified in RFC 4330.
|
---|
| 44 | *
|
---|
| 45 | * For a list of some public NTP servers, see this link:
|
---|
| 46 | * http://support.ntp.org/bin/view/Servers/NTPPoolServers
|
---|
| 47 | *
|
---|
| 48 | * @todo:
|
---|
| 49 | * - complete SNTP_CHECK_RESPONSE checks 3 and 4
|
---|
| 50 | */
|
---|
| 51 |
|
---|
| 52 | #include "lwip/apps/sntp.h"
|
---|
| 53 |
|
---|
| 54 | #include "lwip/opt.h"
|
---|
| 55 | #include "lwip/timeouts.h"
|
---|
| 56 | #include "lwip/udp.h"
|
---|
| 57 | #include "lwip/dns.h"
|
---|
| 58 | #include "lwip/ip_addr.h"
|
---|
| 59 | #include "lwip/pbuf.h"
|
---|
| 60 | #include "lwip/dhcp.h"
|
---|
| 61 |
|
---|
| 62 | #include <string.h>
|
---|
| 63 | #include <time.h>
|
---|
| 64 |
|
---|
| 65 | #if LWIP_UDP
|
---|
| 66 |
|
---|
| 67 | /* Handle support for more than one server via SNTP_MAX_SERVERS */
|
---|
| 68 | #if SNTP_MAX_SERVERS > 1
|
---|
| 69 | #define SNTP_SUPPORT_MULTIPLE_SERVERS 1
|
---|
| 70 | #else /* NTP_MAX_SERVERS > 1 */
|
---|
| 71 | #define SNTP_SUPPORT_MULTIPLE_SERVERS 0
|
---|
| 72 | #endif /* NTP_MAX_SERVERS > 1 */
|
---|
| 73 |
|
---|
| 74 | #ifndef SNTP_SUPPRESS_DELAY_CHECK
|
---|
| 75 | #if SNTP_UPDATE_DELAY < 15000
|
---|
| 76 | #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
|
---|
| 77 | #endif
|
---|
| 78 | #endif
|
---|
| 79 |
|
---|
| 80 | /* the various debug levels for this file */
|
---|
| 81 | #define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
|
---|
| 82 | #define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
|
---|
| 83 | #define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
|
---|
| 84 | #define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
|
---|
| 85 | #define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
|
---|
| 86 |
|
---|
| 87 | #define SNTP_ERR_KOD 1
|
---|
| 88 |
|
---|
| 89 | /* SNTP protocol defines */
|
---|
| 90 | #define SNTP_MSG_LEN 48
|
---|
| 91 |
|
---|
| 92 | #define SNTP_OFFSET_LI_VN_MODE 0
|
---|
| 93 | #define SNTP_LI_MASK 0xC0
|
---|
| 94 | #define SNTP_LI_NO_WARNING (0x00 << 6)
|
---|
| 95 | #define SNTP_LI_LAST_MINUTE_61_SEC (0x01 << 6)
|
---|
| 96 | #define SNTP_LI_LAST_MINUTE_59_SEC (0x02 << 6)
|
---|
| 97 | #define SNTP_LI_ALARM_CONDITION (0x03 << 6) /* (clock not synchronized) */
|
---|
| 98 |
|
---|
| 99 | #define SNTP_VERSION_MASK 0x38
|
---|
| 100 | #define SNTP_VERSION (4/* NTP Version 4*/<<3)
|
---|
| 101 |
|
---|
| 102 | #define SNTP_MODE_MASK 0x07
|
---|
| 103 | #define SNTP_MODE_CLIENT 0x03
|
---|
| 104 | #define SNTP_MODE_SERVER 0x04
|
---|
| 105 | #define SNTP_MODE_BROADCAST 0x05
|
---|
| 106 |
|
---|
| 107 | #define SNTP_OFFSET_STRATUM 1
|
---|
| 108 | #define SNTP_STRATUM_KOD 0x00
|
---|
| 109 |
|
---|
| 110 | #define SNTP_OFFSET_ORIGINATE_TIME 24
|
---|
| 111 | #define SNTP_OFFSET_RECEIVE_TIME 32
|
---|
| 112 | #define SNTP_OFFSET_TRANSMIT_TIME 40
|
---|
| 113 |
|
---|
| 114 | /* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */
|
---|
| 115 | #define DIFF_SEC_1970_2036 ((u32_t)2085978496L)
|
---|
| 116 |
|
---|
| 117 | /** Convert NTP timestamp fraction to microseconds.
|
---|
| 118 | */
|
---|
| 119 | #ifndef SNTP_FRAC_TO_US
|
---|
| 120 | # if LWIP_HAVE_INT64
|
---|
| 121 | # define SNTP_FRAC_TO_US(f) ((u32_t)(((u64_t)(f) * 1000000UL) >> 32))
|
---|
| 122 | # else
|
---|
| 123 | # define SNTP_FRAC_TO_US(f) ((u32_t)(f) / 4295)
|
---|
| 124 | # endif
|
---|
| 125 | #endif /* !SNTP_FRAC_TO_US */
|
---|
| 126 |
|
---|
| 127 | /* Configure behaviour depending on native, microsecond or second precision.
|
---|
| 128 | * Treat NTP timestamps as signed two's-complement integers. This way,
|
---|
| 129 | * timestamps that have the MSB set simply become negative offsets from
|
---|
| 130 | * the epoch (Feb 7, 2036 06:28:16 UTC). Representable dates range from
|
---|
| 131 | * 1968 to 2104.
|
---|
| 132 | */
|
---|
| 133 | #ifndef SNTP_SET_SYSTEM_TIME_NTP
|
---|
| 134 | # ifdef SNTP_SET_SYSTEM_TIME_US
|
---|
| 135 | # define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
|
---|
| 136 | SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f))
|
---|
| 137 | # else
|
---|
| 138 | # define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
|
---|
| 139 | SNTP_SET_SYSTEM_TIME((u32_t)((s) + DIFF_SEC_1970_2036))
|
---|
| 140 | # endif
|
---|
| 141 | #endif /* !SNTP_SET_SYSTEM_TIME_NTP */
|
---|
| 142 |
|
---|
| 143 | /* Get the system time either natively as NTP timestamp or convert from
|
---|
| 144 | * Unix time in seconds and microseconds. Take care to avoid overflow if the
|
---|
| 145 | * microsecond value is at the maximum of 999999. Also add 0.5 us fudge to
|
---|
| 146 | * avoid special values like 0, and to mask round-off errors that would
|
---|
| 147 | * otherwise break round-trip conversion identity.
|
---|
| 148 | */
|
---|
| 149 | #ifndef SNTP_GET_SYSTEM_TIME_NTP
|
---|
| 150 | # define SNTP_GET_SYSTEM_TIME_NTP(s, f) do { \
|
---|
| 151 | u32_t sec_, usec_; \
|
---|
| 152 | SNTP_GET_SYSTEM_TIME(sec_, usec_); \
|
---|
| 153 | (s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \
|
---|
| 154 | (f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \
|
---|
| 155 | } while (0)
|
---|
| 156 | #endif /* !SNTP_GET_SYSTEM_TIME_NTP */
|
---|
| 157 |
|
---|
| 158 | /* Start offset of the timestamps to extract from the SNTP packet */
|
---|
| 159 | #define SNTP_OFFSET_TIMESTAMPS \
|
---|
| 160 | (SNTP_OFFSET_TRANSMIT_TIME + 8 - sizeof(struct sntp_timestamps))
|
---|
| 161 |
|
---|
| 162 | /* Round-trip delay arithmetic helpers */
|
---|
| 163 | #if SNTP_COMP_ROUNDTRIP
|
---|
| 164 | # if !LWIP_HAVE_INT64
|
---|
| 165 | # error "SNTP round-trip delay compensation requires 64-bit arithmetic"
|
---|
| 166 | # endif
|
---|
| 167 | # define SNTP_SEC_FRAC_TO_S64(s, f) \
|
---|
| 168 | ((s64_t)(((u64_t)(s) << 32) | (u32_t)(f)))
|
---|
| 169 | # define SNTP_TIMESTAMP_TO_S64(t) \
|
---|
| 170 | SNTP_SEC_FRAC_TO_S64(lwip_ntohl((t).sec), lwip_ntohl((t).frac))
|
---|
| 171 | #endif /* SNTP_COMP_ROUNDTRIP */
|
---|
| 172 |
|
---|
| 173 | /**
|
---|
| 174 | * 64-bit NTP timestamp, in network byte order.
|
---|
| 175 | */
|
---|
| 176 | struct sntp_time {
|
---|
| 177 | u32_t sec;
|
---|
| 178 | u32_t frac;
|
---|
| 179 | };
|
---|
| 180 |
|
---|
| 181 | /**
|
---|
| 182 | * Timestamps to be extracted from the NTP header.
|
---|
| 183 | */
|
---|
| 184 | struct sntp_timestamps {
|
---|
| 185 | #if SNTP_COMP_ROUNDTRIP || SNTP_CHECK_RESPONSE >= 2
|
---|
| 186 | struct sntp_time orig;
|
---|
| 187 | struct sntp_time recv;
|
---|
| 188 | #endif
|
---|
| 189 | struct sntp_time xmit;
|
---|
| 190 | };
|
---|
| 191 |
|
---|
| 192 | /**
|
---|
| 193 | * SNTP packet format (without optional fields)
|
---|
| 194 | * Timestamps are coded as 64 bits:
|
---|
| 195 | * - signed 32 bits seconds since Feb 07, 2036, 06:28:16 UTC (epoch 1)
|
---|
| 196 | * - unsigned 32 bits seconds fraction (2^32 = 1 second)
|
---|
| 197 | */
|
---|
| 198 | #ifdef PACK_STRUCT_USE_INCLUDES
|
---|
| 199 | # include "arch/bpstruct.h"
|
---|
| 200 | #endif
|
---|
| 201 | PACK_STRUCT_BEGIN
|
---|
| 202 | struct sntp_msg {
|
---|
| 203 | PACK_STRUCT_FLD_8(u8_t li_vn_mode);
|
---|
| 204 | PACK_STRUCT_FLD_8(u8_t stratum);
|
---|
| 205 | PACK_STRUCT_FLD_8(u8_t poll);
|
---|
| 206 | PACK_STRUCT_FLD_8(u8_t precision);
|
---|
| 207 | PACK_STRUCT_FIELD(u32_t root_delay);
|
---|
| 208 | PACK_STRUCT_FIELD(u32_t root_dispersion);
|
---|
| 209 | PACK_STRUCT_FIELD(u32_t reference_identifier);
|
---|
| 210 | PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
|
---|
| 211 | PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
|
---|
| 212 | PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
|
---|
| 213 | PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
|
---|
| 214 | } PACK_STRUCT_STRUCT;
|
---|
| 215 | PACK_STRUCT_END
|
---|
| 216 | #ifdef PACK_STRUCT_USE_INCLUDES
|
---|
| 217 | # include "arch/epstruct.h"
|
---|
| 218 | #endif
|
---|
| 219 |
|
---|
| 220 | /* function prototypes */
|
---|
| 221 | static void sntp_request(void *arg);
|
---|
| 222 |
|
---|
| 223 | /** The operating mode */
|
---|
| 224 | static u8_t sntp_opmode;
|
---|
| 225 |
|
---|
| 226 | /** The UDP pcb used by the SNTP client */
|
---|
| 227 | static struct udp_pcb *sntp_pcb;
|
---|
| 228 | /** Names/Addresses of servers */
|
---|
| 229 | struct sntp_server {
|
---|
| 230 | #if SNTP_SERVER_DNS
|
---|
| 231 | const char *name;
|
---|
| 232 | #endif /* SNTP_SERVER_DNS */
|
---|
| 233 | ip_addr_t addr;
|
---|
| 234 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
---|
| 235 | /** Reachability shift register as described in RFC 5905 */
|
---|
| 236 | u8_t reachability;
|
---|
| 237 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
---|
| 238 | };
|
---|
| 239 | static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
|
---|
| 240 |
|
---|
| 241 | #if SNTP_GET_SERVERS_FROM_DHCP
|
---|
| 242 | static u8_t sntp_set_servers_from_dhcp;
|
---|
| 243 | #endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
---|
| 244 | #if SNTP_SUPPORT_MULTIPLE_SERVERS
|
---|
| 245 | /** The currently used server (initialized to 0) */
|
---|
| 246 | static u8_t sntp_current_server;
|
---|
| 247 | #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
---|
| 248 | #define sntp_current_server 0
|
---|
| 249 | #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
---|
| 250 |
|
---|
| 251 | #if SNTP_RETRY_TIMEOUT_EXP
|
---|
| 252 | #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
|
---|
| 253 | /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
|
---|
| 254 | static u32_t sntp_retry_timeout;
|
---|
| 255 | #else /* SNTP_RETRY_TIMEOUT_EXP */
|
---|
| 256 | #define SNTP_RESET_RETRY_TIMEOUT()
|
---|
| 257 | #define sntp_retry_timeout SNTP_RETRY_TIMEOUT
|
---|
| 258 | #endif /* SNTP_RETRY_TIMEOUT_EXP */
|
---|
| 259 |
|
---|
| 260 | #if SNTP_CHECK_RESPONSE >= 1
|
---|
| 261 | /** Saves the last server address to compare with response */
|
---|
| 262 | static ip_addr_t sntp_last_server_address;
|
---|
| 263 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
---|
| 264 |
|
---|
| 265 | #if SNTP_CHECK_RESPONSE >= 2
|
---|
| 266 | /** Saves the last timestamp sent (which is sent back by the server)
|
---|
| 267 | * to compare against in response. Stored in network byte order. */
|
---|
| 268 | static struct sntp_time sntp_last_timestamp_sent;
|
---|
| 269 | #endif /* SNTP_CHECK_RESPONSE >= 2 */
|
---|
| 270 |
|
---|
| 271 | #if defined(LWIP_DEBUG) && !defined(sntp_format_time)
|
---|
| 272 | /* Debug print helper. */
|
---|
| 273 | static const char *
|
---|
| 274 | sntp_format_time(s32_t sec)
|
---|
| 275 | {
|
---|
| 276 | time_t ut;
|
---|
| 277 | ut = (u32_t)((u32_t)sec + DIFF_SEC_1970_2036);
|
---|
| 278 | return ctime(&ut);
|
---|
| 279 | }
|
---|
| 280 | #endif /* LWIP_DEBUG && !sntp_format_time */
|
---|
| 281 |
|
---|
| 282 | /**
|
---|
| 283 | * SNTP processing of received timestamp
|
---|
| 284 | */
|
---|
| 285 | static void
|
---|
| 286 | sntp_process(const struct sntp_timestamps *timestamps)
|
---|
| 287 | {
|
---|
| 288 | s32_t sec;
|
---|
| 289 | u32_t frac;
|
---|
| 290 |
|
---|
| 291 | sec = (s32_t)lwip_ntohl(timestamps->xmit.sec);
|
---|
| 292 | frac = lwip_ntohl(timestamps->xmit.frac);
|
---|
| 293 |
|
---|
| 294 | #if SNTP_COMP_ROUNDTRIP
|
---|
| 295 | # if SNTP_CHECK_RESPONSE >= 2
|
---|
| 296 | if (timestamps->recv.sec != 0 || timestamps->recv.frac != 0)
|
---|
| 297 | # endif
|
---|
| 298 | {
|
---|
| 299 | s32_t dest_sec;
|
---|
| 300 | u32_t dest_frac;
|
---|
| 301 | u32_t step_sec;
|
---|
| 302 |
|
---|
| 303 | /* Get the destination time stamp, i.e. the current system time */
|
---|
| 304 | SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac);
|
---|
| 305 |
|
---|
| 306 | step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec)
|
---|
| 307 | : ((u32_t)dest_sec - (u32_t)sec);
|
---|
| 308 | /* In order to avoid overflows, skip the compensation if the clock step
|
---|
| 309 | * is larger than about 34 years. */
|
---|
| 310 | if ((step_sec >> 30) == 0) {
|
---|
| 311 | s64_t t1, t2, t3, t4;
|
---|
| 312 |
|
---|
| 313 | t4 = SNTP_SEC_FRAC_TO_S64(dest_sec, dest_frac);
|
---|
| 314 | t3 = SNTP_SEC_FRAC_TO_S64(sec, frac);
|
---|
| 315 | t1 = SNTP_TIMESTAMP_TO_S64(timestamps->orig);
|
---|
| 316 | t2 = SNTP_TIMESTAMP_TO_S64(timestamps->recv);
|
---|
| 317 | /* Clock offset calculation according to RFC 4330 */
|
---|
| 318 | t4 += ((t2 - t1) + (t3 - t4)) / 2;
|
---|
| 319 |
|
---|
| 320 | sec = (s32_t)((u64_t)t4 >> 32);
|
---|
| 321 | frac = (u32_t)((u64_t)t4);
|
---|
| 322 | }
|
---|
| 323 | }
|
---|
| 324 | #endif /* SNTP_COMP_ROUNDTRIP */
|
---|
| 325 |
|
---|
| 326 | SNTP_SET_SYSTEM_TIME_NTP(sec, frac);
|
---|
| 327 | LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */
|
---|
| 328 | LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %" U32_F " us\n",
|
---|
| 329 | sntp_format_time(sec), SNTP_FRAC_TO_US(frac)));
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | /**
|
---|
| 333 | * Initialize request struct to be sent to server.
|
---|
| 334 | */
|
---|
| 335 | static void
|
---|
| 336 | sntp_initialize_request(struct sntp_msg *req)
|
---|
| 337 | {
|
---|
| 338 | memset(req, 0, SNTP_MSG_LEN);
|
---|
| 339 | req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
|
---|
| 340 |
|
---|
| 341 | #if SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP
|
---|
| 342 | {
|
---|
| 343 | s32_t secs;
|
---|
| 344 | u32_t sec, frac;
|
---|
| 345 | /* Get the transmit timestamp */
|
---|
| 346 | SNTP_GET_SYSTEM_TIME_NTP(secs, frac);
|
---|
| 347 | sec = lwip_htonl((u32_t)secs);
|
---|
| 348 | frac = lwip_htonl(frac);
|
---|
| 349 |
|
---|
| 350 | # if SNTP_CHECK_RESPONSE >= 2
|
---|
| 351 | sntp_last_timestamp_sent.sec = sec;
|
---|
| 352 | sntp_last_timestamp_sent.frac = frac;
|
---|
| 353 | # endif
|
---|
| 354 | req->transmit_timestamp[0] = sec;
|
---|
| 355 | req->transmit_timestamp[1] = frac;
|
---|
| 356 | }
|
---|
| 357 | #endif /* SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP */
|
---|
| 358 | }
|
---|
| 359 |
|
---|
| 360 | /**
|
---|
| 361 | * Retry: send a new request (and increase retry timeout).
|
---|
| 362 | *
|
---|
| 363 | * @param arg is unused (only necessary to conform to sys_timeout)
|
---|
| 364 | */
|
---|
| 365 | static void
|
---|
| 366 | sntp_retry(void *arg)
|
---|
| 367 | {
|
---|
| 368 | LWIP_UNUSED_ARG(arg);
|
---|
| 369 |
|
---|
| 370 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
|
---|
| 371 | sntp_retry_timeout));
|
---|
| 372 |
|
---|
| 373 | /* set up a timer to send a retry and increase the retry delay */
|
---|
| 374 | sys_timeout(sntp_retry_timeout, sntp_request, NULL);
|
---|
| 375 |
|
---|
| 376 | #if SNTP_RETRY_TIMEOUT_EXP
|
---|
| 377 | {
|
---|
| 378 | u32_t new_retry_timeout;
|
---|
| 379 | /* increase the timeout for next retry */
|
---|
| 380 | new_retry_timeout = sntp_retry_timeout << 1;
|
---|
| 381 | /* limit to maximum timeout and prevent overflow */
|
---|
| 382 | if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
|
---|
| 383 | (new_retry_timeout > sntp_retry_timeout)) {
|
---|
| 384 | sntp_retry_timeout = new_retry_timeout;
|
---|
| 385 | }
|
---|
| 386 | }
|
---|
| 387 | #endif /* SNTP_RETRY_TIMEOUT_EXP */
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | #if SNTP_SUPPORT_MULTIPLE_SERVERS
|
---|
| 391 | /**
|
---|
| 392 | * If Kiss-of-Death is received (or another packet parsing error),
|
---|
| 393 | * try the next server or retry the current server and increase the retry
|
---|
| 394 | * timeout if only one server is available.
|
---|
| 395 | * (implicitly, SNTP_MAX_SERVERS > 1)
|
---|
| 396 | *
|
---|
| 397 | * @param arg is unused (only necessary to conform to sys_timeout)
|
---|
| 398 | */
|
---|
| 399 | static void
|
---|
| 400 | sntp_try_next_server(void *arg)
|
---|
| 401 | {
|
---|
| 402 | u8_t old_server, i;
|
---|
| 403 | LWIP_UNUSED_ARG(arg);
|
---|
| 404 |
|
---|
| 405 | old_server = sntp_current_server;
|
---|
| 406 | for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
|
---|
| 407 | sntp_current_server++;
|
---|
| 408 | if (sntp_current_server >= SNTP_MAX_SERVERS) {
|
---|
| 409 | sntp_current_server = 0;
|
---|
| 410 | }
|
---|
| 411 | if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
|
---|
| 412 | #if SNTP_SERVER_DNS
|
---|
| 413 | || (sntp_servers[sntp_current_server].name != NULL)
|
---|
| 414 | #endif
|
---|
| 415 | ) {
|
---|
| 416 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
|
---|
| 417 | (u16_t)sntp_current_server));
|
---|
| 418 | /* new server: reset retry timeout */
|
---|
| 419 | SNTP_RESET_RETRY_TIMEOUT();
|
---|
| 420 | /* instantly send a request to the next server */
|
---|
| 421 | sntp_request(NULL);
|
---|
| 422 | return;
|
---|
| 423 | }
|
---|
| 424 | }
|
---|
| 425 | /* no other valid server found */
|
---|
| 426 | sntp_current_server = old_server;
|
---|
| 427 | sntp_retry(NULL);
|
---|
| 428 | }
|
---|
| 429 | #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
---|
| 430 | /* Always retry on error if only one server is supported */
|
---|
| 431 | #define sntp_try_next_server sntp_retry
|
---|
| 432 | #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
---|
| 433 |
|
---|
| 434 | /** UDP recv callback for the sntp pcb */
|
---|
| 435 | static void
|
---|
| 436 | sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
---|
| 437 | {
|
---|
| 438 | struct sntp_timestamps timestamps;
|
---|
| 439 | u8_t mode;
|
---|
| 440 | u8_t stratum;
|
---|
| 441 | err_t err;
|
---|
| 442 |
|
---|
| 443 | LWIP_UNUSED_ARG(arg);
|
---|
| 444 | LWIP_UNUSED_ARG(pcb);
|
---|
| 445 |
|
---|
| 446 | err = ERR_ARG;
|
---|
| 447 | #if SNTP_CHECK_RESPONSE >= 1
|
---|
| 448 | /* check server address and port */
|
---|
| 449 | if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
|
---|
| 450 | (port == SNTP_PORT))
|
---|
| 451 | #else /* SNTP_CHECK_RESPONSE >= 1 */
|
---|
| 452 | LWIP_UNUSED_ARG(addr);
|
---|
| 453 | LWIP_UNUSED_ARG(port);
|
---|
| 454 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
---|
| 455 | {
|
---|
| 456 | /* process the response */
|
---|
| 457 | if (p->tot_len == SNTP_MSG_LEN) {
|
---|
| 458 | mode = pbuf_get_at(p, SNTP_OFFSET_LI_VN_MODE) & SNTP_MODE_MASK;
|
---|
| 459 | /* if this is a SNTP response... */
|
---|
| 460 | if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
|
---|
| 461 | ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
|
---|
| 462 | stratum = pbuf_get_at(p, SNTP_OFFSET_STRATUM);
|
---|
| 463 |
|
---|
| 464 | if (stratum == SNTP_STRATUM_KOD) {
|
---|
| 465 | /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
---|
| 466 | err = SNTP_ERR_KOD;
|
---|
| 467 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
|
---|
| 468 | } else {
|
---|
| 469 | pbuf_copy_partial(p, ×tamps, sizeof(timestamps), SNTP_OFFSET_TIMESTAMPS);
|
---|
| 470 | #if SNTP_CHECK_RESPONSE >= 2
|
---|
| 471 | /* check originate_timetamp against sntp_last_timestamp_sent */
|
---|
| 472 | if (timestamps.orig.sec != sntp_last_timestamp_sent.sec ||
|
---|
| 473 | timestamps.orig.frac != sntp_last_timestamp_sent.frac) {
|
---|
| 474 | LWIP_DEBUGF(SNTP_DEBUG_WARN,
|
---|
| 475 | ("sntp_recv: Invalid originate timestamp in response\n"));
|
---|
| 476 | } else
|
---|
| 477 | #endif /* SNTP_CHECK_RESPONSE >= 2 */
|
---|
| 478 | /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
|
---|
| 479 | {
|
---|
| 480 | /* correct answer */
|
---|
| 481 | err = ERR_OK;
|
---|
| 482 | }
|
---|
| 483 | }
|
---|
| 484 | } else {
|
---|
| 485 | LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
|
---|
| 486 | /* wait for correct response */
|
---|
| 487 | err = ERR_TIMEOUT;
|
---|
| 488 | }
|
---|
| 489 | } else {
|
---|
| 490 | LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
|
---|
| 491 | }
|
---|
| 492 | }
|
---|
| 493 | #if SNTP_CHECK_RESPONSE >= 1
|
---|
| 494 | else {
|
---|
| 495 | /* packet from wrong remote address or port, wait for correct response */
|
---|
| 496 | err = ERR_TIMEOUT;
|
---|
| 497 | }
|
---|
| 498 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
---|
| 499 |
|
---|
| 500 | pbuf_free(p);
|
---|
| 501 |
|
---|
| 502 | if (err == ERR_OK) {
|
---|
| 503 | /* correct packet received: process it it */
|
---|
| 504 | sntp_process(×tamps);
|
---|
| 505 |
|
---|
| 506 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
---|
| 507 | /* indicate that server responded */
|
---|
| 508 | sntp_servers[sntp_current_server].reachability |= 1;
|
---|
| 509 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
---|
| 510 | /* Set up timeout for next request (only if poll response was received)*/
|
---|
| 511 | if (sntp_opmode == SNTP_OPMODE_POLL) {
|
---|
| 512 | u32_t sntp_update_delay;
|
---|
| 513 | sys_untimeout(sntp_try_next_server, NULL);
|
---|
| 514 | sys_untimeout(sntp_request, NULL);
|
---|
| 515 |
|
---|
| 516 | /* Correct response, reset retry timeout */
|
---|
| 517 | SNTP_RESET_RETRY_TIMEOUT();
|
---|
| 518 |
|
---|
| 519 | sntp_update_delay = (u32_t)SNTP_UPDATE_DELAY;
|
---|
| 520 | sys_timeout(sntp_update_delay, sntp_request, NULL);
|
---|
| 521 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
|
---|
| 522 | sntp_update_delay));
|
---|
| 523 | }
|
---|
| 524 | } else if (err == SNTP_ERR_KOD) {
|
---|
| 525 | /* KOD errors are only processed in case of an explicit poll response */
|
---|
| 526 | if (sntp_opmode == SNTP_OPMODE_POLL) {
|
---|
| 527 | /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
---|
| 528 | sntp_try_next_server(NULL);
|
---|
| 529 | }
|
---|
| 530 | } else {
|
---|
| 531 | /* ignore any broken packet, poll mode: retry after timeout to avoid flooding */
|
---|
| 532 | }
|
---|
| 533 | }
|
---|
| 534 |
|
---|
| 535 | /** Actually send an sntp request to a server.
|
---|
| 536 | *
|
---|
| 537 | * @param server_addr resolved IP address of the SNTP server
|
---|
| 538 | */
|
---|
| 539 | static void
|
---|
| 540 | sntp_send_request(const ip_addr_t *server_addr)
|
---|
| 541 | {
|
---|
| 542 | struct pbuf *p;
|
---|
| 543 |
|
---|
| 544 | LWIP_ASSERT("server_addr != NULL", server_addr != NULL);
|
---|
| 545 |
|
---|
| 546 | p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
---|
| 547 | if (p != NULL) {
|
---|
| 548 | struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
|
---|
| 549 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
|
---|
| 550 | /* initialize request message */
|
---|
| 551 | sntp_initialize_request(sntpmsg);
|
---|
| 552 | /* send request */
|
---|
| 553 | udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
|
---|
| 554 | /* free the pbuf after sending it */
|
---|
| 555 | pbuf_free(p);
|
---|
| 556 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
---|
| 557 | /* indicate new packet has been sent */
|
---|
| 558 | sntp_servers[sntp_current_server].reachability <<= 1;
|
---|
| 559 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
---|
| 560 | /* set up receive timeout: try next server or retry on timeout */
|
---|
| 561 | sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
---|
| 562 | #if SNTP_CHECK_RESPONSE >= 1
|
---|
| 563 | /* save server address to verify it in sntp_recv */
|
---|
| 564 | ip_addr_copy(sntp_last_server_address, *server_addr);
|
---|
| 565 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
---|
| 566 | } else {
|
---|
| 567 | LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
|
---|
| 568 | (u32_t)SNTP_RETRY_TIMEOUT));
|
---|
| 569 | /* out of memory: set up a timer to send a retry */
|
---|
| 570 | sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
|
---|
| 571 | }
|
---|
| 572 | }
|
---|
| 573 |
|
---|
| 574 | #if SNTP_SERVER_DNS
|
---|
| 575 | /**
|
---|
| 576 | * DNS found callback when using DNS names as server address.
|
---|
| 577 | */
|
---|
| 578 | static void
|
---|
| 579 | sntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg)
|
---|
| 580 | {
|
---|
| 581 | LWIP_UNUSED_ARG(hostname);
|
---|
| 582 | LWIP_UNUSED_ARG(arg);
|
---|
| 583 |
|
---|
| 584 | if (ipaddr != NULL) {
|
---|
| 585 | /* Address resolved, send request */
|
---|
| 586 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
|
---|
| 587 | sntp_servers[sntp_current_server].addr = *ipaddr;
|
---|
| 588 | sntp_send_request(ipaddr);
|
---|
| 589 | } else {
|
---|
| 590 | /* DNS resolving failed -> try another server */
|
---|
| 591 | LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
|
---|
| 592 | sntp_try_next_server(NULL);
|
---|
| 593 | }
|
---|
| 594 | }
|
---|
| 595 | #endif /* SNTP_SERVER_DNS */
|
---|
| 596 |
|
---|
| 597 | /**
|
---|
| 598 | * Send out an sntp request.
|
---|
| 599 | *
|
---|
| 600 | * @param arg is unused (only necessary to conform to sys_timeout)
|
---|
| 601 | */
|
---|
| 602 | static void
|
---|
| 603 | sntp_request(void *arg)
|
---|
| 604 | {
|
---|
| 605 | ip_addr_t sntp_server_address;
|
---|
| 606 | err_t err;
|
---|
| 607 |
|
---|
| 608 | LWIP_UNUSED_ARG(arg);
|
---|
| 609 |
|
---|
| 610 | /* initialize SNTP server address */
|
---|
| 611 | #if SNTP_SERVER_DNS
|
---|
| 612 | if (sntp_servers[sntp_current_server].name) {
|
---|
| 613 | /* always resolve the name and rely on dns-internal caching & timeout */
|
---|
| 614 | ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
|
---|
| 615 | err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
|
---|
| 616 | sntp_dns_found, NULL);
|
---|
| 617 | if (err == ERR_INPROGRESS) {
|
---|
| 618 | /* DNS request sent, wait for sntp_dns_found being called */
|
---|
| 619 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
|
---|
| 620 | return;
|
---|
| 621 | } else if (err == ERR_OK) {
|
---|
| 622 | sntp_servers[sntp_current_server].addr = sntp_server_address;
|
---|
| 623 | }
|
---|
| 624 | } else
|
---|
| 625 | #endif /* SNTP_SERVER_DNS */
|
---|
| 626 | {
|
---|
| 627 | sntp_server_address = sntp_servers[sntp_current_server].addr;
|
---|
| 628 | err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
|
---|
| 629 | }
|
---|
| 630 |
|
---|
| 631 | if (err == ERR_OK) {
|
---|
| 632 | LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
|
---|
| 633 | ipaddr_ntoa(&sntp_server_address)));
|
---|
| 634 | sntp_send_request(&sntp_server_address);
|
---|
| 635 | } else {
|
---|
| 636 | /* address conversion failed, try another server */
|
---|
| 637 | LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
|
---|
| 638 | sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
|
---|
| 639 | }
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | /**
|
---|
| 643 | * @ingroup sntp
|
---|
| 644 | * Initialize this module.
|
---|
| 645 | * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
|
---|
| 646 | */
|
---|
| 647 | void
|
---|
| 648 | sntp_init(void)
|
---|
| 649 | {
|
---|
| 650 | /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
---|
| 651 |
|
---|
| 652 | #ifdef SNTP_SERVER_ADDRESS
|
---|
| 653 | #if SNTP_SERVER_DNS
|
---|
| 654 | sntp_setservername(0, SNTP_SERVER_ADDRESS);
|
---|
| 655 | #else
|
---|
| 656 | #error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
|
---|
| 657 | #endif
|
---|
| 658 | #endif /* SNTP_SERVER_ADDRESS */
|
---|
| 659 |
|
---|
| 660 | if (sntp_pcb == NULL) {
|
---|
| 661 | sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
---|
| 662 | LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
|
---|
| 663 | if (sntp_pcb != NULL) {
|
---|
| 664 | udp_recv(sntp_pcb, sntp_recv, NULL);
|
---|
| 665 |
|
---|
| 666 | if (sntp_opmode == SNTP_OPMODE_POLL) {
|
---|
| 667 | SNTP_RESET_RETRY_TIMEOUT();
|
---|
| 668 | #if SNTP_STARTUP_DELAY
|
---|
| 669 | sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
|
---|
| 670 | #else
|
---|
| 671 | sntp_request(NULL);
|
---|
| 672 | #endif
|
---|
| 673 | } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
|
---|
| 674 | ip_set_option(sntp_pcb, SOF_BROADCAST);
|
---|
| 675 | udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
|
---|
| 676 | }
|
---|
| 677 | }
|
---|
| 678 | }
|
---|
| 679 | }
|
---|
| 680 |
|
---|
| 681 | /**
|
---|
| 682 | * @ingroup sntp
|
---|
| 683 | * Stop this module.
|
---|
| 684 | */
|
---|
| 685 | void
|
---|
| 686 | sntp_stop(void)
|
---|
| 687 | {
|
---|
| 688 | LWIP_ASSERT_CORE_LOCKED();
|
---|
| 689 | if (sntp_pcb != NULL) {
|
---|
| 690 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
---|
| 691 | u8_t i;
|
---|
| 692 | for (i = 0; i < SNTP_MAX_SERVERS; i++) {
|
---|
| 693 | sntp_servers[i].reachability = 0;
|
---|
| 694 | }
|
---|
| 695 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
---|
| 696 | sys_untimeout(sntp_request, NULL);
|
---|
| 697 | sys_untimeout(sntp_try_next_server, NULL);
|
---|
| 698 | udp_remove(sntp_pcb);
|
---|
| 699 | sntp_pcb = NULL;
|
---|
| 700 | }
|
---|
| 701 | }
|
---|
| 702 |
|
---|
| 703 | /**
|
---|
| 704 | * @ingroup sntp
|
---|
| 705 | * Get enabled state.
|
---|
| 706 | */
|
---|
| 707 | u8_t sntp_enabled(void)
|
---|
| 708 | {
|
---|
| 709 | return (sntp_pcb != NULL) ? 1 : 0;
|
---|
| 710 | }
|
---|
| 711 |
|
---|
| 712 | /**
|
---|
| 713 | * @ingroup sntp
|
---|
| 714 | * Sets the operating mode.
|
---|
| 715 | * @param operating_mode one of the available operating modes
|
---|
| 716 | */
|
---|
| 717 | void
|
---|
| 718 | sntp_setoperatingmode(u8_t operating_mode)
|
---|
| 719 | {
|
---|
| 720 | LWIP_ASSERT_CORE_LOCKED();
|
---|
| 721 | LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
|
---|
| 722 | LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
|
---|
| 723 | sntp_opmode = operating_mode;
|
---|
| 724 | }
|
---|
| 725 |
|
---|
| 726 | /**
|
---|
| 727 | * @ingroup sntp
|
---|
| 728 | * Gets the operating mode.
|
---|
| 729 | */
|
---|
| 730 | u8_t
|
---|
| 731 | sntp_getoperatingmode(void)
|
---|
| 732 | {
|
---|
| 733 | return sntp_opmode;
|
---|
| 734 | }
|
---|
| 735 |
|
---|
| 736 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
---|
| 737 | /**
|
---|
| 738 | * @ingroup sntp
|
---|
| 739 | * Gets the server reachability shift register as described in RFC 5905.
|
---|
| 740 | *
|
---|
| 741 | * @param idx the index of the NTP server
|
---|
| 742 | */
|
---|
| 743 | u8_t
|
---|
| 744 | sntp_getreachability(u8_t idx)
|
---|
| 745 | {
|
---|
| 746 | if (idx < SNTP_MAX_SERVERS) {
|
---|
| 747 | return sntp_servers[idx].reachability;
|
---|
| 748 | }
|
---|
| 749 | return 0;
|
---|
| 750 | }
|
---|
| 751 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
---|
| 752 |
|
---|
| 753 | #if SNTP_GET_SERVERS_FROM_DHCP
|
---|
| 754 | /**
|
---|
| 755 | * Config SNTP server handling by IP address, name, or DHCP; clear table
|
---|
| 756 | * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
|
---|
| 757 | */
|
---|
| 758 | void
|
---|
| 759 | sntp_servermode_dhcp(int set_servers_from_dhcp)
|
---|
| 760 | {
|
---|
| 761 | u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
|
---|
| 762 | LWIP_ASSERT_CORE_LOCKED();
|
---|
| 763 | if (sntp_set_servers_from_dhcp != new_mode) {
|
---|
| 764 | sntp_set_servers_from_dhcp = new_mode;
|
---|
| 765 | }
|
---|
| 766 | }
|
---|
| 767 | #endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
---|
| 768 |
|
---|
| 769 | /**
|
---|
| 770 | * @ingroup sntp
|
---|
| 771 | * Initialize one of the NTP servers by IP address
|
---|
| 772 | *
|
---|
| 773 | * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
---|
| 774 | * @param server IP address of the NTP server to set
|
---|
| 775 | */
|
---|
| 776 | void
|
---|
| 777 | sntp_setserver(u8_t idx, const ip_addr_t *server)
|
---|
| 778 | {
|
---|
| 779 | LWIP_ASSERT_CORE_LOCKED();
|
---|
| 780 | if (idx < SNTP_MAX_SERVERS) {
|
---|
| 781 | if (server != NULL) {
|
---|
| 782 | sntp_servers[idx].addr = (*server);
|
---|
| 783 | } else {
|
---|
| 784 | ip_addr_set_zero(&sntp_servers[idx].addr);
|
---|
| 785 | }
|
---|
| 786 | #if SNTP_SERVER_DNS
|
---|
| 787 | sntp_servers[idx].name = NULL;
|
---|
| 788 | #endif
|
---|
| 789 | }
|
---|
| 790 | }
|
---|
| 791 |
|
---|
| 792 | #if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
|
---|
| 793 | /**
|
---|
| 794 | * Initialize one of the NTP servers by IP address, required by DHCP
|
---|
| 795 | *
|
---|
| 796 | * @param num the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
---|
| 797 | * @param server IP address of the NTP server to set
|
---|
| 798 | */
|
---|
| 799 | void
|
---|
| 800 | dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
---|
| 801 | {
|
---|
| 802 | LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
|
---|
| 803 | (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
---|
| 804 | num ? ip4_addr1(server) : 0,
|
---|
| 805 | num ? ip4_addr2(server) : 0,
|
---|
| 806 | num ? ip4_addr3(server) : 0,
|
---|
| 807 | num ? ip4_addr4(server) : 0, num));
|
---|
| 808 | if (sntp_set_servers_from_dhcp && num) {
|
---|
| 809 | u8_t i;
|
---|
| 810 | for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
|
---|
| 811 | ip_addr_t addr;
|
---|
| 812 | ip_addr_copy_from_ip4(addr, server[i]);
|
---|
| 813 | sntp_setserver(i, &addr);
|
---|
| 814 | }
|
---|
| 815 | for (i = num; i < SNTP_MAX_SERVERS; i++) {
|
---|
| 816 | sntp_setserver(i, NULL);
|
---|
| 817 | }
|
---|
| 818 | }
|
---|
| 819 | }
|
---|
| 820 | #endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
|
---|
| 821 |
|
---|
| 822 | /**
|
---|
| 823 | * @ingroup sntp
|
---|
| 824 | * Obtain one of the currently configured by IP address (or DHCP) NTP servers
|
---|
| 825 | *
|
---|
| 826 | * @param idx the index of the NTP server
|
---|
| 827 | * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
|
---|
| 828 | * server has not been configured by address (or at all).
|
---|
| 829 | */
|
---|
| 830 | const ip_addr_t *
|
---|
| 831 | sntp_getserver(u8_t idx)
|
---|
| 832 | {
|
---|
| 833 | if (idx < SNTP_MAX_SERVERS) {
|
---|
| 834 | return &sntp_servers[idx].addr;
|
---|
| 835 | }
|
---|
| 836 | return IP_ADDR_ANY;
|
---|
| 837 | }
|
---|
| 838 |
|
---|
| 839 | #if SNTP_SERVER_DNS
|
---|
| 840 | /**
|
---|
| 841 | * Initialize one of the NTP servers by name
|
---|
| 842 | *
|
---|
| 843 | * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
---|
| 844 | * @param server DNS name of the NTP server to set, to be resolved at contact time
|
---|
| 845 | */
|
---|
| 846 | void
|
---|
| 847 | sntp_setservername(u8_t idx, const char *server)
|
---|
| 848 | {
|
---|
| 849 | LWIP_ASSERT_CORE_LOCKED();
|
---|
| 850 | if (idx < SNTP_MAX_SERVERS) {
|
---|
| 851 | sntp_servers[idx].name = server;
|
---|
| 852 | }
|
---|
| 853 | }
|
---|
| 854 |
|
---|
| 855 | /**
|
---|
| 856 | * Obtain one of the currently configured by name NTP servers.
|
---|
| 857 | *
|
---|
| 858 | * @param idx the index of the NTP server
|
---|
| 859 | * @return IP address of the indexed NTP server or NULL if the NTP
|
---|
| 860 | * server has not been configured by name (or at all)
|
---|
| 861 | */
|
---|
| 862 | const char *
|
---|
| 863 | sntp_getservername(u8_t idx)
|
---|
| 864 | {
|
---|
| 865 | if (idx < SNTP_MAX_SERVERS) {
|
---|
| 866 | return sntp_servers[idx].name;
|
---|
| 867 | }
|
---|
| 868 | return NULL;
|
---|
| 869 | }
|
---|
| 870 | #endif /* SNTP_SERVER_DNS */
|
---|
| 871 |
|
---|
| 872 | #endif /* LWIP_UDP */
|
---|