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 ICMPv6 Router Advertisement.
32  *
33  */
34 
35 #include "border_router/router_advertisement.hpp"
36 
37 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
38 
39 namespace ot {
40 
41 namespace BorderRouter {
42 
43 namespace RouterAdv {
44 
GetNextOption(const Option * aCurOption,const uint8_t * aBuffer,uint16_t aBufferLength)45 const Option *Option::GetNextOption(const Option *aCurOption, const uint8_t *aBuffer, uint16_t aBufferLength)
46 {
47     const uint8_t *nextOption = nullptr;
48     const uint8_t *bufferEnd  = aBuffer + aBufferLength;
49 
50     VerifyOrExit(aBuffer != nullptr, nextOption = nullptr);
51 
52     if (aCurOption == nullptr)
53     {
54         nextOption = aBuffer;
55     }
56     else
57     {
58         nextOption = reinterpret_cast<const uint8_t *>(aCurOption) + aCurOption->GetSize();
59     }
60 
61     VerifyOrExit(nextOption + sizeof(Option) <= bufferEnd, nextOption = nullptr);
62     VerifyOrExit(reinterpret_cast<const Option *>(nextOption)->GetSize() > 0, nextOption = nullptr);
63     VerifyOrExit(nextOption + reinterpret_cast<const Option *>(nextOption)->GetSize() <= bufferEnd,
64                  nextOption = nullptr);
65 
66 exit:
67     return reinterpret_cast<const Option *>(nextOption);
68 }
69 
PrefixInfoOption(void)70 PrefixInfoOption::PrefixInfoOption(void)
71     : Option(Type::kPrefixInfo, sizeof(*this) / kLengthUnit)
72     , mPrefixLength(0)
73     , mReserved1(0)
74     , mValidLifetime(0)
75     , mPreferredLifetime(0)
76     , mReserved2(0)
77 {
78     OT_UNUSED_VARIABLE(mReserved2);
79 
80     mPrefix.Clear();
81 }
82 
SetOnLink(bool aOnLink)83 void PrefixInfoOption::SetOnLink(bool aOnLink)
84 {
85     if (aOnLink)
86     {
87         mReserved1 |= kOnLinkFlagMask;
88     }
89     else
90     {
91         mReserved1 &= ~kOnLinkFlagMask;
92     }
93 }
94 
SetAutoAddrConfig(bool aAutoAddrConfig)95 void PrefixInfoOption::SetAutoAddrConfig(bool aAutoAddrConfig)
96 {
97     if (aAutoAddrConfig)
98     {
99         mReserved1 |= kAutoConfigFlagMask;
100     }
101     else
102     {
103         mReserved1 &= ~kAutoConfigFlagMask;
104     }
105 }
106 
SetPrefix(const Ip6::Prefix & aPrefix)107 void PrefixInfoOption::SetPrefix(const Ip6::Prefix &aPrefix)
108 {
109     mPrefixLength = aPrefix.mLength;
110     mPrefix       = static_cast<const Ip6::Address &>(aPrefix.mPrefix);
111 }
112 
GetPrefix(void) const113 Ip6::Prefix PrefixInfoOption::GetPrefix(void) const
114 {
115     Ip6::Prefix prefix;
116 
117     prefix.Set(mPrefix.GetBytes(), mPrefixLength);
118     return prefix;
119 }
120 
RouteInfoOption(void)121 RouteInfoOption::RouteInfoOption(void)
122     : Option(Type::kRouteInfo, 0)
123     , mPrefixLength(0)
124     , mReserved(0)
125     , mRouteLifetime(0)
126 {
127     OT_UNUSED_VARIABLE(mReserved);
128 
129     mPrefix.Clear();
130 }
131 
SetPreference(RoutePreference aPreference)132 void RouteInfoOption::SetPreference(RoutePreference aPreference)
133 {
134     mReserved &= ~kPreferenceMask;
135     mReserved |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
136 }
137 
GetPreference(void) const138 RouteInfoOption::RoutePreference RouteInfoOption::GetPreference(void) const
139 {
140     return NetworkData::RoutePreferenceFromValue((mReserved & kPreferenceMask) >> kPreferenceOffset);
141 }
142 
SetPrefix(const Ip6::Prefix & aPrefix)143 void RouteInfoOption::SetPrefix(const Ip6::Prefix &aPrefix)
144 {
145     // The total length (in bytes) of a Router Information Option
146     // is: (8 bytes fixed option header) + (0, 8, or 16 bytes prefix).
147     // Because the length of the option must be padded with 8 bytes,
148     // the length of the prefix (in bits) must be padded with 64 bits.
149     SetLength((aPrefix.mLength + kLengthUnit * CHAR_BIT - 1) / (kLengthUnit * CHAR_BIT) + 1);
150 
151     mPrefixLength = aPrefix.mLength;
152     mPrefix       = static_cast<const Ip6::Address &>(aPrefix.mPrefix);
153 }
154 
GetPrefix(void) const155 Ip6::Prefix RouteInfoOption::GetPrefix(void) const
156 {
157     Ip6::Prefix prefix;
158 
159     prefix.Set(mPrefix.GetBytes(), mPrefixLength);
160     return prefix;
161 }
162 
IsValid(void) const163 bool RouteInfoOption::IsValid(void) const
164 {
165     return (GetLength() == 1 || GetLength() == 2 || GetLength() == 3) &&
166            (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) && NetworkData::IsRoutePreferenceValid(GetPreference());
167 }
168 
SetToDefault(void)169 void RouterAdvMessage::SetToDefault(void)
170 {
171     mHeader.Clear();
172     mHeader.SetType(Ip6::Icmp::Header::kTypeRouterAdvert);
173     mReachableTime = 0;
174     mRetransTimer  = 0;
175 }
176 
operator =(const RouterAdvMessage & aOther)177 const RouterAdvMessage &RouterAdvMessage::operator=(const RouterAdvMessage &aOther)
178 {
179     mHeader = aOther.mHeader;
180 
181     // Set zero value and let platform do the calculation.
182     mHeader.SetChecksum(0);
183 
184     mReachableTime = aOther.mReachableTime;
185     mRetransTimer  = aOther.mRetransTimer;
186 
187     return *this;
188 }
189 
operator ==(const RouterAdvMessage & aOther) const190 bool RouterAdvMessage::operator==(const RouterAdvMessage &aOther) const
191 {
192     return memcmp(&mHeader.mData, &aOther.mHeader.mData, sizeof(mHeader.mData)) == 0 &&
193            mReachableTime == aOther.mReachableTime && mRetransTimer == aOther.mRetransTimer;
194 }
195 
RouterSolicitMessage(void)196 RouterSolicitMessage::RouterSolicitMessage(void)
197 {
198     mHeader.Clear();
199     mHeader.SetType(Ip6::Icmp::Header::kTypeRouterSolicit);
200 }
201 
202 } // namespace RouterAdv
203 
204 } // namespace BorderRouter
205 
206 } // namespace ot
207 
208 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
209