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