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