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