feat(sntp): 板端 SNTP 校时接入——coreSNTP 序列化器 + [sntp] 段 + 设置页(#73)
- vendored coreSNTP v2.0.0 序列化器(MIT,仅 serializer+LICENSE,零堆), 48 字节报文编解码在库,节奏与准入判据在本方(RFC 4330 §10 调研口径) - App/sync/time_sntp.c 挂 timeSyncTask 的 8888 事件循环,等待切片 ≤50 ms, 不饿任务狗与 IWDG;懒建 UDP socket,代际变化/禁用/死错误码即关闭归还 - 防伪 = OriginTimestamp 逐位等于发出时 T1(含低 16 位随机小数位); mode/stratum/闰秒指示/KoD 按 RFC 拒收;DENY·RSTR 换服务器、RATE 只退避 - 主备轮换 + 失败指数退避(5 s 起、60 s 封顶)+ 首轮 1~5 分钟随机错峰; 成功恢复 poll_min 周期(1~1440 分,出厂默认 60,默认不启用不发包) - 钟面 = 本地时间:UTC+8 固定偏移落 sys_clock_set_unix(§1.1 时基裁定, 第三个写入口,装置仍不存时区);|offset|<2 s 只记日志不步进,冷启动或 更大偏差步进并回写 SD2506,留痕 [SNTP] step 与 syslog OPER - 首个校验通过的同步置 SYS_EVT_TIMESYNC_READY(就绪位,消费方按需 NoClear) - [sntp] 配置段(enable/server1/server2/poll_min)属主 sntp_cfg.c, 注册在 net_cfg_load();UI 页 31「SNTP 设置」(密码叶):启用开关 + 主/备服务器 octet 编辑 + 周期(分) + 保存,复用 net_cfg_save_request 链 - 测试与门禁:test/host/sntp 新套件(报文/防伪/KoD/退避周期/阶跃域/配置 注册表)、net_cfg 与 time_sync 套件补 fake、黄金参考 66→74 张零漂移、 字符集 228 字、Keil 0 错 0 警(RO +5,848 B 含字体)、覆盖率基线回填 - 文档:墙钟维护说明 §16、网络配置说明 [sntp] 节、配置文件设计说明变更记录、 产品需求 FR-TIME-3 与 8.3/9.1.2 台账、UI 补齐规划/UI补齐 31 叶口径、 登记簿销项并登记「SNTP 校时真机判据」等台架(PC 时间源 192.168.31.161/.13)
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,845 @@
|
||||
/*
|
||||
* coreSNTP
|
||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core_sntp_serializer.c
|
||||
* @brief Implementation of the Serializer API of the coreSNTP library.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* Include API header. */
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
#include "core_sntp_config_defaults.h"
|
||||
|
||||
/**
|
||||
* @brief The version of SNTP supported by the coreSNTP library by complying
|
||||
* with the SNTPv4 specification defined in [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
*/
|
||||
#define SNTP_VERSION ( 4U )
|
||||
|
||||
/**
|
||||
* @brief The bit mask for the "Mode" information in the first byte of an SNTP packet.
|
||||
* The "Mode" field occupies bits 0-2 of the byte.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_MODE_BITS_MASK ( 0x07U )
|
||||
|
||||
/**
|
||||
* @brief The value indicating a "client" in the "Mode" field of an SNTP packet.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_MODE_CLIENT ( 3U )
|
||||
|
||||
/**
|
||||
* @brief The value indicating a "server" in the "Mode" field of an SNTP packet.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_MODE_SERVER ( 4U )
|
||||
|
||||
/**
|
||||
* @brief The position of the least significant bit of the "Leap Indicator" field
|
||||
* in first byte of an SNTP packet. The "Leap Indicator" field occupies bits 6-7 of the byte.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_LEAP_INDICATOR_LSB_POSITION ( 6 )
|
||||
|
||||
/**
|
||||
* @brief Value of Stratum field in SNTP packet representing a Kiss-o'-Death message
|
||||
* from server.
|
||||
*/
|
||||
#define SNTP_KISS_OF_DEATH_STRATUM ( 0U )
|
||||
|
||||
/**
|
||||
* @brief The position of least significant bit of the "Version" information
|
||||
* in the first byte of an SNTP packet. "Version" field occupies bits 3-5 of
|
||||
* the byte.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_VERSION_LSB_POSITION ( 3 )
|
||||
|
||||
/**
|
||||
* @brief The integer value of the Kiss-o'-Death ASCII code, "DENY", used
|
||||
* for comparison with data in an SNTP response.
|
||||
* @note Refer to [RFC 4330 Section 8](https://tools.ietf.org/html/rfc4330#section-8)
|
||||
* for more information.
|
||||
*/
|
||||
#define KOD_CODE_DENY_UINT_VALUE ( 0x44454e59U )
|
||||
|
||||
/**
|
||||
* @brief The integer value of the Kiss-o'-Death ASCII code, "RSTR", used
|
||||
* for comparison with data in an SNTP response.
|
||||
* @note Refer to [RFC 4330 Section 8](https://tools.ietf.org/html/rfc4330#section-8)
|
||||
* for more information.
|
||||
*/
|
||||
#define KOD_CODE_RSTR_UINT_VALUE ( 0x52535452U )
|
||||
|
||||
/**
|
||||
* @brief The integer value of the Kiss-o'-Death ASCII code, "RATE", used
|
||||
* for comparison with data in an SNTP response.
|
||||
* @note Refer to [RFC 4330 Section 8](https://tools.ietf.org/html/rfc4330#section-8)
|
||||
* for more information.
|
||||
*/
|
||||
#define KOD_CODE_RATE_UINT_VALUE ( 0x52415445U )
|
||||
|
||||
/**
|
||||
* @brief Macro to represent exactly half of the total number of seconds in an NTP era.
|
||||
* As 32 bits are used to represent the "seconds" part of an SNTP timestamp, the half of
|
||||
* the total range of seconds in an NTP era is 2^31 seconds, which represents ~68 years.
|
||||
*
|
||||
* @note This macro represents the edge case of calculating the client system clock-offset
|
||||
* relative to server time as the library ASSUMES that the client and server times are within
|
||||
* 2^31 seconds apart in duration. This is done to support calculating clock-offset for the
|
||||
* cases when server and client systems are in adjacent NTP eras, which can occur when NTP time
|
||||
* wraps around in 2036, and the relative NTP era presence of client and server times is
|
||||
* determined based on comparing first order difference values between all possible NTP era
|
||||
* configurations of the systems.
|
||||
*/
|
||||
#define CLOCK_OFFSET_MAX_TIME_DIFFERENCE ( ( ( ( int64_t ) INT32_MAX + 1 ) * 1000 ) )
|
||||
|
||||
/**
|
||||
* @brief Macro to represent the total number of milliseconds that are represented in an
|
||||
* NTP era period. This macro represents a duration of ~136 years.
|
||||
*
|
||||
* @note Rationale for calculation: The "seconds" part of an NTP timestamp is represented in
|
||||
* unsigned 32 bit width, thus, the total range of seconds it represents is 2^32,
|
||||
* i.e. (UINT32_MAX + 1).
|
||||
*/
|
||||
#define TOTAL_MILLISECONDS_IN_NTP_ERA ( ( ( int64_t ) UINT32_MAX + 1 ) * 1000 )
|
||||
|
||||
/**
|
||||
* @brief Structure representing an SNTP packet header.
|
||||
* For more information on SNTP packet format, refer to
|
||||
* [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4).
|
||||
*
|
||||
* @note This does not include extension fields for authentication data
|
||||
* for secure SNTP communication. Authentication data follows the
|
||||
* packet header represented by this structure.
|
||||
*/
|
||||
typedef struct SntpPacket
|
||||
{
|
||||
/**
|
||||
* @brief Bits 6-7 leap indicator, bits 3-5 are version number, bits 0-2 are mode
|
||||
*/
|
||||
uint8_t leapVersionMode;
|
||||
|
||||
/**
|
||||
* @brief stratum
|
||||
*/
|
||||
uint8_t stratum;
|
||||
|
||||
/**
|
||||
* @brief poll interval
|
||||
*/
|
||||
uint8_t poll;
|
||||
|
||||
/**
|
||||
* @brief precision
|
||||
*/
|
||||
uint8_t precision;
|
||||
|
||||
/**
|
||||
* @brief root delay
|
||||
*/
|
||||
uint32_t rootDelay;
|
||||
|
||||
/**
|
||||
* @brief root dispersion
|
||||
*/
|
||||
uint32_t rootDispersion;
|
||||
|
||||
/**
|
||||
* @brief reference ID
|
||||
*/
|
||||
uint32_t refId;
|
||||
|
||||
/**
|
||||
* @brief reference time
|
||||
*/
|
||||
SntpTimestamp_t refTime;
|
||||
|
||||
/**
|
||||
* @brief origin timestamp
|
||||
*/
|
||||
SntpTimestamp_t originTime;
|
||||
|
||||
/**
|
||||
* @brief receive timestamp
|
||||
*/
|
||||
SntpTimestamp_t receiveTime;
|
||||
|
||||
/**
|
||||
* @brief transmit timestamp
|
||||
*/
|
||||
SntpTimestamp_t transmitTime;
|
||||
} SntpPacket_t;
|
||||
|
||||
/**
|
||||
* @brief Utility macro to fill 32-bit integer in word-sized
|
||||
* memory in network byte (or Big Endian) order.
|
||||
*
|
||||
* @param[out] pWordMemory Pointer to the word-sized memory in which
|
||||
* the 32-bit integer will be filled.
|
||||
* @param[in] data The 32-bit integer to fill in the @p wordMemory
|
||||
* in network byte order.
|
||||
*
|
||||
* @note This utility ensures that data is filled in memory
|
||||
* in expected network byte order, as an assignment operation
|
||||
* (like *pWordMemory = word) can cause undesired side-effect
|
||||
* of network-byte ordering getting reversed on Little Endian platforms.
|
||||
*/
|
||||
static void fillWordMemoryInNetworkOrder( uint32_t * pWordMemory,
|
||||
uint32_t data )
|
||||
{
|
||||
uint8_t * pByteMemory = ( uint8_t * ) pWordMemory;
|
||||
|
||||
assert( pWordMemory != NULL );
|
||||
|
||||
pByteMemory[ 0 ] = ( uint8_t ) ( data >> 24 );
|
||||
pByteMemory[ 1 ] = ( uint8_t ) ( ( data >> 16 ) & 0x000000FFU );
|
||||
pByteMemory[ 2 ] = ( uint8_t ) ( ( data >> 8 ) & 0x000000FFU );
|
||||
pByteMemory[ 3 ] = ( uint8_t ) ( ( data ) & 0x000000FFU );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility macro to generate a 32-bit integer from memory containing
|
||||
* integer in network (or Big Endian) byte order.
|
||||
* @param[in] ptr Pointer to the memory containing 32-bit integer in network
|
||||
* byte order.
|
||||
*
|
||||
* @return The host representation of the 32-bit integer in the passed word
|
||||
* memory.
|
||||
*/
|
||||
static uint32_t readWordFromNetworkByteOrderMemory( const uint32_t * ptr )
|
||||
{
|
||||
const uint8_t * pMemStartByte = ( const uint8_t * ) ptr;
|
||||
|
||||
assert( ptr != NULL );
|
||||
|
||||
return ( uint32_t ) ( ( ( ( uint32_t ) pMemStartByte[ 0 ] ) << 24 ) |
|
||||
( 0x00FF0000U & ( ( ( uint32_t ) pMemStartByte[ 1 ] ) << 16 ) ) |
|
||||
( 0x0000FF00U & ( ( ( uint32_t ) pMemStartByte[ 2 ] ) << 8 ) ) |
|
||||
( ( uint32_t ) pMemStartByte[ 3 ] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to return absolute (or positively signed) value of an signed
|
||||
* 64 bit integer.
|
||||
*
|
||||
* @param[in] value The integer to return the absolute value of.
|
||||
*
|
||||
* @return The absolute value of @p value.
|
||||
*/
|
||||
static int64_t absoluteOf( int64_t value )
|
||||
{
|
||||
return ( value >= 0 ) ? value : ( ( int64_t ) 0 - value );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to determine whether a timestamp represents a zero
|
||||
* timestamp value.
|
||||
*
|
||||
* @note This utility is used to determine whether a timestamp value is
|
||||
* invalid. According to the SNTPv4 specification, a zero timestamp value
|
||||
* is considered invalid.
|
||||
*
|
||||
* @param[in] pTime The timestamp whose value is to be inspected for
|
||||
* zero value.
|
||||
*
|
||||
* @return `true` if the timestamp is zero; otherwise `false`.
|
||||
*/
|
||||
static bool isZeroTimestamp( const SntpTimestamp_t * pTime )
|
||||
{
|
||||
bool isSecondsZero = ( pTime->seconds == 0U ) ? true : false;
|
||||
bool isFractionsZero = ( pTime->fractions == 0U ) ? true : false;
|
||||
|
||||
return( isSecondsZero && isFractionsZero );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to convert the "fractions" part of an SNTP timestamp to milliseconds
|
||||
* duration of time.
|
||||
* @param[in] fractions The fractions value.
|
||||
*
|
||||
* @return The milliseconds equivalent of the @p fractions value.
|
||||
*/
|
||||
static uint32_t fractionsToMs( uint32_t fractions )
|
||||
{
|
||||
return( fractions / ( 1000U * SNTP_FRACTION_VALUE_PER_MICROSECOND ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to safely calculate difference between server and client timestamps and
|
||||
* return the difference in the resolution of milliseconds as a signed 64 bit integer.
|
||||
* The calculated value represents the effective subtraction as ( @p serverTimeSec - @p clientTimeSec ).
|
||||
*
|
||||
* @note This utility SUPPORTS the cases of server and client timestamps being in different NTP eras,
|
||||
* and ASSUMES that the server and client systems are within 68 years of each other.
|
||||
* To handle the case of different NTP eras, this function calculates difference values for all
|
||||
* possible combinations of NTP eras of server and client times (i.e. 1. both timestamps in same era,
|
||||
* 2. server timestamp one era ahead, and 3. client timestamp being one era ahead), and determines
|
||||
* the NTP era configuration by choosing the difference value of the smallest absolute value.
|
||||
*
|
||||
* @param[in] pServerTime The server timestamp.
|
||||
* @param[in] pClientTime The client timestamp.
|
||||
*
|
||||
* @return The calculated difference between server and client times as a signed 64 bit integer.
|
||||
*/
|
||||
static int64_t safeTimeDifference( const SntpTimestamp_t * pServerTime,
|
||||
const SntpTimestamp_t * pClientTime )
|
||||
{
|
||||
int64_t eraAdjustedDiff = 0;
|
||||
|
||||
/* Convert the timestamps into 64 bit signed integer values of milliseconds. */
|
||||
int64_t serverTime = ( ( int64_t ) pServerTime->seconds * 1000 ) + ( int64_t ) fractionsToMs( pServerTime->fractions );
|
||||
int64_t clientTime = ( ( int64_t ) pClientTime->seconds * 1000 ) + ( int64_t ) fractionsToMs( pClientTime->fractions );
|
||||
|
||||
/* The difference between the 2 timestamps is calculated by determining the whether the timestamps
|
||||
* are present in the same NTP era or adjacent NTP eras (i.e. the NTP timestamp overflow case). */
|
||||
|
||||
/* First, calculate the first order time difference assuming that server and client times
|
||||
* are in the same NTP era. */
|
||||
int64_t diffWithNoEraAdjustment = serverTime - clientTime;
|
||||
|
||||
/* Store the absolute value of the time difference which will be used for comparison with
|
||||
* different cases of relative NTP era configuration of client and server times. */
|
||||
int64_t absSameEraDiff = absoluteOf( diffWithNoEraAdjustment );
|
||||
|
||||
/* If the absolute difference value is 2^31 seconds, it means that the server and client times are
|
||||
* away by exactly half the range of SNTP timestamp "second" values representable in unsigned 32 bits.
|
||||
* In such a case, irrespective of whether the 2 systems exist in the same or adjacent NTP eras, the
|
||||
* time difference calculated between the systems will ALWAYS yield the same value when viewed from
|
||||
* all NTP era configurations of the times.
|
||||
* For such a case, we will ASSUME that the server time is AHEAD of client time, and thus, generate
|
||||
* a positive clock-offset value.
|
||||
*/
|
||||
if( absSameEraDiff == CLOCK_OFFSET_MAX_TIME_DIFFERENCE )
|
||||
{
|
||||
/* It does not matter whether server and client are in the same era for this
|
||||
* special case as the difference value for both same and adjacent eras will yield
|
||||
* the same absolute value of 2^31.*/
|
||||
eraAdjustedDiff = CLOCK_OFFSET_MAX_TIME_DIFFERENCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Determine if server time belongs to an NTP era different than the client time, and accordingly
|
||||
* choose the 64 bit representation of the first order difference to account for the era.
|
||||
* The logic for determining the relative era presence of the timestamps is by calculating the
|
||||
* first order difference (of "Server Time - Client Time") for all the 3 different era combinations
|
||||
* (1. both timestamps in same era, 2. server time one era ahead, 3. client time one era ahead)
|
||||
* and choosing the NTP era configuration that has the smallest first order difference value.
|
||||
*/
|
||||
int64_t diffWithServerEraAdjustment = serverTime + TOTAL_MILLISECONDS_IN_NTP_ERA -
|
||||
clientTime; /* This helps determine whether server is an
|
||||
* era ahead of client time. */
|
||||
int64_t diffWithClientEraAdjustment = serverTime -
|
||||
( TOTAL_MILLISECONDS_IN_NTP_ERA + clientTime ); /* This helps determine whether server is an
|
||||
* era behind of client time. */
|
||||
|
||||
/* Store the absolute value equivalents of all the time difference configurations
|
||||
* for easier comparison to smallest value from them. */
|
||||
int64_t absServerEraAheadDiff = absoluteOf( diffWithServerEraAdjustment );
|
||||
int64_t absClientEraAheadDiff = absoluteOf( diffWithClientEraAdjustment );
|
||||
|
||||
/* Determine the correct relative era of client and server times by checking which era
|
||||
* configuration of difference value represents the least difference. */
|
||||
if( ( absSameEraDiff <= absServerEraAheadDiff ) && ( absSameEraDiff <= absClientEraAheadDiff ) )
|
||||
{
|
||||
/* Both server and client times are in the same era. */
|
||||
eraAdjustedDiff = diffWithNoEraAdjustment;
|
||||
}
|
||||
/* Check if server time is an NTP era ahead of client time. */
|
||||
else if( absServerEraAheadDiff < absSameEraDiff )
|
||||
{
|
||||
/* Server time is in NTP era 1 while client time is in NTP era 0. */
|
||||
eraAdjustedDiff = diffWithServerEraAdjustment;
|
||||
}
|
||||
/* Now, we know that the client time is an era ahead of server time. */
|
||||
else
|
||||
{
|
||||
/* Server time is in NTP era 0 while client time is in NTP era 1. */
|
||||
eraAdjustedDiff = diffWithClientEraAdjustment;
|
||||
}
|
||||
}
|
||||
|
||||
return eraAdjustedDiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to calculate clock offset of system relative to the
|
||||
* server using the on-wire protocol specified in the NTPv4 specification.
|
||||
* For more information on on-wire protocol, refer to
|
||||
* [RFC 5905 Section 8](https://tools.ietf.org/html/rfc5905#section-8).
|
||||
*
|
||||
* @note The following diagram explains the calculation of the clock
|
||||
* offset:
|
||||
*
|
||||
* T2 T3
|
||||
* --------------------------------- <----- *SNTP/NTP server*
|
||||
* /\ \
|
||||
* / \
|
||||
* Request* / \ *Response*
|
||||
* / \/
|
||||
* --------------------------------- <----- *SNTP client*
|
||||
* T1 T4
|
||||
*
|
||||
* The four most recent timestamps, T1 through T4, are used to compute
|
||||
* the clock offset of SNTP client relative to the server where:
|
||||
*
|
||||
* T1 = Client Request Transmit Time
|
||||
* T2 = Server Receive Time (of client request)
|
||||
* T3 = Server Response Transmit Time
|
||||
* T4 = Client Receive Time (of server response)
|
||||
*
|
||||
* Clock Offset = T(NTP/SNTP server) - T(SNTP client)
|
||||
* = [( T2 - T1 ) + ( T3 - T4 )]
|
||||
* ---------------------------
|
||||
* 2
|
||||
*
|
||||
* @note Both NTPv4 and SNTPv4 specifications suggest calculating the
|
||||
* clock offset value, if possible. As the timestamp format uses 64 bit
|
||||
* integer and there exist 2 orders of arithmetic calculations on the
|
||||
* timestamp values (subtraction followed by addition as shown in the
|
||||
* diagram above), the clock offset for the system can be calculated
|
||||
* ONLY if the value can be represented in 62 significant bits and 2 sign
|
||||
* bits i.e. if the system clock is within 34 years (in the future or past)
|
||||
* of the server time.
|
||||
*
|
||||
* @param[in] pClientTxTime The system time of sending the SNTP request.
|
||||
* This is the same as "T1" in the above diagram.
|
||||
* @param[in] pServerRxTime The server time of receiving the SNTP request
|
||||
* packet from the client. This is the same as "T2" in the above diagram.
|
||||
* @param[in] pServerTxTime The server time of sending the SNTP response
|
||||
* packet. This is the same as "T3" in the above diagram.
|
||||
* @param[in] pClientRxTime The system time of receiving the SNTP response
|
||||
* from the server. This is the same as "T4" in the above diagram.
|
||||
* @param[out] pClockOffset This will be filled with the calculated offset value
|
||||
* of the system clock relative to the server time with the assumption that the
|
||||
* system clock is within 68 years of server time.
|
||||
*/
|
||||
static void calculateClockOffset( const SntpTimestamp_t * pClientTxTime,
|
||||
const SntpTimestamp_t * pServerRxTime,
|
||||
const SntpTimestamp_t * pServerTxTime,
|
||||
const SntpTimestamp_t * pClientRxTime,
|
||||
int64_t * pClockOffset )
|
||||
{
|
||||
/* Variable for storing the first-order difference between timestamps. */
|
||||
int64_t firstOrderDiffSend = 0;
|
||||
int64_t firstOrderDiffRecv = 0;
|
||||
|
||||
assert( pClientTxTime != NULL );
|
||||
assert( pServerRxTime != NULL );
|
||||
assert( pServerTxTime != NULL );
|
||||
assert( pClientRxTime != NULL );
|
||||
assert( pClockOffset != NULL );
|
||||
|
||||
/* Perform first order difference of timestamps on the network send path i.e. T2 - T1.
|
||||
* Note: The calculated difference value will always represent years in the range of
|
||||
*[-68 years, +68 years]. */
|
||||
firstOrderDiffSend = safeTimeDifference( pServerRxTime, pClientTxTime );
|
||||
|
||||
/* Perform first order difference of timestamps on the network receive path i.e. T3 - T4.
|
||||
* Note: The calculated difference value will always represent years in the range of
|
||||
*[-68 years, +68 years]. */
|
||||
firstOrderDiffRecv = safeTimeDifference( pServerTxTime, pClientRxTime );
|
||||
|
||||
/* Now calculate the system clock-offset relative to server time as the average of the
|
||||
* first order difference of timestamps in both directions of network path.
|
||||
* Note: This will ALWAYS represent offset in the range of [-68 years, +68 years]. */
|
||||
*pClockOffset = ( firstOrderDiffSend + firstOrderDiffRecv ) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a SNTP response packet by determining whether it is a rejected
|
||||
* or accepted response to an SNTP request, and accordingly, populate the
|
||||
* @p pParsedResponse parameter with the parsed data.
|
||||
*
|
||||
* @note If the server has rejected the request with the a Kiss-o'-Death message,
|
||||
* then this function will set the associated rejection code in the output parameter
|
||||
* while setting the remaining members to zero.
|
||||
* If the server has accepted the time request, then the function will set the
|
||||
* rejectedResponseCode member of the output parameter to #SNTP_KISS_OF_DEATH_CODE_NONE,
|
||||
* and set the other the members with appropriate data extracted from the response
|
||||
* packet.
|
||||
*
|
||||
* @param[in] pResponsePacket The SNTP response packet from server to parse.
|
||||
* @param[in] pRequestTxTime The system time (in SNTP timestamp format) of
|
||||
* sending the SNTP request to server.
|
||||
* @param[in] pResponseRxTime The system time (in SNTP timestamp format) of
|
||||
* receiving the SNTP response from server.
|
||||
* @param[out] pParsedResponse The parameter that will be populated with data
|
||||
* parsed from the response packet, @p pResponsePacket.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess if the server response does not represent a Kiss-o'-Death
|
||||
* message.
|
||||
* - #SntpRejectedResponseChangeServer if the server rejected with a code
|
||||
* indicating that client cannot be retry requests to it.
|
||||
* - #SntpRejectedResponseRetryWithBackoff if the server rejected with a code
|
||||
* indicating that client should back-off before retrying request.
|
||||
* - #SntpRejectedResponseOtherCode if the server rejected with a code
|
||||
* other than "DENY", "RSTR" and "RATE".
|
||||
*/
|
||||
static SntpStatus_t parseValidSntpResponse( const SntpPacket_t * pResponsePacket,
|
||||
const SntpTimestamp_t * pRequestTxTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
SntpResponseData_t * pParsedResponse )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
assert( pResponsePacket != NULL );
|
||||
assert( pResponseRxTime != NULL );
|
||||
assert( pParsedResponse != NULL );
|
||||
|
||||
/* Clear the output parameter memory to zero. */
|
||||
( void ) memset( pParsedResponse, 0, sizeof( *pParsedResponse ) );
|
||||
|
||||
/* Determine if the server has accepted or rejected the request for time. */
|
||||
if( pResponsePacket->stratum == SNTP_KISS_OF_DEATH_STRATUM )
|
||||
{
|
||||
/* Server has sent a Kiss-o'-Death message i.e. rejected the request. */
|
||||
|
||||
/* Extract the kiss-code sent by the server from the "Reference ID" field
|
||||
* of the SNTP packet. */
|
||||
pParsedResponse->rejectedResponseCode =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->refId );
|
||||
|
||||
/* Determine the return code based on the Kiss-o'-Death code. */
|
||||
switch( pParsedResponse->rejectedResponseCode )
|
||||
{
|
||||
case KOD_CODE_DENY_UINT_VALUE:
|
||||
case KOD_CODE_RSTR_UINT_VALUE:
|
||||
status = SntpRejectedResponseChangeServer;
|
||||
break;
|
||||
|
||||
case KOD_CODE_RATE_UINT_VALUE:
|
||||
status = SntpRejectedResponseRetryWithBackoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = SntpRejectedResponseOtherCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Server has responded successfully to the time request. */
|
||||
|
||||
SntpTimestamp_t serverRxTime;
|
||||
|
||||
/* Map of integer value to SntpLeapSecondInfo_t enumeration type for the
|
||||
* "Leap Indicator" field in the first byte of an SNTP packet.
|
||||
* Note: This map is used to not violate MISRA Rule 10.5 when directly
|
||||
* converting an integer to enumeration type.
|
||||
*/
|
||||
const SntpLeapSecondInfo_t leapIndicatorTypeMap[] =
|
||||
{
|
||||
NoLeapSecond,
|
||||
LastMinuteHas61Seconds,
|
||||
LastMinuteHas59Seconds,
|
||||
AlarmServerNotSynchronized
|
||||
};
|
||||
|
||||
/* Set the Kiss-o'-Death code value to NULL as server has responded favorably
|
||||
* to the time request. */
|
||||
pParsedResponse->rejectedResponseCode = SNTP_KISS_OF_DEATH_CODE_NONE;
|
||||
|
||||
/* Fill the output parameter with the server time which is the
|
||||
* "transmit" time in the response packet. */
|
||||
pParsedResponse->serverTime.seconds =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->transmitTime.seconds );
|
||||
pParsedResponse->serverTime.fractions =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->transmitTime.fractions );
|
||||
|
||||
/* Extract information of any upcoming leap second from the response. */
|
||||
pParsedResponse->leapSecondType = leapIndicatorTypeMap[
|
||||
( pResponsePacket->leapVersionMode >> SNTP_LEAP_INDICATOR_LSB_POSITION ) ];
|
||||
|
||||
/* Store the "receive" time in SNTP response packet in host order. */
|
||||
serverRxTime.seconds =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->receiveTime.seconds );
|
||||
serverRxTime.fractions =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->receiveTime.fractions );
|
||||
|
||||
/* Calculate system clock offset relative to server time, if possible, within
|
||||
* the 64 bit integer width of the SNTP timestamp. */
|
||||
calculateClockOffset( pRequestTxTime,
|
||||
&serverRxTime,
|
||||
&pParsedResponse->serverTime,
|
||||
pResponseRxTime,
|
||||
&pParsedResponse->clockOffsetMs );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SntpStatus_t Sntp_SerializeRequest( SntpTimestamp_t * pRequestTime,
|
||||
uint32_t randomNumber,
|
||||
void * pBuffer,
|
||||
size_t bufferSize )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
if( pRequestTime == NULL )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( pBuffer == NULL )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( bufferSize < SNTP_PACKET_BASE_SIZE )
|
||||
{
|
||||
status = SntpErrorBufferTooSmall;
|
||||
}
|
||||
|
||||
/* Zero timestamps for client request time is not allowed to protect against
|
||||
* attack spoofing server response containing zero value for "originate timestamp".
|
||||
* Note: In SNTP/NTP communication, the "originate timestamp" of a valid server response
|
||||
* matches the "transmit timestamp" in corresponding client request packet. */
|
||||
else if( isZeroTimestamp( pRequestTime ) == true )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* MISRA Ref 11.5.1 [Void pointer assignment] */
|
||||
/* More details at: https://github.com/FreeRTOS/coreSNTP/blob/main/MISRA.md#rule-115 */
|
||||
/* coverity[misra_c_2012_rule_11_5_violation] */
|
||||
SntpPacket_t * pRequestPacket = ( SntpPacket_t * ) pBuffer;
|
||||
|
||||
/* Fill the buffer with zero as most fields are zero for a standard SNTP
|
||||
* request packet.*/
|
||||
( void ) memset( pBuffer, 0, sizeof( SntpPacket_t ) );
|
||||
|
||||
/* Set the first byte of the request packet for "Version" and "Mode" fields */
|
||||
pRequestPacket->leapVersionMode = 0U /* Leap Indicator */ |
|
||||
( SNTP_VERSION << SNTP_VERSION_LSB_POSITION ) /* Version Number */ |
|
||||
SNTP_MODE_CLIENT /* Mode */;
|
||||
|
||||
|
||||
/* Add passed random number to non-significant bits of the fractions part
|
||||
* of the transmit timestamp.
|
||||
* This is suggested by the SNTPv4 (and NTPv4) specification(s)
|
||||
* to protect against replay attacks. Refer to RFC 4330 Section 3 for
|
||||
* more information.
|
||||
* Adding random bits to the least significant 16 bits of the fractions
|
||||
* part of the timestamp affects only ~15 microseconds of information
|
||||
* (calculated as 0xFFFF * 232 picoseconds).
|
||||
*/
|
||||
pRequestTime->fractions = ( pRequestTime->fractions
|
||||
| ( randomNumber >> 16 ) );
|
||||
|
||||
/* Update the request buffer with request timestamp in network byte order. */
|
||||
fillWordMemoryInNetworkOrder( &pRequestPacket->transmitTime.seconds,
|
||||
pRequestTime->seconds );
|
||||
fillWordMemoryInNetworkOrder( &pRequestPacket->transmitTime.fractions,
|
||||
pRequestTime->fractions );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SntpStatus_t Sntp_DeserializeResponse( const SntpTimestamp_t * pRequestTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
const void * pResponseBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResponseData_t * pParsedResponse )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
/* MISRA Ref 11.5.1 [Void pointer assignment] */
|
||||
/* More details at: https://github.com/FreeRTOS/coreSNTP/blob/main/MISRA.md#rule-115 */
|
||||
/* coverity[misra_c_2012_rule_11_5_violation] */
|
||||
const SntpPacket_t * pResponsePacket = ( const SntpPacket_t * ) pResponseBuffer;
|
||||
|
||||
if( ( pRequestTime == NULL ) || ( pResponseRxTime == NULL ) ||
|
||||
( pResponseBuffer == NULL ) || ( pParsedResponse == NULL ) )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( bufferSize < SNTP_PACKET_BASE_SIZE )
|
||||
{
|
||||
status = SntpErrorBufferTooSmall;
|
||||
}
|
||||
|
||||
/* Zero timestamps for client request time is not allowed to protect against
|
||||
* attack spoofing server response containing zero value for "originate timestamp".
|
||||
* Note: In SNTP/NTP communication, the "originate timestamp" of a valid server response
|
||||
* matches the "transmit timestamp" in corresponding client request packet. */
|
||||
else if( isZeroTimestamp( pRequestTime ) == true )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
/* Check if the packet represents a server in the "Mode" field. */
|
||||
else if( ( pResponsePacket->leapVersionMode & SNTP_MODE_BITS_MASK ) != SNTP_MODE_SERVER )
|
||||
{
|
||||
status = SntpInvalidResponse;
|
||||
}
|
||||
|
||||
/* Check if any of the timestamps in the response packet are zero, which is invalid.
|
||||
* Note: This is done to protect against a nuanced server spoofing attack where if the
|
||||
* SNTP client resets its internal state of "Client transmit timestamp" (OR "originate
|
||||
* timestamp" from server perspective) to zero as a protection against replay attack, an
|
||||
* an attacker with this knowledge of the client operation can spoof a server response
|
||||
* containing the "originate timestamp" as zero. Thus, to protect against such attack,
|
||||
* a server response packet with any zero timestamp is rejected. */
|
||||
else if( ( isZeroTimestamp( &pResponsePacket->originTime ) == true ) ||
|
||||
( isZeroTimestamp( &pResponsePacket->receiveTime ) == true ) ||
|
||||
( isZeroTimestamp( &pResponsePacket->transmitTime ) == true ) )
|
||||
{
|
||||
status = SntpInvalidResponse;
|
||||
}
|
||||
|
||||
|
||||
/* Validate that the server has sent the client's request timestamp in the
|
||||
* "originate" timestamp field of the response. */
|
||||
else if( ( pRequestTime->seconds !=
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->originTime.seconds ) ) ||
|
||||
( pRequestTime->fractions !=
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->originTime.fractions ) ) )
|
||||
|
||||
{
|
||||
status = SntpInvalidResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* As the response packet is valid, parse more information from it and
|
||||
* populate the output parameter. */
|
||||
|
||||
status = parseValidSntpResponse( pResponsePacket,
|
||||
pRequestTime,
|
||||
pResponseRxTime,
|
||||
pParsedResponse );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
|
||||
uint16_t desiredAccuracy,
|
||||
uint32_t * pPollInterval )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
if( ( clockFreqTolerance == 0U ) || ( desiredAccuracy == 0U ) || ( pPollInterval == NULL ) )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t exactIntervalForAccuracy = 0U;
|
||||
uint8_t log2PollInterval = 0U;
|
||||
|
||||
/* Calculate the poll interval required for achieving the exact desired clock accuracy
|
||||
* with the following formulae:
|
||||
*
|
||||
* System Clock Drift Rate ( microseconds / second ) = Clock Frequency Tolerance (in PPM )
|
||||
* Maximum Clock Drift ( milliseconds ) = Desired Accuracy ( milliseconds )
|
||||
*
|
||||
* Poll Interval ( seconds ) = Maximum Clock Drift
|
||||
* ---------------------------
|
||||
* System Clock Drift Rate
|
||||
*
|
||||
* = Maximum Drift ( milliseconds ) * 1000 ( microseconds / millisecond )
|
||||
* ------------------------------------------------------------------------
|
||||
* System Clock Drift Rate ( microseconds / second )
|
||||
*
|
||||
* = Desired Accuracy * 1000
|
||||
* ------------------------------
|
||||
* Clock Frequency Tolerance
|
||||
*/
|
||||
exactIntervalForAccuracy = ( ( uint32_t ) desiredAccuracy * 1000U ) / clockFreqTolerance;
|
||||
|
||||
/* Check if calculated poll interval value falls in the supported range of seconds. */
|
||||
if( exactIntervalForAccuracy == 0U )
|
||||
{
|
||||
/* Poll interval value is less than 1 second, and is not supported by the function. */
|
||||
status = SntpZeroPollInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* To calculate the log 2 value of the exact poll interval value, first determine the highest
|
||||
* bit set in the value. */
|
||||
while( exactIntervalForAccuracy != 0U )
|
||||
{
|
||||
log2PollInterval++;
|
||||
exactIntervalForAccuracy /= 2U;
|
||||
}
|
||||
|
||||
/* Convert the highest bit in the exact poll interval value to the nearest integer
|
||||
* value lower or equal to the log2 of the exact poll interval value. */
|
||||
log2PollInterval--;
|
||||
|
||||
/* Calculate the poll interval as the closest exponent of 2 value that achieves
|
||||
* equal or higher accuracy than the desired accuracy. */
|
||||
*pPollInterval = ( ( ( uint32_t ) 1U ) << log2PollInterval );
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
|
||||
uint32_t * pUnixTimeSecs,
|
||||
uint32_t * pUnixTimeMicrosecs )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
if( ( pSntpTime == NULL ) || ( pUnixTimeSecs == NULL ) || ( pUnixTimeMicrosecs == NULL ) )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
/* Handle case when SNTP timestamp is in SNTP era 0 time range
|
||||
* (i.e. time before 7 Feb 2036 6:28:15 UTC). */
|
||||
if( pSntpTime->seconds >= SNTP_TIME_AT_UNIX_EPOCH_SECS )
|
||||
{
|
||||
*pUnixTimeSecs = pSntpTime->seconds - SNTP_TIME_AT_UNIX_EPOCH_SECS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle case when timestamp represents date in SNTP era 1
|
||||
* (i.e. time from 7 Feb 2036 6:28:16 UTC onwards). */
|
||||
*pUnixTimeSecs = UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME + pSntpTime->seconds;
|
||||
}
|
||||
|
||||
/* Convert SNTP fractions to microseconds for UNIX time. */
|
||||
*pUnixTimeMicrosecs = pSntpTime->fractions / SNTP_FRACTION_VALUE_PER_MICROSECOND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 模块名称:coreSNTP 定制配置(本仓 glue 文件,非 vendor 原文)
|
||||
* 模块功能:core_sntp_config_defaults.h 在**未**定义 SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
* 时会包含本文件;本仓使用 vendor 库的 serializer 层,默认值即所需
|
||||
* ——日志宏 LogError/LogWarn/LogInfo/LogDebug 保持 defaults 的编译期
|
||||
* 空实现:serializer 的失败路径都已有应用层 DBG 判读(time_sntp.c
|
||||
* 在调用点按返回码记录),库内再开日志只增栈/Flash 不增信息量。
|
||||
* 错误/丢弃类留痕统一放调用方(App/sync/time_sntp.c),
|
||||
* 避免 vendor 文件与本仓日志栈耦合。
|
||||
* 适用平台:STM32F407ZGTx / 主机单测(test/host/sntp)
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-11-04
|
||||
* 修改记录:
|
||||
* v1.0 2026-11-04 王建锋 创建初始版本(SNTP 客户端接入 #57)
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_CONFIG_H
|
||||
#define CORE_SNTP_CONFIG_H
|
||||
|
||||
/* 本文件刻意不覆盖任何默认宏;如将来需要库内日志,在此映射:
|
||||
* #define LogError(message) ...
|
||||
* (注意 vendor 调用形态为 LogError(("..."))——参数自带外括号) */
|
||||
|
||||
#endif /* CORE_SNTP_CONFIG_H */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* coreSNTP
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core_sntp_config_defaults.h
|
||||
* @brief This file represents the default values for the configuration macros
|
||||
* of the coreSNTP library.
|
||||
*
|
||||
* @note This file SHOULD NOT be modified. If custom values are needed for
|
||||
* any configuration macro, a core_sntp_config.h file should be provided to
|
||||
* the SNTP library to override the default values defined in this file.
|
||||
* To build the library with the core_sntp_config.h file, make sure to
|
||||
* not set the SNTP_DO_NOT_USE_CUSTOM_CONFIG preprocessor macro.
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_CONFIG_DEFAULTS_H_
|
||||
#define CORE_SNTP_CONFIG_DEFAULTS_H_
|
||||
|
||||
/* The macro definition for SNTP_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
|
||||
* documentation only. */
|
||||
|
||||
/**
|
||||
* @brief Define this macro to build the SNTP library without the custom config
|
||||
* file core_sntp_config.h.
|
||||
*
|
||||
* Without the custom config, the SNTP library builds with
|
||||
* default values of config macros defined in core_sntp_config_defaults.h file.
|
||||
*
|
||||
* If a custom config is provided, then SNTP_DO_NOT_USE_CUSTOM_CONFIG should not
|
||||
* be defined.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#endif
|
||||
|
||||
/* SNTP_DO_NOT_USE_CUSTOM_CONFIG allows building the SNTP library
|
||||
* without a custom config. If a custom config is provided, the
|
||||
* SNTP_DO_NOT_USE_CUSTOM_CONFIG macro should not be defined. */
|
||||
#ifndef SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#include "core_sntp_config.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Error" level
|
||||
* messages.
|
||||
*
|
||||
* To enable error level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports error logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to core_sntp_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Error logging is turned off, and no code is generated for calls
|
||||
* to the macro in the SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogError
|
||||
#define LogError( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Warning" level
|
||||
* messages.
|
||||
*
|
||||
* To enable warning level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports warning logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to core_sntp_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
|
||||
*
|
||||
* <b>Default value</b>: Warning logs are turned off, and no code is generated for calls
|
||||
* to the macro in the SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogWarn
|
||||
#define LogWarn( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Info" level
|
||||
* messages.
|
||||
*
|
||||
* To enable info level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports info logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to core_sntp_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
|
||||
*
|
||||
* <b>Default value</b>: Info logging is turned off, and no code is generated for calls
|
||||
* to the macro in the SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogInfo
|
||||
#define LogInfo( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Debug" level
|
||||
* messages.
|
||||
*
|
||||
* To enable debug level logging from SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports debug logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to core_sntp_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
|
||||
*
|
||||
* <b>Default value</b>: Debug logging is turned off, and no code is generated for calls
|
||||
* to the macro in the SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogDebug
|
||||
#define LogDebug( message )
|
||||
#endif
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CONFIG_DEFAULTS_H_ */
|
||||
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* coreSNTP
|
||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file core_sntp_serializer.h
|
||||
* @brief API for serializing SNTP request packets and, and de-serializing SNTP
|
||||
* response packets.
|
||||
* This API layer adheres to the SNTPv4 specification defined in
|
||||
* [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_SERIALIZER_H_
|
||||
#define CORE_SNTP_SERIALIZER_H_
|
||||
|
||||
/* Standard include. */
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The base packet size of request and response of the (S)NTP protocol.
|
||||
* @note This is the packet size without any authentication headers for security
|
||||
* mechanism. If the application uses a security mechanism for communicating with
|
||||
* an (S)NTP server, it can add authentication data after the SNTP packet is
|
||||
* serialized with the @ref Sntp_SerializeRequest API function.
|
||||
*/
|
||||
#define SNTP_PACKET_BASE_SIZE ( 48U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief Number of SNTP timestamp fractions in 1 microsecond.
|
||||
*
|
||||
* The fraction's part of an SNTP timestamp is 32-bits wide, thereby, giving a
|
||||
* resolution of 2^(-32) seconds ~ 232 picoseconds.
|
||||
*
|
||||
* @note The application can use this value to convert microseconds part of system
|
||||
* time into SNTP timestamp fractions. For example, if the microseconds
|
||||
* part of system time is n microseconds, the fractions value to be used for the
|
||||
* SNTP timestamp part will be n * SNTP_FRACTION_VALUE_PER_MICROSECOND.
|
||||
*/
|
||||
#define SNTP_FRACTION_VALUE_PER_MICROSECOND ( 4295U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The seconds part of SNTP time at the UNIX epoch time, which represents
|
||||
* an offset of 70 years (in seconds) between SNTP epoch and UNIX epoch time.
|
||||
* SNTP uses 1st Jan 1900 UTC as the epoch time, whereas UNIX standard uses
|
||||
* 1st Jan 1970 UTC as the epoch time, thereby, causing an offset of 70 years
|
||||
* between them.
|
||||
*
|
||||
* Difference of 70 years = ((70 * 365) + 17 leap days) * 24 * 3600 seconds
|
||||
*
|
||||
* @note If your system follows UNIX time, the application can use this value to
|
||||
* convert seconds part of a system time to seconds part of the equivalent SNTP
|
||||
* time. For example, if the seconds part of system time is n seconds, the seconds
|
||||
* value to be used for the SNTP timestamp will be n + SNTP_TO_UNIX_OFFSET_SECS.
|
||||
*/
|
||||
#define SNTP_TIME_AT_UNIX_EPOCH_SECS ( 2208988800U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The seconds value of SNTP timestamp for the largest UNIX time when
|
||||
* using signed 32-bit integer for seconds.
|
||||
* The largest time representable with a 32-bit signed integer in UNIX time
|
||||
* is 19 Jan 2038 3h 14m 7s UTC. However, as the SNTP time overflows at
|
||||
* 7 Feb 2036 6h 28m 16s UTC, therefore, the SNTP time for the largest UNIX time
|
||||
* represents the time duration between the 2 timestamps.
|
||||
*
|
||||
* SNTP Time at Largest Time Duration in the range
|
||||
* Signed 32-bit UNIX time = [7 Feb 2036 6:28:16, 19 Jan 2038 3:14:07]
|
||||
*/
|
||||
#define SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS ( 61505151U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The UNIX time (in seconds) at the smallest SNTP time in era 1,
|
||||
* i.e. UNIX time at 7 Feb 2036 6:28:16 UTC/
|
||||
*
|
||||
* Time Duration = 7 Feb 6:28:16 UTC (SNTP Era 1 Epoch) -
|
||||
* 1 Jan 1970 0:0:0 UTC (UNIX epoch)
|
||||
* = 66 years, 37 days, 6 hours, 28 minutes and 16 seconds
|
||||
* = ((66 * 365) + 16 leap days) * 24 * 3600) + (6 * 3600)
|
||||
* + (28 * 60) + 16
|
||||
*/
|
||||
#define UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME ( 2085978496U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The fixed-length of any Kiss-o'-Death message ASCII code sent
|
||||
* in an SNTP server response.
|
||||
* @note An SNTP server sends a Kiss-o'-Death message to reject a time request
|
||||
* from the client. For more information on the Kiss-o'-Death codes, refer to the
|
||||
* [SNTPv4 specification Section 8](https://tools.ietf.org/html/rfc4330#section-8).
|
||||
*/
|
||||
#define SNTP_KISS_OF_DEATH_CODE_LENGTH ( 4U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The value for the #SntpResponseData_t.rejectedResponseCode member
|
||||
* when that the server response packet does not contain a Kiss-o'-Death
|
||||
* message, and therefore, does not have a "kiss code".
|
||||
* The server sends a "kiss-code" only when it rejects an SNTP request
|
||||
* with a Kiss-o'-Death message.
|
||||
*/
|
||||
#define SNTP_KISS_OF_DEATH_CODE_NONE ( 0U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_enum_types
|
||||
* @brief Enumeration of status codes that can be returned
|
||||
* by the coreSNTP Library API.
|
||||
*/
|
||||
typedef enum SntpStatus
|
||||
{
|
||||
/**
|
||||
* @brief Successful operation of an SNTP API.
|
||||
*/
|
||||
SntpSuccess,
|
||||
|
||||
/**
|
||||
* @brief Invalid parameter passed to an API function.
|
||||
*/
|
||||
SntpErrorBadParameter,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message to reject the request for time.
|
||||
* This status can be returned by the @ref Sntp_ReceiveTimeResponse API.
|
||||
*/
|
||||
SntpRejectedResponse,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message with non-retryable code (i.e. DENY or RSTR).
|
||||
*/
|
||||
SntpRejectedResponseChangeServer,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message with a RATE code, which means that
|
||||
* client should back-off before retrying.
|
||||
*/
|
||||
SntpRejectedResponseRetryWithBackoff,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message with a code, specific to the server.
|
||||
* Application can inspect the ASCII kiss-code from @ref Sntp_DeserializeResponse API.
|
||||
*/
|
||||
SntpRejectedResponseOtherCode,
|
||||
|
||||
/**
|
||||
* @brief Application provided insufficient buffer space for serializing
|
||||
* or de-serializing an SNTP packet.
|
||||
* The minimum size of an SNTP packet is #SNTP_PACKET_BASE_SIZE
|
||||
* bytes. */
|
||||
SntpErrorBufferTooSmall,
|
||||
|
||||
/**
|
||||
* @brief Server response failed validation checks for expected data in SNTP packet.
|
||||
*/
|
||||
SntpInvalidResponse,
|
||||
|
||||
/**
|
||||
* @brief Poll interval value is under 1 second which cannot be calculated
|
||||
* by @ref Sntp_CalculatePollInterval.
|
||||
*/
|
||||
SntpZeroPollInterval,
|
||||
|
||||
/**
|
||||
* @brief The user-defined DNS resolution interface, @ref SntpResolveDns_t, failed to resolve
|
||||
* address for a time server. This status is returned by the @ref Sntp_SendTimeRequest API.
|
||||
*/
|
||||
SntpErrorDnsFailure,
|
||||
|
||||
/**
|
||||
* @brief Networking operation of sending or receiving SNTP packet through the user-defined UDP
|
||||
* transport interface, @ref UdpTransportInterface_t, failed.
|
||||
* This status is returned by either of @ref Sntp_SendTimeRequest OR @ref Sntp_ReceiveTimeResponse
|
||||
* APIs.
|
||||
*/
|
||||
SntpErrorNetworkFailure,
|
||||
|
||||
/**
|
||||
* @brief Time server is not authenticated from the authentication data in its response.
|
||||
* This status can be returned by the user-supplied definition of the
|
||||
* @ref SntpValidateServerAuth_t authentication interface.
|
||||
*/
|
||||
SntpServerNotAuthenticated,
|
||||
|
||||
/**
|
||||
* @brief Failure from the user-supplied authentication interface, @ref SntpAuthenticationInterface_t,
|
||||
* in either generating authentication data for SNTP request OR validating the authentication
|
||||
* data in SNTP response from server.
|
||||
*/
|
||||
SntpErrorAuthFailure,
|
||||
|
||||
/**
|
||||
* @brief A timeout occurred in sending time request packet over the network to a server through the
|
||||
* @ref Sntp_SendTimeRequest API.
|
||||
*/
|
||||
SntpErrorSendTimeout,
|
||||
|
||||
/**
|
||||
* @brief A timeout has occurred in receiving server response with the @ref Sntp_ReceiveTimeResponse
|
||||
* API.
|
||||
*/
|
||||
SntpErrorResponseTimeout,
|
||||
|
||||
/**
|
||||
* @brief No SNTP packet for server response is received from the network by the
|
||||
* @ref Sntp_ReceiveTimeResponse API.
|
||||
*/
|
||||
SntpNoResponseReceived,
|
||||
|
||||
/**
|
||||
* @brief The SNTP context passed to @ref Sntp_SendTimeRequest or @ref Sntp_ReceiveTimeResponse APIs is
|
||||
* is uninitialized.
|
||||
*/
|
||||
SntpErrorContextNotInitialized
|
||||
} SntpStatus_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_enum_types
|
||||
* @brief Enumeration for leap second information that an SNTP server can
|
||||
* send its response to a time request. An SNTP server sends information about
|
||||
* whether there is an upcoming leap second adjustment in the last day of the
|
||||
* current month.
|
||||
*
|
||||
* @note A leap second is an adjustment made in atomic clock time because Earth's rotation
|
||||
* can be inconsistent. Leap seconds are usually incorporated as an extra second insertion
|
||||
* or second deletion in the last minute before midnight i.e. in the minute of 23h:59m UTC
|
||||
* on the last day of June or December. For more information on leap seconds, refer to
|
||||
* https://www.nist.gov/pml/time-and-frequency-division/leap-seconds-faqs.
|
||||
*/
|
||||
typedef enum SntpLeapSecondInfo
|
||||
{
|
||||
NoLeapSecond = 0x00, /**< @brief There is no upcoming leap second adjustment. */
|
||||
LastMinuteHas61Seconds = 0x01, /**< @brief A leap second should be inserted in the last minute before midnight. */
|
||||
LastMinuteHas59Seconds = 0x02, /**< @brief A leap second should be deleted from the last minute before midnight. */
|
||||
AlarmServerNotSynchronized = 0x03 /**< @brief An alarm condition meaning that server's time is not synchronized
|
||||
* to an upstream NTP (or SNTP) server. */
|
||||
} SntpLeapSecondInfo_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Structure representing an SNTP timestamp.
|
||||
*
|
||||
* @note The SNTP timestamp uses 1st January 1900 0h 0m 0s Coordinated Universal Time (UTC)
|
||||
* as the primary epoch i.e. the timestamp represents current time as the amount of time since
|
||||
* the epoch time.
|
||||
* Refer to the [SNTPv4 specification](https://tools.ietf.org/html/rfc4330#section-3) for more
|
||||
* information of the SNTP timestamp format.
|
||||
*/
|
||||
typedef struct SntpTimestamp
|
||||
{
|
||||
uint32_t seconds; /**< @brief Number of seconds since epoch time. */
|
||||
uint32_t fractions; /**< @brief The fractions part of the SNTP timestamp with resolution
|
||||
* of 2^(-32) ~ 232 picoseconds. */
|
||||
} SntpTimestamp_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Structure representing data parsed from an SNTP response from server
|
||||
* as well as data of arithmetic calculations derived from the response.
|
||||
*/
|
||||
typedef struct SntpResponse
|
||||
{
|
||||
/**
|
||||
* @brief The timestamp sent by the server.
|
||||
*/
|
||||
SntpTimestamp_t serverTime;
|
||||
|
||||
/**
|
||||
* @brief The information of an upcoming leap second in the
|
||||
* server response.
|
||||
*/
|
||||
SntpLeapSecondInfo_t leapSecondType;
|
||||
|
||||
/**
|
||||
* @brief If a server responded with Kiss-o'-Death message to reject
|
||||
* time request, this is the fixed length ASCII code sequence for the
|
||||
* rejection.
|
||||
*
|
||||
* The Kiss-o'-Death code is always #SNTP_KISS_OF_DEATH_CODE_LENGTH
|
||||
* bytes long.
|
||||
*
|
||||
* @note If the server does not send a Kiss-o'-Death message in its
|
||||
* response, this value will be #SNTP_KISS_OF_DEATH_CODE_NONE.
|
||||
*/
|
||||
uint32_t rejectedResponseCode;
|
||||
|
||||
/**
|
||||
* @brief The offset (in milliseconds) of the system clock relative to the server time
|
||||
* calculated from timestamps in the client SNTP request and server SNTP response packets.
|
||||
* If the the system time is BEHIND the server time, then the clock-offset value is > 0.
|
||||
* If the system time is AHEAD of the server time, then the clock-offset value is < 0.
|
||||
*
|
||||
* @note This information can be used to synchronize the system clock with a "slew",
|
||||
* "step" OR combination of the two clock correction methodologies depending on the degree
|
||||
* of system clock drift (represented by the clock-offset) and the application's
|
||||
* tolerance for system clock error.
|
||||
*
|
||||
* @note The library calculates the clock-offset value using the On-Wire
|
||||
* protocol suggested by the NTPv4 specification. For more information,
|
||||
* refer to https://tools.ietf.org/html/rfc5905#section-8.
|
||||
*
|
||||
* @note The library ASSUMES that the server and client systems are within
|
||||
* ~68 years of each other clock, whether in the same NTP era or across adjacent
|
||||
* NTP eras. Thus, the client and system times MUST be within ~68 years (or
|
||||
* 2^31 seconds exactly) of each other for correct calculation of clock-offset.
|
||||
*
|
||||
* @note When the server and client times are exactly 2^31 (or INT32_MAX + 1 )
|
||||
* seconds apart, the library ASSUMES that the server time is ahead of the client
|
||||
* time, and return the clock-offset value of INT32_MAX.
|
||||
*/
|
||||
int64_t clockOffsetMs;
|
||||
} SntpResponseData_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Serializes an SNTP request packet to use for querying a
|
||||
* time server.
|
||||
*
|
||||
* This function will fill only #SNTP_PACKET_BASE_SIZE bytes of data in the
|
||||
* passed buffer.
|
||||
*
|
||||
* @param[in, out] pRequestTime The current time of the system, expressed as time
|
||||
* since the SNTP epoch (i.e. 0h of 1st Jan 1900 ). This time will be serialized
|
||||
* in the SNTP request packet. The function will use this parameter to return the
|
||||
* timestamp serialized in the SNTP request. To protect against attacks spoofing
|
||||
* server responses, the timestamp MUST NOT be zero in value.
|
||||
* @param[in] randomNumber A random number (generated by a True Random Generator)
|
||||
* for use in the SNTP request packet to protect against replay attacks as suggested
|
||||
* by SNTPv4 specification. For more information, refer to
|
||||
* [RFC 4330 Section 3](https://tools.ietf.org/html/rfc4330#section-3).
|
||||
* @param[out] pBuffer The buffer that will be populated with the serialized
|
||||
* SNTP request packet.
|
||||
* @param[in] bufferSize The size of the @p pBuffer buffer. It should be at least
|
||||
* #SNTP_PACKET_BASE_SIZE bytes in size.
|
||||
*
|
||||
* @note It is recommended to use a True Random Generator (TRNG) to generate
|
||||
* the random number.
|
||||
* @note The application MUST save the @p pRequestTime value for de-serializing
|
||||
* the server response with @ref Sntp_DeserializeResponse API.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess when serialization operation is successful.
|
||||
* - #SntpErrorBadParameter if an invalid parameter is passed.
|
||||
* - #SntpErrorBufferTooSmall if the buffer does not have the minimum size
|
||||
* for serializing an SNTP request packet.
|
||||
*/
|
||||
/* @[define_sntp_serializerequest] */
|
||||
SntpStatus_t Sntp_SerializeRequest( SntpTimestamp_t * pRequestTime,
|
||||
uint32_t randomNumber,
|
||||
void * pBuffer,
|
||||
size_t bufferSize );
|
||||
/* @[define_sntp_serializerequest] */
|
||||
|
||||
/**
|
||||
* @brief De-serializes an SNTP packet received from a server as a response
|
||||
* to a SNTP request.
|
||||
*
|
||||
* This function will parse only the #SNTP_PACKET_BASE_SIZE bytes of data
|
||||
* in the passed buffer.
|
||||
*
|
||||
* @note If the server has sent a Kiss-o'-Death message to reject the associated
|
||||
* time request, the API function will return the appropriate return code and,
|
||||
* also, provide the ASCII code (of fixed length, #SNTP_KISS_OF_DEATH_CODE_LENGTH bytes)
|
||||
* in the #SntpResponseData_t.rejectedResponseCode member of @p pParsedResponse parameter,
|
||||
* parsed from the response packet.
|
||||
* The application SHOULD respect the server rejection and take appropriate action
|
||||
* based on the rejection code.
|
||||
* If the server response represents an accepted SNTP client request, then the API
|
||||
* function will set the #SntpResponseData_t.rejectedResponseCode member of
|
||||
* @p pParsedResponse parameter to #SNTP_KISS_OF_DEATH_CODE_NONE.
|
||||
*
|
||||
* @note If the server has positively responded with its clock time, then this API
|
||||
* function will calculate the clock-offset. For the clock-offset to be correctly
|
||||
* calculated, the system clock MUST be within ~68 years (or 2^31 seconds) of the server
|
||||
* time mentioned. This function supports clock-offset calculation when server and client
|
||||
* timestamps are in adjacent NTP eras, with one system is in NTP era 0 (i.e. before 7 Feb 2036
|
||||
* 6h:28m:14s UTC) and another system in NTP era 1 (on or after 7 Feb 2036 6h:28m:14s UTC).
|
||||
*
|
||||
* @note In the special case when the server and client times are exactly 2^31 seconds apart,
|
||||
* the library ASSUMES that the server time is ahead of the client time, and returns the
|
||||
* positive clock-offset value of INT32_MAX seconds.
|
||||
*
|
||||
* @param[in] pRequestTime The system time used in the SNTP request packet
|
||||
* that is associated with the server response. This MUST be the same as the
|
||||
* time returned by the @ref Sntp_SerializeRequest API. To protect against attacks
|
||||
* spoofing server responses, this timestamp MUST NOT be zero in value.
|
||||
* @param[in] pResponseRxTime The time of the system, expressed as time since the
|
||||
* SNTP epoch (i.e. 0h of 1st Jan 1900 ), at receiving SNTP response from server.
|
||||
* This time will be used to calculate system clock offset relative to server.
|
||||
* @param[in] pResponseBuffer The buffer containing the SNTP response from the
|
||||
* server.
|
||||
* @param[in] bufferSize The size of the @p pResponseBuffer containing the SNTP
|
||||
* response. It MUST be at least #SNTP_PACKET_BASE_SIZE bytes
|
||||
* long for a valid SNTP response.
|
||||
* @param[out] pParsedResponse The information parsed from the SNTP response packet.
|
||||
* If possible to calculate without overflow, it also contains the system clock
|
||||
* offset relative to the server time.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess if the de-serialization operation is successful.
|
||||
* - #SntpErrorBadParameter if an invalid parameter is passed.
|
||||
* - #SntpErrorBufferTooSmall if the buffer does not have the minimum size
|
||||
* required for a valid SNTP response packet.
|
||||
* - #SntpInvalidResponse if the response fails sanity checks expected in an
|
||||
* SNTP response.
|
||||
* - #SntpRejectedResponseChangeServer if the server rejected with a code
|
||||
* indicating that client cannot be retry requests to it.
|
||||
* - #SntpRejectedResponseRetryWithBackoff if the server rejected with a code
|
||||
* indicating that client should back-off before retrying request.
|
||||
* - #SntpRejectedResponseOtherCode if the server rejected with a code that
|
||||
* application can inspect in the @p pParsedResponse parameter.
|
||||
*/
|
||||
/* @[define_sntp_deserializeresponse] */
|
||||
SntpStatus_t Sntp_DeserializeResponse( const SntpTimestamp_t * pRequestTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
const void * pResponseBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResponseData_t * pParsedResponse );
|
||||
/* @[define_sntp_deserializeresponse] */
|
||||
|
||||
/**
|
||||
* @brief Utility to calculate the poll interval of sending periodic time queries
|
||||
* to servers to achieve a desired system clock accuracy for a given
|
||||
* frequency tolerance of the system clock.
|
||||
*
|
||||
* For example, from the SNTPv4 specification, "if the frequency tolerance
|
||||
* is 200 parts per million (PPM) and the required accuracy is one minute,
|
||||
* the maximum timeout is about 3.5 days". In this example, the system
|
||||
* clock frequency tolerance is 200 PPM and the desired accuracy is
|
||||
* 60000 milliseconds (or 1 minute) for which this API function
|
||||
* will return the maximum poll interval value as 2^18 seconds (or ~3 days).
|
||||
*
|
||||
* @note The poll interval returned is a power of 2, which is the
|
||||
* standard way to represent the value. According to the SNTPv4 specification
|
||||
* Best Practices, an SNTP client SHOULD NOT have a poll interval less than 15 seconds.
|
||||
* https://tools.ietf.org/html/rfc4330#section-10. This API function DOES NOT
|
||||
* support poll interval calculation less than 1 second.
|
||||
*
|
||||
* @param[in] clockFreqTolerance The frequency tolerance of system clock
|
||||
* in parts per million (PPM) units. This parameter MUST be non-zero.
|
||||
* @param[in] desiredAccuracy The acceptable maximum drift, in milliseconds,
|
||||
* for the system clock. The maximum value (0xFFFF) represents ~1 minute of
|
||||
* desired clock accuracy. This parameter MUST be non-zero.
|
||||
* @param[out] pPollInterval This is filled with the poll interval, in seconds
|
||||
* calculated as the closest power of 2 value that will achieve either the
|
||||
* exact desired or higher clock accuracy @p desiredAccuracy, for the given clock
|
||||
* frequency tolerance, @p clockFreqTolerance.
|
||||
*
|
||||
* @return Returns one of the following:
|
||||
* - #SntpSuccess if calculation is successful.
|
||||
* - #SntpErrorBadParameter for an invalid parameter passed to the function.
|
||||
* - #SntpZeroPollInterval if calculated poll interval is less than 1 second.
|
||||
*/
|
||||
/* @[define_sntp_calculatepollinterval] */
|
||||
SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
|
||||
uint16_t desiredAccuracy,
|
||||
uint32_t * pPollInterval );
|
||||
/* @[define_sntp_calculatepollinterval] */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility to convert SNTP timestamp (that uses 1st Jan 1900 as the epoch) to
|
||||
* UNIX timestamp (that uses 1st Jan 1970 as the epoch).
|
||||
*
|
||||
* Refer to (this image)[docs/doxygen/images/Ntp_To_Unix_Time.png].
|
||||
*
|
||||
* @note The function also correctly handles SNTP era overflow (from 7 Feb 2036 6h 28m 16s,
|
||||
* i.e., SNTP era 1) to ensure accurate conversion across SNTP eras.
|
||||
*
|
||||
* @param[in] pSntpTime The SNTP timestamp to convert to UNIX time.
|
||||
* @param[out] pUnixTimeSecs This will be filled with the seconds part of the
|
||||
* UNIX time equivalent of the SNTP time, @p pSntpTime.
|
||||
* @param[out] pUnixTimeMicrosecs This will be filled with the microseconds part
|
||||
* of the UNIX time equivalent of the SNTP time, @p pSntpTime.
|
||||
*
|
||||
* @return Returns one of the following:
|
||||
* - #SntpSuccess if conversion to UNIX time is successful
|
||||
* - #SntpErrorBadParameter if any of the passed parameters are NULL.
|
||||
*/
|
||||
/* @[define_sntp_converttounixtime] */
|
||||
SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
|
||||
uint32_t * pUnixTimeSecs,
|
||||
uint32_t * pUnixTimeMicrosecs );
|
||||
/* @[define_sntp_converttounixtime] */
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* ifndef CORE_SNTP_SERIALIZER_H_ */
|
||||
Reference in New Issue
Block a user