1 /*
2  *  Copyright (c) 2020, 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 /**
30  * @file
31  *   This file includes definitions for IPv6 Neighbor Discovery (ND).
32  *
33  * See RFC 4861 (https://tools.ietf.org/html/rfc4861) and RFC 4191 (https://tools.ietf.org/html/rfc4191).
34  *
35  */
36 
37 #ifndef ND6_HPP_
38 #define ND6_HPP_
39 
40 #include "openthread-core-config.h"
41 
42 #include <stdint.h>
43 
44 #include <openthread/netdata.h>
45 #include <openthread/platform/toolchain.h>
46 
47 #include "common/const_cast.hpp"
48 #include "common/encoding.hpp"
49 #include "common/equatable.hpp"
50 #include "common/heap_array.hpp"
51 #include "net/icmp6.hpp"
52 #include "net/ip6.hpp"
53 #include "thread/network_data_types.hpp"
54 
55 namespace ot {
56 namespace Ip6 {
57 namespace Nd {
58 
59 typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference
60 
61 /**
62  * Represents the variable length options in Neighbor Discovery messages.
63  *
64  * @sa PrefixInfoOption
65  * @sa RouteInfoOption
66  *
67  */
68 OT_TOOL_PACKED_BEGIN
69 class Option
70 {
71     friend class RouterAdvert;
72 
73 public:
74     enum Type : uint8_t
75     {
76         kTypePrefixInfo       = 3,  ///< Prefix Information Option.
77         kTypeRouteInfo        = 24, ///< Route Information Option.
78         kTypeRaFlagsExtension = 26, ///< RA Flags Extension Option.
79     };
80 
81     static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets.
82 
83     /**
84      * Gets the option type.
85      *
86      * @returns  The option type.
87      *
88      */
GetType(void) const89     uint8_t GetType(void) const { return mType; }
90 
91     /**
92      * Sets the option type.
93      *
94      * @param[in] aType  The option type.
95      *
96      *
97      */
SetType(Type aType)98     void SetType(Type aType) { mType = aType; }
99 
100     /**
101      * Sets the length based on a given total option size in bytes.
102      *
103      * Th option must end on a 64-bit boundary, so the length is derived as `(aSize + 7) / 8 * 8`.
104      *
105      * @param[in]  aSize  The size of option in bytes.
106      *
107      */
SetSize(uint16_t aSize)108     void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); }
109 
110     /**
111      * Returns the size of the option in bytes.
112      *
113      * @returns  The size of the option in bytes.
114      *
115      */
GetSize(void) const116     uint16_t GetSize(void) const { return mLength * kLengthUnit; }
117 
118     /**
119      * Sets the length of the option (in unit of 8 bytes).
120      *
121      * @param[in]  aLength  The length of the option in unit of 8 bytes.
122      *
123      */
SetLength(uint8_t aLength)124     void SetLength(uint8_t aLength) { mLength = aLength; }
125 
126     /**
127      * Returns the length of the option (in unit of 8 bytes).
128      *
129      * @returns  The length of the option in unit of 8 bytes.
130      *
131      */
GetLength(void) const132     uint16_t GetLength(void) const { return mLength; }
133 
134     /**
135      * Indicates whether or not this option is valid.
136      *
137      * @retval TRUE   The option is valid.
138      * @retval FALSE  The option is not valid.
139      *
140      */
IsValid(void) const141     bool IsValid(void) const { return mLength > 0; }
142 
143 private:
144     class Iterator : public Unequatable<Iterator>
145     {
146     public:
147         Iterator(void);
148         Iterator(const void *aStart, const void *aEnd);
149 
operator *(void)150         const Option &operator*(void) { return *mOption; }
operator ++(void)151         void          operator++(void) { Advance(); }
operator ++(int)152         void          operator++(int) { Advance(); }
operator ==(const Iterator & aOther) const153         bool          operator==(const Iterator &aOther) const { return mOption == aOther.mOption; }
154 
155     private:
156         static const Option *Next(const Option *aOption);
157         void                 Advance(void);
158         const Option        *Validate(const Option *aOption) const;
159 
160         const Option *mOption;
161         const Option *mEnd;
162     };
163 
164     uint8_t mType;   // Type of the option.
165     uint8_t mLength; // Length of the option in unit of 8 octets, including the `mType` and `mLength` fields.
166 } OT_TOOL_PACKED_END;
167 
168 /**
169  * Represents the Prefix Information Option.
170  *
171  * See section 4.6.2 of RFC 4861 for definition of this option [https://tools.ietf.org/html/rfc4861#section-4.6.2]
172  *
173  */
174 OT_TOOL_PACKED_BEGIN
175 class PrefixInfoOption : public Option, private Clearable<PrefixInfoOption>
176 {
177     friend class Clearable<PrefixInfoOption>;
178 
179 public:
180     static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type.
181 
182     /**
183      * Initializes the Prefix Info option with proper type and length and sets all other fields to zero.
184      *
185      */
186     void Init(void);
187 
188     /**
189      * Indicates whether or not the on-link flag is set.
190      *
191      * @retval TRUE  The on-link flag is set.
192      * @retval FALSE The on-link flag is not set.
193      *
194      */
IsOnLinkFlagSet(void) const195     bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlagMask) != 0; }
196 
197     /**
198      * Sets the on-link (L) flag.
199      *
200      */
SetOnLinkFlag(void)201     void SetOnLinkFlag(void) { mFlags |= kOnLinkFlagMask; }
202 
203     /**
204      * Clears the on-link (L) flag.
205      *
206      */
ClearOnLinkFlag(void)207     void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlagMask; }
208 
209     /**
210      * Indicates whether or not the autonomous address-configuration (A) flag is set.
211      *
212      * @retval TRUE  The auto address-config flag is set.
213      * @retval FALSE The auto address-config flag is not set.
214      *
215      */
IsAutoAddrConfigFlagSet(void) const216     bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlagMask) != 0; }
217 
218     /**
219      * Sets the autonomous address-configuration (A) flag.
220      *
221      */
SetAutoAddrConfigFlag(void)222     void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlagMask; }
223 
224     /**
225      * Clears the autonomous address-configuration (A) flag.
226      *
227      */
ClearAutoAddrConfigFlag(void)228     void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlagMask; }
229 
230     /**
231      * Sets the valid lifetime of the prefix in seconds.
232      *
233      * @param[in]  aValidLifetime  The valid lifetime in seconds.
234      *
235      */
SetValidLifetime(uint32_t aValidLifetime)236     void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = BigEndian::HostSwap32(aValidLifetime); }
237 
238     /**
239      * THis method gets the valid lifetime of the prefix in seconds.
240      *
241      * @returns  The valid lifetime in seconds.
242      *
243      */
GetValidLifetime(void) const244     uint32_t GetValidLifetime(void) const { return BigEndian::HostSwap32(mValidLifetime); }
245 
246     /**
247      * Sets the preferred lifetime of the prefix in seconds.
248      *
249      * @param[in]  aPreferredLifetime  The preferred lifetime in seconds.
250      *
251      */
SetPreferredLifetime(uint32_t aPreferredLifetime)252     void SetPreferredLifetime(uint32_t aPreferredLifetime)
253     {
254         mPreferredLifetime = BigEndian::HostSwap32(aPreferredLifetime);
255     }
256 
257     /**
258      * THis method returns the preferred lifetime of the prefix in seconds.
259      *
260      * @returns  The preferred lifetime in seconds.
261      *
262      */
GetPreferredLifetime(void) const263     uint32_t GetPreferredLifetime(void) const { return BigEndian::HostSwap32(mPreferredLifetime); }
264 
265     /**
266      * Sets the prefix.
267      *
268      * @param[in]  aPrefix  The prefix contained in this option.
269      *
270      */
271     void SetPrefix(const Prefix &aPrefix);
272 
273     /**
274      * Gets the prefix in this option.
275      *
276      * @param[out] aPrefix   Reference to a `Prefix` to return the prefix.
277      *
278      */
279     void GetPrefix(Prefix &aPrefix) const;
280 
281     /**
282      * Indicates whether or not the option is valid.
283      *
284      * @retval TRUE  The option is valid
285      * @retval FALSE The option is not valid.
286      *
287      */
288     bool IsValid(void) const;
289 
290     PrefixInfoOption(void) = delete;
291 
292 private:
293     // Prefix Information Option
294     //
295     //   0                   1                   2                   3
296     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
297     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298     //  |     Type      |    Length     | Prefix Length |L|A| Reserved1 |
299     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
300     //  |                         Valid Lifetime                        |
301     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302     //  |                       Preferred Lifetime                      |
303     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304     //  |                           Reserved2                           |
305     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306     //  |                                                               |
307     //  +                                                               +
308     //  |                                                               |
309     //  +                            Prefix                             +
310     //  |                                                               |
311     //  +                                                               +
312     //  |                                                               |
313     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314 
315     static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Autonomous address-configuration flag.
316     static constexpr uint8_t kOnLinkFlagMask     = 0x80; // On-link flag.
317 
318     uint8_t  mPrefixLength;      // The prefix length in bits.
319     uint8_t  mFlags;             // The flags field.
320     uint32_t mValidLifetime;     // The valid lifetime of the prefix.
321     uint32_t mPreferredLifetime; // The preferred lifetime of the prefix.
322     uint32_t mReserved2;         // The reserved field.
323     Address  mPrefix;            // The prefix.
324 } OT_TOOL_PACKED_END;
325 
326 static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure");
327 
328 /**
329  * Represents the Route Information Option.
330  *
331  * See section 2.3 of RFC 4191 for definition of this option. [https://tools.ietf.org/html/rfc4191#section-2.3]
332  *
333  */
334 OT_TOOL_PACKED_BEGIN
335 class RouteInfoOption : public Option, private Clearable<RouteInfoOption>
336 {
337     friend class Clearable<RouteInfoOption>;
338 
339 public:
340     static constexpr uint16_t kMinSize = kLengthUnit;    ///< Minimum size (in bytes) of a Route Info Option
341     static constexpr Type     kType    = kTypeRouteInfo; ///< Route Information Option Type.
342 
343     /**
344      * Initializes the option setting the type and clearing (setting to zero) all other fields.
345      *
346      */
347     void Init(void);
348 
349     /**
350      * Sets the route preference.
351      *
352      * @param[in]  aPreference  The route preference.
353      *
354      */
355     void SetPreference(RoutePreference aPreference);
356 
357     /**
358      * Gets the route preference.
359      *
360      * @returns  The route preference.
361      *
362      */
363     RoutePreference GetPreference(void) const;
364 
365     /**
366      * Sets the lifetime of the route in seconds.
367      *
368      * @param[in]  aLifetime  The lifetime of the route in seconds.
369      *
370      */
SetRouteLifetime(uint32_t aLifetime)371     void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = BigEndian::HostSwap32(aLifetime); }
372 
373     /**
374      * Gets Route Lifetime in seconds.
375      *
376      * @returns  The Route Lifetime in seconds.
377      *
378      */
GetRouteLifetime(void) const379     uint32_t GetRouteLifetime(void) const { return BigEndian::HostSwap32(mRouteLifetime); }
380 
381     /**
382      * Sets the prefix and adjusts the option length based on the prefix length.
383      *
384      * @param[in]  aPrefix  The prefix contained in this option.
385      *
386      */
387     void SetPrefix(const Prefix &aPrefix);
388 
389     /**
390      * Gets the prefix in this option.
391      *
392      * @param[out] aPrefix   Reference to a `Prefix` to return the prefix.
393      *
394      */
395     void GetPrefix(Prefix &aPrefix) const;
396 
397     /**
398      * Tells whether this option is valid.
399      *
400      * @returns  A boolean indicates whether this option is valid.
401      *
402      */
403     bool IsValid(void) const;
404 
405     /**
406      * Calculates the minimum option length for a given prefix length.
407      *
408      * The option length (which is in unit of 8 octets) can be 1, 2, or 3 depending on the prefix length. It can be 1
409      * for a zero prefix length, 2 if the prefix length is not greater than 64, and 3 otherwise.
410      *
411      * @param[in] aPrefixLength   The prefix length (in bits).
412      *
413      * @returns The option length (in unit of 8 octet) for @p aPrefixLength.
414      *
415      */
416     static uint8_t OptionLengthForPrefix(uint8_t aPrefixLength);
417 
418     /**
419      * Calculates the minimum option size (in bytes) for a given prefix length.
420      *
421      * @param[in] aPrefixLength   The prefix length (in bits).
422      *
423      * @returns The option size (in bytes) for @p aPrefixLength.
424      *
425      */
OptionSizeForPrefix(uint8_t aPrefixLength)426     static uint16_t OptionSizeForPrefix(uint8_t aPrefixLength)
427     {
428         return kLengthUnit * OptionLengthForPrefix(aPrefixLength);
429     }
430 
431     RouteInfoOption(void) = delete;
432 
433 private:
434     // Route Information Option
435     //
436     //   0                   1                   2                   3
437     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
438     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
439     //  |     Type      |    Length     | Prefix Length |Resvd|Prf|Resvd|
440     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
441     //  |                        Route Lifetime                         |
442     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
443     //  |                   Prefix (Variable Length)                    |
444     //  .                                                               .
445     //  .                                                               .
446     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
447 
448     static constexpr uint8_t kPreferenceOffset = 3;
449     static constexpr uint8_t kPreferenceMask   = 3 << kPreferenceOffset;
450 
GetPrefixBytes(void)451     uint8_t       *GetPrefixBytes(void) { return AsNonConst(AsConst(this)->GetPrefixBytes()); }
GetPrefixBytes(void) const452     const uint8_t *GetPrefixBytes(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
453 
454     uint8_t  mPrefixLength;  // The prefix length in bits.
455     uint8_t  mResvdPrf;      // The preference.
456     uint32_t mRouteLifetime; // The lifetime in seconds.
457     // Followed by prefix bytes (variable length).
458 
459 } OT_TOOL_PACKED_END;
460 
461 static_assert(sizeof(RouteInfoOption) == 8, "invalid RouteInfoOption structure");
462 
463 /**
464  * Represents an RA Flags Extension Option.
465  *
466  * See RFC-5175 [https://tools.ietf.org/html/rfc5175]
467  *
468  */
469 OT_TOOL_PACKED_BEGIN
470 class RaFlagsExtOption : public Option, private Clearable<RaFlagsExtOption>
471 {
472     friend class Clearable<RaFlagsExtOption>;
473 
474 public:
475     static constexpr Type kType = kTypeRaFlagsExtension; ///< RA Flags Extension Option type.
476 
477     /**
478      * Initializes the RA Flags Extension option with proper type and length and sets all flags to zero.
479      *
480      */
481     void Init(void);
482 
483     /**
484      * Tells whether this option is valid.
485      *
486      * @returns  A boolean indicates whether this option is valid.
487      *
488      */
IsValid(void) const489     bool IsValid(void) const { return GetSize() >= sizeof(*this); }
490 
491     /**
492      * Indicates whether or not the Stub Router Flag is set.
493      *
494      * @retval TRUE   The Stub Router Flag is set.
495      * @retval FALSE  The Stub Router Flag is not set.
496      *
497      */
IsStubRouterFlagSet(void) const498     bool IsStubRouterFlagSet(void) const { return (mFlags[0] & kStubRouterFlag) != 0; }
499 
500     /**
501      * Sets the Stub Router Flag.
502      *
503      */
SetStubRouterFlag(void)504     void SetStubRouterFlag(void) { mFlags[0] |= kStubRouterFlag; }
505 
506     RaFlagsExtOption(void) = delete;
507 
508 private:
509     // RA Flags Extension Option
510     //
511     //   0                   1                   2                   3
512     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
513     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514     //  |     Type      |    Length     |         Bit fields available ..
515     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516     //  ... for assignment                                              |
517     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                .
518 
519     // Stub router flags defined in [https://www.ietf.org/archive/id/draft-hui-stub-router-ra-flag-01.txt]
520 
521     static constexpr uint8_t kStubRouterFlag = 1 << 7;
522 
523     uint8_t mFlags[6];
524 } OT_TOOL_PACKED_END;
525 
526 static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption structure");
527 
528 /**
529  * Defines Router Advertisement components.
530  *
531  */
532 class RouterAdvert
533 {
534 public:
535     /**
536      * Represent an RA message header.
537      *
538      * See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191]
539      *
540      */
541     OT_TOOL_PACKED_BEGIN
542     class Header : public Equatable<Header>, public Clearable<Header>
543     {
544         friend class Clearable<Header>;
545 
546     public:
547         /**
548          * Initializes the Router Advertisement message with
549          * zero router lifetime, reachable time and retransmission timer.
550          *
551          */
Header(void)552         Header(void) { SetToDefault(); }
553 
554         /**
555          * Indicates whether the header is valid by checking the type field to match Router Advertisement ICMPv6 type.
556          *
557          * @retval TRUE  The header is valid.
558          * @retval FALSE The header is not valid.
559          *
560          */
IsValid(void) const561         bool IsValid(void) const { return GetType() == Icmp::Header::kTypeRouterAdvert; }
562 
563         /**
564          * Sets the RA message to default values.
565          *
566          */
567         void SetToDefault(void);
568 
569         /**
570          * Sets the checksum value.
571          *
572          * @param[in]  aChecksum  The checksum value.
573          *
574          */
SetChecksum(uint16_t aChecksum)575         void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); }
576 
577         /**
578          * Sets the Router Lifetime in seconds.
579          *
580          * @param[in]  aRouterLifetime  The router lifetime in seconds.
581          *
582          */
SetRouterLifetime(uint16_t aRouterLifetime)583         void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = BigEndian::HostSwap16(aRouterLifetime); }
584 
585         /**
586          * Gets the Router Lifetime (in seconds).
587          *
588          * Router Lifetime set to zero indicates that the sender is not a default router.
589          *
590          * @returns  The router lifetime in seconds.
591          *
592          */
GetRouterLifetime(void) const593         uint16_t GetRouterLifetime(void) const { return BigEndian::HostSwap16(mRouterLifetime); }
594 
595         /**
596          * Sets the default router preference.
597          *
598          * @param[in]  aPreference  The router preference.
599          *
600          */
601         void SetDefaultRouterPreference(RoutePreference aPreference);
602 
603         /**
604          * Gets the default router preference.
605          *
606          * @returns  The router preference.
607          *
608          */
609         RoutePreference GetDefaultRouterPreference(void) const;
610 
611         /**
612          * Indicates whether or not the Managed Address Config Flag is set in the RA message header.
613          *
614          * @retval TRUE   The Managed Address Config Flag is set.
615          * @retval FALSE  The Managed Address Config Flag is not set.
616          *
617          */
IsManagedAddressConfigFlagSet(void) const618         bool IsManagedAddressConfigFlagSet(void) const { return (mFlags & kManagedAddressConfigFlag) != 0; }
619 
620         /**
621          * Sets the Managed Address Config Flag in the RA message.
622          *
623          */
SetManagedAddressConfigFlag(void)624         void SetManagedAddressConfigFlag(void) { mFlags |= kManagedAddressConfigFlag; }
625 
626         /**
627          * Indicates whether or not the Other Config Flag is set in the RA message header.
628          *
629          * @retval TRUE   The Other Config Flag is set.
630          * @retval FALSE  The Other Config Flag is not set.
631          *
632          */
IsOtherConfigFlagSet(void) const633         bool IsOtherConfigFlagSet(void) const { return (mFlags & kOtherConfigFlag) != 0; }
634 
635         /**
636          * Sets the Other Config Flag in the RA message.
637          *
638          */
SetOtherConfigFlag(void)639         void SetOtherConfigFlag(void) { mFlags |= kOtherConfigFlag; }
640 
641         /**
642          * This method returns the ICMPv6 message type.
643          *
644          * @returns The ICMPv6 message type.
645          *
646          */
GetType(void) const647         Icmp::Header::Type GetType(void) const { return static_cast<Icmp::Header::Type>(mType); }
648 
649     private:
650         // Router Advertisement Message
651         //
652         //   0                   1                   2                   3
653         //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
654         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
655         //  |     Type      |     Code      |          Checksum             |
656         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
657         //  | Cur Hop Limit |M|O| |Prf|     |       Router Lifetime         |
658         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
659         //  |                         Reachable Time                        |
660         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
661         //  |                          Retrans Timer                        |
662         //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
663         //  |   Options ...
664         //  +-+-+-+-+-+-+-+-+-+-+-+-
665 
666         static constexpr uint8_t kManagedAddressConfigFlag = 1 << 7;
667         static constexpr uint8_t kOtherConfigFlag          = 1 << 6;
668         static constexpr uint8_t kPreferenceOffset         = 3;
669         static constexpr uint8_t kPreferenceMask           = 3 << kPreferenceOffset;
670 
671         uint8_t  mType;
672         uint8_t  mCode;
673         uint16_t mChecksum;
674         uint8_t  mCurHopLimit;
675         uint8_t  mFlags;
676         uint16_t mRouterLifetime;
677         uint32_t mReachableTime;
678         uint32_t mRetransTimer;
679     } OT_TOOL_PACKED_END;
680 
681     static_assert(sizeof(Header) == 16, "Invalid RA `Header`");
682 
683     typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet.
684 
685     /**
686      * Represents a received RA message.
687      *
688      */
689     class RxMessage
690     {
691     public:
692         /**
693          * Initializes the RA message from a received packet data buffer.
694          *
695          * @param[in] aPacket   A received packet data.
696          *
697          */
RxMessage(const Icmp6Packet & aPacket)698         explicit RxMessage(const Icmp6Packet &aPacket)
699             : mData(aPacket)
700         {
701         }
702 
703         /**
704          * Gets the RA message as an `Icmp6Packet`.
705          *
706          * @returns The RA message as an `Icmp6Packet`.
707          *
708          */
GetAsPacket(void) const709         const Icmp6Packet &GetAsPacket(void) const { return mData; }
710 
711         /**
712          * Indicates whether or not the received RA message is valid.
713          *
714          * @retval TRUE   If the RA message is valid.
715          * @retval FALSE  If the RA message is not valid.
716          *
717          */
IsValid(void) const718         bool IsValid(void) const
719         {
720             return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) &&
721                    (GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert);
722         }
723 
724         /**
725          * Gets the RA message's header.
726          *
727          * @returns The RA message's header.
728          *
729          */
GetHeader(void) const730         const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); }
731 
732         /**
733          * Indicates whether or not the received RA message contains any options.
734          *
735          * @retval TRUE   If the RA message contains at least one option.
736          * @retval FALSE  If the RA message contains no options.
737          *
738          */
ContainsAnyOptions(void) const739         bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); }
740 
741         /**
742          * Returns pointer to the start of option bytes (after header).
743          *
744          * @returns Pointer to start of options.
745          *
746          */
GetOptionStart(void) const747         const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
748 
749         /**
750          * Gets the length (number of bytes) of options.
751          *
752          * @returns Number of bytes after header specifying RA options.
753          *
754          */
GetOptionLength(void) const755         uint16_t GetOptionLength(void) const { return ContainsAnyOptions() ? mData.GetLength() - sizeof(Header) : 0; }
756 
757         // The following methods are intended to support range-based `for`
758         // loop iteration over `Option`s in the RA message.
759 
begin(void) const760         Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); }
end(void) const761         Option::Iterator end(void) const { return Option::Iterator(); }
762 
763     private:
GetDataEnd(void) const764         const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); }
765 
766         Data<kWithUint16Length> mData;
767     };
768 
769     /**
770      * Represents an RA message to be sent.
771      *
772      */
773     class TxMessage
774     {
775     public:
776         /**
777          * Gets the prepared RA message as an `Icmp6Packet`.
778          *
779          * @param[out] aPacket   A reference to an `Icmp6Packet`.
780          *
781          */
GetAsPacket(Icmp6Packet & aPacket) const782         void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); }
783 
784         /**
785          * Appends the RA header.
786          *
787          * @param[in] aHeader  The RA header.
788          *
789          * @retval kErrorNone    Header is written successfully.
790          * @retval kErrorNoBufs  Insufficient available buffers to grow the message.
791          *
792          */
793         Error AppendHeader(const Header &aHeader);
794 
795         /**
796          * Appends a Prefix Info Option to the RA message.
797          *
798          * The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags
799          * set.
800          *
801          * @param[in] aPrefix             The prefix.
802          * @param[in] aValidLifetime      The valid lifetime in seconds.
803          * @param[in] aPreferredLifetime  The preferred lifetime in seconds.
804          *
805          * @retval kErrorNone    Option is appended successfully.
806          * @retval kErrorNoBufs  Insufficient available buffers to grow the message.
807          *
808          */
809         Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime);
810 
811         /**
812          * Appends a Route Info Option to the RA message.
813          *
814          * @param[in] aPrefix             The prefix.
815          * @param[in] aRouteLifetime      The route lifetime in seconds.
816          * @param[in] aPreference         The route preference.
817          *
818          * @retval kErrorNone    Option is appended successfully.
819          * @retval kErrorNoBufs  Insufficient available buffers to grow the message.
820          *
821          */
822         Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
823 
824         /**
825          * Appends a Flags Extension Option to the RA message.
826          *
827          * @param[in] aStubRouterFlag    The stub router flag.
828          *
829          * @retval kErrorNone    Option is appended successfully.
830          * @retval kErrorNoBufs  Insufficient available buffers to grow the message.
831          *
832          */
833         Error AppendFlagsExtensionOption(bool aStubRouterFlag);
834 
835         /**
836          * Appends bytes from a given buffer to the RA message.
837          *
838          * @param[in] aBytes     A pointer to the buffer containing the bytes to append.
839          * @param[in] aLength    The buffer length.
840          *
841          * @retval kErrorNone    Bytes are appended successfully.
842          * @retval kErrorNoBufs  Insufficient available buffers to grow the message.
843          *
844          */
845         Error AppendBytes(const uint8_t *aBytes, uint16_t aLength);
846 
847         /**
848          * Indicates whether or not the received RA message contains any options.
849          *
850          * @retval TRUE   If the RA message contains at least one option.
851          * @retval FALSE  If the RA message contains no options.
852          *
853          */
ContainsAnyOptions(void) const854         bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); }
855 
856     private:
857         static constexpr uint16_t kCapacityIncrement = 256;
858 
859         Option *AppendOption(uint16_t aOptionSize);
860 
861         Heap::Array<uint8_t, kCapacityIncrement> mArray;
862     };
863 
864     RouterAdvert(void) = delete;
865 };
866 
867 /**
868  * Implements the Router Solicitation message.
869  *
870  * See section 4.1 of RFC 4861 for definition of this message.
871  * https://tools.ietf.org/html/rfc4861#section-4.1
872  *
873  */
874 OT_TOOL_PACKED_BEGIN
875 class RouterSolicitMessage
876 {
877 public:
878     /**
879      * Initializes the Router Solicitation message.
880      *
881      */
882     RouterSolicitMessage(void);
883 
884 private:
885     Icmp::Header mHeader; // The common ICMPv6 header.
886 } OT_TOOL_PACKED_END;
887 
888 static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure");
889 
890 /**
891  * Represents a Neighbor Solicitation (NS) message.
892  *
893  */
894 OT_TOOL_PACKED_BEGIN
895 class NeighborSolicitMessage : public Clearable<NeighborSolicitMessage>
896 {
897 public:
898     /**
899      * Initializes the Neighbor Solicitation message.
900      *
901      */
902     NeighborSolicitMessage(void);
903 
904     /**
905      * Indicates whether the Neighbor Solicitation message is valid (proper Type and Code).
906      *
907      * @retval TRUE  If the message is valid.
908      * @retval FALSE If the message is not valid.
909      *
910      */
IsValid(void) const911     bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); }
912 
913     /**
914      * Gets the Target Address field.
915      *
916      * @returns The Target Address.
917      *
918      */
GetTargetAddress(void) const919     const Address &GetTargetAddress(void) const { return mTargetAddress; }
920 
921     /**
922      * Sets the Target Address field.
923      *
924      * @param[in] aTargetAddress  The Target Address.
925      *
926      */
SetTargetAddress(const Address & aTargetAddress)927     void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; }
928 
929 private:
930     // Neighbor Solicitation Message (RFC 4861)
931     //
932     //   0                   1                   2                   3
933     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
934     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
935     //  |     Type      |     Code      |          Checksum             |
936     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
937     //  |                           Reserved                            |
938     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939     //  |                                                               |
940     //  +                                                               +
941     //  |                                                               |
942     //  +                       Target Address                          +
943     //  |                                                               |
944     //  +                                                               +
945     //  |                                                               |
946     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
947     //  |   Options ...
948     //  +-+-+-+-+-+-+-+-+-+-+-+-
949 
950     uint8_t  mType;
951     uint8_t  mCode;
952     uint16_t mChecksum;
953     uint32_t mReserved;
954     Address  mTargetAddress;
955 } OT_TOOL_PACKED_END;
956 
957 static_assert(sizeof(NeighborSolicitMessage) == 24, "Invalid NeighborSolicitMessage definition");
958 
959 /**
960  * Represents a Neighbor Advertisement (NA) message.
961  *
962  */
963 OT_TOOL_PACKED_BEGIN
964 class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage>
965 {
966 public:
967     NeighborAdvertMessage(void);
968 
969     /**
970      * Indicates whether the Neighbor Advertisement message is valid (proper Type and Code).
971      *
972      * @retval TRUE  If the message is valid.
973      * @retval FALSE If the message is not valid.
974      *
975      */
IsValid(void) const976     bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); }
977 
978     /**
979      * Indicates whether or not the Router Flag is set in the NA message.
980      *
981      * @retval TRUE   The Router Flag is set.
982      * @retval FALSE  The Router Flag is not set.
983      *
984      */
IsRouterFlagSet(void) const985     bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; }
986 
987     /**
988      * Sets the Router Flag in the NA message.
989      *
990      */
SetRouterFlag(void)991     void SetRouterFlag(void) { mFlags |= kRouterFlag; }
992 
993     /**
994      * Indicates whether or not the Solicited Flag is set in the NA message.
995      *
996      * @retval TRUE   The Solicited Flag is set.
997      * @retval FALSE  The Solicited Flag is not set.
998      *
999      */
IsSolicitedFlagSet(void) const1000     bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; }
1001 
1002     /**
1003      * Sets the Solicited Flag in the NA message.
1004      *
1005      */
SetSolicitedFlag(void)1006     void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; }
1007 
1008     /**
1009      * Indicates whether or not the Override Flag is set in the NA message.
1010      *
1011      * @retval TRUE   The Override Flag is set.
1012      * @retval FALSE  The Override Flag is not set.
1013      *
1014      */
IsOverrideFlagSet(void) const1015     bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; }
1016 
1017     /**
1018      * Sets the Override Flag in the NA message.
1019      *
1020      */
SetOverrideFlag(void)1021     void SetOverrideFlag(void) { mFlags |= kOverrideFlag; }
1022 
1023     /**
1024      * Gets the Target Address field.
1025      *
1026      * @returns The Target Address.
1027      *
1028      */
GetTargetAddress(void) const1029     const Address &GetTargetAddress(void) const { return mTargetAddress; }
1030 
1031     /**
1032      * Sets the Target Address field.
1033      *
1034      * @param[in] aTargetAddress  The Target Address.
1035      *
1036      */
SetTargetAddress(const Address & aTargetAddress)1037     void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; }
1038 
1039 private:
1040     // Neighbor Advertisement Message (RFC 4861)
1041     //
1042     //   0                   1                   2                   3
1043     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1044     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1045     //  |     Type      |     Code      |          Checksum             |
1046     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1047     //  |R|S|O|                     Reserved                            |
1048     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1049     //  |                                                               |
1050     //  +                                                               +
1051     //  |                                                               |
1052     //  +                       Target Address                          +
1053     //  |                                                               |
1054     //  +                                                               +
1055     //  |                                                               |
1056     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1057     //  |   Options ...
1058     //  +-+-+-+-+-+-+-+-+-+-+-+-
1059 
1060     static constexpr uint8_t kRouterFlag    = (1 << 7);
1061     static constexpr uint8_t kSolicitedFlag = (1 << 6);
1062     static constexpr uint8_t kOverrideFlag  = (1 << 5);
1063 
1064     uint8_t  mType;
1065     uint8_t  mCode;
1066     uint16_t mChecksum;
1067     uint8_t  mFlags;
1068     uint8_t  mReserved[3];
1069     Address  mTargetAddress;
1070 } OT_TOOL_PACKED_END;
1071 
1072 static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition");
1073 
1074 } // namespace Nd
1075 } // namespace Ip6
1076 } // namespace ot
1077 
1078 #endif // ND6_HPP_
1079