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