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/message.hpp" 39 #include "common/non_copyable.hpp" 40 #include "common/timer.hpp" 41 #include "net/ip6.hpp" 42 #include "net/netif.hpp" 43 44 /** 45 * @file 46 * This file includes definitions for the SNTP client. 47 */ 48 49 namespace ot { 50 namespace Sntp { 51 52 using ot::Encoding::BigEndian::HostSwap32; 53 54 /** 55 * This class implements SNTP header generation and parsing. 56 * 57 */ 58 OT_TOOL_PACKED_BEGIN 59 class Header 60 { 61 public: 62 /** 63 * Default constructor for SNTP Header. 64 * 65 */ 66 Header(void); 67 68 /** 69 * Defines supported SNTP modes. 70 * 71 */ 72 enum Mode : uint8_t 73 { 74 kModeClient = 3, 75 kModeServer = 4, 76 }; 77 78 static constexpr uint8_t kKissCodeLength = 4; ///< Length of the kiss code in ASCII format 79 80 /** 81 * This method returns the flags field value. 82 * 83 * @returns Value of the flags field (LI, VN and Mode). 84 * 85 */ GetFlags(void) const86 uint8_t GetFlags(void) const { return mFlags; } 87 88 /** 89 * This method sets the flags field. 90 * 91 * @param[in] aFlags The value of the flags field. 92 * 93 */ SetFlags(uint8_t aFlags)94 void SetFlags(uint8_t aFlags) { mFlags = aFlags; } 95 96 /** 97 * This method returns the SNTP operational mode. 98 * 99 * @returns SNTP operational mode. 100 * 101 */ GetMode(void) const102 Mode GetMode(void) const { return static_cast<Mode>((mFlags & kModeMask) >> kModeOffset); } 103 104 /** 105 * This method returns the packet stratum field value. 106 * 107 * @returns Value of the packet stratum. 108 * 109 */ GetStratum(void) const110 uint8_t GetStratum(void) const { return mStratum; } 111 112 /** 113 * This method sets the packet stratum field value. 114 * 115 * @param[in] aStratum The value of the packet stratum field. 116 * 117 */ SetStratum(uint8_t aStratum)118 void SetStratum(uint8_t aStratum) { mStratum = aStratum; } 119 120 /** 121 * This method returns the poll field value. 122 * 123 * @returns Value of the poll field. 124 * 125 */ GetPoll(void) const126 uint8_t GetPoll(void) const { return mPoll; } 127 128 /** 129 * This method sets the poll field. 130 * 131 * @param[in] aPoll The value of the poll field. 132 * 133 */ SetPoll(uint8_t aPoll)134 void SetPoll(uint8_t aPoll) { mPoll = aPoll; } 135 136 /** 137 * This method returns the precision field value. 138 * 139 * @returns Value of the precision field. 140 * 141 */ GetPrecision(void) const142 uint8_t GetPrecision(void) const { return mPrecision; } 143 144 /** 145 * This method sets the precision field. 146 * 147 * @param[in] aPrecision The value of the precision field. 148 * 149 */ SetPrecision(uint8_t aPrecision)150 void SetPrecision(uint8_t aPrecision) { mPrecision = aPrecision; } 151 152 /** 153 * This method returns the root delay field value. 154 * 155 * @returns Value of the root delay field. 156 * 157 */ GetRootDelay(void) const158 uint32_t GetRootDelay(void) const { return HostSwap32(mRootDelay); } 159 160 /** 161 * This method sets the root delay field. 162 * 163 * @param[in] aRootDelay The value of the root delay field. 164 * 165 */ SetRootDelay(uint32_t aRootDelay)166 void SetRootDelay(uint32_t aRootDelay) { mRootDelay = HostSwap32(aRootDelay); } 167 168 /** 169 * This method returns the root dispersion field value. 170 * 171 * @returns Value of the root dispersion field. 172 * 173 */ GetRootDispersion(void) const174 uint32_t GetRootDispersion(void) const { return HostSwap32(mRootDispersion); } 175 176 /** 177 * This method sets the root dispersion field. 178 * 179 * @param[in] aRootDispersion The value of the root dispersion field. 180 * 181 */ SetRootDispersion(uint32_t aRootDispersion)182 void SetRootDispersion(uint32_t aRootDispersion) { mRootDispersion = HostSwap32(aRootDispersion); } 183 184 /** 185 * This method returns the reference identifier field value. 186 * 187 * @returns Value of the reference identifier field. 188 * 189 */ GetReferenceId(void) const190 uint32_t GetReferenceId(void) const { return HostSwap32(mReferenceId); } 191 192 /** 193 * This method sets the reference identifier field. 194 * 195 * @param[in] aReferenceId The value of the reference identifier field. 196 * 197 */ SetReferenceId(uint32_t aReferenceId)198 void SetReferenceId(uint32_t aReferenceId) { mReferenceId = HostSwap32(aReferenceId); } 199 200 /** 201 * This method returns the kiss code in ASCII format. 202 * 203 * @returns Value of the reference identifier field in ASCII format. 204 * 205 */ GetKissCode(void)206 char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); } 207 208 /** 209 * This method returns the reference timestamp seconds field. 210 * 211 * @returns Value of the reference timestamp seconds field. 212 * 213 */ GetReferenceTimestampSeconds(void) const214 uint32_t GetReferenceTimestampSeconds(void) const { return HostSwap32(mReferenceTimestampSeconds); } 215 216 /** 217 * This method sets the reference timestamp seconds field. 218 * 219 * @param[in] aReferenceTimestampSeconds Value of the reference timestamp seconds field. 220 * 221 */ SetReferenceTimestampSeconds(uint32_t aReferenceTimestampSeconds)222 void SetReferenceTimestampSeconds(uint32_t aReferenceTimestampSeconds) 223 { 224 mReferenceTimestampSeconds = HostSwap32(aReferenceTimestampSeconds); 225 } 226 227 /** 228 * This method returns the reference timestamp fraction field. 229 * 230 * @returns Value of the reference timestamp fraction field. 231 * 232 */ GetReferenceTimestampFraction(void) const233 uint32_t GetReferenceTimestampFraction(void) const { return HostSwap32(mReferenceTimestampFraction); } 234 235 /** 236 * This method sets the reference timestamp fraction field. 237 * 238 * @param[in] aReferenceTimestampFraction Value of the reference timestamp fraction field. 239 * 240 */ SetReferenceTimestampFraction(uint32_t aReferenceTimestampFraction)241 void SetReferenceTimestampFraction(uint32_t aReferenceTimestampFraction) 242 { 243 mReferenceTimestampFraction = HostSwap32(aReferenceTimestampFraction); 244 } 245 246 /** 247 * This method returns the originate timestamp seconds field. 248 * 249 * @returns Value of the originate timestamp seconds field. 250 * 251 */ GetOriginateTimestampSeconds(void) const252 uint32_t GetOriginateTimestampSeconds(void) const { return HostSwap32(mOriginateTimestampSeconds); } 253 254 /** 255 * This method sets the originate timestamp seconds field. 256 * 257 * @param[in] aOriginateTimestampSeconds Value of the originate timestamp seconds field. 258 * 259 */ SetOriginateTimestampSeconds(uint32_t aOriginateTimestampSeconds)260 void SetOriginateTimestampSeconds(uint32_t aOriginateTimestampSeconds) 261 { 262 mOriginateTimestampSeconds = HostSwap32(aOriginateTimestampSeconds); 263 } 264 265 /** 266 * This method returns the originate timestamp fraction field. 267 * 268 * @returns Value of the originate timestamp fraction field. 269 * 270 */ GetOriginateTimestampFraction(void) const271 uint32_t GetOriginateTimestampFraction(void) const { return HostSwap32(mOriginateTimestampFraction); } 272 273 /** 274 * This method sets the originate timestamp fraction field. 275 * 276 * @param[in] aOriginateTimestampFraction Value of the originate timestamp fraction field. 277 * 278 */ SetOriginateTimestampFraction(uint32_t aOriginateTimestampFraction)279 void SetOriginateTimestampFraction(uint32_t aOriginateTimestampFraction) 280 { 281 mOriginateTimestampFraction = HostSwap32(aOriginateTimestampFraction); 282 } 283 284 /** 285 * This method returns the receive timestamp seconds field. 286 * 287 * @returns Value of the receive timestamp seconds field. 288 * 289 */ GetReceiveTimestampSeconds(void) const290 uint32_t GetReceiveTimestampSeconds(void) const { return HostSwap32(mReceiveTimestampSeconds); } 291 292 /** 293 * This method sets the receive timestamp seconds field. 294 * 295 * @param[in] aReceiveTimestampSeconds Value of the receive timestamp seconds field. 296 * 297 */ SetReceiveTimestampSeconds(uint32_t aReceiveTimestampSeconds)298 void SetReceiveTimestampSeconds(uint32_t aReceiveTimestampSeconds) 299 { 300 mReceiveTimestampSeconds = HostSwap32(aReceiveTimestampSeconds); 301 } 302 303 /** 304 * This method returns the receive timestamp fraction field. 305 * 306 * @returns Value of the receive timestamp fraction field. 307 * 308 */ GetReceiveTimestampFraction(void) const309 uint32_t GetReceiveTimestampFraction(void) const { return HostSwap32(mReceiveTimestampFraction); } 310 311 /** 312 * This method sets the receive timestamp fraction field. 313 * 314 * @param[in] aReceiveTimestampFraction Value of the receive timestamp fraction field. 315 * 316 */ SetReceiveTimestampFraction(uint32_t aReceiveTimestampFraction)317 void SetReceiveTimestampFraction(uint32_t aReceiveTimestampFraction) 318 { 319 mReceiveTimestampFraction = HostSwap32(aReceiveTimestampFraction); 320 } 321 322 /** 323 * This method returns the transmit timestamp seconds field. 324 * 325 * @returns Value of the transmit timestamp seconds field. 326 * 327 */ GetTransmitTimestampSeconds(void) const328 uint32_t GetTransmitTimestampSeconds(void) const { return HostSwap32(mTransmitTimestampSeconds); } 329 330 /** 331 * This method sets the transmit timestamp seconds field. 332 * 333 * @param[in] aTransmitTimestampSeconds Value of the transmit timestamp seconds field. 334 * 335 */ SetTransmitTimestampSeconds(uint32_t aTransmitTimestampSeconds)336 void SetTransmitTimestampSeconds(uint32_t aTransmitTimestampSeconds) 337 { 338 mTransmitTimestampSeconds = HostSwap32(aTransmitTimestampSeconds); 339 } 340 341 /** 342 * This method returns the transmit timestamp fraction field. 343 * 344 * @returns Value of the transmit timestamp fraction field. 345 * 346 */ GetTransmitTimestampFraction(void) const347 uint32_t GetTransmitTimestampFraction(void) const { return HostSwap32(mTransmitTimestampFraction); } 348 349 /** 350 * This method sets the transmit timestamp fraction field. 351 * 352 * @param[in] aTransmitTimestampFraction Value of the transmit timestamp fraction field. 353 * 354 */ SetTransmitTimestampFraction(uint32_t aTransmitTimestampFraction)355 void SetTransmitTimestampFraction(uint32_t aTransmitTimestampFraction) 356 { 357 mTransmitTimestampFraction = HostSwap32(aTransmitTimestampFraction); 358 } 359 360 private: 361 static constexpr uint8_t kNtpVersion = 4; // Current NTP version. 362 static constexpr uint8_t kLeapOffset = 6; // Leap Indicator field offset. 363 static constexpr uint8_t kLeapMask = 0x03 << kLeapOffset; // Leap Indicator field mask. 364 static constexpr uint8_t kVersionOffset = 3; // Version field offset. 365 static constexpr uint8_t kVersionMask = 0x07 << kVersionOffset; // Version field mask. 366 static constexpr uint8_t kModeOffset = 0; // Mode field offset. 367 static constexpr uint8_t kModeMask = 0x07 << kModeOffset; // Mode filed mask. 368 369 uint8_t mFlags; // SNTP flags: LI Leap Indicator, VN Version Number and Mode. 370 uint8_t mStratum; // Packet Stratum. 371 uint8_t mPoll; // Maximum interval between successive messages, in log2 seconds. 372 uint8_t mPrecision; // The precision of the system clock, in log2 seconds. 373 uint32_t mRootDelay; // Total round-trip delay to the reference clock, in NTP short format. 374 uint32_t mRootDispersion; // Total dispersion to the reference clock. 375 uint32_t mReferenceId; // ID identifying the particular server or reference clock. 376 uint32_t mReferenceTimestampSeconds; // Time the system clock was last set or corrected (NTP format). 377 uint32_t mReferenceTimestampFraction; // Fraction part of above value. 378 uint32_t mOriginateTimestampSeconds; // Time at the client when the request departed for the server (NTP format). 379 uint32_t mOriginateTimestampFraction; // Fraction part of above value. 380 uint32_t mReceiveTimestampSeconds; // Time at the server when the request arrived from the client (NTP format). 381 uint32_t mReceiveTimestampFraction; // Fraction part of above value. 382 uint32_t mTransmitTimestampSeconds; // Time at the server when the response left for the client (NTP format). 383 uint32_t mTransmitTimestampFraction; // Fraction part of above value. 384 } OT_TOOL_PACKED_END; 385 386 /** 387 * This class implements metadata required for SNTP retransmission. 388 * 389 */ 390 class QueryMetadata 391 { 392 friend class Client; 393 394 public: 395 /** 396 * Default constructor for the object. 397 * 398 */ 399 QueryMetadata(void); 400 401 /** 402 * This constructor initializes the object with specific values. 403 * 404 * @param[in] aHandler Pointer to a handler function for the response. 405 * @param[in] aContext Context for the handler function. 406 * 407 */ 408 QueryMetadata(otSntpResponseHandler aHandler, void *aContext); 409 410 /** 411 * This method appends request data to the message. 412 * 413 * @param[in] aMessage A reference to the message. 414 * 415 * @retval kErrorNone Successfully appended the bytes. 416 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 417 * 418 */ AppendTo(Message & aMessage) const419 Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); } 420 421 /** 422 * This method reads request data from the message. 423 * 424 * @param[in] aMessage A reference to the message. 425 * 426 */ ReadFrom(const Message & aMessage)427 void ReadFrom(const Message &aMessage) 428 { 429 Error error = aMessage.Read(aMessage.GetLength() - sizeof(*this), *this); 430 431 OT_ASSERT(error == kErrorNone); 432 OT_UNUSED_VARIABLE(error); 433 } 434 435 /** 436 * This method updates request data in the message. 437 * 438 * @param[in] aMessage A reference to the message. 439 * 440 */ UpdateIn(Message & aMessage) const441 void UpdateIn(Message &aMessage) const { aMessage.Write(aMessage.GetLength() - sizeof(*this), *this); } 442 443 private: 444 uint32_t mTransmitTimestamp; ///< Time at the client when the request departed for the server. 445 otSntpResponseHandler mResponseHandler; ///< A function pointer that is called on response reception. 446 void * mResponseContext; ///< A pointer to arbitrary context information. 447 TimeMilli mTransmissionTime; ///< Time when the timer should shoot for this message. 448 Ip6::Address mSourceAddress; ///< IPv6 address of the message source. 449 Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination. 450 uint16_t mDestinationPort; ///< UDP port of the message destination. 451 uint8_t mRetransmissionCount; ///< Number of retransmissions. 452 }; 453 454 /** 455 * This class implements SNTP client. 456 * 457 */ 458 class Client : private NonCopyable 459 { 460 public: 461 /** 462 * This constructor initializes the object. 463 * 464 * @param[in] aInstance A reference to the OpenThread instance. 465 * 466 */ 467 explicit Client(Instance &aInstance); 468 469 /** 470 * This method starts the SNTP client. 471 * 472 * @retval kErrorNone Successfully started the SNTP client. 473 * @retval kErrorAlready The socket is already open. 474 */ 475 Error Start(void); 476 477 /** 478 * This method stops the SNTP client. 479 * 480 * @retval kErrorNone Successfully stopped the SNTP client. 481 * 482 */ 483 Error Stop(void); 484 485 /** 486 * This method returns the unix era number. 487 * 488 * @returns The unix era number. 489 * 490 */ GetUnixEra(void) const491 uint32_t GetUnixEra(void) const { return mUnixEra; } 492 493 /** 494 * This method sets the unix era number. 495 * 496 * @param[in] aUnixEra The unix era number. 497 * 498 */ SetUnixEra(uint32_t aUnixEra)499 void SetUnixEra(uint32_t aUnixEra) { mUnixEra = aUnixEra; } 500 501 /** 502 * This method sends an SNTP query. 503 * 504 * @param[in] aQuery A pointer to specify SNTP query parameters. 505 * @param[in] aHandler A function pointer that shall be called on response reception or time-out. 506 * @param[in] aContext A pointer to arbitrary context information. 507 * 508 * @retval kErrorNone Successfully sent SNTP query. 509 * @retval kErrorNoBufs Failed to allocate retransmission data. 510 * @retval kErrorInvalidArgs Invalid arguments supplied. 511 * 512 */ 513 Error Query(const otSntpQuery *aQuery, otSntpResponseHandler aHandler, void *aContext); 514 515 private: 516 static constexpr uint32_t kTimeAt1970 = 2208988800UL; // num seconds between 1st Jan 1900 and 1st Jan 1970. 517 518 static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_SNTP_CLIENT_RESPONSE_TIMEOUT; 519 static constexpr uint8_t kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT; 520 521 Message *NewMessage(const Header &aHeader); 522 Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata); 523 void DequeueMessage(Message &aMessage); 524 Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 525 void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 526 527 Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata); 528 void FinalizeSntpTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata, uint64_t aTime, Error aResult); 529 530 static void HandleRetransmissionTimer(Timer &aTimer); 531 void HandleRetransmissionTimer(void); 532 533 static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); 534 void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 535 536 Ip6::Udp::Socket mSocket; 537 538 MessageQueue mPendingQueries; 539 TimerMilli mRetransmissionTimer; 540 541 uint32_t mUnixEra; 542 }; 543 544 } // namespace Sntp 545 } // namespace ot 546 547 #endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 548 549 #endif // SNTP_CLIENT_HPP_ 550