xref: /aosp_15_r20/external/ot-br-posix/src/backbone_router/nd_proxy.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker /*
2*4a64e381SAndroid Build Coastguard Worker  *    Copyright (c) 2020, The OpenThread Authors.
3*4a64e381SAndroid Build Coastguard Worker  *    All rights reserved.
4*4a64e381SAndroid Build Coastguard Worker  *
5*4a64e381SAndroid Build Coastguard Worker  *    Redistribution and use in source and binary forms, with or without
6*4a64e381SAndroid Build Coastguard Worker  *    modification, are permitted provided that the following conditions are met:
7*4a64e381SAndroid Build Coastguard Worker  *    1. Redistributions of source code must retain the above copyright
8*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer.
9*4a64e381SAndroid Build Coastguard Worker  *    2. Redistributions in binary form must reproduce the above copyright
10*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer in the
11*4a64e381SAndroid Build Coastguard Worker  *       documentation and/or other materials provided with the distribution.
12*4a64e381SAndroid Build Coastguard Worker  *    3. Neither the name of the copyright holder nor the
13*4a64e381SAndroid Build Coastguard Worker  *       names of its contributors may be used to endorse or promote products
14*4a64e381SAndroid Build Coastguard Worker  *       derived from this software without specific prior written permission.
15*4a64e381SAndroid Build Coastguard Worker  *
16*4a64e381SAndroid Build Coastguard Worker  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*4a64e381SAndroid Build Coastguard Worker  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4a64e381SAndroid Build Coastguard Worker  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4a64e381SAndroid Build Coastguard Worker  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*4a64e381SAndroid Build Coastguard Worker  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4a64e381SAndroid Build Coastguard Worker  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4a64e381SAndroid Build Coastguard Worker  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4a64e381SAndroid Build Coastguard Worker  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4a64e381SAndroid Build Coastguard Worker  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4a64e381SAndroid Build Coastguard Worker  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4a64e381SAndroid Build Coastguard Worker  *    POSSIBILITY OF SUCH DAMAGE.
27*4a64e381SAndroid Build Coastguard Worker  */
28*4a64e381SAndroid Build Coastguard Worker 
29*4a64e381SAndroid Build Coastguard Worker /**
30*4a64e381SAndroid Build Coastguard Worker  * @file
31*4a64e381SAndroid Build Coastguard Worker  *   The file implements the ND Proxy management.
32*4a64e381SAndroid Build Coastguard Worker  */
33*4a64e381SAndroid Build Coastguard Worker 
34*4a64e381SAndroid Build Coastguard Worker #define OTBR_LOG_TAG "NDPROXY"
35*4a64e381SAndroid Build Coastguard Worker 
36*4a64e381SAndroid Build Coastguard Worker #include "backbone_router/nd_proxy.hpp"
37*4a64e381SAndroid Build Coastguard Worker 
38*4a64e381SAndroid Build Coastguard Worker #if OTBR_ENABLE_DUA_ROUTING
39*4a64e381SAndroid Build Coastguard Worker 
40*4a64e381SAndroid Build Coastguard Worker #include <openthread/backbone_router_ftd.h>
41*4a64e381SAndroid Build Coastguard Worker 
42*4a64e381SAndroid Build Coastguard Worker #include <assert.h>
43*4a64e381SAndroid Build Coastguard Worker #include <net/if.h>
44*4a64e381SAndroid Build Coastguard Worker #include <netinet/icmp6.h>
45*4a64e381SAndroid Build Coastguard Worker #include <netinet/ip6.h>
46*4a64e381SAndroid Build Coastguard Worker #include <sys/ioctl.h>
47*4a64e381SAndroid Build Coastguard Worker #include <unistd.h>
48*4a64e381SAndroid Build Coastguard Worker 
49*4a64e381SAndroid Build Coastguard Worker #if __linux__
50*4a64e381SAndroid Build Coastguard Worker #include <linux/netfilter.h>
51*4a64e381SAndroid Build Coastguard Worker #else
52*4a64e381SAndroid Build Coastguard Worker #error "Platform not supported"
53*4a64e381SAndroid Build Coastguard Worker #endif
54*4a64e381SAndroid Build Coastguard Worker 
55*4a64e381SAndroid Build Coastguard Worker #include "backbone_router/constants.hpp"
56*4a64e381SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
57*4a64e381SAndroid Build Coastguard Worker #include "common/logging.hpp"
58*4a64e381SAndroid Build Coastguard Worker #include "common/types.hpp"
59*4a64e381SAndroid Build Coastguard Worker #include "utils/system_utils.hpp"
60*4a64e381SAndroid Build Coastguard Worker 
61*4a64e381SAndroid Build Coastguard Worker namespace otbr {
62*4a64e381SAndroid Build Coastguard Worker namespace BackboneRouter {
63*4a64e381SAndroid Build Coastguard Worker 
Enable(const Ip6Prefix & aDomainPrefix)64*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::Enable(const Ip6Prefix &aDomainPrefix)
65*4a64e381SAndroid Build Coastguard Worker {
66*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
67*4a64e381SAndroid Build Coastguard Worker 
68*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!IsEnabled());
69*4a64e381SAndroid Build Coastguard Worker 
70*4a64e381SAndroid Build Coastguard Worker     assert(aDomainPrefix.IsValid());
71*4a64e381SAndroid Build Coastguard Worker     mDomainPrefix = aDomainPrefix;
72*4a64e381SAndroid Build Coastguard Worker 
73*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = InitIcmp6RawSocket());
74*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = UpdateMacAddress());
75*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = InitNetfilterQueue());
76*4a64e381SAndroid Build Coastguard Worker 
77*4a64e381SAndroid Build Coastguard Worker     // Add ip6tables rule for unicast ICMPv6 messages
78*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(SystemUtils::ExecuteCommand(
79*4a64e381SAndroid Build Coastguard Worker                      "ip6tables -t raw -A PREROUTING -6 -d %s -p icmpv6 --icmpv6-type neighbor-solicitation -i %s -j "
80*4a64e381SAndroid Build Coastguard Worker                      "NFQUEUE --queue-num 88",
81*4a64e381SAndroid Build Coastguard Worker                      mDomainPrefix.ToString().c_str(), mBackboneInterfaceName.c_str()) == 0,
82*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
83*4a64e381SAndroid Build Coastguard Worker 
84*4a64e381SAndroid Build Coastguard Worker exit:
85*4a64e381SAndroid Build Coastguard Worker     if (error != OTBR_ERROR_NONE)
86*4a64e381SAndroid Build Coastguard Worker     {
87*4a64e381SAndroid Build Coastguard Worker         FiniNetfilterQueue();
88*4a64e381SAndroid Build Coastguard Worker         FiniIcmp6RawSocket();
89*4a64e381SAndroid Build Coastguard Worker     }
90*4a64e381SAndroid Build Coastguard Worker 
91*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__);
92*4a64e381SAndroid Build Coastguard Worker }
93*4a64e381SAndroid Build Coastguard Worker 
Disable(void)94*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::Disable(void)
95*4a64e381SAndroid Build Coastguard Worker {
96*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
97*4a64e381SAndroid Build Coastguard Worker 
98*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsEnabled());
99*4a64e381SAndroid Build Coastguard Worker 
100*4a64e381SAndroid Build Coastguard Worker     FiniNetfilterQueue();
101*4a64e381SAndroid Build Coastguard Worker     FiniIcmp6RawSocket();
102*4a64e381SAndroid Build Coastguard Worker 
103*4a64e381SAndroid Build Coastguard Worker     // Remove ip6tables rule for unicast ICMPv6 messages
104*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(SystemUtils::ExecuteCommand(
105*4a64e381SAndroid Build Coastguard Worker                      "ip6tables -t raw -D PREROUTING -6 -d %s -p icmpv6 --icmpv6-type neighbor-solicitation -i %s -j "
106*4a64e381SAndroid Build Coastguard Worker                      "NFQUEUE --queue-num 88",
107*4a64e381SAndroid Build Coastguard Worker                      mDomainPrefix.ToString().c_str(), mBackboneInterfaceName.c_str()) == 0,
108*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
109*4a64e381SAndroid Build Coastguard Worker 
110*4a64e381SAndroid Build Coastguard Worker exit:
111*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__);
112*4a64e381SAndroid Build Coastguard Worker }
113*4a64e381SAndroid Build Coastguard Worker 
Init(void)114*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::Init(void)
115*4a64e381SAndroid Build Coastguard Worker {
116*4a64e381SAndroid Build Coastguard Worker     mBackboneIfIndex = if_nametoindex(mBackboneInterfaceName.c_str());
117*4a64e381SAndroid Build Coastguard Worker     VerifyOrDie(mBackboneIfIndex > 0, "if_nametoindex failed");
118*4a64e381SAndroid Build Coastguard Worker }
119*4a64e381SAndroid Build Coastguard Worker 
Update(MainloopContext & aMainloop)120*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::Update(MainloopContext &aMainloop)
121*4a64e381SAndroid Build Coastguard Worker {
122*4a64e381SAndroid Build Coastguard Worker     if (mIcmp6RawSock >= 0)
123*4a64e381SAndroid Build Coastguard Worker     {
124*4a64e381SAndroid Build Coastguard Worker         aMainloop.AddFdToReadSet(mIcmp6RawSock);
125*4a64e381SAndroid Build Coastguard Worker     }
126*4a64e381SAndroid Build Coastguard Worker 
127*4a64e381SAndroid Build Coastguard Worker     if (mUnicastNsQueueSock >= 0)
128*4a64e381SAndroid Build Coastguard Worker     {
129*4a64e381SAndroid Build Coastguard Worker         aMainloop.AddFdToReadSet(mUnicastNsQueueSock);
130*4a64e381SAndroid Build Coastguard Worker     }
131*4a64e381SAndroid Build Coastguard Worker }
132*4a64e381SAndroid Build Coastguard Worker 
Process(const MainloopContext & aMainloop)133*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::Process(const MainloopContext &aMainloop)
134*4a64e381SAndroid Build Coastguard Worker {
135*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsEnabled());
136*4a64e381SAndroid Build Coastguard Worker 
137*4a64e381SAndroid Build Coastguard Worker     if (FD_ISSET(mIcmp6RawSock, &aMainloop.mReadFdSet))
138*4a64e381SAndroid Build Coastguard Worker     {
139*4a64e381SAndroid Build Coastguard Worker         ProcessMulticastNeighborSolicition();
140*4a64e381SAndroid Build Coastguard Worker     }
141*4a64e381SAndroid Build Coastguard Worker 
142*4a64e381SAndroid Build Coastguard Worker     if (FD_ISSET(mUnicastNsQueueSock, &aMainloop.mReadFdSet))
143*4a64e381SAndroid Build Coastguard Worker     {
144*4a64e381SAndroid Build Coastguard Worker         ProcessUnicastNeighborSolicition();
145*4a64e381SAndroid Build Coastguard Worker     }
146*4a64e381SAndroid Build Coastguard Worker exit:
147*4a64e381SAndroid Build Coastguard Worker     return;
148*4a64e381SAndroid Build Coastguard Worker }
149*4a64e381SAndroid Build Coastguard Worker 
ProcessMulticastNeighborSolicition()150*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::ProcessMulticastNeighborSolicition()
151*4a64e381SAndroid Build Coastguard Worker {
152*4a64e381SAndroid Build Coastguard Worker     struct msghdr     msghdr;
153*4a64e381SAndroid Build Coastguard Worker     sockaddr_in6      sin6;
154*4a64e381SAndroid Build Coastguard Worker     struct iovec      iovec;
155*4a64e381SAndroid Build Coastguard Worker     ssize_t           len;
156*4a64e381SAndroid Build Coastguard Worker     struct icmp6_hdr *icmp6header;
157*4a64e381SAndroid Build Coastguard Worker     struct cmsghdr   *cmsghdr;
158*4a64e381SAndroid Build Coastguard Worker     unsigned char     cbuf[2 * CMSG_SPACE(sizeof(struct in6_pktinfo))];
159*4a64e381SAndroid Build Coastguard Worker     uint8_t           packet[kMaxICMP6PacketSize];
160*4a64e381SAndroid Build Coastguard Worker     otbrError         error = OTBR_ERROR_NONE;
161*4a64e381SAndroid Build Coastguard Worker     bool              found = false;
162*4a64e381SAndroid Build Coastguard Worker 
163*4a64e381SAndroid Build Coastguard Worker     iovec.iov_len  = kMaxICMP6PacketSize;
164*4a64e381SAndroid Build Coastguard Worker     iovec.iov_base = packet;
165*4a64e381SAndroid Build Coastguard Worker 
166*4a64e381SAndroid Build Coastguard Worker     msghdr.msg_name       = &sin6;
167*4a64e381SAndroid Build Coastguard Worker     msghdr.msg_namelen    = sizeof(sin6);
168*4a64e381SAndroid Build Coastguard Worker     msghdr.msg_iov        = &iovec;
169*4a64e381SAndroid Build Coastguard Worker     msghdr.msg_iovlen     = 1;
170*4a64e381SAndroid Build Coastguard Worker     msghdr.msg_control    = cbuf;
171*4a64e381SAndroid Build Coastguard Worker     msghdr.msg_controllen = sizeof(cbuf);
172*4a64e381SAndroid Build Coastguard Worker 
173*4a64e381SAndroid Build Coastguard Worker     len = recvmsg(mIcmp6RawSock, &msghdr, 0);
174*4a64e381SAndroid Build Coastguard Worker 
175*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(len >= static_cast<ssize_t>(sizeof(struct icmp6_hdr)), error = OTBR_ERROR_ERRNO);
176*4a64e381SAndroid Build Coastguard Worker 
177*4a64e381SAndroid Build Coastguard Worker     {
178*4a64e381SAndroid Build Coastguard Worker         Ip6Address &src = *reinterpret_cast<Ip6Address *>(&sin6.sin6_addr);
179*4a64e381SAndroid Build Coastguard Worker 
180*4a64e381SAndroid Build Coastguard Worker         icmp6header = reinterpret_cast<icmp6_hdr *>(packet);
181*4a64e381SAndroid Build Coastguard Worker 
182*4a64e381SAndroid Build Coastguard Worker         // only process neighbor solicit
183*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(icmp6header->icmp6_type == ND_NEIGHBOR_SOLICIT, error = OTBR_ERROR_PARSE);
184*4a64e381SAndroid Build Coastguard Worker 
185*4a64e381SAndroid Build Coastguard Worker         otbrLogDebug("NdProxyManager: Received ND-NS from %s", src.ToString().c_str());
186*4a64e381SAndroid Build Coastguard Worker 
187*4a64e381SAndroid Build Coastguard Worker         for (cmsghdr = CMSG_FIRSTHDR(&msghdr); cmsghdr; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr))
188*4a64e381SAndroid Build Coastguard Worker         {
189*4a64e381SAndroid Build Coastguard Worker             if (cmsghdr->cmsg_level != IPPROTO_IPV6)
190*4a64e381SAndroid Build Coastguard Worker             {
191*4a64e381SAndroid Build Coastguard Worker                 continue;
192*4a64e381SAndroid Build Coastguard Worker             }
193*4a64e381SAndroid Build Coastguard Worker 
194*4a64e381SAndroid Build Coastguard Worker             switch (cmsghdr->cmsg_type)
195*4a64e381SAndroid Build Coastguard Worker             {
196*4a64e381SAndroid Build Coastguard Worker             case IPV6_PKTINFO:
197*4a64e381SAndroid Build Coastguard Worker                 if (cmsghdr->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
198*4a64e381SAndroid Build Coastguard Worker                 {
199*4a64e381SAndroid Build Coastguard Worker                     struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsghdr);
200*4a64e381SAndroid Build Coastguard Worker                     Ip6Address         &dst     = *reinterpret_cast<Ip6Address *>(&pktinfo->ipi6_addr);
201*4a64e381SAndroid Build Coastguard Worker                     uint32_t            ifindex = pktinfo->ipi6_ifindex;
202*4a64e381SAndroid Build Coastguard Worker 
203*4a64e381SAndroid Build Coastguard Worker                     for (const Ip6Address &ipaddr : mNdProxySet)
204*4a64e381SAndroid Build Coastguard Worker                     {
205*4a64e381SAndroid Build Coastguard Worker                         if (ipaddr.ToSolicitedNodeMulticastAddress() == dst)
206*4a64e381SAndroid Build Coastguard Worker                         {
207*4a64e381SAndroid Build Coastguard Worker                             found = true;
208*4a64e381SAndroid Build Coastguard Worker                             break;
209*4a64e381SAndroid Build Coastguard Worker                         }
210*4a64e381SAndroid Build Coastguard Worker                     }
211*4a64e381SAndroid Build Coastguard Worker 
212*4a64e381SAndroid Build Coastguard Worker                     otbrLogDebug("NdProxyManager: dst=%s, ifindex=%d, proxying=%s", dst.ToString().c_str(), ifindex,
213*4a64e381SAndroid Build Coastguard Worker                                  found ? "Y" : "N");
214*4a64e381SAndroid Build Coastguard Worker                 }
215*4a64e381SAndroid Build Coastguard Worker                 break;
216*4a64e381SAndroid Build Coastguard Worker 
217*4a64e381SAndroid Build Coastguard Worker             case IPV6_HOPLIMIT:
218*4a64e381SAndroid Build Coastguard Worker                 if (cmsghdr->cmsg_len == CMSG_LEN(sizeof(int)))
219*4a64e381SAndroid Build Coastguard Worker                 {
220*4a64e381SAndroid Build Coastguard Worker                     int hops = *(int *)CMSG_DATA(cmsghdr);
221*4a64e381SAndroid Build Coastguard Worker 
222*4a64e381SAndroid Build Coastguard Worker                     otbrLogDebug("NdProxyManager: hops=%d (%s)", hops, hops == 255 ? "Good" : "Bad");
223*4a64e381SAndroid Build Coastguard Worker 
224*4a64e381SAndroid Build Coastguard Worker                     VerifyOrExit(hops == 255);
225*4a64e381SAndroid Build Coastguard Worker                 }
226*4a64e381SAndroid Build Coastguard Worker                 break;
227*4a64e381SAndroid Build Coastguard Worker             }
228*4a64e381SAndroid Build Coastguard Worker         }
229*4a64e381SAndroid Build Coastguard Worker 
230*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(found, error = OTBR_ERROR_NOT_FOUND);
231*4a64e381SAndroid Build Coastguard Worker 
232*4a64e381SAndroid Build Coastguard Worker         {
233*4a64e381SAndroid Build Coastguard Worker             struct nd_neighbor_solicit *ns     = reinterpret_cast<struct nd_neighbor_solicit *>(packet);
234*4a64e381SAndroid Build Coastguard Worker             Ip6Address                 &target = *reinterpret_cast<Ip6Address *>(&ns->nd_ns_target);
235*4a64e381SAndroid Build Coastguard Worker 
236*4a64e381SAndroid Build Coastguard Worker             otbrLogInfo("NdProxyManager: send solicited NA for multicast NS: src=%s, target=%s", src.ToString().c_str(),
237*4a64e381SAndroid Build Coastguard Worker                         target.ToString().c_str());
238*4a64e381SAndroid Build Coastguard Worker 
239*4a64e381SAndroid Build Coastguard Worker             SendNeighborAdvertisement(target, src);
240*4a64e381SAndroid Build Coastguard Worker         }
241*4a64e381SAndroid Build Coastguard Worker     }
242*4a64e381SAndroid Build Coastguard Worker 
243*4a64e381SAndroid Build Coastguard Worker exit:
244*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__);
245*4a64e381SAndroid Build Coastguard Worker }
246*4a64e381SAndroid Build Coastguard Worker 
ProcessUnicastNeighborSolicition(void)247*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::ProcessUnicastNeighborSolicition(void)
248*4a64e381SAndroid Build Coastguard Worker {
249*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
250*4a64e381SAndroid Build Coastguard Worker     char      packet[kMaxICMP6PacketSize];
251*4a64e381SAndroid Build Coastguard Worker     ssize_t   len;
252*4a64e381SAndroid Build Coastguard Worker 
253*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((len = recv(mUnicastNsQueueSock, packet, sizeof(packet), 0)) >= 0, error = OTBR_ERROR_ERRNO);
254*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(nfq_handle_packet(mNfqHandler, packet, len) == 0, error = OTBR_ERROR_ERRNO);
255*4a64e381SAndroid Build Coastguard Worker 
256*4a64e381SAndroid Build Coastguard Worker     error = OTBR_ERROR_NONE;
257*4a64e381SAndroid Build Coastguard Worker 
258*4a64e381SAndroid Build Coastguard Worker exit:
259*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__);
260*4a64e381SAndroid Build Coastguard Worker }
261*4a64e381SAndroid Build Coastguard Worker 
HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent,const otIp6Address * aDua)262*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aDua)
263*4a64e381SAndroid Build Coastguard Worker {
264*4a64e381SAndroid Build Coastguard Worker     Ip6Address target;
265*4a64e381SAndroid Build Coastguard Worker 
266*4a64e381SAndroid Build Coastguard Worker     if (aEvent != OT_BACKBONE_ROUTER_NDPROXY_CLEARED)
267*4a64e381SAndroid Build Coastguard Worker     {
268*4a64e381SAndroid Build Coastguard Worker         assert(aDua != nullptr);
269*4a64e381SAndroid Build Coastguard Worker         target = Ip6Address(aDua->mFields.m8);
270*4a64e381SAndroid Build Coastguard Worker     }
271*4a64e381SAndroid Build Coastguard Worker 
272*4a64e381SAndroid Build Coastguard Worker     switch (aEvent)
273*4a64e381SAndroid Build Coastguard Worker     {
274*4a64e381SAndroid Build Coastguard Worker     case OT_BACKBONE_ROUTER_NDPROXY_ADDED:
275*4a64e381SAndroid Build Coastguard Worker     case OT_BACKBONE_ROUTER_NDPROXY_RENEWED:
276*4a64e381SAndroid Build Coastguard Worker     {
277*4a64e381SAndroid Build Coastguard Worker         bool isNewInsert = mNdProxySet.insert(target).second;
278*4a64e381SAndroid Build Coastguard Worker 
279*4a64e381SAndroid Build Coastguard Worker         if (isNewInsert)
280*4a64e381SAndroid Build Coastguard Worker         {
281*4a64e381SAndroid Build Coastguard Worker             JoinSolicitedNodeMulticastGroup(target);
282*4a64e381SAndroid Build Coastguard Worker         }
283*4a64e381SAndroid Build Coastguard Worker 
284*4a64e381SAndroid Build Coastguard Worker         SendNeighborAdvertisement(target, Ip6Address::GetLinkLocalAllNodesMulticastAddress());
285*4a64e381SAndroid Build Coastguard Worker         break;
286*4a64e381SAndroid Build Coastguard Worker     }
287*4a64e381SAndroid Build Coastguard Worker     case OT_BACKBONE_ROUTER_NDPROXY_REMOVED:
288*4a64e381SAndroid Build Coastguard Worker         mNdProxySet.erase(target);
289*4a64e381SAndroid Build Coastguard Worker         LeaveSolicitedNodeMulticastGroup(target);
290*4a64e381SAndroid Build Coastguard Worker         break;
291*4a64e381SAndroid Build Coastguard Worker     case OT_BACKBONE_ROUTER_NDPROXY_CLEARED:
292*4a64e381SAndroid Build Coastguard Worker         for (const Ip6Address &proxingTarget : mNdProxySet)
293*4a64e381SAndroid Build Coastguard Worker         {
294*4a64e381SAndroid Build Coastguard Worker             LeaveSolicitedNodeMulticastGroup(proxingTarget);
295*4a64e381SAndroid Build Coastguard Worker         }
296*4a64e381SAndroid Build Coastguard Worker         mNdProxySet.clear();
297*4a64e381SAndroid Build Coastguard Worker         break;
298*4a64e381SAndroid Build Coastguard Worker     }
299*4a64e381SAndroid Build Coastguard Worker }
300*4a64e381SAndroid Build Coastguard Worker 
SendNeighborAdvertisement(const Ip6Address & aTarget,const Ip6Address & aDst)301*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::SendNeighborAdvertisement(const Ip6Address &aTarget, const Ip6Address &aDst)
302*4a64e381SAndroid Build Coastguard Worker {
303*4a64e381SAndroid Build Coastguard Worker     uint8_t                    packet[kMaxICMP6PacketSize];
304*4a64e381SAndroid Build Coastguard Worker     uint16_t                   len = 0;
305*4a64e381SAndroid Build Coastguard Worker     struct nd_neighbor_advert &na  = *reinterpret_cast<struct nd_neighbor_advert *>(packet);
306*4a64e381SAndroid Build Coastguard Worker     struct nd_opt_hdr         &opt = *reinterpret_cast<struct nd_opt_hdr *>(packet + sizeof(struct nd_neighbor_advert));
307*4a64e381SAndroid Build Coastguard Worker     bool                       isSolicited = !aDst.IsMulticast();
308*4a64e381SAndroid Build Coastguard Worker     sockaddr_in6               dst;
309*4a64e381SAndroid Build Coastguard Worker     otbrError                  error = OTBR_ERROR_NONE;
310*4a64e381SAndroid Build Coastguard Worker     otBackboneRouterNdProxyInfo aNdProxyInfo;
311*4a64e381SAndroid Build Coastguard Worker 
312*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(otBackboneRouterGetNdProxyInfo(mHost.GetInstance(), reinterpret_cast<const otIp6Address *>(&aTarget),
313*4a64e381SAndroid Build Coastguard Worker                                                 &aNdProxyInfo) == OT_ERROR_NONE,
314*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_OPENTHREAD);
315*4a64e381SAndroid Build Coastguard Worker 
316*4a64e381SAndroid Build Coastguard Worker     memset(packet, 0, sizeof(packet));
317*4a64e381SAndroid Build Coastguard Worker 
318*4a64e381SAndroid Build Coastguard Worker     na.nd_na_type = ND_NEIGHBOR_ADVERT;
319*4a64e381SAndroid Build Coastguard Worker     na.nd_na_code = 0;
320*4a64e381SAndroid Build Coastguard Worker     // set Solicited
321*4a64e381SAndroid Build Coastguard Worker     na.nd_na_flags_reserved = isSolicited ? ND_NA_FLAG_SOLICITED : 0;
322*4a64e381SAndroid Build Coastguard Worker     // set Router
323*4a64e381SAndroid Build Coastguard Worker     na.nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
324*4a64e381SAndroid Build Coastguard Worker     // set Override
325*4a64e381SAndroid Build Coastguard Worker     na.nd_na_flags_reserved |= aNdProxyInfo.mTimeSinceLastTransaction <= kDuaRecentTime ? ND_NA_FLAG_OVERRIDE : 0;
326*4a64e381SAndroid Build Coastguard Worker 
327*4a64e381SAndroid Build Coastguard Worker     memcpy(&na.nd_na_target, aTarget.m8, sizeof(Ip6Address));
328*4a64e381SAndroid Build Coastguard Worker     len += sizeof(struct nd_neighbor_advert);
329*4a64e381SAndroid Build Coastguard Worker 
330*4a64e381SAndroid Build Coastguard Worker     opt.nd_opt_type = ND_OPT_TARGET_LINKADDR;
331*4a64e381SAndroid Build Coastguard Worker     opt.nd_opt_len  = 1;
332*4a64e381SAndroid Build Coastguard Worker 
333*4a64e381SAndroid Build Coastguard Worker     memcpy(reinterpret_cast<uint8_t *>(&opt) + 2, mMacAddress.m8, sizeof(mMacAddress));
334*4a64e381SAndroid Build Coastguard Worker 
335*4a64e381SAndroid Build Coastguard Worker     len += (opt.nd_opt_len * 8);
336*4a64e381SAndroid Build Coastguard Worker 
337*4a64e381SAndroid Build Coastguard Worker     aDst.CopyTo(dst);
338*4a64e381SAndroid Build Coastguard Worker 
339*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(sendto(mIcmp6RawSock, packet, len, 0, reinterpret_cast<const sockaddr *>(&dst), sizeof(dst)) == len,
340*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
341*4a64e381SAndroid Build Coastguard Worker 
342*4a64e381SAndroid Build Coastguard Worker exit:
343*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__);
344*4a64e381SAndroid Build Coastguard Worker }
345*4a64e381SAndroid Build Coastguard Worker 
UpdateMacAddress(void)346*4a64e381SAndroid Build Coastguard Worker otbrError NdProxyManager::UpdateMacAddress(void)
347*4a64e381SAndroid Build Coastguard Worker {
348*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
349*4a64e381SAndroid Build Coastguard Worker 
350*4a64e381SAndroid Build Coastguard Worker #if !__APPLE__
351*4a64e381SAndroid Build Coastguard Worker     struct ifreq ifr;
352*4a64e381SAndroid Build Coastguard Worker 
353*4a64e381SAndroid Build Coastguard Worker     memset(&ifr, 0, sizeof(ifr));
354*4a64e381SAndroid Build Coastguard Worker     strncpy(ifr.ifr_name, mBackboneInterfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
355*4a64e381SAndroid Build Coastguard Worker 
356*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(ioctl(mIcmp6RawSock, SIOCGIFHWADDR, &ifr) != -1, error = OTBR_ERROR_ERRNO);
357*4a64e381SAndroid Build Coastguard Worker     memcpy(mMacAddress.m8, ifr.ifr_hwaddr.sa_data, sizeof(mMacAddress));
358*4a64e381SAndroid Build Coastguard Worker #else
359*4a64e381SAndroid Build Coastguard Worker     ExitNow(error = OTBR_ERROR_NOT_IMPLEMENTED);
360*4a64e381SAndroid Build Coastguard Worker #endif
361*4a64e381SAndroid Build Coastguard Worker exit:
362*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: UpdateMacAddress to %s", mMacAddress.ToString().c_str());
363*4a64e381SAndroid Build Coastguard Worker     return error;
364*4a64e381SAndroid Build Coastguard Worker }
365*4a64e381SAndroid Build Coastguard Worker 
InitIcmp6RawSocket(void)366*4a64e381SAndroid Build Coastguard Worker otbrError NdProxyManager::InitIcmp6RawSocket(void)
367*4a64e381SAndroid Build Coastguard Worker {
368*4a64e381SAndroid Build Coastguard Worker     otbrError           error = OTBR_ERROR_NONE;
369*4a64e381SAndroid Build Coastguard Worker     int                 on    = 1;
370*4a64e381SAndroid Build Coastguard Worker     int                 hops  = 255;
371*4a64e381SAndroid Build Coastguard Worker     struct icmp6_filter filter;
372*4a64e381SAndroid Build Coastguard Worker 
373*4a64e381SAndroid Build Coastguard Worker     mIcmp6RawSock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
374*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mIcmp6RawSock >= 0, error = OTBR_ERROR_ERRNO);
375*4a64e381SAndroid Build Coastguard Worker 
376*4a64e381SAndroid Build Coastguard Worker #if __linux__
377*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, SOL_SOCKET, SO_BINDTODEVICE, mBackboneInterfaceName.c_str(),
378*4a64e381SAndroid Build Coastguard Worker                             mBackboneInterfaceName.length()) == 0,
379*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
380*4a64e381SAndroid Build Coastguard Worker #else  // __NetBSD__ || __FreeBSD__ || __APPLE__
381*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(
382*4a64e381SAndroid Build Coastguard Worker         setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_BOUND_IF, mBackboneIfName.c_str(), mBackboneIfName.size()),
383*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_ERRNO);
384*4a64e381SAndroid Build Coastguard Worker #endif // __linux__
385*4a64e381SAndroid Build Coastguard Worker 
386*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) == 0,
387*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
388*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == 0,
389*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
390*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) == 0,
391*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
392*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) == 0,
393*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
394*4a64e381SAndroid Build Coastguard Worker 
395*4a64e381SAndroid Build Coastguard Worker     ICMP6_FILTER_SETBLOCKALL(&filter);
396*4a64e381SAndroid Build Coastguard Worker     ICMP6_FILTER_SETPASS(ND_NEIGHBOR_SOLICIT, &filter);
397*4a64e381SAndroid Build Coastguard Worker 
398*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == 0,
399*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
400*4a64e381SAndroid Build Coastguard Worker exit:
401*4a64e381SAndroid Build Coastguard Worker     if (error != OTBR_ERROR_NONE)
402*4a64e381SAndroid Build Coastguard Worker     {
403*4a64e381SAndroid Build Coastguard Worker         FiniIcmp6RawSocket();
404*4a64e381SAndroid Build Coastguard Worker     }
405*4a64e381SAndroid Build Coastguard Worker 
406*4a64e381SAndroid Build Coastguard Worker     return error;
407*4a64e381SAndroid Build Coastguard Worker }
408*4a64e381SAndroid Build Coastguard Worker 
FiniIcmp6RawSocket(void)409*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::FiniIcmp6RawSocket(void)
410*4a64e381SAndroid Build Coastguard Worker {
411*4a64e381SAndroid Build Coastguard Worker     if (mIcmp6RawSock != -1)
412*4a64e381SAndroid Build Coastguard Worker     {
413*4a64e381SAndroid Build Coastguard Worker         close(mIcmp6RawSock);
414*4a64e381SAndroid Build Coastguard Worker         mIcmp6RawSock = -1;
415*4a64e381SAndroid Build Coastguard Worker     }
416*4a64e381SAndroid Build Coastguard Worker }
417*4a64e381SAndroid Build Coastguard Worker 
InitNetfilterQueue(void)418*4a64e381SAndroid Build Coastguard Worker otbrError NdProxyManager::InitNetfilterQueue(void)
419*4a64e381SAndroid Build Coastguard Worker {
420*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_ERRNO;
421*4a64e381SAndroid Build Coastguard Worker 
422*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((mNfqHandler = nfq_open()) != nullptr);
423*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(nfq_unbind_pf(mNfqHandler, AF_INET6) >= 0);
424*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(nfq_bind_pf(mNfqHandler, AF_INET6) >= 0);
425*4a64e381SAndroid Build Coastguard Worker 
426*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((mNfqQueueHandler = nfq_create_queue(mNfqHandler, 88, HandleNetfilterQueue, this)) != nullptr);
427*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(nfq_set_mode(mNfqQueueHandler, NFQNL_COPY_PACKET, 0xffff) >= 0);
428*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((mUnicastNsQueueSock = nfq_fd(mNfqHandler)) >= 0);
429*4a64e381SAndroid Build Coastguard Worker 
430*4a64e381SAndroid Build Coastguard Worker     error = OTBR_ERROR_NONE;
431*4a64e381SAndroid Build Coastguard Worker 
432*4a64e381SAndroid Build Coastguard Worker exit:
433*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__);
434*4a64e381SAndroid Build Coastguard Worker 
435*4a64e381SAndroid Build Coastguard Worker     if (error != OTBR_ERROR_NONE)
436*4a64e381SAndroid Build Coastguard Worker     {
437*4a64e381SAndroid Build Coastguard Worker         FiniNetfilterQueue();
438*4a64e381SAndroid Build Coastguard Worker     }
439*4a64e381SAndroid Build Coastguard Worker 
440*4a64e381SAndroid Build Coastguard Worker     return error;
441*4a64e381SAndroid Build Coastguard Worker }
442*4a64e381SAndroid Build Coastguard Worker 
FiniNetfilterQueue(void)443*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::FiniNetfilterQueue(void)
444*4a64e381SAndroid Build Coastguard Worker {
445*4a64e381SAndroid Build Coastguard Worker     if (mUnicastNsQueueSock != -1)
446*4a64e381SAndroid Build Coastguard Worker     {
447*4a64e381SAndroid Build Coastguard Worker         close(mUnicastNsQueueSock);
448*4a64e381SAndroid Build Coastguard Worker         mUnicastNsQueueSock = -1;
449*4a64e381SAndroid Build Coastguard Worker     }
450*4a64e381SAndroid Build Coastguard Worker 
451*4a64e381SAndroid Build Coastguard Worker     if (mNfqQueueHandler != nullptr)
452*4a64e381SAndroid Build Coastguard Worker     {
453*4a64e381SAndroid Build Coastguard Worker         nfq_destroy_queue(mNfqQueueHandler);
454*4a64e381SAndroid Build Coastguard Worker         mNfqQueueHandler = nullptr;
455*4a64e381SAndroid Build Coastguard Worker     }
456*4a64e381SAndroid Build Coastguard Worker 
457*4a64e381SAndroid Build Coastguard Worker     if (mNfqHandler != nullptr)
458*4a64e381SAndroid Build Coastguard Worker     {
459*4a64e381SAndroid Build Coastguard Worker         nfq_close(mNfqHandler);
460*4a64e381SAndroid Build Coastguard Worker         mNfqHandler = nullptr;
461*4a64e381SAndroid Build Coastguard Worker     }
462*4a64e381SAndroid Build Coastguard Worker }
463*4a64e381SAndroid Build Coastguard Worker 
HandleNetfilterQueue(struct nfq_q_handle * aNfQueueHandler,struct nfgenmsg * aNfMsg,struct nfq_data * aNfData,void * aContext)464*4a64e381SAndroid Build Coastguard Worker int NdProxyManager::HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler,
465*4a64e381SAndroid Build Coastguard Worker                                          struct nfgenmsg     *aNfMsg,
466*4a64e381SAndroid Build Coastguard Worker                                          struct nfq_data     *aNfData,
467*4a64e381SAndroid Build Coastguard Worker                                          void                *aContext)
468*4a64e381SAndroid Build Coastguard Worker {
469*4a64e381SAndroid Build Coastguard Worker     return static_cast<NdProxyManager *>(aContext)->HandleNetfilterQueue(aNfQueueHandler, aNfMsg, aNfData);
470*4a64e381SAndroid Build Coastguard Worker }
471*4a64e381SAndroid Build Coastguard Worker 
HandleNetfilterQueue(struct nfq_q_handle * aNfQueueHandler,struct nfgenmsg * aNfMsg,struct nfq_data * aNfData)472*4a64e381SAndroid Build Coastguard Worker int NdProxyManager::HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler,
473*4a64e381SAndroid Build Coastguard Worker                                          struct nfgenmsg     *aNfMsg,
474*4a64e381SAndroid Build Coastguard Worker                                          struct nfq_data     *aNfData)
475*4a64e381SAndroid Build Coastguard Worker {
476*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aNfMsg);
477*4a64e381SAndroid Build Coastguard Worker 
478*4a64e381SAndroid Build Coastguard Worker     struct nfqnl_msg_packet_hdr *ph;
479*4a64e381SAndroid Build Coastguard Worker     unsigned char               *data;
480*4a64e381SAndroid Build Coastguard Worker     uint32_t                     id      = 0;
481*4a64e381SAndroid Build Coastguard Worker     int                          ret     = 0;
482*4a64e381SAndroid Build Coastguard Worker     int                          len     = 0;
483*4a64e381SAndroid Build Coastguard Worker     int                          verdict = NF_ACCEPT;
484*4a64e381SAndroid Build Coastguard Worker 
485*4a64e381SAndroid Build Coastguard Worker     Ip6Address        dst;
486*4a64e381SAndroid Build Coastguard Worker     Ip6Address        src;
487*4a64e381SAndroid Build Coastguard Worker     struct icmp6_hdr *icmp6header = nullptr;
488*4a64e381SAndroid Build Coastguard Worker     struct ip6_hdr   *ip6header   = nullptr;
489*4a64e381SAndroid Build Coastguard Worker     otbrError         error       = OTBR_ERROR_NONE;
490*4a64e381SAndroid Build Coastguard Worker 
491*4a64e381SAndroid Build Coastguard Worker     if ((ph = nfq_get_msg_packet_hdr(aNfData)) != nullptr)
492*4a64e381SAndroid Build Coastguard Worker     {
493*4a64e381SAndroid Build Coastguard Worker         id = ntohl(ph->packet_id);
494*4a64e381SAndroid Build Coastguard Worker         otbrLogDebug("NdProxyManager: %s: id %d", __FUNCTION__, id);
495*4a64e381SAndroid Build Coastguard Worker     }
496*4a64e381SAndroid Build Coastguard Worker 
497*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((len = nfq_get_payload(aNfData, &data)) > 0, error = OTBR_ERROR_PARSE);
498*4a64e381SAndroid Build Coastguard Worker 
499*4a64e381SAndroid Build Coastguard Worker     ip6header = reinterpret_cast<struct ip6_hdr *>(data);
500*4a64e381SAndroid Build Coastguard Worker     src       = *reinterpret_cast<Ip6Address *>(&ip6header->ip6_src);
501*4a64e381SAndroid Build Coastguard Worker     dst       = *reinterpret_cast<Ip6Address *>(&ip6header->ip6_dst);
502*4a64e381SAndroid Build Coastguard Worker 
503*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(ip6header->ip6_nxt == IPPROTO_ICMPV6);
504*4a64e381SAndroid Build Coastguard Worker 
505*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("NdProxyManager: Handle Neighbor Solicitation: from %s to %s", src.ToString().c_str(),
506*4a64e381SAndroid Build Coastguard Worker                  dst.ToString().c_str());
507*4a64e381SAndroid Build Coastguard Worker 
508*4a64e381SAndroid Build Coastguard Worker     icmp6header = reinterpret_cast<struct icmp6_hdr *>(data + sizeof(struct ip6_hdr));
509*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(icmp6header->icmp6_type == ND_NEIGHBOR_SOLICIT);
510*4a64e381SAndroid Build Coastguard Worker 
511*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mNdProxySet.find(dst) != mNdProxySet.end(), error = OTBR_ERROR_NOT_FOUND);
512*4a64e381SAndroid Build Coastguard Worker 
513*4a64e381SAndroid Build Coastguard Worker     {
514*4a64e381SAndroid Build Coastguard Worker         struct nd_neighbor_solicit &ns = *reinterpret_cast<struct nd_neighbor_solicit *>(data + sizeof(struct ip6_hdr));
515*4a64e381SAndroid Build Coastguard Worker         Ip6Address                 &target = *reinterpret_cast<Ip6Address *>(&ns.nd_ns_target);
516*4a64e381SAndroid Build Coastguard Worker 
517*4a64e381SAndroid Build Coastguard Worker         otbrLogDebug("NdProxyManager: %s: target: %s, hoplimit %d", __FUNCTION__, target.ToString().c_str(),
518*4a64e381SAndroid Build Coastguard Worker                      ip6header->ip6_hlim);
519*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(ip6header->ip6_hlim == 255, error = OTBR_ERROR_PARSE);
520*4a64e381SAndroid Build Coastguard Worker         SendNeighborAdvertisement(target, src);
521*4a64e381SAndroid Build Coastguard Worker         verdict = NF_DROP;
522*4a64e381SAndroid Build Coastguard Worker     }
523*4a64e381SAndroid Build Coastguard Worker 
524*4a64e381SAndroid Build Coastguard Worker exit:
525*4a64e381SAndroid Build Coastguard Worker     ret = nfq_set_verdict(aNfQueueHandler, id, verdict, len, data);
526*4a64e381SAndroid Build Coastguard Worker 
527*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: %s (nfq_set_verdict id  %d, ret %d verdict %d)", __FUNCTION__, id, ret,
528*4a64e381SAndroid Build Coastguard Worker                   verdict);
529*4a64e381SAndroid Build Coastguard Worker 
530*4a64e381SAndroid Build Coastguard Worker     return ret;
531*4a64e381SAndroid Build Coastguard Worker }
532*4a64e381SAndroid Build Coastguard Worker 
JoinSolicitedNodeMulticastGroup(const Ip6Address & aTarget) const533*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::JoinSolicitedNodeMulticastGroup(const Ip6Address &aTarget) const
534*4a64e381SAndroid Build Coastguard Worker {
535*4a64e381SAndroid Build Coastguard Worker     ipv6_mreq  mreq;
536*4a64e381SAndroid Build Coastguard Worker     otbrError  error                     = OTBR_ERROR_NONE;
537*4a64e381SAndroid Build Coastguard Worker     Ip6Address solicitedMulticastAddress = aTarget.ToSolicitedNodeMulticastAddress();
538*4a64e381SAndroid Build Coastguard Worker 
539*4a64e381SAndroid Build Coastguard Worker     mreq.ipv6mr_interface = mBackboneIfIndex;
540*4a64e381SAndroid Build Coastguard Worker     solicitedMulticastAddress.CopyTo(mreq.ipv6mr_multiaddr);
541*4a64e381SAndroid Build Coastguard Worker 
542*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == 0,
543*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
544*4a64e381SAndroid Build Coastguard Worker exit:
545*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: JoinSolicitedNodeMulticastGroup of %s: %s", aTarget.ToString().c_str(),
546*4a64e381SAndroid Build Coastguard Worker                   solicitedMulticastAddress.ToString().c_str());
547*4a64e381SAndroid Build Coastguard Worker }
548*4a64e381SAndroid Build Coastguard Worker 
LeaveSolicitedNodeMulticastGroup(const Ip6Address & aTarget) const549*4a64e381SAndroid Build Coastguard Worker void NdProxyManager::LeaveSolicitedNodeMulticastGroup(const Ip6Address &aTarget) const
550*4a64e381SAndroid Build Coastguard Worker {
551*4a64e381SAndroid Build Coastguard Worker     ipv6_mreq  mreq;
552*4a64e381SAndroid Build Coastguard Worker     otbrError  error                     = OTBR_ERROR_NONE;
553*4a64e381SAndroid Build Coastguard Worker     Ip6Address solicitedMulticastAddress = aTarget.ToSolicitedNodeMulticastAddress();
554*4a64e381SAndroid Build Coastguard Worker 
555*4a64e381SAndroid Build Coastguard Worker     mreq.ipv6mr_interface = mBackboneIfIndex;
556*4a64e381SAndroid Build Coastguard Worker     solicitedMulticastAddress.CopyTo(mreq.ipv6mr_multiaddr);
557*4a64e381SAndroid Build Coastguard Worker 
558*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) == 0,
559*4a64e381SAndroid Build Coastguard Worker                  error = OTBR_ERROR_ERRNO);
560*4a64e381SAndroid Build Coastguard Worker exit:
561*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NdProxyManager: LeaveSolicitedNodeMulticastGroup of %s: %s", aTarget.ToString().c_str(),
562*4a64e381SAndroid Build Coastguard Worker                   solicitedMulticastAddress.ToString().c_str());
563*4a64e381SAndroid Build Coastguard Worker }
564*4a64e381SAndroid Build Coastguard Worker 
565*4a64e381SAndroid Build Coastguard Worker } // namespace BackboneRouter
566*4a64e381SAndroid Build Coastguard Worker } // namespace otbr
567*4a64e381SAndroid Build Coastguard Worker 
568*4a64e381SAndroid Build Coastguard Worker #endif // OTBR_ENABLE_DUA_ROUTING
569