• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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