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