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/locator_getters.hpp"
41 #include "common/logging.hpp"
42 #include "instance/instance.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 
64     mIfIndex     = aIfIndex;
65     mInitialized = true;
66 
67     LogInfo("Init %s", ToString().AsCString());
68 
69 exit:
70     return error;
71 }
72 
Deinit(void)73 void InfraIf::Deinit(void)
74 {
75     mInitialized = false;
76     mIsRunning   = false;
77     mIfIndex     = 0;
78 
79     LogInfo("Deinit");
80 }
81 
HasAddress(const Ip6::Address & aAddress) const82 bool InfraIf::HasAddress(const Ip6::Address &aAddress) const
83 {
84     OT_ASSERT(mInitialized);
85 
86     return otPlatInfraIfHasAddress(mIfIndex, &aAddress);
87 }
88 
Send(const Icmp6Packet & aPacket,const Ip6::Address & aDestination) const89 Error InfraIf::Send(const Icmp6Packet &aPacket, const Ip6::Address &aDestination) const
90 {
91     OT_ASSERT(mInitialized);
92 
93     return otPlatInfraIfSendIcmp6Nd(mIfIndex, &aDestination, aPacket.GetBytes(), aPacket.GetLength());
94 }
95 
HandledReceived(uint32_t aIfIndex,const Ip6::Address & aSource,const Icmp6Packet & aPacket)96 void InfraIf::HandledReceived(uint32_t aIfIndex, const Ip6::Address &aSource, const Icmp6Packet &aPacket)
97 {
98     Error error = kErrorNone;
99 
100     VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
101     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorDrop);
102     VerifyOrExit(aPacket.GetBytes() != nullptr, error = kErrorInvalidArgs);
103     VerifyOrExit(aPacket.GetLength() >= sizeof(Ip6::Icmp::Header), error = kErrorParse);
104 
105     Get<RoutingManager>().HandleReceived(aPacket, aSource);
106 
107 exit:
108     if (error != kErrorNone)
109     {
110         LogDebg("Dropped ICMPv6 message: %s", ErrorToString(error));
111     }
112 }
113 
DiscoverNat64Prefix(void) const114 Error InfraIf::DiscoverNat64Prefix(void) const
115 {
116     OT_ASSERT(mInitialized);
117 
118     return otPlatInfraIfDiscoverNat64Prefix(mIfIndex);
119 }
120 
DiscoverNat64PrefixDone(uint32_t aIfIndex,const Ip6::Prefix & aPrefix)121 void InfraIf::DiscoverNat64PrefixDone(uint32_t aIfIndex, const Ip6::Prefix &aPrefix)
122 {
123     Error error = kErrorNone;
124 
125     OT_UNUSED_VARIABLE(aPrefix);
126 
127     VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
128     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
129 
130 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
131     Get<RoutingManager>().HandleDiscoverNat64PrefixDone(aPrefix);
132 #endif
133 
134 exit:
135     if (error != kErrorNone)
136     {
137         LogDebg("Failed to handle discovered NAT64 synthetic addresses: %s", ErrorToString(error));
138     }
139 }
140 
HandleStateChanged(uint32_t aIfIndex,bool aIsRunning)141 Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning)
142 {
143     Error error = kErrorNone;
144 
145     VerifyOrExit(mInitialized, error = kErrorInvalidState);
146     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
147 
148     VerifyOrExit(aIsRunning != mIsRunning);
149     LogInfo("State changed: %sRUNNING -> %sRUNNING", mIsRunning ? "" : "NOT ", aIsRunning ? "" : "NOT ");
150 
151     mIsRunning = aIsRunning;
152 
153     Get<RoutingManager>().HandleInfraIfStateChanged();
154 
155 exit:
156     return error;
157 }
158 
ToString(void) const159 InfraIf::InfoString InfraIf::ToString(void) const
160 {
161     InfoString string;
162 
163     string.Append("infra netif %lu", ToUlong(mIfIndex));
164     return string;
165 }
166 
167 //---------------------------------------------------------------------------------------------------------------------
168 
otPlatInfraIfRecvIcmp6Nd(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Address * aSrcAddress,const uint8_t * aBuffer,uint16_t aBufferLength)169 extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance         *aInstance,
170                                          uint32_t            aInfraIfIndex,
171                                          const otIp6Address *aSrcAddress,
172                                          const uint8_t      *aBuffer,
173                                          uint16_t            aBufferLength)
174 {
175     InfraIf::Icmp6Packet packet;
176 
177     packet.Init(aBuffer, aBufferLength);
178     AsCoreType(aInstance).Get<InfraIf>().HandledReceived(aInfraIfIndex, AsCoreType(aSrcAddress), packet);
179 }
180 
otPlatInfraIfStateChanged(otInstance * aInstance,uint32_t aInfraIfIndex,bool aIsRunning)181 extern "C" otError otPlatInfraIfStateChanged(otInstance *aInstance, uint32_t aInfraIfIndex, bool aIsRunning)
182 {
183     return AsCoreType(aInstance).Get<InfraIf>().HandleStateChanged(aInfraIfIndex, aIsRunning);
184 }
185 
otPlatInfraIfDiscoverNat64PrefixDone(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Prefix * aIp6Prefix)186 extern "C" void otPlatInfraIfDiscoverNat64PrefixDone(otInstance        *aInstance,
187                                                      uint32_t           aInfraIfIndex,
188                                                      const otIp6Prefix *aIp6Prefix)
189 {
190     AsCoreType(aInstance).Get<InfraIf>().DiscoverNat64PrefixDone(aInfraIfIndex, AsCoreType(aIp6Prefix));
191 }
192 
193 } // namespace BorderRouter
194 } // namespace ot
195 
196 //---------------------------------------------------------------------------------------------------------------------
197 
198 #if OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE
otPlatInfraIfHasAddress(uint32_t,const otIp6Address *)199 OT_TOOL_WEAK bool otPlatInfraIfHasAddress(uint32_t, const otIp6Address *) { return false; }
200 
otPlatInfraIfSendIcmp6Nd(uint32_t,const otIp6Address *,const uint8_t *,uint16_t)201 OT_TOOL_WEAK otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, const uint8_t *, uint16_t)
202 {
203     return OT_ERROR_FAILED;
204 }
205 
otPlatInfraIfDiscoverNat64Prefix(uint32_t)206 OT_TOOL_WEAK otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; }
207 #endif
208 
209 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
210