1 /*
2  *    Copyright (c) 2022, 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" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file implements infrastructure network interface.
31  */
32 
33 #include "infra_if.hpp"
34 #include "common/num_utils.hpp"
35 
36 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
37 
38 #include "border_router/routing_manager.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/logging.hpp"
43 #include "net/icmp6.hpp"
44 
45 namespace ot {
46 namespace BorderRouter {
47 
48 RegisterLogModule("InfraIf");
49 
InfraIf(Instance & aInstance)50 InfraIf::InfraIf(Instance &aInstance)
51     : InstanceLocator(aInstance)
52     , mInitialized(false)
53     , mIsRunning(false)
54     , mIfIndex(0)
55 {
56 }
57 
Init(uint32_t aIfIndex)58 Error InfraIf::Init(uint32_t aIfIndex)
59 {
60     Error error = kErrorNone;
61 
62     VerifyOrExit(!mInitialized, error = kErrorInvalidState);
63     VerifyOrExit(aIfIndex > 0, error = kErrorInvalidArgs);
64 
65     mIfIndex     = aIfIndex;
66     mInitialized = true;
67 
68     LogInfo("Init %s", ToString().AsCString());
69 
70 exit:
71     return error;
72 }
73 
Deinit(void)74 void InfraIf::Deinit(void)
75 {
76     mInitialized = false;
77     mIsRunning   = false;
78     mIfIndex     = 0;
79 
80     LogInfo("Deinit");
81 }
82 
HasAddress(const Ip6::Address & aAddress) const83 bool InfraIf::HasAddress(const Ip6::Address &aAddress) const
84 {
85     OT_ASSERT(mInitialized);
86 
87     return otPlatInfraIfHasAddress(mIfIndex, &aAddress);
88 }
89 
Send(const Icmp6Packet & aPacket,const Ip6::Address & aDestination) const90 Error InfraIf::Send(const Icmp6Packet &aPacket, const Ip6::Address &aDestination) const
91 {
92     OT_ASSERT(mInitialized);
93 
94     return otPlatInfraIfSendIcmp6Nd(mIfIndex, &aDestination, aPacket.GetBytes(), aPacket.GetLength());
95 }
96 
HandledReceived(uint32_t aIfIndex,const Ip6::Address & aSource,const Icmp6Packet & aPacket)97 void InfraIf::HandledReceived(uint32_t aIfIndex, const Ip6::Address &aSource, const Icmp6Packet &aPacket)
98 {
99     Error error = kErrorNone;
100 
101     VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
102     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorDrop);
103     VerifyOrExit(aPacket.GetBytes() != nullptr, error = kErrorInvalidArgs);
104     VerifyOrExit(aPacket.GetLength() >= sizeof(Ip6::Icmp::Header), error = kErrorParse);
105 
106     Get<RoutingManager>().HandleReceived(aPacket, aSource);
107 
108 exit:
109     if (error != kErrorNone)
110     {
111         LogDebg("Dropped ICMPv6 message: %s", ErrorToString(error));
112     }
113 }
114 
DiscoverNat64Prefix(void) const115 Error InfraIf::DiscoverNat64Prefix(void) const
116 {
117     OT_ASSERT(mInitialized);
118 
119     return otPlatInfraIfDiscoverNat64Prefix(mIfIndex);
120 }
121 
DiscoverNat64PrefixDone(uint32_t aIfIndex,const Ip6::Prefix & aPrefix)122 void InfraIf::DiscoverNat64PrefixDone(uint32_t aIfIndex, const Ip6::Prefix &aPrefix)
123 {
124     Error error = kErrorNone;
125 
126     OT_UNUSED_VARIABLE(aPrefix);
127 
128     VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
129     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
130 
131 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
132     Get<RoutingManager>().HandleDiscoverNat64PrefixDone(aPrefix);
133 #endif
134 
135 exit:
136     if (error != kErrorNone)
137     {
138         LogDebg("Failed to handle discovered NAT64 synthetic addresses: %s", ErrorToString(error));
139     }
140 }
141 
HandleStateChanged(uint32_t aIfIndex,bool aIsRunning)142 Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning)
143 {
144     Error error = kErrorNone;
145 
146     VerifyOrExit(mInitialized, error = kErrorInvalidState);
147     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
148 
149     VerifyOrExit(aIsRunning != mIsRunning);
150     LogInfo("State changed: %sRUNNING -> %sRUNNING", mIsRunning ? "" : "NOT ", aIsRunning ? "" : "NOT ");
151 
152     mIsRunning = aIsRunning;
153 
154     Get<RoutingManager>().HandleInfraIfStateChanged();
155 
156 exit:
157     return error;
158 }
159 
ToString(void) const160 InfraIf::InfoString InfraIf::ToString(void) const
161 {
162     InfoString string;
163 
164     string.Append("infra netif %lu", ToUlong(mIfIndex));
165     return string;
166 }
167 
168 //---------------------------------------------------------------------------------------------------------------------
169 
otPlatInfraIfRecvIcmp6Nd(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Address * aSrcAddress,const uint8_t * aBuffer,uint16_t aBufferLength)170 extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance         *aInstance,
171                                          uint32_t            aInfraIfIndex,
172                                          const otIp6Address *aSrcAddress,
173                                          const uint8_t      *aBuffer,
174                                          uint16_t            aBufferLength)
175 {
176     InfraIf::Icmp6Packet packet;
177 
178     packet.Init(aBuffer, aBufferLength);
179     AsCoreType(aInstance).Get<InfraIf>().HandledReceived(aInfraIfIndex, AsCoreType(aSrcAddress), packet);
180 }
181 
otPlatInfraIfStateChanged(otInstance * aInstance,uint32_t aInfraIfIndex,bool aIsRunning)182 extern "C" otError otPlatInfraIfStateChanged(otInstance *aInstance, uint32_t aInfraIfIndex, bool aIsRunning)
183 {
184     return AsCoreType(aInstance).Get<InfraIf>().HandleStateChanged(aInfraIfIndex, aIsRunning);
185 }
186 
otPlatInfraIfDiscoverNat64PrefixDone(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Prefix * aIp6Prefix)187 extern "C" void otPlatInfraIfDiscoverNat64PrefixDone(otInstance        *aInstance,
188                                                      uint32_t           aInfraIfIndex,
189                                                      const otIp6Prefix *aIp6Prefix)
190 {
191     AsCoreType(aInstance).Get<InfraIf>().DiscoverNat64PrefixDone(aInfraIfIndex, AsCoreType(aIp6Prefix));
192 }
193 
194 } // namespace BorderRouter
195 } // namespace ot
196 
197 //---------------------------------------------------------------------------------------------------------------------
198 
199 #if OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE
otPlatInfraIfHasAddress(uint32_t,const otIp6Address *)200 OT_TOOL_WEAK bool otPlatInfraIfHasAddress(uint32_t, const otIp6Address *) { return false; }
201 
otPlatInfraIfSendIcmp6Nd(uint32_t,const otIp6Address *,const uint8_t *,uint16_t)202 OT_TOOL_WEAK otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, const uint8_t *, uint16_t)
203 {
204     return OT_ERROR_FAILED;
205 }
206 
otPlatInfraIfDiscoverNat64Prefix(uint32_t)207 OT_TOOL_WEAK otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; }
208 #endif
209 
210 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
211