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 #include "posix/platform/multicast_routing.hpp"
30
31 #if OPENTHREAD_POSIX_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
32
33 #include <assert.h>
34 #include <net/if.h>
35 #include <netinet/icmp6.h>
36 #include <netinet/in.h>
37 #include <stdio.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #ifdef __linux__
43 #include <linux/mroute6.h>
44 #else
45 #error "Multicast Routing feature is not ported to non-Linux platforms yet."
46 #endif
47
48 #include <openthread/backbone_router_ftd.h>
49 #include <openthread/logging.h>
50
51 #include "core/common/arg_macros.hpp"
52 #include "core/common/debug.hpp"
53
54 namespace ot {
55 namespace Posix {
56
57 #define LogResult(aError, ...) \
58 do \
59 { \
60 otError _err = (aError); \
61 \
62 if (_err == OT_ERROR_NONE) \
63 { \
64 otLogInfoPlat(OT_FIRST_ARG(__VA_ARGS__) ": %s" OT_REST_ARGS(__VA_ARGS__), otThreadErrorToString(_err)); \
65 } \
66 else \
67 { \
68 otLogWarnPlat(OT_FIRST_ARG(__VA_ARGS__) ": %s" OT_REST_ARGS(__VA_ARGS__), otThreadErrorToString(_err)); \
69 } \
70 } while (false)
71
SetUp(void)72 void MulticastRoutingManager::SetUp(void)
73 {
74 OT_ASSERT(gInstance != nullptr);
75
76 otBackboneRouterSetMulticastListenerCallback(gInstance,
77 &MulticastRoutingManager::HandleBackboneMulticastListenerEvent, this);
78 Mainloop::Manager::Get().Add(*this);
79 }
80
TearDown(void)81 void MulticastRoutingManager::TearDown(void)
82 {
83 OT_ASSERT(gInstance != nullptr);
84
85 otBackboneRouterSetMulticastListenerCallback(gInstance, nullptr, nullptr);
86 Mainloop::Manager::Get().Remove(*this);
87 }
88
HandleBackboneMulticastListenerEvent(void * aContext,otBackboneRouterMulticastListenerEvent aEvent,const otIp6Address * aAddress)89 void MulticastRoutingManager::HandleBackboneMulticastListenerEvent(void *aContext,
90 otBackboneRouterMulticastListenerEvent aEvent,
91 const otIp6Address *aAddress)
92 {
93 static_cast<MulticastRoutingManager *>(aContext)->HandleBackboneMulticastListenerEvent(
94 aEvent, static_cast<const Ip6::Address &>(*aAddress));
95 }
96
HandleBackboneMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent,const Ip6::Address & aAddress)97 void MulticastRoutingManager::HandleBackboneMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent,
98 const Ip6::Address &aAddress)
99 {
100 switch (aEvent)
101 {
102 case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED:
103 Add(aAddress);
104 break;
105 case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED:
106 Remove(aAddress);
107 break;
108 }
109 }
110
Enable(void)111 void MulticastRoutingManager::Enable(void)
112 {
113 VerifyOrExit(!IsEnabled());
114
115 InitMulticastRouterSock();
116
117 LogResult(OT_ERROR_NONE, "MulticastRoutingManager: %s", __FUNCTION__);
118 exit:
119 return;
120 }
121
Disable(void)122 void MulticastRoutingManager::Disable(void)
123 {
124 FinalizeMulticastRouterSock();
125
126 LogResult(OT_ERROR_NONE, "MulticastRoutingManager: %s", __FUNCTION__);
127 }
128
Add(const Ip6::Address & aAddress)129 void MulticastRoutingManager::Add(const Ip6::Address &aAddress)
130 {
131 VerifyOrExit(IsEnabled());
132
133 UnblockInboundMulticastForwardingCache(aAddress);
134 UpdateMldReport(aAddress, true);
135
136 LogResult(OT_ERROR_NONE, "MulticastRoutingManager: %s: %s", __FUNCTION__, aAddress.ToString().AsCString());
137
138 exit:
139 return;
140 }
141
Remove(const Ip6::Address & aAddress)142 void MulticastRoutingManager::Remove(const Ip6::Address &aAddress)
143 {
144 otError error = OT_ERROR_NONE;
145
146 VerifyOrExit(IsEnabled());
147
148 RemoveInboundMulticastForwardingCache(aAddress);
149 UpdateMldReport(aAddress, false);
150
151 LogResult(error, "MulticastRoutingManager: %s: %s", __FUNCTION__, aAddress.ToString().AsCString());
152
153 exit:
154 return;
155 }
156
UpdateMldReport(const Ip6::Address & aAddress,bool isAdd)157 void MulticastRoutingManager::UpdateMldReport(const Ip6::Address &aAddress, bool isAdd)
158 {
159 struct ipv6_mreq ipv6mr;
160 otError error = OT_ERROR_NONE;
161
162 ipv6mr.ipv6mr_interface = if_nametoindex(otSysGetInfraNetifName());
163 memcpy(&ipv6mr.ipv6mr_multiaddr, aAddress.GetBytes(), sizeof(ipv6mr.ipv6mr_multiaddr));
164 error = (setsockopt(mMulticastRouterSock, IPPROTO_IPV6, (isAdd ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP),
165 (void *)&ipv6mr, sizeof(ipv6mr))
166 ? OT_ERROR_FAILED
167 : OT_ERROR_NONE);
168
169 LogResult(error, "MulticastRoutingManager: %s: address %s %s", __FUNCTION__, aAddress.ToString().AsCString(),
170 (isAdd ? "Added" : "Removed"));
171 }
172
HasMulticastListener(const Ip6::Address & aAddress) const173 bool MulticastRoutingManager::HasMulticastListener(const Ip6::Address &aAddress) const
174 {
175 bool found = false;
176 otBackboneRouterMulticastListenerIterator iter = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT;
177 otBackboneRouterMulticastListenerInfo listenerInfo;
178
179 while (otBackboneRouterMulticastListenerGetNext(gInstance, &iter, &listenerInfo) == OT_ERROR_NONE)
180 {
181 VerifyOrExit(static_cast<const Ip6::Address &>(listenerInfo.mAddress) != aAddress, found = true);
182 }
183
184 exit:
185 return found;
186 }
187
Update(otSysMainloopContext & aContext)188 void MulticastRoutingManager::Update(otSysMainloopContext &aContext)
189 {
190 VerifyOrExit(IsEnabled());
191
192 FD_SET(mMulticastRouterSock, &aContext.mReadFdSet);
193 aContext.mMaxFd = OT_MAX(aContext.mMaxFd, mMulticastRouterSock);
194
195 exit:
196 return;
197 }
198
Process(const otSysMainloopContext & aContext)199 void MulticastRoutingManager::Process(const otSysMainloopContext &aContext)
200 {
201 VerifyOrExit(IsEnabled());
202
203 ExpireMulticastForwardingCache();
204
205 if (FD_ISSET(mMulticastRouterSock, &aContext.mReadFdSet))
206 {
207 ProcessMulticastRouterMessages();
208 }
209
210 exit:
211 return;
212 }
213
InitMulticastRouterSock(void)214 void MulticastRoutingManager::InitMulticastRouterSock(void)
215 {
216 int one = 1;
217 struct icmp6_filter filter;
218 struct mif6ctl mif6ctl;
219
220 // Create a Multicast Routing socket
221 mMulticastRouterSock = SocketWithCloseExec(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, kSocketBlock);
222 VerifyOrDie(mMulticastRouterSock != -1, OT_EXIT_ERROR_ERRNO);
223
224 // Enable Multicast Forwarding in Kernel
225 VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_INIT, &one, sizeof(one)), OT_EXIT_ERROR_ERRNO);
226
227 // Filter all ICMPv6 messages
228 ICMP6_FILTER_SETBLOCKALL(&filter);
229 VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_ICMPV6, ICMP6_FILTER, (void *)&filter, sizeof(filter)),
230 OT_EXIT_ERROR_ERRNO);
231
232 memset(&mif6ctl, 0, sizeof(mif6ctl));
233 mif6ctl.mif6c_flags = 0;
234 mif6ctl.vifc_threshold = 1;
235 mif6ctl.vifc_rate_limit = 0;
236
237 // Add Thread network interface to MIF
238 mif6ctl.mif6c_mifi = kMifIndexThread;
239 mif6ctl.mif6c_pifi = if_nametoindex(gNetifName);
240 VerifyOrDie(mif6ctl.mif6c_pifi > 0, OT_EXIT_ERROR_ERRNO);
241 VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MIF, &mif6ctl, sizeof(mif6ctl)),
242 OT_EXIT_ERROR_ERRNO);
243
244 // Add Backbone network interface to MIF
245 mif6ctl.mif6c_mifi = kMifIndexBackbone;
246 mif6ctl.mif6c_pifi = otSysGetInfraNetifIndex();
247 VerifyOrDie(mif6ctl.mif6c_pifi > 0, OT_EXIT_ERROR_ERRNO);
248 VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MIF, &mif6ctl, sizeof(mif6ctl)),
249 OT_EXIT_ERROR_ERRNO);
250 }
251
FinalizeMulticastRouterSock(void)252 void MulticastRoutingManager::FinalizeMulticastRouterSock(void)
253 {
254 VerifyOrExit(IsEnabled());
255
256 close(mMulticastRouterSock);
257 mMulticastRouterSock = -1;
258
259 exit:
260 return;
261 }
262
ProcessMulticastRouterMessages(void)263 void MulticastRoutingManager::ProcessMulticastRouterMessages(void)
264 {
265 otError error = OT_ERROR_NONE;
266 char buf[sizeof(struct mrt6msg)];
267 int nr;
268 struct mrt6msg *mrt6msg;
269 Ip6::Address src, dst;
270
271 nr = read(mMulticastRouterSock, buf, sizeof(buf));
272
273 VerifyOrExit(nr >= static_cast<int>(sizeof(struct mrt6msg)), error = OT_ERROR_FAILED);
274
275 mrt6msg = reinterpret_cast<struct mrt6msg *>(buf);
276
277 VerifyOrExit(mrt6msg->im6_mbz == 0);
278 VerifyOrExit(mrt6msg->im6_msgtype == MRT6MSG_NOCACHE);
279
280 src.SetBytes(mrt6msg->im6_src.s6_addr);
281 dst.SetBytes(mrt6msg->im6_dst.s6_addr);
282
283 error = AddMulticastForwardingCache(src, dst, static_cast<MifIndex>(mrt6msg->im6_mif));
284
285 exit:
286 LogResult(error, "MulticastRoutingManager: %s", __FUNCTION__);
287 }
288
AddMulticastForwardingCache(const Ip6::Address & aSrcAddr,const Ip6::Address & aGroupAddr,MifIndex aIif)289 otError MulticastRoutingManager::AddMulticastForwardingCache(const Ip6::Address &aSrcAddr,
290 const Ip6::Address &aGroupAddr,
291 MifIndex aIif)
292 {
293 otError error = OT_ERROR_NONE;
294 struct mf6cctl mf6cctl;
295 MifIndex forwardMif = kMifIndexNone;
296
297 VerifyOrExit(aIif == kMifIndexThread || aIif == kMifIndexBackbone, error = OT_ERROR_INVALID_ARGS);
298
299 ExpireMulticastForwardingCache();
300
301 if (aIif == kMifIndexBackbone)
302 {
303 // Forward multicast traffic from Backbone to Thread if the group address is subscribed by any Thread device via
304 // MLR.
305 if (HasMulticastListener(aGroupAddr))
306 {
307 forwardMif = kMifIndexThread;
308 }
309 }
310 else
311 {
312 VerifyOrExit(!aSrcAddr.IsLinkLocal(), error = OT_ERROR_NONE);
313 VerifyOrExit(aSrcAddr.GetPrefix() != AsCoreType(otThreadGetMeshLocalPrefix(gInstance)), error = OT_ERROR_NONE);
314 // Forward multicast traffic from Thread to Backbone if multicast scope > kRealmLocalScope
315 // TODO: (MLR) allow scope configuration of outbound multicast routing
316 if (aGroupAddr.GetScope() > Ip6::Address::kRealmLocalScope)
317 {
318 forwardMif = kMifIndexBackbone;
319 }
320 }
321
322 memset(&mf6cctl, 0, sizeof(mf6cctl));
323
324 memcpy(mf6cctl.mf6cc_origin.sin6_addr.s6_addr, aSrcAddr.GetBytes(), sizeof(mf6cctl.mf6cc_origin.sin6_addr.s6_addr));
325 memcpy(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr, aGroupAddr.GetBytes(),
326 sizeof(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr));
327 mf6cctl.mf6cc_parent = aIif;
328
329 if (forwardMif != kMifIndexNone)
330 {
331 IF_SET(forwardMif, &mf6cctl.mf6cc_ifset);
332 }
333
334 // Note that kernel reports repetitive `MRT6MSG_NOCACHE` upcalls with a rate limit (e.g. once per 10s for Linux).
335 // Because of it, we need to add a "blocking" MFC even if there is no forwarding for this group address.
336 // When a Multicast Listener is later added, the "blocking" MFC will be altered to be a "forwarding" MFC so that
337 // corresponding multicast traffic can be forwarded instantly.
338 VerifyOrExit(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MFC, &mf6cctl, sizeof(mf6cctl)),
339 error = OT_ERROR_FAILED);
340
341 SaveMulticastForwardingCache(aSrcAddr, aGroupAddr, aIif, forwardMif);
342 exit:
343 LogResult(error, "MulticastRoutingManager: %s: add dynamic route: %s %s => %s %s", __FUNCTION__,
344 MifIndexToString(aIif), aSrcAddr.ToString().AsCString(), aGroupAddr.ToString().AsCString(),
345 MifIndexToString(forwardMif));
346
347 return error;
348 }
349
UnblockInboundMulticastForwardingCache(const Ip6::Address & aGroupAddr)350 void MulticastRoutingManager::UnblockInboundMulticastForwardingCache(const Ip6::Address &aGroupAddr)
351 {
352 struct mf6cctl mf6cctl;
353
354 memset(&mf6cctl, 0, sizeof(mf6cctl));
355 memcpy(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr, aGroupAddr.GetBytes(),
356 sizeof(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr));
357 mf6cctl.mf6cc_parent = kMifIndexBackbone;
358 IF_SET(kMifIndexThread, &mf6cctl.mf6cc_ifset);
359
360 for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
361 {
362 otError error;
363
364 if (!mfc.IsValid() || mfc.mIif != kMifIndexBackbone || mfc.mOif == kMifIndexThread ||
365 mfc.mGroupAddr != aGroupAddr)
366 {
367 continue;
368 }
369
370 // Unblock this inbound route
371 memcpy(mf6cctl.mf6cc_origin.sin6_addr.s6_addr, mfc.mSrcAddr.GetBytes(),
372 sizeof(mf6cctl.mf6cc_origin.sin6_addr.s6_addr));
373
374 error = (0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MFC, &mf6cctl, sizeof(mf6cctl)))
375 ? OT_ERROR_NONE
376 : OT_ERROR_FAILED;
377
378 mfc.Set(kMifIndexBackbone, kMifIndexThread);
379
380 LogResult(error, "MulticastRoutingManager: %s: %s %s => %s %s", __FUNCTION__, MifIndexToString(mfc.mIif),
381 mfc.mSrcAddr.ToString().AsCString(), mfc.mGroupAddr.ToString().AsCString(),
382 MifIndexToString(kMifIndexThread));
383 }
384 }
385
RemoveInboundMulticastForwardingCache(const Ip6::Address & aGroupAddr)386 void MulticastRoutingManager::RemoveInboundMulticastForwardingCache(const Ip6::Address &aGroupAddr)
387 {
388 for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
389 {
390 if (mfc.IsValid() && mfc.mIif == kMifIndexBackbone && mfc.mGroupAddr == aGroupAddr)
391 {
392 RemoveMulticastForwardingCache(mfc);
393 }
394 }
395 }
396
ExpireMulticastForwardingCache(void)397 void MulticastRoutingManager::ExpireMulticastForwardingCache(void)
398 {
399 struct sioc_sg_req6 sioc_sg_req6;
400 uint64_t now = otPlatTimeGet();
401 struct mf6cctl mf6cctl;
402
403 VerifyOrExit(now >= mLastExpireTime + kMulticastForwardingCacheExpiringInterval * US_PER_S);
404
405 mLastExpireTime = now;
406
407 memset(&mf6cctl, 0, sizeof(mf6cctl));
408 memset(&sioc_sg_req6, 0, sizeof(sioc_sg_req6));
409
410 for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
411 {
412 if (mfc.IsValid() && mfc.mLastUseTime + kMulticastForwardingCacheExpireTimeout * US_PER_S < now)
413 {
414 if (!UpdateMulticastRouteInfo(mfc))
415 {
416 // The multicast route is expired
417 RemoveMulticastForwardingCache(mfc);
418 }
419 }
420 }
421
422 DumpMulticastForwardingCache();
423
424 exit:
425 return;
426 }
427
UpdateMulticastRouteInfo(MulticastForwardingCache & aMfc) const428 bool MulticastRoutingManager::UpdateMulticastRouteInfo(MulticastForwardingCache &aMfc) const
429 {
430 bool updated = false;
431 struct sioc_sg_req6 sioc_sg_req6;
432
433 memset(&sioc_sg_req6, 0, sizeof(sioc_sg_req6));
434
435 memcpy(sioc_sg_req6.src.sin6_addr.s6_addr, aMfc.mSrcAddr.GetBytes(), sizeof(sioc_sg_req6.src.sin6_addr.s6_addr));
436 memcpy(sioc_sg_req6.grp.sin6_addr.s6_addr, aMfc.mGroupAddr.GetBytes(), sizeof(sioc_sg_req6.grp.sin6_addr.s6_addr));
437
438 if (ioctl(mMulticastRouterSock, SIOCGETSGCNT_IN6, &sioc_sg_req6) != -1)
439 {
440 unsigned long validPktCnt;
441
442 otLogDebgPlat("MulticastRoutingManager: %s: SIOCGETSGCNT_IN6 %s => %s: bytecnt=%lu, pktcnt=%lu, wrong_if=%lu",
443 __FUNCTION__, aMfc.mSrcAddr.ToString().AsCString(), aMfc.mGroupAddr.ToString().AsCString(),
444 sioc_sg_req6.bytecnt, sioc_sg_req6.pktcnt, sioc_sg_req6.wrong_if);
445
446 validPktCnt = sioc_sg_req6.pktcnt - sioc_sg_req6.wrong_if;
447 if (validPktCnt != aMfc.mValidPktCnt)
448 {
449 aMfc.SetValidPktCnt(validPktCnt);
450
451 updated = true;
452 }
453 }
454 else
455 {
456 otLogDebgPlat("MulticastRoutingManager: %s: SIOCGETSGCNT_IN6 %s => %s failed: %s", __FUNCTION__,
457 aMfc.mSrcAddr.ToString().AsCString(), aMfc.mGroupAddr.ToString().AsCString(), strerror(errno));
458 }
459
460 return updated;
461 }
462
MifIndexToString(MifIndex aMif)463 const char *MulticastRoutingManager::MifIndexToString(MifIndex aMif)
464 {
465 const char *string = "Unknown";
466
467 switch (aMif)
468 {
469 case kMifIndexNone:
470 string = "None";
471 break;
472 case kMifIndexThread:
473 string = "Thread";
474 break;
475 case kMifIndexBackbone:
476 string = "Backbone";
477 break;
478 }
479
480 return string;
481 }
482
DumpMulticastForwardingCache(void) const483 void MulticastRoutingManager::DumpMulticastForwardingCache(void) const
484 {
485 #if OPENTHREAD_CONFIG_LOG_PLATFORM && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_DEBG)
486 otLogDebgPlat("MulticastRoutingManager: ==================== MFC ENTRIES ====================");
487
488 for (const MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
489 {
490 if (mfc.IsValid())
491 {
492 otLogDebgPlat("MulticastRoutingManager: %s %s => %s %s", MifIndexToString(mfc.mIif),
493 mfc.mSrcAddr.ToString().AsCString(), mfc.mGroupAddr.ToString().AsCString(),
494 MifIndexToString(mfc.mOif));
495 }
496 }
497
498 otLogDebgPlat("MulticastRoutingManager: =====================================================");
499 #endif
500 }
501
HandleStateChange(otInstance * aInstance,otChangedFlags aFlags)502 void MulticastRoutingManager::HandleStateChange(otInstance *aInstance, otChangedFlags aFlags)
503 {
504 if (aFlags & OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE)
505 {
506 otBackboneRouterState state = otBackboneRouterGetState(aInstance);
507
508 switch (state)
509 {
510 case OT_BACKBONE_ROUTER_STATE_DISABLED:
511 case OT_BACKBONE_ROUTER_STATE_SECONDARY:
512 Disable();
513 break;
514 case OT_BACKBONE_ROUTER_STATE_PRIMARY:
515 Enable();
516 break;
517 }
518 }
519 }
520
Set(MulticastRoutingManager::MifIndex aIif,MulticastRoutingManager::MifIndex aOif)521 void MulticastRoutingManager::MulticastForwardingCache::Set(MulticastRoutingManager::MifIndex aIif,
522 MulticastRoutingManager::MifIndex aOif)
523 {
524 mIif = aIif;
525 mOif = aOif;
526 mValidPktCnt = 0;
527 mLastUseTime = otPlatTimeGet();
528 }
529
Set(const Ip6::Address & aSrcAddr,const Ip6::Address & aGroupAddr,MifIndex aIif,MifIndex aOif)530 void MulticastRoutingManager::MulticastForwardingCache::Set(const Ip6::Address &aSrcAddr,
531 const Ip6::Address &aGroupAddr,
532 MifIndex aIif,
533 MifIndex aOif)
534 {
535 mSrcAddr = aSrcAddr;
536 mGroupAddr = aGroupAddr;
537 Set(aIif, aOif);
538 }
539
SetValidPktCnt(unsigned long aValidPktCnt)540 void MulticastRoutingManager::MulticastForwardingCache::SetValidPktCnt(unsigned long aValidPktCnt)
541 {
542 mValidPktCnt = aValidPktCnt;
543 mLastUseTime = otPlatTimeGet();
544 }
545
SaveMulticastForwardingCache(const Ip6::Address & aSrcAddr,const Ip6::Address & aGroupAddr,MulticastRoutingManager::MifIndex aIif,MulticastRoutingManager::MifIndex aOif)546 void MulticastRoutingManager::SaveMulticastForwardingCache(const Ip6::Address &aSrcAddr,
547 const Ip6::Address &aGroupAddr,
548 MulticastRoutingManager::MifIndex aIif,
549 MulticastRoutingManager::MifIndex aOif)
550 {
551 MulticastForwardingCache *invalid = nullptr;
552 MulticastForwardingCache *oldest = nullptr;
553
554 for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
555 {
556 if (mfc.IsValid())
557 {
558 if (mfc.mSrcAddr == aSrcAddr && mfc.mGroupAddr == aGroupAddr)
559 {
560 mfc.Set(aIif, aOif);
561 ExitNow();
562 }
563
564 if (oldest == nullptr || mfc.mLastUseTime < oldest->mLastUseTime)
565 {
566 oldest = &mfc;
567 }
568 }
569 else if (invalid == nullptr)
570 {
571 invalid = &mfc;
572 }
573 }
574
575 if (invalid != nullptr)
576 {
577 invalid->Set(aSrcAddr, aGroupAddr, aIif, aOif);
578 }
579 else
580 {
581 RemoveMulticastForwardingCache(*oldest);
582 oldest->Set(aSrcAddr, aGroupAddr, aIif, aOif);
583 }
584
585 exit:
586 return;
587 }
588
RemoveMulticastForwardingCache(MulticastRoutingManager::MulticastForwardingCache & aMfc) const589 void MulticastRoutingManager::RemoveMulticastForwardingCache(
590 MulticastRoutingManager::MulticastForwardingCache &aMfc) const
591 {
592 otError error;
593 struct mf6cctl mf6cctl;
594
595 memset(&mf6cctl, 0, sizeof(mf6cctl));
596
597 memcpy(mf6cctl.mf6cc_origin.sin6_addr.s6_addr, aMfc.mSrcAddr.GetBytes(),
598 sizeof(mf6cctl.mf6cc_origin.sin6_addr.s6_addr));
599 memcpy(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr, aMfc.mGroupAddr.GetBytes(),
600 sizeof(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr));
601
602 mf6cctl.mf6cc_parent = aMfc.mIif;
603
604 error = (0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_DEL_MFC, &mf6cctl, sizeof(mf6cctl)))
605 ? OT_ERROR_NONE
606 : OT_ERROR_FAILED;
607
608 LogResult(error, "MulticastRoutingManager: %s: %s %s => %s %s", __FUNCTION__, MifIndexToString(aMfc.mIif),
609 aMfc.mSrcAddr.ToString().AsCString(), aMfc.mGroupAddr.ToString().AsCString(),
610 MifIndexToString(aMfc.mOif));
611
612 aMfc.Erase();
613 }
614
615 } // namespace Posix
616 } // namespace ot
617
618 #endif // OPENTHREAD_POSIX_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
619