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 implementations for IPv6 Neighbor Discovery (ND6).
32  *
33  */
34 
35 #include "nd6.hpp"
36 
37 #include "common/as_core_type.hpp"
38 #include "common/code_utils.hpp"
39 #include "instance/instance.hpp"
40 
41 namespace ot {
42 namespace Ip6 {
43 namespace Nd {
44 
45 //----------------------------------------------------------------------------------------------------------------------
46 // Option::Iterator
47 
Iterator(void)48 Option::Iterator::Iterator(void)
49     : mOption(nullptr)
50     , mEnd(nullptr)
51 {
52     // An empty iterator (used to indicate `end()` of list).
53 }
54 
Iterator(const void * aStart,const void * aEnd)55 Option::Iterator::Iterator(const void *aStart, const void *aEnd)
56     : mOption(nullptr)
57     , mEnd(reinterpret_cast<const Option *>(aEnd))
58 {
59     // Note that `Validate()` uses `mEnd` so can only be called after
60     // `mEnd` is set.
61 
62     mOption = Validate(reinterpret_cast<const Option *>(aStart));
63 }
64 
Next(const Option * aOption)65 const Option *Option::Iterator::Next(const Option *aOption)
66 {
67     return reinterpret_cast<const Option *>(reinterpret_cast<const uint8_t *>(aOption) + aOption->GetSize());
68 }
69 
Advance(void)70 void Option::Iterator::Advance(void) { mOption = (mOption != nullptr) ? Validate(Next(mOption)) : nullptr; }
71 
Validate(const Option * aOption) const72 const Option *Option::Iterator::Validate(const Option *aOption) const
73 {
74     // Check if `aOption` is well-formed and fits in the range
75     // up to `mEnd`. Returns `aOption` if it is valid, `nullptr`
76     // otherwise.
77 
78     return ((aOption != nullptr) && ((aOption + 1) <= mEnd) && aOption->IsValid() && (Next(aOption) <= mEnd)) ? aOption
79                                                                                                               : nullptr;
80 }
81 
82 //----------------------------------------------------------------------------------------------------------------------
83 // PrefixInfoOption
84 
Init(void)85 void PrefixInfoOption::Init(void)
86 {
87     Clear();
88     SetType(kTypePrefixInfo);
89     SetSize(sizeof(PrefixInfoOption));
90 
91     OT_UNUSED_VARIABLE(mReserved2);
92 }
93 
SetPrefix(const Prefix & aPrefix)94 void PrefixInfoOption::SetPrefix(const Prefix &aPrefix)
95 {
96     mPrefixLength = aPrefix.mLength;
97     mPrefix       = AsCoreType(&aPrefix.mPrefix);
98 }
99 
GetPrefix(Prefix & aPrefix) const100 void PrefixInfoOption::GetPrefix(Prefix &aPrefix) const { aPrefix.Set(mPrefix.GetBytes(), mPrefixLength); }
101 
IsValid(void) const102 bool PrefixInfoOption::IsValid(void) const
103 {
104     return (GetSize() >= sizeof(*this)) && (mPrefixLength <= Prefix::kMaxLength) &&
105            (GetPreferredLifetime() <= GetValidLifetime());
106 }
107 
108 //----------------------------------------------------------------------------------------------------------------------
109 // RouteInfoOption
110 
Init(void)111 void RouteInfoOption::Init(void)
112 {
113     Clear();
114     SetType(kTypeRouteInfo);
115 }
116 
SetPreference(RoutePreference aPreference)117 void RouteInfoOption::SetPreference(RoutePreference aPreference)
118 {
119     mResvdPrf &= ~kPreferenceMask;
120     mResvdPrf |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
121 }
122 
GetPreference(void) const123 RoutePreference RouteInfoOption::GetPreference(void) const
124 {
125     return NetworkData::RoutePreferenceFromValue((mResvdPrf & kPreferenceMask) >> kPreferenceOffset);
126 }
127 
SetPrefix(const Prefix & aPrefix)128 void RouteInfoOption::SetPrefix(const Prefix &aPrefix)
129 {
130     SetLength(OptionLengthForPrefix(aPrefix.mLength));
131     mPrefixLength = aPrefix.mLength;
132     memcpy(GetPrefixBytes(), aPrefix.GetBytes(), aPrefix.GetBytesSize());
133 }
134 
GetPrefix(Prefix & aPrefix) const135 void RouteInfoOption::GetPrefix(Prefix &aPrefix) const { aPrefix.Set(GetPrefixBytes(), mPrefixLength); }
136 
IsValid(void) const137 bool RouteInfoOption::IsValid(void) const
138 {
139     return (GetSize() >= kMinSize) && (mPrefixLength <= Prefix::kMaxLength) &&
140            (GetLength() >= OptionLengthForPrefix(mPrefixLength)) &&
141            NetworkData::IsRoutePreferenceValid(GetPreference());
142 }
143 
OptionLengthForPrefix(uint8_t aPrefixLength)144 uint8_t RouteInfoOption::OptionLengthForPrefix(uint8_t aPrefixLength)
145 {
146     static constexpr uint8_t kMaxPrefixLenForOptionLen1 = 0;
147     static constexpr uint8_t kMaxPrefixLenForOptionLen2 = 64;
148 
149     uint8_t length;
150 
151     // The Option Length can be 1, 2, or 3 depending on the prefix
152     // length
153     //
154     // - 1 when prefix len is zero.
155     // - 2 when prefix len is less then or equal to 64.
156     // - 3 otherwise.
157 
158     if (aPrefixLength == kMaxPrefixLenForOptionLen1)
159     {
160         length = 1;
161     }
162     else if (aPrefixLength <= kMaxPrefixLenForOptionLen2)
163     {
164         length = 2;
165     }
166     else
167     {
168         length = 3;
169     }
170 
171     return length;
172 }
173 
174 //----------------------------------------------------------------------------------------------------------------------
175 // RaFlagsExtOption
176 
Init(void)177 void RaFlagsExtOption::Init(void)
178 {
179     Clear();
180     SetType(kTypeRaFlagsExtension);
181     SetSize(sizeof(RaFlagsExtOption));
182 }
183 
184 //----------------------------------------------------------------------------------------------------------------------
185 // RouterAdver::Header
186 
SetToDefault(void)187 void RouterAdvert::Header::SetToDefault(void)
188 {
189     OT_UNUSED_VARIABLE(mCode);
190     OT_UNUSED_VARIABLE(mCurHopLimit);
191     OT_UNUSED_VARIABLE(mReachableTime);
192     OT_UNUSED_VARIABLE(mRetransTimer);
193 
194     Clear();
195     mType = Icmp::Header::kTypeRouterAdvert;
196 }
197 
GetDefaultRouterPreference(void) const198 RoutePreference RouterAdvert::Header::GetDefaultRouterPreference(void) const
199 {
200     return NetworkData::RoutePreferenceFromValue((mFlags & kPreferenceMask) >> kPreferenceOffset);
201 }
202 
SetDefaultRouterPreference(RoutePreference aPreference)203 void RouterAdvert::Header::SetDefaultRouterPreference(RoutePreference aPreference)
204 {
205     mFlags &= ~kPreferenceMask;
206     mFlags |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
207 }
208 
209 //----------------------------------------------------------------------------------------------------------------------
210 // RouterAdver::TxMessage
211 
AppendOption(uint16_t aOptionSize)212 Option *RouterAdvert::TxMessage::AppendOption(uint16_t aOptionSize)
213 {
214     // This method appends an option with a given size to the RA
215     // message by reserving space in the data buffer if there is
216     // room. On success returns pointer to the option, on failure
217     // returns `nullptr`. The returned option needs to be
218     // initialized and populated by the caller.
219 
220     Option  *option    = nullptr;
221     uint16_t oldLength = mArray.GetLength();
222 
223     SuccessOrExit(AppendBytes(nullptr, aOptionSize));
224     option = reinterpret_cast<Option *>(&mArray[oldLength]);
225 
226 exit:
227     return option;
228 }
229 
AppendBytes(const uint8_t * aBytes,uint16_t aLength)230 Error RouterAdvert::TxMessage::AppendBytes(const uint8_t *aBytes, uint16_t aLength)
231 {
232     Error error = kErrorNone;
233 
234     for (; aLength > 0; aLength--)
235     {
236         uint8_t byte;
237 
238         byte = (aBytes == nullptr) ? 0 : *aBytes++;
239         SuccessOrExit(error = mArray.PushBack(byte));
240     }
241 
242 exit:
243     return error;
244 }
245 
AppendHeader(const Header & aHeader)246 Error RouterAdvert::TxMessage::AppendHeader(const Header &aHeader)
247 {
248     return AppendBytes(reinterpret_cast<const uint8_t *>(&aHeader), sizeof(Header));
249 }
250 
AppendPrefixInfoOption(const Prefix & aPrefix,uint32_t aValidLifetime,uint32_t aPreferredLifetime)251 Error RouterAdvert::TxMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
252                                                       uint32_t      aValidLifetime,
253                                                       uint32_t      aPreferredLifetime)
254 {
255     Error             error = kErrorNone;
256     PrefixInfoOption *pio;
257 
258     pio = static_cast<PrefixInfoOption *>(AppendOption(sizeof(PrefixInfoOption)));
259     VerifyOrExit(pio != nullptr, error = kErrorNoBufs);
260 
261     pio->Init();
262     pio->SetOnLinkFlag();
263     pio->SetAutoAddrConfigFlag();
264     pio->SetValidLifetime(aValidLifetime);
265     pio->SetPreferredLifetime(aPreferredLifetime);
266     pio->SetPrefix(aPrefix);
267 
268 exit:
269     return error;
270 }
271 
AppendRouteInfoOption(const Prefix & aPrefix,uint32_t aRouteLifetime,RoutePreference aPreference)272 Error RouterAdvert::TxMessage::AppendRouteInfoOption(const Prefix   &aPrefix,
273                                                      uint32_t        aRouteLifetime,
274                                                      RoutePreference aPreference)
275 {
276     Error            error = kErrorNone;
277     RouteInfoOption *rio;
278 
279     rio = static_cast<RouteInfoOption *>(AppendOption(RouteInfoOption::OptionSizeForPrefix(aPrefix.GetLength())));
280     VerifyOrExit(rio != nullptr, error = kErrorNoBufs);
281 
282     rio->Init();
283     rio->SetRouteLifetime(aRouteLifetime);
284     rio->SetPreference(aPreference);
285     rio->SetPrefix(aPrefix);
286 
287 exit:
288     return error;
289 }
290 
AppendFlagsExtensionOption(bool aStubRouterFlag)291 Error RouterAdvert::TxMessage::AppendFlagsExtensionOption(bool aStubRouterFlag)
292 {
293     Error             error = kErrorNone;
294     RaFlagsExtOption *flagsOption;
295 
296     flagsOption = static_cast<RaFlagsExtOption *>(AppendOption(sizeof(RaFlagsExtOption)));
297     VerifyOrExit(flagsOption != nullptr, error = kErrorNoBufs);
298 
299     flagsOption->Init();
300 
301     if (aStubRouterFlag)
302     {
303         flagsOption->SetStubRouterFlag();
304     }
305 
306 exit:
307     return error;
308 }
309 
310 //----------------------------------------------------------------------------------------------------------------------
311 // RouterSolicitMessage
312 
RouterSolicitMessage(void)313 RouterSolicitMessage::RouterSolicitMessage(void)
314 {
315     mHeader.Clear();
316     mHeader.SetType(Icmp::Header::kTypeRouterSolicit);
317 }
318 
319 //----------------------------------------------------------------------------------------------------------------------
320 // NeighborSolicitMessage
321 
NeighborSolicitMessage(void)322 NeighborSolicitMessage::NeighborSolicitMessage(void)
323 {
324     OT_UNUSED_VARIABLE(mChecksum);
325     OT_UNUSED_VARIABLE(mReserved);
326 
327     Clear();
328     mType = Icmp::Header::kTypeNeighborSolicit;
329 }
330 
331 //----------------------------------------------------------------------------------------------------------------------
332 // NeighborAdvertMessage
333 
NeighborAdvertMessage(void)334 NeighborAdvertMessage::NeighborAdvertMessage(void)
335 {
336     OT_UNUSED_VARIABLE(mChecksum);
337     OT_UNUSED_VARIABLE(mReserved);
338 
339     Clear();
340     mType = Icmp::Header::kTypeNeighborAdvert;
341 }
342 
343 } // namespace Nd
344 } // namespace Ip6
345 } // namespace ot
346