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 Router Advertisement.
32  *
33  * See RFC 4861: Neighbor Discovery for IP version 6 (https://tools.ietf.org/html/rfc4861).
34  *
35  */
36 
37 #ifndef ROUTER_ADVERTISEMENT_HPP_
38 #define ROUTER_ADVERTISEMENT_HPP_
39 
40 #include "openthread-core-config.h"
41 
42 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
43 
44 #include <stdint.h>
45 
46 #include <openthread/netdata.h>
47 #include <openthread/platform/toolchain.h>
48 
49 #include "common/encoding.hpp"
50 #include "common/equatable.hpp"
51 #include "net/icmp6.hpp"
52 #include "net/ip6.hpp"
53 #include "thread/network_data_types.hpp"
54 
55 using ot::Encoding::BigEndian::HostSwap16;
56 using ot::Encoding::BigEndian::HostSwap32;
57 
58 namespace ot {
59 
60 namespace BorderRouter {
61 
62 namespace RouterAdv {
63 
64 /**
65  * This class represents the variable length options in Neighbor
66  * Discovery messages.
67  *
68  * @sa PrefixInfoOption
69  * @sa RouteInfoOption
70  *
71  */
72 OT_TOOL_PACKED_BEGIN
73 class Option
74 {
75 public:
76     enum class Type : uint8_t
77     {
78         kPrefixInfo = 3,  ///< Prefix Information Option.
79         kRouteInfo  = 24, ///< Route Information Option.
80     };
81 
82     static constexpr uint8_t kLengthUnit = 8; ///< The unit of length in octets.
83 
84     /**
85      * This constructor initializes the option with given type and length.
86      *
87      * @param[in]  aType    The type of this option.
88      * @param[in]  aLength  The length of this option in unit of 8 octets.
89      *
90      */
Option(Type aType,uint8_t aLength=0)91     explicit Option(Type aType, uint8_t aLength = 0)
92         : mType(aType)
93         , mLength(aLength)
94     {
95     }
96 
97     /**
98      * This method returns the type of this option.
99      *
100      * @returns  The option type.
101      *
102      */
GetType(void) const103     Type GetType(void) const { return mType; }
104 
105     /**
106      * This method sets the size of the option (in bytes).
107      *
108      * Since the option must end on their natural 64-bits boundaries,
109      * the actual length set to the option is padded to (aSize + 7) / 8 * 8.
110      *
111      * @param[in]  aSize  The size of the option in unit of 1 byte.
112      *
113      */
SetSize(uint16_t aSize)114     void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); }
115 
116     /**
117      * This method returns the size of the option (in bytes).
118      *
119      * @returns  The size of the option in unit of 1 byte.
120      *
121      */
GetSize(void) const122     uint16_t GetSize(void) const { return mLength * kLengthUnit; }
123 
124     /**
125      * This method sets the length of the option (in unit of 8 bytes).
126      *
127      * @param[in]  aLength  The length of the option in unit of 8 bytes.
128      *
129      */
SetLength(uint8_t aLength)130     void SetLength(uint8_t aLength) { mLength = aLength; }
131 
132     /**
133      * This method returns the length of the option (in unit of 8 bytes).
134      *
135      * @returns  The length of the option in unit of 8 bytes.
136      *
137      */
GetLength(void) const138     uint16_t GetLength(void) const { return mLength; }
139 
140     /**
141      * This helper method returns a pointer to the next valid option in the buffer.
142      *
143      * @param[in]  aCurOption     The current option. Use nullptr to get the first option.
144      * @param[in]  aBuffer        The buffer within which the options are held.
145      * @param[in]  aBufferLength  The length of the buffer.
146      *
147      * @returns  A pointer to the next option if there are a valid one. Otherwise, nullptr.
148      *
149      */
150     static const Option *GetNextOption(const Option *aCurOption, const uint8_t *aBuffer, uint16_t aBufferLength);
151 
152     /**
153      * This method tells whether this option is valid.
154      *
155      * @return  A boolean that indicates whether this option is valid.
156      *
157      */
IsValid(void) const158     bool IsValid(void) const { return mLength > 0; }
159 
160 private:
161     Type    mType;   // Type of the option.
162     uint8_t mLength; // Length of the option in unit of 8 octets,
163                      // including the `type` and `length` fields.
164 } OT_TOOL_PACKED_END;
165 
166 /**
167  * This class represents the Prefix Information Option.
168  *
169  * See section 4.6.2 of RFC 4861 for definition of this option.
170  * https://tools.ietf.org/html/rfc4861#section-4.6.2
171  *
172  */
173 OT_TOOL_PACKED_BEGIN
174 class PrefixInfoOption : public Option
175 {
176 public:
177     /**
178      * This constructor initializes this option with zero prefix
179      * length, valid lifetime and preferred lifetime.
180      *
181      */
182     PrefixInfoOption(void);
183 
184     /**
185      * This method returns the on-link flag.
186      *
187      * @returns  A boolean which indicates whether the on-link flag is set.
188      *
189      */
GetOnLink(void) const190     bool GetOnLink(void) const { return (mReserved1 & kOnLinkFlagMask) != 0; }
191 
192     /**
193      * This method sets the on-link (L) flag.
194      *
195      * @param[in]  aOnLink  A boolean indicates whether the prefix is on-link or off-link.
196      *
197      */
198     void SetOnLink(bool aOnLink);
199 
200     /**
201      * This method returns the autonomous address-configuration (A) flag.
202      *
203      * @returns  A boolean which indicates whether the A flag is set.
204      *
205      */
GetAutoAddrConfig(void) const206     bool GetAutoAddrConfig(void) const { return (mReserved1 & kAutoConfigFlagMask) != 0; }
207 
208     /**
209      * This method sets the autonomous address-configuration (A) flag.
210      *
211      * @param[in]  aAutoAddrConfig  A boolean indicates whether this prefix can be used
212      *                              for SLAAC.
213      *
214      */
215     void SetAutoAddrConfig(bool aAutoAddrConfig);
216 
217     /**
218      * This method set the valid lifetime of the prefix in seconds.
219      *
220      * @param[in]  aValidLifetime  The valid lifetime in seconds.
221      *
222      */
SetValidLifetime(uint32_t aValidLifetime)223     void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = HostSwap32(aValidLifetime); }
224 
225     /**
226      * THis method returns the valid lifetime of the prefix in seconds.
227      *
228      * @returns  The valid lifetime in seconds.
229      *
230      */
GetValidLifetime(void) const231     uint32_t GetValidLifetime(void) const { return HostSwap32(mValidLifetime); }
232 
233     /**
234      * This method sets the preferred lifetime of the prefix in seconds.
235      *
236      * @param[in]  aPreferredLifetime  The preferred lifetime in seconds.
237      *
238      */
SetPreferredLifetime(uint32_t aPreferredLifetime)239     void SetPreferredLifetime(uint32_t aPreferredLifetime) { mPreferredLifetime = HostSwap32(aPreferredLifetime); }
240 
241     /**
242      * THis method returns the preferred lifetime of the prefix in seconds.
243      *
244      * @returns  The preferred lifetime in seconds.
245      *
246      */
GetPreferredLifetime(void) const247     uint32_t GetPreferredLifetime(void) const { return HostSwap32(mPreferredLifetime); }
248 
249     /**
250      * This method sets the prefix.
251      *
252      * @param[in]  aPrefix  The prefix contained in this option.
253      *
254      */
255     void SetPrefix(const Ip6::Prefix &aPrefix);
256 
257     /**
258      * This method returns the prefix in this option.
259      *
260      * @returns  The IPv6 prefix in this option.
261      *
262      */
263     Ip6::Prefix GetPrefix(void) const;
264 
265     /**
266      * This method tells whether this option is valid.
267      *
268      * @returns  A boolean indicates whether this option is valid.
269      *
270      */
IsValid(void) const271     bool IsValid(void) const
272     {
273         return (GetSize() == sizeof(*this)) && (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) &&
274                (GetPreferredLifetime() <= GetValidLifetime());
275     }
276 
277 private:
278     static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Bit mask of the Automatic Address Configure flag.
279     static constexpr uint8_t kOnLinkFlagMask     = 0x80; // Bit mask of the On-link flag.
280 
281     uint8_t      mPrefixLength;      // The prefix length in bits.
282     uint8_t      mReserved1;         // The reserved field.
283     uint32_t     mValidLifetime;     // The valid lifetime of the prefix.
284     uint32_t     mPreferredLifetime; // The preferred lifetime of the prefix.
285     uint32_t     mReserved2;         // The reserved field.
286     Ip6::Address mPrefix;            // The prefix.
287 } OT_TOOL_PACKED_END;
288 
289 static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure");
290 
291 /**
292  * This class represents the Route Information Option.
293  *
294  * See section 2.3 of RFC 4191 for definition of this option.
295  * https://tools.ietf.org/html/rfc4191#section-2.3
296  *
297  */
298 OT_TOOL_PACKED_BEGIN
299 class RouteInfoOption : public Option
300 {
301 public:
302     /**
303      * This type represents a route preference.
304      *
305      */
306     typedef NetworkData::RoutePreference RoutePreference;
307 
308     /**
309      * This constructor initializes this option with zero prefix length.
310      *
311      */
312     RouteInfoOption(void);
313 
314     /**
315      * This method sets the route preference.
316      *
317      * @param[in]  aPreference  The route preference.
318      *
319      */
320     void SetPreference(RoutePreference aPreference);
321 
322     /**
323      * This method returns the route preference.
324      *
325      * @returns  The route preference.
326      *
327      */
328     RoutePreference GetPreference(void) const;
329 
330     /**
331      * This method sets the lifetime of the route in seconds.
332      *
333      * @param[in]  aLifetime  The lifetime of the route in seconds.
334      *
335      */
SetRouteLifetime(uint32_t aLifetime)336     void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = HostSwap32(aLifetime); }
337 
338     /**
339      * This method returns Route Lifetime in seconds.
340      *
341      * @returns  The Route Lifetime in seconds.
342      *
343      */
GetRouteLifetime(void) const344     uint32_t GetRouteLifetime(void) const { return HostSwap32(mRouteLifetime); }
345 
346     /**
347      * This method sets the prefix.
348      *
349      * @param[in]  aPrefix  The prefix contained in this option.
350      *
351      */
352     void SetPrefix(const Ip6::Prefix &aPrefix);
353 
354     /**
355      * This method returns the prefix in this option.
356      *
357      * @returns  The IPv6 prefix in this option.
358      *
359      */
360     Ip6::Prefix GetPrefix(void) const;
361 
362     /**
363      * This method tells whether this option is valid.
364      *
365      * @returns  A boolean indicates whether this option is valid.
366      *
367      */
368     bool IsValid(void) const;
369 
370 private:
371     static constexpr uint8_t kPreferenceOffset = 3;
372     static constexpr uint8_t kPreferenceMask   = 3 << kPreferenceOffset;
373 
374     uint8_t      mPrefixLength;  // The prefix length in bits.
375     uint8_t      mReserved;      // The reserved field.
376     uint32_t     mRouteLifetime; // The lifetime in seconds.
377     Ip6::Address mPrefix;        // The prefix.
378 } OT_TOOL_PACKED_END;
379 
380 static_assert(sizeof(RouteInfoOption) == 24, "invalid RouteInfoOption structure");
381 
382 /**
383  * This class implements the Router Advertisement message.
384  *
385  * See section 4.2 of RFC 4861 for definition of this message.
386  * https://tools.ietf.org/html/rfc4861#section-4.2
387  *
388  */
389 OT_TOOL_PACKED_BEGIN
390 class RouterAdvMessage : public Unequatable<RouterAdvMessage>
391 {
392 public:
393     /**
394      * This constructor initializes the Router Advertisement message with
395      * zero router lifetime, reachable time and retransmission timer.
396      *
397      */
RouterAdvMessage(void)398     RouterAdvMessage(void) { SetToDefault(); }
399 
400     /**
401      * This method sets the RA message to default values.
402      *
403      */
404     void SetToDefault(void);
405 
406     /**
407      * This method sets the checksum value.
408      *
409      * @param[in]  aChecksum  The checksum value.
410      *
411      */
SetChecksum(uint16_t aChecksum)412     void SetChecksum(uint16_t aChecksum) { mHeader.SetChecksum(aChecksum); }
413 
414     /**
415      * This method sets the Router Lifetime in seconds.
416      *
417      * Zero Router Lifetime means we are not a default router.
418      *
419      * @param[in]  aRouterLifetime  The router lifetime in seconds.
420      *
421      */
SetRouterLifetime(uint16_t aRouterLifetime)422     void SetRouterLifetime(uint16_t aRouterLifetime)
423     {
424         mHeader.mData.m16[kRouteLifetimeIdx] = HostSwap16(aRouterLifetime);
425     }
426 
427     /**
428      * This method returns the Router Lifetime.
429      *
430      * Zero Router Lifetime means we are not a default router.
431      *
432      * @returns  The router lifetime in seconds.
433      *
434      */
GetRouterLifetime(void) const435     uint16_t GetRouterLifetime(void) const { return HostSwap16(mHeader.mData.m16[kRouteLifetimeIdx]); }
436 
437     /**
438      * This method returns the Managed Address Configuration ('m') flag.
439      *
440      * @returns  A boolean which indicates whether the 'm' flag is set.
441      *
442      */
GetManagedAddrConfig(void) const443     bool GetManagedAddrConfig(void) const { return (mHeader.mData.m8[kReservedIdx] & kManagedAddressConfigMask) != 0; }
444 
445     /**
446      * This method overloads the assignment operator.
447      *
448      */
449     const RouterAdvMessage &operator=(const RouterAdvMessage &aOther);
450 
451     /**
452      * This method overloads operator `==` to evaluate whether or not
453      * two instances of `RouterAdvMessage` are equal.
454      *
455      * @param[in]  aOther  The other `RouterAdvMessage` instance to compare with.
456      *
457      * @retval TRUE   If the two `RouterAdvMessage` instances are equal.
458      * @retval FALSE  If the two `RouterAdvMessage` instances are not equal.
459      *
460      */
461     bool operator==(const RouterAdvMessage &aOther) const;
462 
463 private:
464     // The index of Route Lifetime in ICMPv6 Header Data. In unit of 2 octets.
465     static constexpr uint8_t kRouteLifetimeIdx = 1;
466 
467     // The index of Reserved byte in ICMPv6 Header Data. In unit of 1 octet.
468     static constexpr uint8_t kReservedIdx = 1;
469 
470     // The bitmask of the Managed Address Configuration ('m') flag.
471     static constexpr uint8_t kManagedAddressConfigMask = 0x80;
472 
473     Ip6::Icmp::Header mHeader;        // The common ICMPv6 header.
474     uint32_t          mReachableTime; // The reachable time. In milliseconds.
475     uint32_t          mRetransTimer;  // The retransmission timer. In milliseconds.
476 } OT_TOOL_PACKED_END;
477 
478 static_assert(sizeof(RouterAdvMessage) == 16, "invalid RouterAdvMessage structure");
479 
480 /**
481  * This class implements the Router Solicitation message.
482  *
483  * See section 4.1 of RFC 4861 for definition of this message.
484  * https://tools.ietf.org/html/rfc4861#section-4.1
485  *
486  */
487 OT_TOOL_PACKED_BEGIN
488 class RouterSolicitMessage
489 {
490 public:
491     /**
492      * This constructor initializes the Router Solicitation message.
493      *
494      */
495     RouterSolicitMessage(void);
496 
497 private:
498     Ip6::Icmp::Header mHeader; // The common ICMPv6 header.
499 } OT_TOOL_PACKED_END;
500 
501 static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure");
502 
503 } // namespace RouterAdv
504 
505 } // namespace BorderRouter
506 
507 } // namespace ot
508 
509 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
510 
511 #endif // ROUTER_ADVERTISEMENT_HPP_
512