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 "instance/instance.hpp"
39 
40 namespace ot {
41 namespace BorderRouter {
42 
43 RegisterLogModule("InfraIf");
44 
InfraIf(Instance & aInstance)45 InfraIf::InfraIf(Instance &aInstance)
46     : InstanceLocator(aInstance)
47     , mInitialized(false)
48     , mIsRunning(false)
49     , mIfIndex(0)
50 {
51 }
52 
Init(uint32_t aIfIndex)53 Error InfraIf::Init(uint32_t aIfIndex)
54 {
55     Error error = kErrorNone;
56 
57     VerifyOrExit(!mInitialized, error = kErrorInvalidState);
58 
59     mIfIndex     = aIfIndex;
60     mInitialized = true;
61 
62     LogInfo("Init %s", ToString().AsCString());
63 
64 exit:
65     return error;
66 }
67 
Deinit(void)68 void InfraIf::Deinit(void)
69 {
70     mInitialized = false;
71     mIsRunning   = false;
72     mIfIndex     = 0;
73 
74     LogInfo("Deinit");
75 }
76 
HasAddress(const Ip6::Address & aAddress) const77 bool InfraIf::HasAddress(const Ip6::Address &aAddress) const
78 {
79     OT_ASSERT(mInitialized);
80 
81     return otPlatInfraIfHasAddress(mIfIndex, &aAddress);
82 }
83 
Send(const Icmp6Packet & aPacket,const Ip6::Address & aDestination) const84 Error InfraIf::Send(const Icmp6Packet &aPacket, const Ip6::Address &aDestination) const
85 {
86     OT_ASSERT(mInitialized);
87 
88     return otPlatInfraIfSendIcmp6Nd(mIfIndex, &aDestination, aPacket.GetBytes(), aPacket.GetLength());
89 }
90 
HandledReceived(uint32_t aIfIndex,const Ip6::Address & aSource,const Icmp6Packet & aPacket)91 void InfraIf::HandledReceived(uint32_t aIfIndex, const Ip6::Address &aSource, const Icmp6Packet &aPacket)
92 {
93     Error error = kErrorNone;
94 
95     VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
96     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorDrop);
97     VerifyOrExit(aPacket.GetBytes() != nullptr, error = kErrorInvalidArgs);
98     VerifyOrExit(aPacket.GetLength() >= sizeof(Ip6::Icmp::Header), error = kErrorParse);
99 
100     Get<RoutingManager>().HandleReceived(aPacket, aSource);
101 
102 exit:
103     if (error != kErrorNone)
104     {
105         LogDebg("Dropped ICMPv6 message: %s", ErrorToString(error));
106     }
107 }
108 
DiscoverNat64Prefix(void) const109 Error InfraIf::DiscoverNat64Prefix(void) const
110 {
111     OT_ASSERT(mInitialized);
112 
113 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
114     return otPlatInfraIfDiscoverNat64Prefix(mIfIndex);
115 #else
116     return kErrorNotImplemented;
117 #endif
118 }
119 
DiscoverNat64PrefixDone(uint32_t aIfIndex,const Ip6::Prefix & aPrefix)120 void InfraIf::DiscoverNat64PrefixDone(uint32_t aIfIndex, const Ip6::Prefix &aPrefix)
121 {
122     Error error = kErrorNone;
123 
124     OT_UNUSED_VARIABLE(aPrefix);
125 
126     VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
127     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
128 
129 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
130     Get<RoutingManager>().HandleDiscoverNat64PrefixDone(aPrefix);
131 #endif
132 
133 exit:
134     if (error != kErrorNone)
135     {
136         LogDebg("Failed to handle discovered NAT64 synthetic addresses: %s", ErrorToString(error));
137     }
138 }
139 
GetLinkLayerAddress(LinkLayerAddress & aLinkLayerAddress)140 Error InfraIf::GetLinkLayerAddress(LinkLayerAddress &aLinkLayerAddress)
141 {
142     return otPlatGetInfraIfLinkLayerAddress(&GetInstance(), mIfIndex, &aLinkLayerAddress);
143 }
144 
HandleStateChanged(uint32_t aIfIndex,bool aIsRunning)145 Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning)
146 {
147     Error error = kErrorNone;
148 
149     VerifyOrExit(mInitialized, error = kErrorInvalidState);
150     VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
151 
152     VerifyOrExit(aIsRunning != mIsRunning);
153     LogInfo("State changed: %sRUNNING -> %sRUNNING", mIsRunning ? "" : "NOT ", aIsRunning ? "" : "NOT ");
154 
155     mIsRunning = aIsRunning;
156 
157     Get<RoutingManager>().HandleInfraIfStateChanged();
158 
159 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
160     Get<Srp::AdvertisingProxy>().HandleInfraIfStateChanged();
161 #endif
162 
163 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
164     Get<Dns::ServiceDiscovery::Server>().HandleInfraIfStateChanged();
165 #endif
166 
167 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF
168     Get<Dns::Multicast::Core>().HandleInfraIfStateChanged();
169 #endif
170 
171 exit:
172     return error;
173 }
174 
ToString(void) const175 InfraIf::InfoString InfraIf::ToString(void) const
176 {
177     InfoString string;
178 
179     string.Append("infra netif %lu", ToUlong(mIfIndex));
180     return string;
181 }
182 
183 //---------------------------------------------------------------------------------------------------------------------
184 
otPlatInfraIfRecvIcmp6Nd(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Address * aSrcAddress,const uint8_t * aBuffer,uint16_t aBufferLength)185 extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance         *aInstance,
186                                          uint32_t            aInfraIfIndex,
187                                          const otIp6Address *aSrcAddress,
188                                          const uint8_t      *aBuffer,
189                                          uint16_t            aBufferLength)
190 {
191     InfraIf::Icmp6Packet packet;
192 
193     packet.Init(aBuffer, aBufferLength);
194     AsCoreType(aInstance).Get<InfraIf>().HandledReceived(aInfraIfIndex, AsCoreType(aSrcAddress), packet);
195 }
196 
otPlatInfraIfStateChanged(otInstance * aInstance,uint32_t aInfraIfIndex,bool aIsRunning)197 extern "C" otError otPlatInfraIfStateChanged(otInstance *aInstance, uint32_t aInfraIfIndex, bool aIsRunning)
198 {
199     return AsCoreType(aInstance).Get<InfraIf>().HandleStateChanged(aInfraIfIndex, aIsRunning);
200 }
201 
otPlatInfraIfDiscoverNat64PrefixDone(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Prefix * aIp6Prefix)202 extern "C" void otPlatInfraIfDiscoverNat64PrefixDone(otInstance        *aInstance,
203                                                      uint32_t           aInfraIfIndex,
204                                                      const otIp6Prefix *aIp6Prefix)
205 {
206     AsCoreType(aInstance).Get<InfraIf>().DiscoverNat64PrefixDone(aInfraIfIndex, AsCoreType(aIp6Prefix));
207 }
208 
209 } // namespace BorderRouter
210 } // namespace ot
211 
212 //---------------------------------------------------------------------------------------------------------------------
213 
214 #if OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE
otPlatInfraIfHasAddress(uint32_t,const otIp6Address *)215 OT_TOOL_WEAK bool otPlatInfraIfHasAddress(uint32_t, const otIp6Address *) { return false; }
216 
otPlatInfraIfSendIcmp6Nd(uint32_t,const otIp6Address *,const uint8_t *,uint16_t)217 OT_TOOL_WEAK otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, const uint8_t *, uint16_t)
218 {
219     return OT_ERROR_FAILED;
220 }
221 
otPlatInfraIfDiscoverNat64Prefix(uint32_t)222 OT_TOOL_WEAK otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; }
223 #endif
224 
otPlatGetInfraIfLinkLayerAddress(otInstance *,uint32_t,otPlatInfraIfLinkLayerAddress *)225 extern "C" OT_TOOL_WEAK otError otPlatGetInfraIfLinkLayerAddress(otInstance *,
226                                                                  uint32_t,
227                                                                  otPlatInfraIfLinkLayerAddress *)
228 {
229     return OT_ERROR_FAILED;
230 }
231 
232 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
233