1 /* 2 * Copyright (c) 2018, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef SNTP_CLIENT_HPP_ 30 #define SNTP_CLIENT_HPP_ 31 32 #include "openthread-core-config.h" 33 34 #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 35 36 #include <openthread/sntp.h> 37 38 #include "common/clearable.hpp" 39 #include "common/message.hpp" 40 #include "common/non_copyable.hpp" 41 #include "common/timer.hpp" 42 #include "net/ip6.hpp" 43 #include "net/netif.hpp" 44 45 /** 46 * @file 47 * This file includes definitions for the SNTP client. 48 */ 49 50 namespace ot { 51 namespace Sntp { 52 53 /** 54 * Implements SNTP client. 55 */ 56 class Client : private NonCopyable 57 { 58 public: 59 typedef otSntpResponseHandler ResponseHandler; ///< Response handler callback. 60 61 /** 62 * Initializes the object. 63 * 64 * @param[in] aInstance A reference to the OpenThread instance. 65 */ 66 explicit Client(Instance &aInstance); 67 68 /** 69 * Starts the SNTP client. 70 * 71 * @retval kErrorNone Successfully started the SNTP client. 72 * @retval kErrorAlready The socket is already open. 73 */ 74 Error Start(void); 75 76 /** 77 * Stops the SNTP client. 78 * 79 * @retval kErrorNone Successfully stopped the SNTP client. 80 */ 81 Error Stop(void); 82 83 /** 84 * Returns the unix era number. 85 * 86 * @returns The unix era number. 87 */ GetUnixEra(void) const88 uint32_t GetUnixEra(void) const { return mUnixEra; } 89 90 /** 91 * Sets the unix era number. 92 * 93 * @param[in] aUnixEra The unix era number. 94 */ SetUnixEra(uint32_t aUnixEra)95 void SetUnixEra(uint32_t aUnixEra) { mUnixEra = aUnixEra; } 96 97 /** 98 * Sends an SNTP query. 99 * 100 * @param[in] aQuery A pointer to specify SNTP query parameters. 101 * @param[in] aHandler A function pointer that shall be called on response reception or time-out. 102 * @param[in] aContext A pointer to arbitrary context information. 103 * 104 * @retval kErrorNone Successfully sent SNTP query. 105 * @retval kErrorNoBufs Failed to allocate retransmission data. 106 * @retval kErrorInvalidArgs Invalid arguments supplied. 107 */ 108 Error Query(const otSntpQuery *aQuery, ResponseHandler aHandler, void *aContext); 109 110 private: 111 static constexpr uint32_t kTimeAt1970 = 2208988800UL; // num seconds between 1st Jan 1900 and 1st Jan 1970. 112 113 static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_SNTP_CLIENT_RESPONSE_TIMEOUT; 114 static constexpr uint8_t kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT; 115 116 OT_TOOL_PACKED_BEGIN 117 class Header : public Clearable<Header> 118 { 119 public: 120 enum Mode : uint8_t 121 { 122 kModeClient = 3, 123 kModeServer = 4, 124 }; 125 126 static constexpr uint8_t kKissCodeLength = 4; 127 Init(void)128 void Init(void) 129 { 130 Clear(); 131 mFlags = (kNtpVersion << kVersionOffset | kModeClient << kModeOffset); 132 } 133 GetFlags(void) const134 uint8_t GetFlags(void) const { return mFlags; } SetFlags(uint8_t aFlags)135 void SetFlags(uint8_t aFlags) { mFlags = aFlags; } 136 GetMode(void) const137 Mode GetMode(void) const { return static_cast<Mode>((mFlags & kModeMask) >> kModeOffset); } 138 GetStratum(void) const139 uint8_t GetStratum(void) const { return mStratum; } SetStratum(uint8_t aStratum)140 void SetStratum(uint8_t aStratum) { mStratum = aStratum; } 141 GetPoll(void) const142 uint8_t GetPoll(void) const { return mPoll; } SetPoll(uint8_t aPoll)143 void SetPoll(uint8_t aPoll) { mPoll = aPoll; } 144 GetPrecision(void) const145 uint8_t GetPrecision(void) const { return mPrecision; } SetPrecision(uint8_t aPrecision)146 void SetPrecision(uint8_t aPrecision) { mPrecision = aPrecision; } 147 GetRootDelay(void) const148 uint32_t GetRootDelay(void) const { return BigEndian::HostSwap32(mRootDelay); } SetRootDelay(uint32_t aRootDelay)149 void SetRootDelay(uint32_t aRootDelay) { mRootDelay = BigEndian::HostSwap32(aRootDelay); } 150 GetRootDispersion(void) const151 uint32_t GetRootDispersion(void) const { return BigEndian::HostSwap32(mRootDispersion); } SetRootDispersion(uint32_t aRootDispersion)152 void SetRootDispersion(uint32_t aRootDispersion) { mRootDispersion = BigEndian::HostSwap32(aRootDispersion); } 153 GetReferenceId(void) const154 uint32_t GetReferenceId(void) const { return BigEndian::HostSwap32(mReferenceId); } SetReferenceId(uint32_t aReferenceId)155 void SetReferenceId(uint32_t aReferenceId) { mReferenceId = BigEndian::HostSwap32(aReferenceId); } 156 GetKissCode(void)157 char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); } 158 GetReferenceTimestampSeconds(void) const159 uint32_t GetReferenceTimestampSeconds(void) const { return BigEndian::HostSwap32(mReferenceTimestampSeconds); } SetReferenceTimestampSeconds(uint32_t aTimestamp)160 void SetReferenceTimestampSeconds(uint32_t aTimestamp) 161 { 162 mReferenceTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 163 } 164 GetReferenceTimestampFraction(void) const165 uint32_t GetReferenceTimestampFraction(void) const 166 { 167 return BigEndian::HostSwap32(mReferenceTimestampFraction); 168 } SetReferenceTimestampFraction(uint32_t aFraction)169 void SetReferenceTimestampFraction(uint32_t aFraction) 170 { 171 mReferenceTimestampFraction = BigEndian::HostSwap32(aFraction); 172 } 173 GetOriginateTimestampSeconds(void) const174 uint32_t GetOriginateTimestampSeconds(void) const { return BigEndian::HostSwap32(mOriginateTimestampSeconds); } SetOriginateTimestampSeconds(uint32_t aTimestamp)175 void SetOriginateTimestampSeconds(uint32_t aTimestamp) 176 { 177 mOriginateTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 178 } 179 GetOriginateTimestampFraction(void) const180 uint32_t GetOriginateTimestampFraction(void) const 181 { 182 return BigEndian::HostSwap32(mOriginateTimestampFraction); 183 } SetOriginateTimestampFraction(uint32_t aFraction)184 void SetOriginateTimestampFraction(uint32_t aFraction) 185 { 186 mOriginateTimestampFraction = BigEndian::HostSwap32(aFraction); 187 } 188 GetReceiveTimestampSeconds(void) const189 uint32_t GetReceiveTimestampSeconds(void) const { return BigEndian::HostSwap32(mReceiveTimestampSeconds); } SetReceiveTimestampSeconds(uint32_t aTimestamp)190 void SetReceiveTimestampSeconds(uint32_t aTimestamp) 191 { 192 mReceiveTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 193 } 194 GetReceiveTimestampFraction(void) const195 uint32_t GetReceiveTimestampFraction(void) const { return BigEndian::HostSwap32(mReceiveTimestampFraction); } SetReceiveTimestampFraction(uint32_t aFraction)196 void SetReceiveTimestampFraction(uint32_t aFraction) 197 { 198 mReceiveTimestampFraction = BigEndian::HostSwap32(aFraction); 199 } 200 GetTransmitTimestampSeconds(void) const201 uint32_t GetTransmitTimestampSeconds(void) const { return BigEndian::HostSwap32(mTransmitTimestampSeconds); } SetTransmitTimestampSeconds(uint32_t aTimestamp)202 void SetTransmitTimestampSeconds(uint32_t aTimestamp) 203 { 204 mTransmitTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 205 } 206 GetTransmitTimestampFraction(void) const207 uint32_t GetTransmitTimestampFraction(void) const { return BigEndian::HostSwap32(mTransmitTimestampFraction); } SetTransmitTimestampFraction(uint32_t aFraction)208 void SetTransmitTimestampFraction(uint32_t aFraction) 209 { 210 mTransmitTimestampFraction = BigEndian::HostSwap32(aFraction); 211 } 212 213 private: 214 static constexpr uint8_t kNtpVersion = 4; // Current NTP version. 215 static constexpr uint8_t kLeapOffset = 6; // Leap Indicator field offset. 216 static constexpr uint8_t kLeapMask = 0x03 << kLeapOffset; // Leap Indicator field mask. 217 static constexpr uint8_t kVersionOffset = 3; // Version field offset. 218 static constexpr uint8_t kVersionMask = 0x07 << kVersionOffset; // Version field mask. 219 static constexpr uint8_t kModeOffset = 0; // Mode field offset. 220 static constexpr uint8_t kModeMask = 0x07 << kModeOffset; // Mode filed mask. 221 222 uint8_t mFlags; // SNTP flags: LI Leap Indicator, VN Version Number and Mode. 223 uint8_t mStratum; // Packet Stratum. 224 uint8_t mPoll; // Maximum interval between successive messages, in log2 seconds. 225 uint8_t mPrecision; // The precision of the system clock, in log2 seconds. 226 uint32_t mRootDelay; // Total round-trip delay to the reference clock, in NTP short format. 227 uint32_t mRootDispersion; // Total dispersion to the reference clock. 228 uint32_t mReferenceId; // ID identifying the particular server or reference clock. 229 uint32_t mReferenceTimestampSeconds; // Time the system clock was last set or corrected (NTP format). 230 uint32_t mReferenceTimestampFraction; // Fraction part of above value. 231 uint32_t mOriginateTimestampSeconds; // Time at client when request departed for the server (NTP format). 232 uint32_t mOriginateTimestampFraction; // Fraction part of above value. 233 uint32_t mReceiveTimestampSeconds; // Time at server when request arrived from the client (NTP format). 234 uint32_t mReceiveTimestampFraction; // Fraction part of above value. 235 uint32_t mTransmitTimestampSeconds; // Time at server when the response left for the client (NTP format). 236 uint32_t mTransmitTimestampFraction; // Fraction part of above value. 237 } OT_TOOL_PACKED_END; 238 239 struct QueryMetadata : public Message::FooterData<QueryMetadata> 240 { 241 uint32_t mTransmitTimestamp; // Time at client when request departed for server 242 Callback<ResponseHandler> mResponseHandler; // Response handler callback 243 TimeMilli mTransmissionTime; // Time when the timer should shoot for this message 244 Ip6::Address mSourceAddress; // Source IPv6 address 245 Ip6::Address mDestinationAddress; // Destination IPv6 address 246 uint16_t mDestinationPort; // Destination UDP port 247 uint8_t mRetransmissionCount; // Number of retransmissions 248 }; 249 250 Message *NewMessage(const Header &aHeader); 251 Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata); 252 void DequeueMessage(Message &aMessage); 253 Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 254 void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 255 256 Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata); 257 void FinalizeSntpTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata, uint64_t aTime, Error aResult); 258 259 void HandleRetransmissionTimer(void); 260 void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 261 262 using RetxTimer = TimerMilliIn<Client, &Client::HandleRetransmissionTimer>; 263 using ClientSocket = Ip6::Udp::SocketIn<Client, &Client::HandleUdpReceive>; 264 265 ClientSocket mSocket; 266 MessageQueue mPendingQueries; 267 RetxTimer mRetransmissionTimer; 268 269 uint32_t mUnixEra; 270 }; 271 272 } // namespace Sntp 273 } // namespace ot 274 275 #endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 276 277 #endif // SNTP_CLIENT_HPP_ 278