1 /*
2 * Copyright (c) 2016, 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 * This file implements IPv6 network interfaces.
32 */
33
34 #include "netif.hpp"
35
36 #include "common/debug.hpp"
37 #include "common/instance.hpp"
38 #include "common/locator_getters.hpp"
39 #include "common/message.hpp"
40 #include "net/ip6.hpp"
41
42 namespace ot {
43 namespace Ip6 {
44
45 class AddressInfo : public otIp6AddressInfo
46 {
47 public:
AddressInfo(const Netif::UnicastAddress & aAddress)48 explicit AddressInfo(const Netif::UnicastAddress &aAddress)
49 {
50 mAddress = &aAddress.mAddress;
51 mPrefixLength = aAddress.mPrefixLength;
52 mScope = aAddress.GetScope();
53 mPreferred = aAddress.mPreferred;
54 }
55
AddressInfo(const Netif::MulticastAddress & aAddress)56 explicit AddressInfo(const Netif::MulticastAddress &aAddress)
57 {
58 mAddress = &aAddress.GetAddress();
59 mPrefixLength = kMulticastPrefixLength;
60 mScope = aAddress.GetAddress().GetScope();
61 mPreferred = false;
62 }
63
64 private:
65 static constexpr uint8_t kMulticastPrefixLength =
66 128; ///< Multicast prefix length used to notify internal address changes.
67 };
68
69 /*
70 * Certain fixed multicast addresses are defined as a set of chained (linked-list) constant `otNetifMulticastAddress`
71 * entries:
72 *
73 * LinkLocalAllRouters -> RealmLocalAllRouters -> LinkLocalAll -> RealmLocalAll -> RealmLocalAllMplForwarders -> nullptr
74 *
75 * All or a portion of the chain is appended to the end of `mMulticastAddresses` linked-list. If the interface is
76 * subscribed to all-routers multicast addresses (using `SubscribeAllRoutersMulticast()`) then all the five entries
77 * are appended. Otherwise only the last three are appended.
78 *
79 */
80
81 // "ff03::fc"
82 const otNetifMulticastAddress Netif::kRealmLocalAllMplForwardersMulticastAddress = {
83 {{{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc}}},
84 nullptr};
85
86 // "ff03::01"
87 const otNetifMulticastAddress Netif::kRealmLocalAllNodesMulticastAddress = {
88 {{{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}},
89 &Netif::kRealmLocalAllMplForwardersMulticastAddress};
90
91 // "ff02::01"
92 const otNetifMulticastAddress Netif::kLinkLocalAllNodesMulticastAddress = {
93 {{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}},
94 &Netif::kRealmLocalAllNodesMulticastAddress};
95
96 // "ff03::02"
97 const otNetifMulticastAddress Netif::kRealmLocalAllRoutersMulticastAddress = {
98 {{{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}},
99 &Netif::kLinkLocalAllNodesMulticastAddress};
100
101 // "ff02::02"
102 const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = {
103 {{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}},
104 &Netif::kRealmLocalAllRoutersMulticastAddress};
105
106 //---------------------------------------------------------------------------------------------------------------------
107 // Netif
108
Netif(Instance & aInstance)109 Netif::Netif(Instance &aInstance)
110 : InstanceLocator(aInstance)
111 , mMulticastPromiscuous(false)
112 , mAddressCallback(nullptr)
113 , mAddressCallbackContext(nullptr)
114 {
115 }
116
IsMulticastSubscribed(const Address & aAddress) const117 bool Netif::IsMulticastSubscribed(const Address &aAddress) const
118 {
119 return mMulticastAddresses.ContainsMatching(aAddress);
120 }
121
SubscribeAllNodesMulticast(void)122 void Netif::SubscribeAllNodesMulticast(void)
123 {
124 MulticastAddress *tail;
125 MulticastAddress &linkLocalAllNodesAddress =
126 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
127
128 VerifyOrExit(!mMulticastAddresses.Contains(linkLocalAllNodesAddress));
129
130 // Append the fixed chain of three multicast addresses to the
131 // tail of the list:
132 //
133 // LinkLocalAll -> RealmLocalAll -> RealmLocalAllMpl.
134
135 tail = mMulticastAddresses.GetTail();
136
137 if (tail == nullptr)
138 {
139 mMulticastAddresses.SetHead(&linkLocalAllNodesAddress);
140 }
141 else
142 {
143 tail->SetNext(&linkLocalAllNodesAddress);
144 }
145
146 Get<Notifier>().Signal(kEventIp6MulticastSubscribed);
147
148 VerifyOrExit(mAddressCallback != nullptr);
149
150 for (const MulticastAddress *entry = &linkLocalAllNodesAddress; entry; entry = entry->GetNext())
151 {
152 AddressInfo addressInfo(*entry);
153
154 mAddressCallback(&addressInfo,
155 /* IsAdded */ true, mAddressCallbackContext);
156 }
157
158 exit:
159 return;
160 }
161
UnsubscribeAllNodesMulticast(void)162 void Netif::UnsubscribeAllNodesMulticast(void)
163 {
164 MulticastAddress * prev;
165 const MulticastAddress &linkLocalAllNodesAddress =
166 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
167
168 // The tail of multicast address linked list contains the
169 // fixed addresses. Search if LinkLocalAll is present
170 // in the list and find entry before it.
171 //
172 // LinkLocalAll -> RealmLocalAll -> RealmLocalAllMpl.
173
174 SuccessOrExit(mMulticastAddresses.Find(linkLocalAllNodesAddress, prev));
175
176 // This method MUST be called after `UnsubscribeAllRoutersMulticast().
177 // Verify this by checking the chain at the end of the list only
178 // contains three entries and not the five fixed addresses (check that
179 // `prev` entry before `LinkLocalAll` is not `RealmLocalRouters`):
180 //
181 // LinkLocalAllRouters -> RealmLocalAllRouters -> LinkLocalAll
182 // -> RealmLocalAll -> RealmLocalAllMpl.
183
184 OT_ASSERT(prev != static_cast<MulticastAddress *>(
185 const_cast<otNetifMulticastAddress *>(&kRealmLocalAllRoutersMulticastAddress)));
186
187 if (prev == nullptr)
188 {
189 mMulticastAddresses.Clear();
190 }
191 else
192 {
193 prev->SetNext(nullptr);
194 }
195
196 Get<Notifier>().Signal(kEventIp6MulticastUnsubscribed);
197
198 VerifyOrExit(mAddressCallback != nullptr);
199
200 for (const MulticastAddress *entry = &linkLocalAllNodesAddress; entry; entry = entry->GetNext())
201 {
202 AddressInfo addressInfo(*entry);
203
204 mAddressCallback(&addressInfo,
205 /* IsAdded */ false, mAddressCallbackContext);
206 }
207
208 exit:
209 return;
210 }
211
SubscribeAllRoutersMulticast(void)212 void Netif::SubscribeAllRoutersMulticast(void)
213 {
214 Error error = kErrorNone;
215 MulticastAddress *prev = nullptr;
216 MulticastAddress &linkLocalAllRoutersAddress =
217 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
218 MulticastAddress &linkLocalAllNodesAddress =
219 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
220 MulticastAddress &realmLocalAllRoutersAddress =
221 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kRealmLocalAllRoutersMulticastAddress));
222
223 error = mMulticastAddresses.Find(linkLocalAllNodesAddress, prev);
224
225 // This method MUST be called after `SubscribeAllNodesMulticast()`
226 // Ensure that the `LinkLocalAll` was found on the list.
227
228 OT_ASSERT(error == kErrorNone);
229 OT_UNUSED_VARIABLE(error);
230
231 // The tail of multicast address linked list contains the
232 // fixed addresses. We either have a chain of five addresses
233 //
234 // LinkLocalAllRouters -> RealmLocalAllRouters ->
235 // LinkLocalAll -> RealmLocalAll -> RealmLocalAllMpl.
236 //
237 // or just the last three addresses
238 //
239 // LinkLocalAll -> RealmLocalAll -> RealmLocalAllMpl.
240 //
241 // If the previous entry behind `LinkLocalAll` is
242 // `RealmLocalAllRouters` then all five addresses are on
243 // the list already.
244
245 VerifyOrExit(prev != &realmLocalAllRoutersAddress);
246
247 if (prev == nullptr)
248 {
249 mMulticastAddresses.SetHead(&linkLocalAllRoutersAddress);
250 }
251 else
252 {
253 prev->SetNext(&linkLocalAllRoutersAddress);
254 }
255
256 Get<Notifier>().Signal(kEventIp6MulticastSubscribed);
257
258 VerifyOrExit(mAddressCallback != nullptr);
259
260 for (const MulticastAddress *entry = &linkLocalAllRoutersAddress; entry != &linkLocalAllNodesAddress;
261 entry = entry->GetNext())
262 {
263 AddressInfo addressInfo(*entry);
264
265 mAddressCallback(&addressInfo,
266 /* IsAdded */ true, mAddressCallbackContext);
267 }
268
269 exit:
270 return;
271 }
272
UnsubscribeAllRoutersMulticast(void)273 void Netif::UnsubscribeAllRoutersMulticast(void)
274 {
275 MulticastAddress *prev;
276 MulticastAddress &linkLocalAllRoutersAddress =
277 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
278 MulticastAddress &linkLocalAllNodesAddress =
279 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
280
281 // The tail of multicast address linked list contains the
282 // fixed addresses. We check for the chain of five addresses:
283 //
284 // LinkLocalAllRouters -> RealmLocalAllRouters ->
285 // LinkLocalAll -> RealmLocalAll -> RealmLocalAllMpl.
286 //
287 // If found, we then replace the entry behind `LinkLocalAllRouters`
288 // to point to `LinkLocalAll` instead (so that tail contains the
289 // three fixed addresses at end of the chain).
290
291 SuccessOrExit(mMulticastAddresses.Find(linkLocalAllRoutersAddress, prev));
292
293 if (prev == nullptr)
294 {
295 mMulticastAddresses.SetHead(&linkLocalAllNodesAddress);
296 }
297 else
298 {
299 prev->SetNext(&linkLocalAllNodesAddress);
300 }
301
302 Get<Notifier>().Signal(kEventIp6MulticastUnsubscribed);
303
304 VerifyOrExit(mAddressCallback != nullptr);
305
306 for (const MulticastAddress *entry = &linkLocalAllRoutersAddress; entry != &linkLocalAllNodesAddress;
307 entry = entry->GetNext())
308 {
309 AddressInfo addressInfo(*entry);
310
311 mAddressCallback(&addressInfo,
312 /* IsAdded */ false, mAddressCallbackContext);
313 }
314
315 exit:
316 return;
317 }
318
IsMulticastAddressExternal(const MulticastAddress & aAddress) const319 bool Netif::IsMulticastAddressExternal(const MulticastAddress &aAddress) const
320 {
321 return mExtMulticastAddressPool.IsPoolEntry(static_cast<const ExternalMulticastAddress &>(aAddress));
322 }
323
SubscribeMulticast(MulticastAddress & aAddress)324 void Netif::SubscribeMulticast(MulticastAddress &aAddress)
325 {
326 SuccessOrExit(mMulticastAddresses.Add(aAddress));
327
328 Get<Notifier>().Signal(kEventIp6MulticastSubscribed);
329
330 VerifyOrExit(mAddressCallback != nullptr);
331
332 {
333 AddressInfo addressInfo(aAddress);
334
335 mAddressCallback(&addressInfo,
336 /* IsAdded */ true, mAddressCallbackContext);
337 }
338
339 exit:
340 return;
341 }
342
UnsubscribeMulticast(const MulticastAddress & aAddress)343 void Netif::UnsubscribeMulticast(const MulticastAddress &aAddress)
344 {
345 SuccessOrExit(mMulticastAddresses.Remove(aAddress));
346
347 Get<Notifier>().Signal(kEventIp6MulticastUnsubscribed);
348
349 VerifyOrExit(mAddressCallback != nullptr);
350 {
351 AddressInfo addressInfo(aAddress);
352
353 mAddressCallback(&addressInfo,
354 /* IsAdded */ false, mAddressCallbackContext);
355 }
356
357 exit:
358 return;
359 }
360
SubscribeExternalMulticast(const Address & aAddress)361 Error Netif::SubscribeExternalMulticast(const Address &aAddress)
362 {
363 Error error = kErrorNone;
364 MulticastAddress &linkLocalAllRoutersAddress =
365 static_cast<MulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
366 ExternalMulticastAddress *entry;
367
368 VerifyOrExit(aAddress.IsMulticast(), error = kErrorInvalidArgs);
369 VerifyOrExit(!IsMulticastSubscribed(aAddress), error = kErrorAlready);
370
371 // Check that the address is not one of the fixed addresses:
372 // LinkLocalAllRouters -> RealmLocalAllRouters -> LinkLocalAllNodes
373 // -> RealmLocalAllNodes -> RealmLocalAllMpl.
374
375 for (const MulticastAddress *cur = &linkLocalAllRoutersAddress; cur; cur = cur->GetNext())
376 {
377 VerifyOrExit(cur->GetAddress() != aAddress, error = kErrorInvalidArgs);
378 }
379
380 entry = mExtMulticastAddressPool.Allocate();
381 VerifyOrExit(entry != nullptr, error = kErrorNoBufs);
382
383 entry->mAddress = aAddress;
384 #if OPENTHREAD_CONFIG_MLR_ENABLE
385 entry->mMlrState = kMlrStateToRegister;
386 #endif
387 mMulticastAddresses.Push(*entry);
388 Get<Notifier>().Signal(kEventIp6MulticastSubscribed);
389
390 exit:
391 return error;
392 }
393
UnsubscribeExternalMulticast(const Address & aAddress)394 Error Netif::UnsubscribeExternalMulticast(const Address &aAddress)
395 {
396 Error error = kErrorNone;
397 MulticastAddress *entry;
398 MulticastAddress *prev;
399
400 entry = mMulticastAddresses.FindMatching(aAddress, prev);
401 VerifyOrExit(entry != nullptr, error = kErrorNotFound);
402
403 VerifyOrExit(IsMulticastAddressExternal(*entry), error = kErrorInvalidArgs);
404
405 mMulticastAddresses.PopAfter(prev);
406
407 mExtMulticastAddressPool.Free(static_cast<ExternalMulticastAddress &>(*entry));
408
409 Get<Notifier>().Signal(kEventIp6MulticastUnsubscribed);
410
411 exit:
412 return error;
413 }
414
UnsubscribeAllExternalMulticastAddresses(void)415 void Netif::UnsubscribeAllExternalMulticastAddresses(void)
416 {
417 MulticastAddress *next;
418
419 for (MulticastAddress *entry = mMulticastAddresses.GetHead(); entry != nullptr; entry = next)
420 {
421 next = entry->GetNext();
422
423 if (IsMulticastAddressExternal(*entry))
424 {
425 IgnoreError(UnsubscribeExternalMulticast(entry->GetAddress()));
426 }
427 }
428 }
429
SetAddressCallback(otIp6AddressCallback aCallback,void * aCallbackContext)430 void Netif::SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackContext)
431 {
432 mAddressCallback = aCallback;
433 mAddressCallbackContext = aCallbackContext;
434 }
435
AddUnicastAddress(UnicastAddress & aAddress)436 void Netif::AddUnicastAddress(UnicastAddress &aAddress)
437 {
438 SuccessOrExit(mUnicastAddresses.Add(aAddress));
439
440 Get<Notifier>().Signal(aAddress.mRloc ? kEventThreadRlocAdded : kEventIp6AddressAdded);
441
442 VerifyOrExit(mAddressCallback != nullptr);
443
444 {
445 AddressInfo addressInfo(aAddress);
446
447 mAddressCallback(&addressInfo,
448 /* IsAdded */ true, mAddressCallbackContext);
449 }
450
451 exit:
452 return;
453 }
454
RemoveUnicastAddress(const UnicastAddress & aAddress)455 void Netif::RemoveUnicastAddress(const UnicastAddress &aAddress)
456 {
457 SuccessOrExit(mUnicastAddresses.Remove(aAddress));
458
459 Get<Notifier>().Signal(aAddress.mRloc ? kEventThreadRlocRemoved : kEventIp6AddressRemoved);
460
461 VerifyOrExit(mAddressCallback != nullptr);
462 {
463 AddressInfo addressInfo(aAddress);
464
465 mAddressCallback(&addressInfo, /* IsAdded */ false, mAddressCallbackContext);
466 }
467
468 exit:
469 return;
470 }
471
AddExternalUnicastAddress(const UnicastAddress & aAddress)472 Error Netif::AddExternalUnicastAddress(const UnicastAddress &aAddress)
473 {
474 Error error = kErrorNone;
475 UnicastAddress *entry;
476
477 VerifyOrExit(!aAddress.GetAddress().IsMulticast(), error = kErrorInvalidArgs);
478
479 entry = mUnicastAddresses.FindMatching(aAddress.GetAddress());
480
481 if (entry != nullptr)
482 {
483 VerifyOrExit(IsUnicastAddressExternal(*entry), error = kErrorAlready);
484
485 entry->mPrefixLength = aAddress.mPrefixLength;
486 entry->mAddressOrigin = aAddress.mAddressOrigin;
487 entry->mPreferred = aAddress.mPreferred;
488 entry->mValid = aAddress.mValid;
489 ExitNow();
490 }
491
492 VerifyOrExit(!aAddress.GetAddress().IsLinkLocal(), error = kErrorInvalidArgs);
493
494 entry = mExtUnicastAddressPool.Allocate();
495 VerifyOrExit(entry != nullptr, error = kErrorNoBufs);
496
497 *entry = aAddress;
498 mUnicastAddresses.Push(*entry);
499 Get<Notifier>().Signal(kEventIp6AddressAdded);
500
501 exit:
502 return error;
503 }
504
RemoveExternalUnicastAddress(const Address & aAddress)505 Error Netif::RemoveExternalUnicastAddress(const Address &aAddress)
506 {
507 Error error = kErrorNone;
508 UnicastAddress *entry;
509 UnicastAddress *prev;
510
511 entry = mUnicastAddresses.FindMatching(aAddress, prev);
512 VerifyOrExit(entry != nullptr, error = kErrorNotFound);
513
514 VerifyOrExit(IsUnicastAddressExternal(*entry), error = kErrorInvalidArgs);
515
516 mUnicastAddresses.PopAfter(prev);
517 mExtUnicastAddressPool.Free(*entry);
518 Get<Notifier>().Signal(kEventIp6AddressRemoved);
519
520 exit:
521 return error;
522 }
523
RemoveAllExternalUnicastAddresses(void)524 void Netif::RemoveAllExternalUnicastAddresses(void)
525 {
526 UnicastAddress *next;
527
528 for (UnicastAddress *entry = mUnicastAddresses.GetHead(); entry != nullptr; entry = next)
529 {
530 next = entry->GetNext();
531
532 if (IsUnicastAddressExternal(*entry))
533 {
534 IgnoreError(RemoveExternalUnicastAddress(entry->GetAddress()));
535 }
536 }
537 }
538
HasUnicastAddress(const Address & aAddress) const539 bool Netif::HasUnicastAddress(const Address &aAddress) const
540 {
541 return mUnicastAddresses.ContainsMatching(aAddress);
542 }
543
IsUnicastAddressExternal(const UnicastAddress & aAddress) const544 bool Netif::IsUnicastAddressExternal(const UnicastAddress &aAddress) const
545 {
546 return mExtUnicastAddressPool.IsPoolEntry(aAddress);
547 }
548
549 //---------------------------------------------------------------------------------------------------------------------
550 // Netif::UnicastAddress
551
InitAsThreadOrigin(bool aPreferred)552 void Netif::UnicastAddress::InitAsThreadOrigin(bool aPreferred)
553 {
554 Clear();
555 mPrefixLength = NetworkPrefix::kLength;
556 mAddressOrigin = OT_ADDRESS_ORIGIN_THREAD;
557 mPreferred = aPreferred;
558 mValid = true;
559 }
560
InitAsThreadOriginRealmLocalScope(void)561 void Netif::UnicastAddress::InitAsThreadOriginRealmLocalScope(void)
562 {
563 InitAsThreadOrigin();
564 SetScopeOverride(Address::kRealmLocalScope);
565 }
566
InitAsThreadOriginGlobalScope(void)567 void Netif::UnicastAddress::InitAsThreadOriginGlobalScope(void)
568 {
569 Clear();
570 mAddressOrigin = OT_ADDRESS_ORIGIN_THREAD;
571 mValid = true;
572 SetScopeOverride(Address::kGlobalScope);
573 }
574
InitAsSlaacOrigin(uint8_t aPrefixLength,bool aPreferred)575 void Netif::UnicastAddress::InitAsSlaacOrigin(uint8_t aPrefixLength, bool aPreferred)
576 {
577 Clear();
578 mPrefixLength = aPrefixLength;
579 mAddressOrigin = OT_ADDRESS_ORIGIN_SLAAC;
580 mPreferred = aPreferred;
581 mValid = true;
582 }
583
584 //---------------------------------------------------------------------------------------------------------------------
585 // Netif::ExternalMulticastAddress::Iterator
586
Iterator(const Netif & aNetif,Address::TypeFilter aFilter)587 Netif::ExternalMulticastAddress::Iterator::Iterator(const Netif &aNetif, Address::TypeFilter aFilter)
588 : ItemPtrIterator(nullptr)
589 , mNetif(aNetif)
590 , mFilter(aFilter)
591 {
592 AdvanceFrom(mNetif.GetMulticastAddresses().GetHead());
593 }
594
AdvanceFrom(const MulticastAddress * aAddr)595 void Netif::ExternalMulticastAddress::Iterator::AdvanceFrom(const MulticastAddress *aAddr)
596 {
597 while (aAddr != nullptr &&
598 !(mNetif.IsMulticastAddressExternal(*aAddr) && aAddr->GetAddress().MatchesFilter(mFilter)))
599 {
600 aAddr = aAddr->GetNext();
601 }
602
603 mItem = const_cast<ExternalMulticastAddress *>(static_cast<const ExternalMulticastAddress *>(aAddr));
604 }
605
606 } // namespace Ip6
607 } // namespace ot
608