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