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
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 // RouterAdverMessage::Header
175
SetToDefault(void)176 void RouterAdvertMessage::Header::SetToDefault(void)
177 {
178 OT_UNUSED_VARIABLE(mCode);
179 OT_UNUSED_VARIABLE(mCurHopLimit);
180 OT_UNUSED_VARIABLE(mReachableTime);
181 OT_UNUSED_VARIABLE(mRetransTimer);
182
183 Clear();
184 mType = Icmp::Header::kTypeRouterAdvert;
185 }
186
GetDefaultRouterPreference(void) const187 RoutePreference RouterAdvertMessage::Header::GetDefaultRouterPreference(void) const
188 {
189 return NetworkData::RoutePreferenceFromValue((mFlags & kPreferenceMask) >> kPreferenceOffset);
190 }
191
SetDefaultRouterPreference(RoutePreference aPreference)192 void RouterAdvertMessage::Header::SetDefaultRouterPreference(RoutePreference aPreference)
193 {
194 mFlags &= ~kPreferenceMask;
195 mFlags |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
196 }
197
198 //----------------------------------------------------------------------------------------------------------------------
199 // RouterAdverMessage
200
AppendOption(uint16_t aOptionSize)201 Option *RouterAdvertMessage::AppendOption(uint16_t aOptionSize)
202 {
203 // This method appends an option with a given size to the RA
204 // message by reserving space in the data buffer if there is
205 // room. On success returns pointer to the option, on failure
206 // returns `nullptr`. The returned option needs to be
207 // initialized and populated by the caller.
208
209 Option *option = nullptr;
210 uint32_t newLength = mData.GetLength();
211
212 newLength += aOptionSize;
213 VerifyOrExit(newLength <= mMaxLength);
214
215 option = reinterpret_cast<Option *>(AsNonConst(GetDataEnd()));
216 mData.SetLength(static_cast<uint16_t>(newLength));
217
218 exit:
219 return option;
220 }
221
AppendPrefixInfoOption(const Prefix & aPrefix,uint32_t aValidLifetime,uint32_t aPreferredLifetime)222 Error RouterAdvertMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
223 uint32_t aValidLifetime,
224 uint32_t aPreferredLifetime)
225 {
226 Error error = kErrorNone;
227 PrefixInfoOption *pio;
228
229 pio = static_cast<PrefixInfoOption *>(AppendOption(sizeof(PrefixInfoOption)));
230 VerifyOrExit(pio != nullptr, error = kErrorNoBufs);
231
232 pio->Init();
233 pio->SetOnLinkFlag();
234 pio->SetAutoAddrConfigFlag();
235 pio->SetValidLifetime(aValidLifetime);
236 pio->SetPreferredLifetime(aPreferredLifetime);
237 pio->SetPrefix(aPrefix);
238
239 exit:
240 return error;
241 }
242
AppendRouteInfoOption(const Prefix & aPrefix,uint32_t aRouteLifetime,RoutePreference aPreference)243 Error RouterAdvertMessage::AppendRouteInfoOption(const Prefix &aPrefix,
244 uint32_t aRouteLifetime,
245 RoutePreference aPreference)
246 {
247 Error error = kErrorNone;
248 RouteInfoOption *rio;
249
250 rio = static_cast<RouteInfoOption *>(AppendOption(RouteInfoOption::OptionSizeForPrefix(aPrefix.GetLength())));
251 VerifyOrExit(rio != nullptr, error = kErrorNoBufs);
252
253 rio->Init();
254 rio->SetRouteLifetime(aRouteLifetime);
255 rio->SetPreference(aPreference);
256 rio->SetPrefix(aPrefix);
257
258 exit:
259 return error;
260 }
261
262 //----------------------------------------------------------------------------------------------------------------------
263 // RouterSolicitMessage
264
RouterSolicitMessage(void)265 RouterSolicitMessage::RouterSolicitMessage(void)
266 {
267 mHeader.Clear();
268 mHeader.SetType(Icmp::Header::kTypeRouterSolicit);
269 }
270
271 //----------------------------------------------------------------------------------------------------------------------
272 // NeighborSolicitMessage
273
NeighborSolicitMessage(void)274 NeighborSolicitMessage::NeighborSolicitMessage(void)
275 {
276 OT_UNUSED_VARIABLE(mChecksum);
277 OT_UNUSED_VARIABLE(mReserved);
278
279 Clear();
280 mType = Icmp::Header::kTypeNeighborSolicit;
281 }
282
283 //----------------------------------------------------------------------------------------------------------------------
284 // NeighborAdvertMessage
285
NeighborAdvertMessage(void)286 NeighborAdvertMessage::NeighborAdvertMessage(void)
287 {
288 OT_UNUSED_VARIABLE(mChecksum);
289 OT_UNUSED_VARIABLE(mReserved);
290
291 Clear();
292 mType = Icmp::Header::kTypeNeighborAdvert;
293 }
294
295 } // namespace Nd
296 } // namespace Ip6
297 } // namespace ot
298