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 */ 57 class Client : private NonCopyable 58 { 59 public: 60 typedef otSntpResponseHandler ResponseHandler; ///< Response handler callback. 61 62 /** 63 * Initializes the object. 64 * 65 * @param[in] aInstance A reference to the OpenThread instance. 66 * 67 */ 68 explicit Client(Instance &aInstance); 69 70 /** 71 * Starts the SNTP client. 72 * 73 * @retval kErrorNone Successfully started the SNTP client. 74 * @retval kErrorAlready The socket is already open. 75 */ 76 Error Start(void); 77 78 /** 79 * Stops the SNTP client. 80 * 81 * @retval kErrorNone Successfully stopped the SNTP client. 82 * 83 */ 84 Error Stop(void); 85 86 /** 87 * Returns the unix era number. 88 * 89 * @returns The unix era number. 90 * 91 */ GetUnixEra(void) const92 uint32_t GetUnixEra(void) const { return mUnixEra; } 93 94 /** 95 * Sets the unix era number. 96 * 97 * @param[in] aUnixEra The unix era number. 98 * 99 */ SetUnixEra(uint32_t aUnixEra)100 void SetUnixEra(uint32_t aUnixEra) { mUnixEra = aUnixEra; } 101 102 /** 103 * Sends an SNTP query. 104 * 105 * @param[in] aQuery A pointer to specify SNTP query parameters. 106 * @param[in] aHandler A function pointer that shall be called on response reception or time-out. 107 * @param[in] aContext A pointer to arbitrary context information. 108 * 109 * @retval kErrorNone Successfully sent SNTP query. 110 * @retval kErrorNoBufs Failed to allocate retransmission data. 111 * @retval kErrorInvalidArgs Invalid arguments supplied. 112 * 113 */ 114 Error Query(const otSntpQuery *aQuery, ResponseHandler aHandler, void *aContext); 115 116 private: 117 static constexpr uint32_t kTimeAt1970 = 2208988800UL; // num seconds between 1st Jan 1900 and 1st Jan 1970. 118 119 static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_SNTP_CLIENT_RESPONSE_TIMEOUT; 120 static constexpr uint8_t kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT; 121 122 OT_TOOL_PACKED_BEGIN 123 class Header : public Clearable<Header> 124 { 125 public: 126 enum Mode : uint8_t 127 { 128 kModeClient = 3, 129 kModeServer = 4, 130 }; 131 132 static constexpr uint8_t kKissCodeLength = 4; 133 Init(void)134 void Init(void) 135 { 136 Clear(); 137 mFlags = (kNtpVersion << kVersionOffset | kModeClient << kModeOffset); 138 } 139 GetFlags(void) const140 uint8_t GetFlags(void) const { return mFlags; } SetFlags(uint8_t aFlags)141 void SetFlags(uint8_t aFlags) { mFlags = aFlags; } 142 GetMode(void) const143 Mode GetMode(void) const { return static_cast<Mode>((mFlags & kModeMask) >> kModeOffset); } 144 GetStratum(void) const145 uint8_t GetStratum(void) const { return mStratum; } SetStratum(uint8_t aStratum)146 void SetStratum(uint8_t aStratum) { mStratum = aStratum; } 147 GetPoll(void) const148 uint8_t GetPoll(void) const { return mPoll; } SetPoll(uint8_t aPoll)149 void SetPoll(uint8_t aPoll) { mPoll = aPoll; } 150 GetPrecision(void) const151 uint8_t GetPrecision(void) const { return mPrecision; } SetPrecision(uint8_t aPrecision)152 void SetPrecision(uint8_t aPrecision) { mPrecision = aPrecision; } 153 GetRootDelay(void) const154 uint32_t GetRootDelay(void) const { return BigEndian::HostSwap32(mRootDelay); } SetRootDelay(uint32_t aRootDelay)155 void SetRootDelay(uint32_t aRootDelay) { mRootDelay = BigEndian::HostSwap32(aRootDelay); } 156 GetRootDispersion(void) const157 uint32_t GetRootDispersion(void) const { return BigEndian::HostSwap32(mRootDispersion); } SetRootDispersion(uint32_t aRootDispersion)158 void SetRootDispersion(uint32_t aRootDispersion) { mRootDispersion = BigEndian::HostSwap32(aRootDispersion); } 159 GetReferenceId(void) const160 uint32_t GetReferenceId(void) const { return BigEndian::HostSwap32(mReferenceId); } SetReferenceId(uint32_t aReferenceId)161 void SetReferenceId(uint32_t aReferenceId) { mReferenceId = BigEndian::HostSwap32(aReferenceId); } 162 GetKissCode(void)163 char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); } 164 GetReferenceTimestampSeconds(void) const165 uint32_t GetReferenceTimestampSeconds(void) const { return BigEndian::HostSwap32(mReferenceTimestampSeconds); } SetReferenceTimestampSeconds(uint32_t aTimestamp)166 void SetReferenceTimestampSeconds(uint32_t aTimestamp) 167 { 168 mReferenceTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 169 } 170 GetReferenceTimestampFraction(void) const171 uint32_t GetReferenceTimestampFraction(void) const 172 { 173 return BigEndian::HostSwap32(mReferenceTimestampFraction); 174 } SetReferenceTimestampFraction(uint32_t aFraction)175 void SetReferenceTimestampFraction(uint32_t aFraction) 176 { 177 mReferenceTimestampFraction = BigEndian::HostSwap32(aFraction); 178 } 179 GetOriginateTimestampSeconds(void) const180 uint32_t GetOriginateTimestampSeconds(void) const { return BigEndian::HostSwap32(mOriginateTimestampSeconds); } SetOriginateTimestampSeconds(uint32_t aTimestamp)181 void SetOriginateTimestampSeconds(uint32_t aTimestamp) 182 { 183 mOriginateTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 184 } 185 GetOriginateTimestampFraction(void) const186 uint32_t GetOriginateTimestampFraction(void) const 187 { 188 return BigEndian::HostSwap32(mOriginateTimestampFraction); 189 } SetOriginateTimestampFraction(uint32_t aFraction)190 void SetOriginateTimestampFraction(uint32_t aFraction) 191 { 192 mOriginateTimestampFraction = BigEndian::HostSwap32(aFraction); 193 } 194 GetReceiveTimestampSeconds(void) const195 uint32_t GetReceiveTimestampSeconds(void) const { return BigEndian::HostSwap32(mReceiveTimestampSeconds); } SetReceiveTimestampSeconds(uint32_t aTimestamp)196 void SetReceiveTimestampSeconds(uint32_t aTimestamp) 197 { 198 mReceiveTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 199 } 200 GetReceiveTimestampFraction(void) const201 uint32_t GetReceiveTimestampFraction(void) const { return BigEndian::HostSwap32(mReceiveTimestampFraction); } SetReceiveTimestampFraction(uint32_t aFraction)202 void SetReceiveTimestampFraction(uint32_t aFraction) 203 { 204 mReceiveTimestampFraction = BigEndian::HostSwap32(aFraction); 205 } 206 GetTransmitTimestampSeconds(void) const207 uint32_t GetTransmitTimestampSeconds(void) const { return BigEndian::HostSwap32(mTransmitTimestampSeconds); } SetTransmitTimestampSeconds(uint32_t aTimestamp)208 void SetTransmitTimestampSeconds(uint32_t aTimestamp) 209 { 210 mTransmitTimestampSeconds = BigEndian::HostSwap32(aTimestamp); 211 } 212 GetTransmitTimestampFraction(void) const213 uint32_t GetTransmitTimestampFraction(void) const { return BigEndian::HostSwap32(mTransmitTimestampFraction); } SetTransmitTimestampFraction(uint32_t aFraction)214 void SetTransmitTimestampFraction(uint32_t aFraction) 215 { 216 mTransmitTimestampFraction = BigEndian::HostSwap32(aFraction); 217 } 218 219 private: 220 static constexpr uint8_t kNtpVersion = 4; // Current NTP version. 221 static constexpr uint8_t kLeapOffset = 6; // Leap Indicator field offset. 222 static constexpr uint8_t kLeapMask = 0x03 << kLeapOffset; // Leap Indicator field mask. 223 static constexpr uint8_t kVersionOffset = 3; // Version field offset. 224 static constexpr uint8_t kVersionMask = 0x07 << kVersionOffset; // Version field mask. 225 static constexpr uint8_t kModeOffset = 0; // Mode field offset. 226 static constexpr uint8_t kModeMask = 0x07 << kModeOffset; // Mode filed mask. 227 228 uint8_t mFlags; // SNTP flags: LI Leap Indicator, VN Version Number and Mode. 229 uint8_t mStratum; // Packet Stratum. 230 uint8_t mPoll; // Maximum interval between successive messages, in log2 seconds. 231 uint8_t mPrecision; // The precision of the system clock, in log2 seconds. 232 uint32_t mRootDelay; // Total round-trip delay to the reference clock, in NTP short format. 233 uint32_t mRootDispersion; // Total dispersion to the reference clock. 234 uint32_t mReferenceId; // ID identifying the particular server or reference clock. 235 uint32_t mReferenceTimestampSeconds; // Time the system clock was last set or corrected (NTP format). 236 uint32_t mReferenceTimestampFraction; // Fraction part of above value. 237 uint32_t mOriginateTimestampSeconds; // Time at client when request departed for the server (NTP format). 238 uint32_t mOriginateTimestampFraction; // Fraction part of above value. 239 uint32_t mReceiveTimestampSeconds; // Time at server when request arrived from the client (NTP format). 240 uint32_t mReceiveTimestampFraction; // Fraction part of above value. 241 uint32_t mTransmitTimestampSeconds; // Time at server when the response left for the client (NTP format). 242 uint32_t mTransmitTimestampFraction; // Fraction part of above value. 243 } OT_TOOL_PACKED_END; 244 245 class QueryMetadata 246 { 247 public: AppendTo(Message & aMessage) const248 Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); } ReadFrom(const Message & aMessage)249 void ReadFrom(const Message &aMessage) 250 { 251 IgnoreError(aMessage.Read(aMessage.GetLength() - sizeof(*this), *this)); 252 } 253 UpdateIn(Message & aMessage) const254 void UpdateIn(Message &aMessage) const { aMessage.Write(aMessage.GetLength() - sizeof(*this), *this); } 255 256 uint32_t mTransmitTimestamp; // Time at client when request departed for server 257 Callback<ResponseHandler> mResponseHandler; // Response handler callback 258 TimeMilli mTransmissionTime; // Time when the timer should shoot for this message 259 Ip6::Address mSourceAddress; // Source IPv6 address 260 Ip6::Address mDestinationAddress; // Destination IPv6 address 261 uint16_t mDestinationPort; // Destination UDP port 262 uint8_t mRetransmissionCount; // Number of retransmissions 263 }; 264 265 Message *NewMessage(const Header &aHeader); 266 Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata); 267 void DequeueMessage(Message &aMessage); 268 Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 269 void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 270 271 Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata); 272 void FinalizeSntpTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata, uint64_t aTime, Error aResult); 273 274 void HandleRetransmissionTimer(void); 275 276 static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 277 void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 278 279 using RetxTimer = TimerMilliIn<Client, &Client::HandleRetransmissionTimer>; 280 281 Ip6::Udp::Socket mSocket; 282 283 MessageQueue mPendingQueries; 284 RetxTimer mRetransmissionTimer; 285 286 uint32_t mUnixEra; 287 }; 288 289 } // namespace Sntp 290 } // namespace ot 291 292 #endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 293 294 #endif // SNTP_CLIENT_HPP_ 295