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