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)
70 {
71 mOption = (mOption != nullptr) ? Validate(Next(mOption)) : nullptr;
72 }
73
Validate(const Option * aOption) const74 const Option *Option::Iterator::Validate(const Option *aOption) const
75 {
76 // Check if `aOption` is well-formed and fits in the range
77 // up to `mEnd`. Returns `aOption` if it is valid, `nullptr`
78 // otherwise.
79
80 return ((aOption != nullptr) && ((aOption + 1) <= mEnd) && aOption->IsValid() && (Next(aOption) <= mEnd)) ? aOption
81 : nullptr;
82 }
83
84 //----------------------------------------------------------------------------------------------------------------------
85 // PrefixInfoOption
86
Init(void)87 void PrefixInfoOption::Init(void)
88 {
89 Clear();
90 SetType(kTypePrefixInfo);
91 SetSize(sizeof(PrefixInfoOption));
92
93 OT_UNUSED_VARIABLE(mReserved2);
94 }
95
SetPrefix(const Prefix & aPrefix)96 void PrefixInfoOption::SetPrefix(const Prefix &aPrefix)
97 {
98 mPrefixLength = aPrefix.mLength;
99 mPrefix = AsCoreType(&aPrefix.mPrefix);
100 }
101
GetPrefix(Prefix & aPrefix) const102 void PrefixInfoOption::GetPrefix(Prefix &aPrefix) const
103 {
104 aPrefix.Set(mPrefix.GetBytes(), mPrefixLength);
105 }
106
IsValid(void) const107 bool PrefixInfoOption::IsValid(void) const
108 {
109 return (GetSize() >= sizeof(*this)) && (mPrefixLength <= Prefix::kMaxLength) &&
110 (GetPreferredLifetime() <= GetValidLifetime());
111 }
112
113 //----------------------------------------------------------------------------------------------------------------------
114 // RouteInfoOption
115
Init(void)116 void RouteInfoOption::Init(void)
117 {
118 Clear();
119 SetType(kTypeRouteInfo);
120 }
121
SetPreference(RoutePreference aPreference)122 void RouteInfoOption::SetPreference(RoutePreference aPreference)
123 {
124 mResvdPrf &= ~kPreferenceMask;
125 mResvdPrf |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
126 }
127
GetPreference(void) const128 RoutePreference RouteInfoOption::GetPreference(void) const
129 {
130 return NetworkData::RoutePreferenceFromValue((mResvdPrf & kPreferenceMask) >> kPreferenceOffset);
131 }
132
SetPrefix(const Prefix & aPrefix)133 void RouteInfoOption::SetPrefix(const Prefix &aPrefix)
134 {
135 SetLength(OptionLengthForPrefix(aPrefix.mLength));
136 mPrefixLength = aPrefix.mLength;
137 memcpy(GetPrefixBytes(), aPrefix.GetBytes(), aPrefix.GetBytesSize());
138 }
139
GetPrefix(Prefix & aPrefix) const140 void RouteInfoOption::GetPrefix(Prefix &aPrefix) const
141 {
142 aPrefix.Set(GetPrefixBytes(), mPrefixLength);
143 }
144
IsValid(void) const145 bool RouteInfoOption::IsValid(void) const
146 {
147 return (GetSize() >= kMinSize) && (mPrefixLength <= Prefix::kMaxLength) &&
148 (GetLength() >= OptionLengthForPrefix(mPrefixLength)) &&
149 NetworkData::IsRoutePreferenceValid(GetPreference());
150 }
151
OptionLengthForPrefix(uint8_t aPrefixLength)152 uint8_t RouteInfoOption::OptionLengthForPrefix(uint8_t aPrefixLength)
153 {
154 static constexpr uint8_t kMaxPrefixLenForOptionLen1 = 0;
155 static constexpr uint8_t kMaxPrefixLenForOptionLen2 = 64;
156
157 uint8_t length;
158
159 // The Option Length can be 1, 2, or 3 depending on the prefix
160 // length
161 //
162 // - 1 when prefix len is zero.
163 // - 2 when prefix len is less then or equal to 64.
164 // - 3 otherwise.
165
166 if (aPrefixLength == kMaxPrefixLenForOptionLen1)
167 {
168 length = 1;
169 }
170 else if (aPrefixLength <= kMaxPrefixLenForOptionLen2)
171 {
172 length = 2;
173 }
174 else
175 {
176 length = 3;
177 }
178
179 return length;
180 }
181
182 //----------------------------------------------------------------------------------------------------------------------
183 // RouterAdverMessage::Header
184
SetToDefault(void)185 void RouterAdvertMessage::Header::SetToDefault(void)
186 {
187 OT_UNUSED_VARIABLE(mCode);
188 OT_UNUSED_VARIABLE(mCurHopLimit);
189 OT_UNUSED_VARIABLE(mReachableTime);
190 OT_UNUSED_VARIABLE(mRetransTimer);
191
192 Clear();
193 mType = Icmp::Header::kTypeRouterAdvert;
194 }
195
GetDefaultRouterPreference(void) const196 RoutePreference RouterAdvertMessage::Header::GetDefaultRouterPreference(void) const
197 {
198 return NetworkData::RoutePreferenceFromValue((mFlags & kPreferenceMask) >> kPreferenceOffset);
199 }
200
SetDefaultRouterPreference(RoutePreference aPreference)201 void RouterAdvertMessage::Header::SetDefaultRouterPreference(RoutePreference aPreference)
202 {
203 mFlags &= ~kPreferenceMask;
204 mFlags |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
205 }
206
207 //----------------------------------------------------------------------------------------------------------------------
208 // RouterAdverMessage
209
AppendOption(uint16_t aOptionSize)210 Option *RouterAdvertMessage::AppendOption(uint16_t aOptionSize)
211 {
212 // This method appends an option with a given size to the RA
213 // message by reserving space in the data buffer if there is
214 // room. On success returns pointer to the option, on failure
215 // returns `nullptr`. The returned option needs to be
216 // initialized and populated by the caller.
217
218 Option * option = nullptr;
219 uint32_t newLength = mData.GetLength();
220
221 newLength += aOptionSize;
222 VerifyOrExit(newLength <= mMaxLength);
223
224 option = reinterpret_cast<Option *>(AsNonConst(GetDataEnd()));
225 mData.SetLength(static_cast<uint16_t>(newLength));
226
227 exit:
228 return option;
229 }
230
AppendPrefixInfoOption(const Prefix & aPrefix,uint32_t aValidLifetime,uint32_t aPreferredLifetime)231 Error RouterAdvertMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
232 uint32_t aValidLifetime,
233 uint32_t aPreferredLifetime)
234 {
235 Error error = kErrorNone;
236 PrefixInfoOption *pio;
237
238 pio = static_cast<PrefixInfoOption *>(AppendOption(sizeof(PrefixInfoOption)));
239 VerifyOrExit(pio != nullptr, error = kErrorNoBufs);
240
241 pio->Init();
242 pio->SetOnLinkFlag();
243 pio->SetAutoAddrConfigFlag();
244 pio->SetValidLifetime(aValidLifetime);
245 pio->SetPreferredLifetime(aPreferredLifetime);
246 pio->SetPrefix(aPrefix);
247
248 exit:
249 return error;
250 }
251
AppendRouteInfoOption(const Prefix & aPrefix,uint32_t aRouteLifetime,RoutePreference aPreference)252 Error RouterAdvertMessage::AppendRouteInfoOption(const Prefix & aPrefix,
253 uint32_t aRouteLifetime,
254 RoutePreference aPreference)
255 {
256 Error error = kErrorNone;
257 RouteInfoOption *rio;
258
259 rio = static_cast<RouteInfoOption *>(AppendOption(RouteInfoOption::OptionSizeForPrefix(aPrefix.GetLength())));
260 VerifyOrExit(rio != nullptr, error = kErrorNoBufs);
261
262 rio->Init();
263 rio->SetRouteLifetime(aRouteLifetime);
264 rio->SetPreference(aPreference);
265 rio->SetPrefix(aPrefix);
266
267 exit:
268 return error;
269 }
270
271 //----------------------------------------------------------------------------------------------------------------------
272 // RouterAdvMessage
273
RouterSolicitMessage(void)274 RouterSolicitMessage::RouterSolicitMessage(void)
275 {
276 mHeader.Clear();
277 mHeader.SetType(Icmp::Header::kTypeRouterSolicit);
278 }
279
280 } // namespace Nd
281 } // namespace Ip6
282 } // namespace ot
283