| 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 | #include "Time.h"
|
|---|
| 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 | u32_t poll;
|
|---|
| 239 | u8_t stratum;
|
|---|
| 240 | };
|
|---|
| 241 | static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
|
|---|
| 242 |
|
|---|
| 243 | #if SNTP_GET_SERVERS_FROM_DHCP
|
|---|
| 244 | static u8_t sntp_set_servers_from_dhcp;
|
|---|
| 245 | #endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
|---|
| 246 | #if SNTP_SUPPORT_MULTIPLE_SERVERS
|
|---|
| 247 | /** The currently used server (initialized to 0) */
|
|---|
| 248 | static u8_t sntp_current_server;
|
|---|
| 249 | #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
|---|
| 250 | #define sntp_current_server 0
|
|---|
| 251 | #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
|---|
| 252 |
|
|---|
| 253 | #if SNTP_RETRY_TIMEOUT_EXP
|
|---|
| 254 | #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
|
|---|
| 255 | /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
|
|---|
| 256 | static u32_t sntp_retry_timeout;
|
|---|
| 257 | #else /* SNTP_RETRY_TIMEOUT_EXP */
|
|---|
| 258 | #define SNTP_RESET_RETRY_TIMEOUT()
|
|---|
| 259 | #define sntp_retry_timeout SNTP_RETRY_TIMEOUT
|
|---|
| 260 | #endif /* SNTP_RETRY_TIMEOUT_EXP */
|
|---|
| 261 |
|
|---|
| 262 | #if SNTP_CHECK_RESPONSE >= 1
|
|---|
| 263 | /** Saves the last server address to compare with response */
|
|---|
| 264 | static ip_addr_t sntp_last_server_address;
|
|---|
| 265 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
|---|
| 266 |
|
|---|
| 267 | #if SNTP_CHECK_RESPONSE >= 2
|
|---|
| 268 | /** Saves the last timestamp sent (which is sent back by the server)
|
|---|
| 269 | * to compare against in response. Stored in network byte order. */
|
|---|
| 270 | static struct sntp_time sntp_last_timestamp_sent;
|
|---|
| 271 | #endif /* SNTP_CHECK_RESPONSE >= 2 */
|
|---|
| 272 |
|
|---|
| 273 | #if defined(LWIP_DEBUG) && !defined(sntp_format_time)
|
|---|
| 274 | /* Debug print helper. */
|
|---|
| 275 | static const char *
|
|---|
| 276 | sntp_format_time(s32_t sec)
|
|---|
| 277 | {
|
|---|
| 278 | time_t ut;
|
|---|
| 279 | ut = (u32_t)((u32_t)sec + DIFF_SEC_1970_2036);
|
|---|
| 280 | return ctime(&ut);
|
|---|
| 281 | }
|
|---|
| 282 | #endif /* LWIP_DEBUG && !sntp_format_time */
|
|---|
| 283 |
|
|---|
| 284 | /**
|
|---|
| 285 | * SNTP processing of received timestamp
|
|---|
| 286 | */
|
|---|
| 287 | static void
|
|---|
| 288 | sntp_process(const struct sntp_timestamps *timestamps)
|
|---|
| 289 | {
|
|---|
| 290 | s32_t sec;
|
|---|
| 291 | u32_t frac;
|
|---|
| 292 |
|
|---|
| 293 | sec = (s32_t)lwip_ntohl(timestamps->xmit.sec);
|
|---|
| 294 | frac = lwip_ntohl(timestamps->xmit.frac);
|
|---|
| 295 |
|
|---|
| 296 | #if SNTP_COMP_ROUNDTRIP
|
|---|
| 297 | # if SNTP_CHECK_RESPONSE >= 2
|
|---|
| 298 | if (timestamps->recv.sec != 0 || timestamps->recv.frac != 0)
|
|---|
| 299 | # endif
|
|---|
| 300 | {
|
|---|
| 301 | s32_t dest_sec;
|
|---|
| 302 | u32_t dest_frac = 0;
|
|---|
| 303 | u32_t step_sec;
|
|---|
| 304 |
|
|---|
| 305 | /* Get the destination time stamp, i.e. the current system time */
|
|---|
| 306 | //SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac);
|
|---|
| 307 | get_system_time_NTP(&dest_sec, &dest_frac);
|
|---|
| 308 | dest_sec -= DIFF_SEC_1970_2036;
|
|---|
| 309 |
|
|---|
| 310 | step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec)
|
|---|
| 311 | : ((u32_t)dest_sec - (u32_t)sec);
|
|---|
| 312 | /* In order to avoid overflows, skip the compensation if the clock step
|
|---|
| 313 | * is larger than about 34 years. */
|
|---|
| 314 | if ((step_sec >> 30) == 0) {
|
|---|
| 315 | s64_t t1, t2, t3, t4;
|
|---|
| 316 |
|
|---|
| 317 | t4 = SNTP_SEC_FRAC_TO_S64(dest_sec, dest_frac);
|
|---|
| 318 | t3 = SNTP_SEC_FRAC_TO_S64(sec, frac);
|
|---|
| 319 | t1 = SNTP_TIMESTAMP_TO_S64(timestamps->orig);
|
|---|
| 320 | t2 = SNTP_TIMESTAMP_TO_S64(timestamps->recv);
|
|---|
| 321 | /* Clock offset calculation according to RFC 4330 */
|
|---|
| 322 | t4 += ((t2 - t1) + (t3 - t4)) / 2;
|
|---|
| 323 |
|
|---|
| 324 | sec = (s32_t)((u64_t)t4 >> 32);
|
|---|
| 325 | frac = (u32_t)((u64_t)t4);
|
|---|
| 326 | }
|
|---|
| 327 | }
|
|---|
| 328 | #endif /* SNTP_COMP_ROUNDTRIP */
|
|---|
| 329 | set_system_time_NTP((u32_t)sec + DIFF_SEC_1970_2036);
|
|---|
| 330 | //SNTP_SET_SYSTEM_TIME_NTP(sec, frac);
|
|---|
| 331 | LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */
|
|---|
| 332 | LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %" U32_F " us\n",
|
|---|
| 333 | sntp_format_time(sec), SNTP_FRAC_TO_US(frac)));
|
|---|
| 334 | }
|
|---|
| 335 |
|
|---|
| 336 | /**
|
|---|
| 337 | * Initialize request struct to be sent to server.
|
|---|
| 338 | */
|
|---|
| 339 | static void
|
|---|
| 340 | sntp_initialize_request(struct sntp_msg *req)
|
|---|
| 341 | {
|
|---|
| 342 | memset(req, 0, SNTP_MSG_LEN);
|
|---|
| 343 | req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
|
|---|
| 344 |
|
|---|
| 345 | #if SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP
|
|---|
| 346 | {
|
|---|
| 347 | s32_t secs;
|
|---|
| 348 | u32_t sec, frac = 0;
|
|---|
| 349 | /* Get the transmit timestamp */
|
|---|
| 350 | //SNTP_GET_SYSTEM_TIME_NTP(secs, frac);
|
|---|
| 351 | get_system_time_NTP(&secs, &frac);
|
|---|
| 352 | secs -= DIFF_SEC_1970_2036;
|
|---|
| 353 |
|
|---|
| 354 | sec = lwip_htonl((u32_t)secs);
|
|---|
| 355 | frac = lwip_htonl(frac);
|
|---|
| 356 |
|
|---|
| 357 | req->reference_timestamp[0] = sntp_last_timestamp_sent.sec;
|
|---|
| 358 | req->reference_timestamp[1] = sntp_last_timestamp_sent.frac;
|
|---|
| 359 |
|
|---|
| 360 | req->originate_timestamp[0] = sec;
|
|---|
| 361 | req->originate_timestamp[1] = frac;
|
|---|
| 362 |
|
|---|
| 363 | # if SNTP_CHECK_RESPONSE >= 2
|
|---|
| 364 | sntp_last_timestamp_sent.sec = sec;
|
|---|
| 365 | sntp_last_timestamp_sent.frac = frac;
|
|---|
| 366 | # endif
|
|---|
| 367 | req->transmit_timestamp[0] = sec;
|
|---|
| 368 | req->transmit_timestamp[1] = frac;
|
|---|
| 369 | }
|
|---|
| 370 | #endif /* SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP */
|
|---|
| 371 | }
|
|---|
| 372 |
|
|---|
| 373 | /**
|
|---|
| 374 | * Retry: send a new request (and increase retry timeout).
|
|---|
| 375 | *
|
|---|
| 376 | * @param arg is unused (only necessary to conform to sys_timeout)
|
|---|
| 377 | */
|
|---|
| 378 | static void
|
|---|
| 379 | sntp_retry(void *arg)
|
|---|
| 380 | {
|
|---|
| 381 | LWIP_UNUSED_ARG(arg);
|
|---|
| 382 |
|
|---|
| 383 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
|
|---|
| 384 | sntp_retry_timeout));
|
|---|
| 385 |
|
|---|
| 386 | /* set up a timer to send a retry and increase the retry delay */
|
|---|
| 387 | sys_timeout(sntp_retry_timeout, sntp_request, NULL);
|
|---|
| 388 |
|
|---|
| 389 | #if SNTP_RETRY_TIMEOUT_EXP
|
|---|
| 390 | {
|
|---|
| 391 | u32_t new_retry_timeout;
|
|---|
| 392 | /* increase the timeout for next retry */
|
|---|
| 393 | new_retry_timeout = sntp_retry_timeout << 1;
|
|---|
| 394 | /* limit to maximum timeout and prevent overflow */
|
|---|
| 395 | if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
|
|---|
| 396 | (new_retry_timeout > sntp_retry_timeout)) {
|
|---|
| 397 | sntp_retry_timeout = new_retry_timeout;
|
|---|
| 398 | }
|
|---|
| 399 | }
|
|---|
| 400 | #endif /* SNTP_RETRY_TIMEOUT_EXP */
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | #if SNTP_SUPPORT_MULTIPLE_SERVERS
|
|---|
| 404 | /**
|
|---|
| 405 | * If Kiss-of-Death is received (or another packet parsing error),
|
|---|
| 406 | * try the next server or retry the current server and increase the retry
|
|---|
| 407 | * timeout if only one server is available.
|
|---|
| 408 | * (implicitly, SNTP_MAX_SERVERS > 1)
|
|---|
| 409 | *
|
|---|
| 410 | * @param arg is unused (only necessary to conform to sys_timeout)
|
|---|
| 411 | */
|
|---|
| 412 | static void
|
|---|
| 413 | sntp_try_next_server(void *arg)
|
|---|
| 414 | {
|
|---|
| 415 | u8_t old_server, i;
|
|---|
| 416 | LWIP_UNUSED_ARG(arg);
|
|---|
| 417 |
|
|---|
| 418 | old_server = sntp_current_server;
|
|---|
| 419 | for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
|
|---|
| 420 | sntp_current_server++;
|
|---|
| 421 | if (sntp_current_server >= SNTP_MAX_SERVERS) {
|
|---|
| 422 | sntp_current_server = 0;
|
|---|
| 423 | }
|
|---|
| 424 | if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
|
|---|
| 425 | #if SNTP_SERVER_DNS
|
|---|
| 426 | || (sntp_servers[sntp_current_server].name != NULL)
|
|---|
| 427 | #endif
|
|---|
| 428 | ) {
|
|---|
| 429 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
|
|---|
| 430 | (u16_t)sntp_current_server));
|
|---|
| 431 | /* new server: reset retry timeout */
|
|---|
| 432 | SNTP_RESET_RETRY_TIMEOUT();
|
|---|
| 433 | /* instantly send a request to the next server */
|
|---|
| 434 | sntp_request(NULL);
|
|---|
| 435 | return;
|
|---|
| 436 | }
|
|---|
| 437 | }
|
|---|
| 438 | /* no other valid server found */
|
|---|
| 439 | sntp_current_server = old_server;
|
|---|
| 440 | sntp_retry(NULL);
|
|---|
| 441 | }
|
|---|
| 442 | #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
|---|
| 443 | /* Always retry on error if only one server is supported */
|
|---|
| 444 | #define sntp_try_next_server sntp_retry
|
|---|
| 445 | #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
|---|
| 446 |
|
|---|
| 447 | /** UDP recv callback for the sntp pcb */
|
|---|
| 448 | static void
|
|---|
| 449 | sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
|---|
| 450 | {
|
|---|
| 451 | struct sntp_timestamps timestamps;
|
|---|
| 452 | u8_t mode;
|
|---|
| 453 | u8_t stratum;
|
|---|
| 454 | err_t err;
|
|---|
| 455 |
|
|---|
| 456 | LWIP_UNUSED_ARG(arg);
|
|---|
| 457 | LWIP_UNUSED_ARG(pcb);
|
|---|
| 458 |
|
|---|
| 459 | err = ERR_ARG;
|
|---|
| 460 | #if SNTP_CHECK_RESPONSE >= 1
|
|---|
| 461 | /* check server address and port */
|
|---|
| 462 | if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
|
|---|
| 463 | (port == SNTP_PORT))
|
|---|
| 464 | #else /* SNTP_CHECK_RESPONSE >= 1 */
|
|---|
| 465 | LWIP_UNUSED_ARG(addr);
|
|---|
| 466 | LWIP_UNUSED_ARG(port);
|
|---|
| 467 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
|---|
| 468 | {
|
|---|
| 469 | /* process the response */
|
|---|
| 470 | if (p->tot_len == SNTP_MSG_LEN) {
|
|---|
| 471 | mode = pbuf_get_at(p, SNTP_OFFSET_LI_VN_MODE) & SNTP_MODE_MASK;
|
|---|
| 472 | /* if this is a SNTP response... */
|
|---|
| 473 | if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
|
|---|
| 474 | ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
|
|---|
| 475 | stratum = pbuf_get_at(p, SNTP_OFFSET_STRATUM);
|
|---|
| 476 |
|
|---|
| 477 | if (stratum == SNTP_STRATUM_KOD) {
|
|---|
| 478 | /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
|---|
| 479 | err = SNTP_ERR_KOD;
|
|---|
| 480 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
|
|---|
| 481 | } else {
|
|---|
| 482 | pbuf_copy_partial(p, ×tamps, sizeof(timestamps), SNTP_OFFSET_TIMESTAMPS);
|
|---|
| 483 | #if SNTP_CHECK_RESPONSE >= 2
|
|---|
| 484 | /* check originate_timetamp against sntp_last_timestamp_sent */
|
|---|
| 485 | if (timestamps.orig.sec != sntp_last_timestamp_sent.sec ||
|
|---|
| 486 | timestamps.orig.frac != sntp_last_timestamp_sent.frac) {
|
|---|
| 487 | LWIP_DEBUGF(SNTP_DEBUG_WARN,
|
|---|
| 488 | ("sntp_recv: Invalid originate timestamp in response\n"));
|
|---|
| 489 | } else
|
|---|
| 490 | #endif /* SNTP_CHECK_RESPONSE >= 2 */
|
|---|
| 491 | /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
|
|---|
| 492 | {
|
|---|
| 493 | /* correct answer */
|
|---|
| 494 | err = ERR_OK;
|
|---|
| 495 | }
|
|---|
| 496 | }
|
|---|
| 497 | } else {
|
|---|
| 498 | LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
|
|---|
| 499 | /* wait for correct response */
|
|---|
| 500 | err = ERR_TIMEOUT;
|
|---|
| 501 | }
|
|---|
| 502 | } else {
|
|---|
| 503 | LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
|
|---|
| 504 | }
|
|---|
| 505 | }
|
|---|
| 506 | #if SNTP_CHECK_RESPONSE >= 1
|
|---|
| 507 | else {
|
|---|
| 508 | /* packet from wrong remote address or port, wait for correct response */
|
|---|
| 509 | err = ERR_TIMEOUT;
|
|---|
| 510 | }
|
|---|
| 511 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
|---|
| 512 |
|
|---|
| 513 | pbuf_free(p);
|
|---|
| 514 |
|
|---|
| 515 | if (err == ERR_OK) {
|
|---|
| 516 | /* correct packet received: process it it */
|
|---|
| 517 | sntp_servers[sntp_current_server].stratum = stratum;
|
|---|
| 518 | sntp_process(×tamps);
|
|---|
| 519 |
|
|---|
| 520 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
|---|
| 521 | /* indicate that server responded */
|
|---|
| 522 | sntp_servers[sntp_current_server].reachability |= 1;
|
|---|
| 523 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
|---|
| 524 | /* Set up timeout for next request (only if poll response was received)*/
|
|---|
| 525 | if (sntp_opmode == SNTP_OPMODE_POLL) {
|
|---|
| 526 | sys_untimeout(sntp_try_next_server, NULL);
|
|---|
| 527 | sys_untimeout(sntp_request, NULL);
|
|---|
| 528 | u32_t sntp_update_delay;
|
|---|
| 529 | /* Correct response, reset retry timeout */
|
|---|
| 530 | SNTP_RESET_RETRY_TIMEOUT();
|
|---|
| 531 |
|
|---|
| 532 | if(sntp_servers[sntp_current_server].reachability == 255) sntp_servers[sntp_current_server].poll = 1024000;
|
|---|
| 533 | else sntp_servers[sntp_current_server].poll = 64000;
|
|---|
| 534 |
|
|---|
| 535 | sntp_update_delay = sntp_servers[sntp_current_server].poll;
|
|---|
| 536 |
|
|---|
| 537 | sys_timeout(sntp_update_delay, sntp_request, NULL);
|
|---|
| 538 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
|
|---|
| 539 | sntp_update_delay));
|
|---|
| 540 | }
|
|---|
| 541 | } else if (err == SNTP_ERR_KOD) {
|
|---|
| 542 | /* KOD errors are only processed in case of an explicit poll response */
|
|---|
| 543 | if (sntp_opmode == SNTP_OPMODE_POLL) {
|
|---|
| 544 | /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
|---|
| 545 | sys_untimeout(sntp_request, NULL); /*исправление 11.08.2021*/
|
|---|
| 546 | sntp_try_next_server(NULL);
|
|---|
| 547 | }
|
|---|
| 548 | } else {
|
|---|
| 549 | /* ignore any broken packet, poll mode: retry after timeout to avoid flooding */
|
|---|
| 550 | }
|
|---|
| 551 | }
|
|---|
| 552 |
|
|---|
| 553 | /** Actually send an sntp request to a server.
|
|---|
| 554 | *
|
|---|
| 555 | * @param server_addr resolved IP address of the SNTP server
|
|---|
| 556 | */
|
|---|
| 557 | static void
|
|---|
| 558 | sntp_send_request(const ip_addr_t *server_addr)
|
|---|
| 559 | {
|
|---|
| 560 | struct pbuf *p;
|
|---|
| 561 |
|
|---|
| 562 | LWIP_ASSERT("server_addr != NULL", server_addr != NULL);
|
|---|
| 563 |
|
|---|
| 564 | p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
|---|
| 565 | if (p != NULL) {
|
|---|
| 566 | struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
|
|---|
| 567 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
|
|---|
| 568 | /* initialize request message */
|
|---|
| 569 | sntp_initialize_request(sntpmsg);
|
|---|
| 570 | /* send request */
|
|---|
| 571 | udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
|
|---|
| 572 | /* free the pbuf after sending it */
|
|---|
| 573 | pbuf_free(p);
|
|---|
| 574 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
|---|
| 575 | /* indicate new packet has been sent */
|
|---|
| 576 | sntp_servers[sntp_current_server].reachability <<= 1;
|
|---|
| 577 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
|---|
| 578 | /* set up receive timeout: try next server or retry on timeout */
|
|---|
| 579 | sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
|---|
| 580 | #if SNTP_CHECK_RESPONSE >= 1
|
|---|
| 581 | /* save server address to verify it in sntp_recv */
|
|---|
| 582 | ip_addr_copy(sntp_last_server_address, *server_addr);
|
|---|
| 583 | #endif /* SNTP_CHECK_RESPONSE >= 1 */
|
|---|
| 584 | } else {
|
|---|
| 585 | LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
|
|---|
| 586 | (u32_t)SNTP_RETRY_TIMEOUT));
|
|---|
| 587 | /* out of memory: set up a timer to send a retry */
|
|---|
| 588 | sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
|
|---|
| 589 | }
|
|---|
| 590 | }
|
|---|
| 591 |
|
|---|
| 592 | #if SNTP_SERVER_DNS
|
|---|
| 593 | /**
|
|---|
| 594 | * DNS found callback when using DNS names as server address.
|
|---|
| 595 | */
|
|---|
| 596 | static void
|
|---|
| 597 | sntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg)
|
|---|
| 598 | {
|
|---|
| 599 | LWIP_UNUSED_ARG(hostname);
|
|---|
| 600 | LWIP_UNUSED_ARG(arg);
|
|---|
| 601 |
|
|---|
| 602 | if (ipaddr != NULL) {
|
|---|
| 603 | /* Address resolved, send request */
|
|---|
| 604 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
|
|---|
| 605 | sntp_servers[sntp_current_server].addr = *ipaddr;
|
|---|
| 606 | sntp_send_request(ipaddr);
|
|---|
| 607 | } else {
|
|---|
| 608 | /* DNS resolving failed -> try another server */
|
|---|
| 609 | LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
|
|---|
| 610 | sntp_try_next_server(NULL);
|
|---|
| 611 | }
|
|---|
| 612 | }
|
|---|
| 613 | #endif /* SNTP_SERVER_DNS */
|
|---|
| 614 |
|
|---|
| 615 | /**
|
|---|
| 616 | * Send out an sntp request.
|
|---|
| 617 | *
|
|---|
| 618 | * @param arg is unused (only necessary to conform to sys_timeout)
|
|---|
| 619 | */
|
|---|
| 620 | static void
|
|---|
| 621 | sntp_request(void *arg)
|
|---|
| 622 | {
|
|---|
| 623 | ip_addr_t sntp_server_address;
|
|---|
| 624 | err_t err;
|
|---|
| 625 |
|
|---|
| 626 | LWIP_UNUSED_ARG(arg);
|
|---|
| 627 |
|
|---|
| 628 | /* initialize SNTP server address */
|
|---|
| 629 | #if SNTP_SERVER_DNS
|
|---|
| 630 | if (sntp_servers[sntp_current_server].name) {
|
|---|
| 631 | /* always resolve the name and rely on dns-internal caching & timeout */
|
|---|
| 632 | ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
|
|---|
| 633 | err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
|
|---|
| 634 | sntp_dns_found, NULL);
|
|---|
| 635 | if (err == ERR_INPROGRESS) {
|
|---|
| 636 | /* DNS request sent, wait for sntp_dns_found being called */
|
|---|
| 637 | LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
|
|---|
| 638 | return;
|
|---|
| 639 | } else if (err == ERR_OK) {
|
|---|
| 640 | sntp_servers[sntp_current_server].addr = sntp_server_address;
|
|---|
| 641 | }
|
|---|
| 642 | } else
|
|---|
| 643 | #endif /* SNTP_SERVER_DNS */
|
|---|
| 644 | {
|
|---|
| 645 | sntp_server_address = sntp_servers[sntp_current_server].addr;
|
|---|
| 646 | err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
|
|---|
| 647 | }
|
|---|
| 648 |
|
|---|
| 649 | if (err == ERR_OK) {
|
|---|
| 650 | LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
|
|---|
| 651 | ipaddr_ntoa(&sntp_server_address)));
|
|---|
| 652 | sntp_send_request(&sntp_server_address);
|
|---|
| 653 | } else {
|
|---|
| 654 | /* address conversion failed, try another server */
|
|---|
| 655 | LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
|
|---|
| 656 | sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
|
|---|
| 657 | }
|
|---|
| 658 | }
|
|---|
| 659 |
|
|---|
| 660 | /**
|
|---|
| 661 | * @ingroup sntp
|
|---|
| 662 | * Initialize this module.
|
|---|
| 663 | * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
|
|---|
| 664 | */
|
|---|
| 665 | void
|
|---|
| 666 | sntp_init(void)
|
|---|
| 667 | {
|
|---|
| 668 | /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
|
|---|
| 669 |
|
|---|
| 670 | #ifdef SNTP_SERVER_ADDRESS
|
|---|
| 671 | #if SNTP_SERVER_DNS
|
|---|
| 672 | sntp_setservername(0, SNTP_SERVER_ADDRESS);
|
|---|
| 673 | #else
|
|---|
| 674 | #error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
|
|---|
| 675 | #endif
|
|---|
| 676 | #endif /* SNTP_SERVER_ADDRESS */
|
|---|
| 677 |
|
|---|
| 678 | if (sntp_pcb == NULL) {
|
|---|
| 679 | sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
|---|
| 680 | LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
|
|---|
| 681 | if (sntp_pcb != NULL) {
|
|---|
| 682 | udp_recv(sntp_pcb, sntp_recv, NULL);
|
|---|
| 683 |
|
|---|
| 684 | if (sntp_opmode == SNTP_OPMODE_POLL) {
|
|---|
| 685 | SNTP_RESET_RETRY_TIMEOUT();
|
|---|
| 686 | #if SNTP_STARTUP_DELAY
|
|---|
| 687 | sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
|
|---|
| 688 | #else
|
|---|
| 689 | sntp_request(NULL);
|
|---|
| 690 | #endif
|
|---|
| 691 | } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
|
|---|
| 692 | ip_set_option(sntp_pcb, SOF_BROADCAST);
|
|---|
| 693 | udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
|
|---|
| 694 | }
|
|---|
| 695 | }
|
|---|
| 696 | }
|
|---|
| 697 | }
|
|---|
| 698 |
|
|---|
| 699 | /**
|
|---|
| 700 | * @ingroup sntp
|
|---|
| 701 | * Stop this module.
|
|---|
| 702 | */
|
|---|
| 703 | void
|
|---|
| 704 | sntp_stop(void)
|
|---|
| 705 | {
|
|---|
| 706 | LWIP_ASSERT_CORE_LOCKED();
|
|---|
| 707 | if (sntp_pcb != NULL) {
|
|---|
| 708 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
|---|
| 709 | u8_t i;
|
|---|
| 710 | for (i = 0; i < SNTP_MAX_SERVERS; i++) {
|
|---|
| 711 | sntp_servers[i].reachability = 0;
|
|---|
| 712 | }
|
|---|
| 713 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
|---|
| 714 | sys_untimeout(sntp_request, NULL);
|
|---|
| 715 | sys_untimeout(sntp_try_next_server, NULL);
|
|---|
| 716 | udp_remove(sntp_pcb);
|
|---|
| 717 | sntp_pcb = NULL;
|
|---|
| 718 | }
|
|---|
| 719 | }
|
|---|
| 720 |
|
|---|
| 721 | /**
|
|---|
| 722 | * @ingroup sntp
|
|---|
| 723 | * Get enabled state.
|
|---|
| 724 | */
|
|---|
| 725 | u8_t sntp_enabled(void)
|
|---|
| 726 | {
|
|---|
| 727 | return (sntp_pcb != NULL) ? 1 : 0;
|
|---|
| 728 | }
|
|---|
| 729 |
|
|---|
| 730 | /**
|
|---|
| 731 | * @ingroup sntp
|
|---|
| 732 | * Sets the operating mode.
|
|---|
| 733 | * @param operating_mode one of the available operating modes
|
|---|
| 734 | */
|
|---|
| 735 | void
|
|---|
| 736 | sntp_setoperatingmode(u8_t operating_mode)
|
|---|
| 737 | {
|
|---|
| 738 | LWIP_ASSERT_CORE_LOCKED();
|
|---|
| 739 | LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
|
|---|
| 740 | LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
|
|---|
| 741 | sntp_opmode = operating_mode;
|
|---|
| 742 | }
|
|---|
| 743 |
|
|---|
| 744 | /**
|
|---|
| 745 | * @ingroup sntp
|
|---|
| 746 | * Gets the operating mode.
|
|---|
| 747 | */
|
|---|
| 748 | u8_t
|
|---|
| 749 | sntp_getoperatingmode(void)
|
|---|
| 750 | {
|
|---|
| 751 | return sntp_opmode;
|
|---|
| 752 | }
|
|---|
| 753 |
|
|---|
| 754 | #if SNTP_MONITOR_SERVER_REACHABILITY
|
|---|
| 755 | /**
|
|---|
| 756 | * @ingroup sntp
|
|---|
| 757 | * Gets the server reachability shift register as described in RFC 5905.
|
|---|
| 758 | *
|
|---|
| 759 | * @param idx the index of the NTP server
|
|---|
| 760 | */
|
|---|
| 761 | u8_t
|
|---|
| 762 | sntp_getreachability(u8_t idx)
|
|---|
| 763 | {
|
|---|
| 764 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 765 | return sntp_servers[idx].reachability;
|
|---|
| 766 | }
|
|---|
| 767 | return 0;
|
|---|
| 768 | }
|
|---|
| 769 | #endif /* SNTP_MONITOR_SERVER_REACHABILITY */
|
|---|
| 770 |
|
|---|
| 771 | u32_t sntp_getpool(u8_t idx)
|
|---|
| 772 | {
|
|---|
| 773 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 774 | return sntp_servers[idx].poll;
|
|---|
| 775 | }
|
|---|
| 776 | return 0;
|
|---|
| 777 | }
|
|---|
| 778 |
|
|---|
| 779 | u8_t sntp_getstratum(u8_t idx)
|
|---|
| 780 | {
|
|---|
| 781 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 782 | return sntp_servers[idx].stratum;
|
|---|
| 783 | }
|
|---|
| 784 | return 0;
|
|---|
| 785 | }
|
|---|
| 786 |
|
|---|
| 787 | #if SNTP_GET_SERVERS_FROM_DHCP
|
|---|
| 788 | /**
|
|---|
| 789 | * Config SNTP server handling by IP address, name, or DHCP; clear table
|
|---|
| 790 | * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
|
|---|
| 791 | */
|
|---|
| 792 | void
|
|---|
| 793 | sntp_servermode_dhcp(int set_servers_from_dhcp)
|
|---|
| 794 | {
|
|---|
| 795 | u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
|
|---|
| 796 | LWIP_ASSERT_CORE_LOCKED();
|
|---|
| 797 | if (sntp_set_servers_from_dhcp != new_mode) {
|
|---|
| 798 | sntp_set_servers_from_dhcp = new_mode;
|
|---|
| 799 | }
|
|---|
| 800 | }
|
|---|
| 801 | #endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
|---|
| 802 |
|
|---|
| 803 | /**
|
|---|
| 804 | * @ingroup sntp
|
|---|
| 805 | * Initialize one of the NTP servers by IP address
|
|---|
| 806 | *
|
|---|
| 807 | * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
|---|
| 808 | * @param server IP address of the NTP server to set
|
|---|
| 809 | */
|
|---|
| 810 | void
|
|---|
| 811 | sntp_setserver(u8_t idx, const ip_addr_t *server)
|
|---|
| 812 | {
|
|---|
| 813 | LWIP_ASSERT_CORE_LOCKED();
|
|---|
| 814 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 815 | if (server != NULL) {
|
|---|
| 816 | sntp_servers[idx].addr = (*server);
|
|---|
| 817 | sntp_servers[idx].poll = (u32_t)SNTP_UPDATE_DELAY;
|
|---|
| 818 | sntp_servers[idx].stratum = 0;
|
|---|
| 819 | sntp_servers[idx].reachability = 0;
|
|---|
| 820 | } else {
|
|---|
| 821 | ip_addr_set_zero(&sntp_servers[idx].addr);
|
|---|
| 822 | }
|
|---|
| 823 | #if SNTP_SERVER_DNS
|
|---|
| 824 | sntp_servers[idx].name = NULL;
|
|---|
| 825 | #endif
|
|---|
| 826 | }
|
|---|
| 827 | }
|
|---|
| 828 |
|
|---|
| 829 | #if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
|
|---|
| 830 | /**
|
|---|
| 831 | * Initialize one of the NTP servers by IP address, required by DHCP
|
|---|
| 832 | *
|
|---|
| 833 | * @param num the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
|---|
| 834 | * @param server IP address of the NTP server to set
|
|---|
| 835 | */
|
|---|
| 836 | void
|
|---|
| 837 | dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
|---|
| 838 | {
|
|---|
| 839 | LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
|
|---|
| 840 | (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
|---|
| 841 | ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
|
|---|
| 842 | if (sntp_set_servers_from_dhcp && num) {
|
|---|
| 843 | u8_t i;
|
|---|
| 844 | for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
|
|---|
| 845 | ip_addr_t addr;
|
|---|
| 846 | ip_addr_copy_from_ip4(addr, server[i]);
|
|---|
| 847 | sntp_setserver(i, &addr);
|
|---|
| 848 | }
|
|---|
| 849 | for (i = num; i < SNTP_MAX_SERVERS; i++) {
|
|---|
| 850 | sntp_setserver(i, NULL);
|
|---|
| 851 | }
|
|---|
| 852 | }
|
|---|
| 853 | }
|
|---|
| 854 | #endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
|
|---|
| 855 |
|
|---|
| 856 | /**
|
|---|
| 857 | * @ingroup sntp
|
|---|
| 858 | * Obtain one of the currently configured by IP address (or DHCP) NTP servers
|
|---|
| 859 | *
|
|---|
| 860 | * @param idx the index of the NTP server
|
|---|
| 861 | * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
|
|---|
| 862 | * server has not been configured by address (or at all).
|
|---|
| 863 | */
|
|---|
| 864 | const ip_addr_t *
|
|---|
| 865 | sntp_getserver(u8_t idx)
|
|---|
| 866 | {
|
|---|
| 867 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 868 | return &sntp_servers[idx].addr;
|
|---|
| 869 | }
|
|---|
| 870 | return IP_ADDR_ANY;
|
|---|
| 871 | }
|
|---|
| 872 |
|
|---|
| 873 | #if SNTP_SERVER_DNS
|
|---|
| 874 | /**
|
|---|
| 875 | * Initialize one of the NTP servers by name
|
|---|
| 876 | *
|
|---|
| 877 | * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
|---|
| 878 | * @param server DNS name of the NTP server to set, to be resolved at contact time
|
|---|
| 879 | */
|
|---|
| 880 | void
|
|---|
| 881 | sntp_setservername(u8_t idx, const char *server)
|
|---|
| 882 | {
|
|---|
| 883 | LWIP_ASSERT_CORE_LOCKED();
|
|---|
| 884 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 885 | sntp_servers[idx].name = server;
|
|---|
| 886 | }
|
|---|
| 887 | }
|
|---|
| 888 |
|
|---|
| 889 | /**
|
|---|
| 890 | * Obtain one of the currently configured by name NTP servers.
|
|---|
| 891 | *
|
|---|
| 892 | * @param idx the index of the NTP server
|
|---|
| 893 | * @return IP address of the indexed NTP server or NULL if the NTP
|
|---|
| 894 | * server has not been configured by name (or at all)
|
|---|
| 895 | */
|
|---|
| 896 | const char *
|
|---|
| 897 | sntp_getservername(u8_t idx)
|
|---|
| 898 | {
|
|---|
| 899 | if (idx < SNTP_MAX_SERVERS) {
|
|---|
| 900 | return sntp_servers[idx].name;
|
|---|
| 901 | }
|
|---|
| 902 | return NULL;
|
|---|
| 903 | }
|
|---|
| 904 | #endif /* SNTP_SERVER_DNS */
|
|---|
| 905 |
|
|---|
| 906 | #endif /* LWIP_UDP */
|
|---|