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