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 includes definitions for IPv6 network interfaces.
32  */
33 
34 #ifndef NET_NETIF_HPP_
35 #define NET_NETIF_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include "common/clearable.hpp"
40 #include "common/code_utils.hpp"
41 #include "common/iterator_utils.hpp"
42 #include "common/linked_list.hpp"
43 #include "common/locator.hpp"
44 #include "common/message.hpp"
45 #include "common/non_copyable.hpp"
46 #include "common/tasklet.hpp"
47 #include "mac/mac_types.hpp"
48 #include "net/ip6_address.hpp"
49 #include "net/socket.hpp"
50 #include "thread/mlr_types.hpp"
51 
52 namespace ot {
53 namespace Ip6 {
54 
55 class Ip6;
56 
57 /**
58  * @addtogroup core-ip6-netif
59  *
60  * @brief
61  *   This module includes definitions for IPv6 network interfaces.
62  *
63  * @{
64  *
65  */
66 
67 /**
68  * This class implements an IPv6 network interface.
69  *
70  */
71 class Netif : public InstanceLocator, private NonCopyable
72 {
73     friend class Ip6;
74     friend class Address;
75 
76 public:
77     /**
78      * This class implements an IPv6 network interface unicast address.
79      *
80      */
81     class UnicastAddress : public otNetifAddress,
82                            public LinkedListEntry<UnicastAddress>,
83                            public Clearable<UnicastAddress>
84     {
85         friend class LinkedList<UnicastAddress>;
86 
87     public:
88         /**
89          * This method clears and initializes the unicast address as a preferred, valid, thread-origin address with
90          * 64-bit prefix length.
91          *
92          * @param[in]   aPreferred  Whether to initialize as a preferred address.
93          *
94          */
95         void InitAsThreadOrigin(bool aPreferred = false);
96 
97         /**
98          * This method clears and initializes the unicast address as a valid (but not preferred), thread-origin,
99          * realm-local scope (overridden) address with 64-bit prefix length.
100          *
101          */
102         void InitAsThreadOriginRealmLocalScope(void);
103 
104         /**
105          * This method clears and initializes the unicast address as a valid (but not preferred), thread-origin, global
106          * scope address.
107          *
108          */
109         void InitAsThreadOriginGlobalScope(void);
110 
111         /**
112          * This method clears and initializes the unicast address as a valid, SLAAC-origin address with a given
113          * preferred flag and a given prefix length.
114          *
115          * @param[in] aPrefixLength    The prefix length (in bits).
116          * @param[in] aPreferred       The preferred flag.
117          *
118          */
119         void InitAsSlaacOrigin(uint8_t aPrefixLength, bool aPreferred);
120 
121         /**
122          * This method returns the unicast address.
123          *
124          * @returns The unicast address.
125          *
126          */
GetAddress(void) const127         const Address &GetAddress(void) const { return static_cast<const Address &>(mAddress); }
128 
129         /**
130          * This method returns the unicast address.
131          *
132          * @returns The unicast address.
133          *
134          */
GetAddress(void)135         Address &GetAddress(void) { return static_cast<Address &>(mAddress); }
136 
137         /**
138          * This method returns the address's prefix length (in bits).
139          *
140          * @returns The prefix length (in bits).
141          *
142          */
GetPrefixLength(void) const143         uint8_t GetPrefixLength(void) const { return mPrefixLength; }
144 
145         /**
146          * This method indicates whether the address has a given prefix (i.e. same prefix length and matches the
147          * prefix).
148          *
149          * @param[in] aPrefix   A prefix to check against.
150          *
151          * @retval TRUE  The address has and fully matches the @p aPrefix.
152          * @retval FALSE The address does not contain or match the @p aPrefix.
153          *
154          */
HasPrefix(const Prefix & aPrefix) const155         bool HasPrefix(const Prefix &aPrefix) const
156         {
157             return (mPrefixLength == aPrefix.GetLength()) && GetAddress().MatchesPrefix(aPrefix);
158         }
159 
160         /**
161          * This method returns the IPv6 scope value.
162          *
163          * @returns The IPv6 scope value.
164          *
165          */
GetScope(void) const166         uint8_t GetScope(void) const
167         {
168             return mScopeOverrideValid ? static_cast<uint8_t>(mScopeOverride) : GetAddress().GetScope();
169         }
170 
171         /**
172          * This method sets the IPv6 scope override value.
173          *
174          * @param[in]  aScope  The IPv6 scope value.
175          *
176          */
SetScopeOverride(uint8_t aScope)177         void SetScopeOverride(uint8_t aScope)
178         {
179             mScopeOverride      = aScope;
180             mScopeOverrideValid = true;
181         }
182 
183     private:
Matches(const Address & aAddress) const184         bool Matches(const Address &aAddress) const { return GetAddress() == aAddress; }
185     };
186 
187     /**
188      * This class implements an IPv6 network interface multicast address.
189      *
190      */
191     class MulticastAddress : public otNetifMulticastAddress,
192                              public LinkedListEntry<MulticastAddress>,
193                              public Clearable<MulticastAddress>
194     {
195         friend class LinkedList<MulticastAddress>;
196 
197     public:
198         /**
199          * This method returns the multicast address.
200          *
201          * @returns The multicast address.
202          *
203          */
GetAddress(void) const204         const Address &GetAddress(void) const { return static_cast<const Address &>(mAddress); }
205 
206         /**
207          * This method returns the multicast address.
208          *
209          * @returns The multicast address.
210          *
211          */
GetAddress(void)212         Address &GetAddress(void) { return static_cast<Address &>(mAddress); }
213 
214         /**
215          * This method returns the next multicast address subscribed to the interface.
216          *
217          * @returns A pointer to the next multicast address.
218          *
219          */
GetNext(void) const220         const MulticastAddress *GetNext(void) const { return static_cast<const MulticastAddress *>(mNext); }
221 
222         /**
223          * This method returns the next multicast address subscribed to the interface.
224          *
225          * @returns A pointer to the next multicast address.
226          *
227          */
GetNext(void)228         MulticastAddress *GetNext(void)
229         {
230             return static_cast<MulticastAddress *>(const_cast<otNetifMulticastAddress *>(mNext));
231         }
232 
233     private:
Matches(const Address & aAddress) const234         bool Matches(const Address &aAddress) const { return GetAddress() == aAddress; }
235     };
236 
237     class ExternalMulticastAddress : public MulticastAddress
238     {
239         friend class Netif;
240         friend class LinkedList<ExternalMulticastAddress>;
241 
242     public:
243         /**
244          * This class represents an iterator for iterating external multicast addresses in a `Netif` instance.
245          *
246          */
247         class Iterator : public ItemPtrIterator<ExternalMulticastAddress, Iterator>
248         {
249             friend class ItemPtrIterator<ExternalMulticastAddress, Iterator>;
250             friend class Netif;
251 
252         public:
253             /**
254              * This constructor initializes an `Iterator` instance to start from the first external multicast address
255              * that matches a given IPv6 address type filter.
256              *
257              * @param[in] aNetif   A reference to the `Netif` instance.
258              * @param[in] aFilter  The IPv6 address type filter.
259              *
260              */
261             explicit Iterator(const Netif &aNetif, Address::TypeFilter aFilter = Address::kTypeAny);
262 
263         private:
264             class Builder
265             {
266             public:
Builder(const Netif & aNetif,Address::TypeFilter aFilter)267                 Builder(const Netif &aNetif, Address::TypeFilter aFilter)
268                     : mNetif(aNetif)
269                     , mFilter(aFilter)
270                 {
271                 }
272 
begin(void)273                 Iterator begin(void) { return Iterator(mNetif, mFilter); }
end(void)274                 Iterator end(void) { return Iterator(mNetif, Iterator::kEndIterator); }
275 
276             private:
277                 const Netif &       mNetif;
278                 Address::TypeFilter mFilter;
279             };
280 
281             enum IteratorType : uint8_t
282             {
283                 kEndIterator,
284             };
285 
Iterator(const Netif & aNetif,IteratorType)286             Iterator(const Netif &aNetif, IteratorType)
287                 : mNetif(aNetif)
288             {
289             }
290 
291             void AdvanceFrom(const MulticastAddress *aAddr);
Advance(void)292             void Advance(void) { AdvanceFrom(mItem->GetNext()); }
293 
294             const Netif &       mNetif;
295             Address::TypeFilter mFilter;
296         };
297 
298 #if OPENTHREAD_CONFIG_MLR_ENABLE
299         /**
300          * This method returns the current Multicast Listener Registration (MLR) state.
301          *
302          * @returns The current Multicast Listener Registration state.
303          *
304          */
GetMlrState(void) const305         MlrState GetMlrState(void) const { return mMlrState; }
306 
307         /**
308          * This method sets the Multicast Listener Registration (MLR) state.
309          *
310          * @param[in] aState  The new Multicast Listener Registration state.
311          *
312          */
SetMlrState(MlrState aState)313         void SetMlrState(MlrState aState) { mMlrState = aState; }
314 #endif
315 
316     private:
GetNext(void)317         ExternalMulticastAddress *GetNext(void)
318         {
319             return static_cast<ExternalMulticastAddress *>(const_cast<otNetifMulticastAddress *>(mNext));
320         }
321 
322 #if OPENTHREAD_CONFIG_MLR_ENABLE
323         MlrState mMlrState;
324 #endif
325     };
326 
327     /**
328      * This constructor initializes the network interface.
329      *
330      * @param[in]  aInstance        A reference to the OpenThread instance.
331      *
332      */
333     explicit Netif(Instance &aInstance);
334 
335     /**
336      * This method registers a callback to notify internal IPv6 address changes.
337      *
338      * @param[in]  aCallback         A pointer to a function that is called when an IPv6 address is added or removed.
339      * @param[in]  aCallbackContext  A pointer to application-specific context.
340      *
341      */
342     void SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackContext);
343 
344     /**
345      * This method returns the linked list of unicast addresses.
346      *
347      * @returns The linked list of unicast addresses.
348      *
349      */
GetUnicastAddresses(void) const350     const LinkedList<UnicastAddress> &GetUnicastAddresses(void) const { return mUnicastAddresses; }
351 
352     /**
353      * This method adds a unicast address to the network interface.
354      *
355      * This method is intended for addresses internal to OpenThread. The @p aAddress instance is directly added in the
356      * unicast address linked list.
357      *
358      * If @p aAddress is already added, the call to `AddUnicastAddress()` with the same address will perform no action.
359      *
360      * @param[in]  aAddress  A reference to the unicast address.
361      *
362      */
363     void AddUnicastAddress(UnicastAddress &aAddress);
364 
365     /**
366      * This method removes a unicast address from the network interface.
367      *
368      * This method is intended for addresses internal to OpenThread. The @p aAddress instance is removed from the
369      * unicast address linked list.
370      *
371      * If @p aAddress is not in the list, the call to `RemoveUnicastAddress()` will perform no action.
372      *
373      * @param[in]  aAddress  A reference to the unicast address.
374      *
375      */
376     void RemoveUnicastAddress(const UnicastAddress &aAddress);
377 
378     /**
379      * This method indicates whether or not an address is assigned to the interface.
380      *
381      * @param[in]  aAddress  A reference to the unicast address.
382      *
383      * @retval TRUE   If @p aAddress is assigned to the network interface,
384      * @retval FALSE  If @p aAddress is not assigned to the network interface.
385      *
386      */
387     bool HasUnicastAddress(const Address &aAddress) const;
388 
389     /**
390      * This method indicates whether or not a unicast address is assigned to the network interface.
391      *
392      * @param[in]  aAddress  A reference to the unicast address.
393      *
394      * @retval TRUE   If @p aAddress is assigned to the network interface,
395      * @retval FALSE  If @p aAddress is not assigned to the network interface.
396      *
397      */
HasUnicastAddress(const UnicastAddress & aAddress) const398     bool HasUnicastAddress(const UnicastAddress &aAddress) const { return mUnicastAddresses.Contains(aAddress); }
399 
400     /**
401      * This method indicates whether a unicast address is an external or internal address.
402      *
403      * @param[in] aAddress  A reference to the unicast address.
404      *
405      * @retval TRUE   The address is an external address.
406      * @retval FALSE  The address is not an external address (it is an OpenThread internal address).
407      *
408      */
409     bool IsUnicastAddressExternal(const UnicastAddress &aAddress) const;
410 
411     /**
412      * This method adds an external (to OpenThread) unicast address to the network interface.
413      *
414      * For external address, the @p aAddress instance is not directly used (i.e., it can be temporary). It is copied
415      * into a local entry (allocated from an internal pool) before being added in the unicast address linked list.
416      * The maximum number of external addresses is specified by `OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS`.
417      *
418      * @param[in]  aAddress  A reference to the unicast address.
419      *
420      * @retval kErrorNone         Successfully added (or updated) the unicast address.
421      * @retval kErrorInvalidArgs  The address indicated by @p aAddress is an internal address.
422      * @retval kErrorNoBufs       The maximum number of allowed external addresses are already added.
423      *
424      */
425     Error AddExternalUnicastAddress(const UnicastAddress &aAddress);
426 
427     /**
428      * This method removes a external (to OpenThread) unicast address from the network interface.
429      *
430      * @param[in]  aAddress  A reference to the unicast address.
431      *
432      * @retval kErrorNone         Successfully removed the unicast address.
433      * @retval kErrorInvalidArgs  The address indicated by @p aAddress is an internal address.
434      * @retval kErrorNotFound     The unicast address was not found.
435      *
436      */
437     Error RemoveExternalUnicastAddress(const Address &aAddress);
438 
439     /**
440      * This method removes all the previously added external (to OpenThread) unicast addresses from the
441      * network interface.
442      *
443      */
444     void RemoveAllExternalUnicastAddresses(void);
445 
446     /**
447      * This method indicates whether or not the network interface is subscribed to a multicast address.
448      *
449      * @param[in]  aAddress  The multicast address to check.
450      *
451      * @retval TRUE   If the network interface is subscribed to @p aAddress.
452      * @retval FALSE  If the network interface is not subscribed to @p aAddress.
453      *
454      */
455     bool IsMulticastSubscribed(const Address &aAddress) const;
456 
457     /**
458      * This method subscribes the network interface to the link-local and realm-local all routers addresses.
459      *
460      * @note This method MUST be called after `SubscribeAllNodesMulticast()` or its behavior is undefined.
461      *
462      */
463     void SubscribeAllRoutersMulticast(void);
464 
465     /**
466      * This method unsubscribes the network interface to the link-local and realm-local all routers address.
467      *
468      */
469     void UnsubscribeAllRoutersMulticast(void);
470 
471     /**
472      * This method returns the linked list of multicast addresses.
473      *
474      * @returns The linked list of multicast addresses.
475      *
476      */
GetMulticastAddresses(void) const477     const LinkedList<MulticastAddress> &GetMulticastAddresses(void) const { return mMulticastAddresses; }
478 
479     /**
480      * This method indicates whether a multicast address is an external or internal address.
481      *
482      * @param[in] aAddress  A reference to the multicast address.
483      *
484      * @retval TRUE   The address is an external address.
485      * @retval FALSE  The address is not an external address (it is an OpenThread internal address).
486      *
487      */
488     bool IsMulticastAddressExternal(const MulticastAddress &aAddress) const;
489 
490     /**
491      * This method subscribes the network interface to a multicast address.
492      *
493      * This method is intended for addresses internal to OpenThread. The @p aAddress instance is directly added in the
494      * multicast address linked list.
495      *
496      * @param[in]  aAddress  A reference to the multicast address.
497      *
498      */
499     void SubscribeMulticast(MulticastAddress &aAddress);
500 
501     /**
502      * This method unsubscribes the network interface to a multicast address.
503      *
504      * This method is intended for addresses internal to OpenThread. The @p aAddress instance is directly removed from
505      * the multicast address linked list.
506      *
507      * @param[in]  aAddress  A reference to the multicast address.
508      *
509      */
510     void UnsubscribeMulticast(const MulticastAddress &aAddress);
511 
512     /**
513      * This method subscribes the network interface to the external (to OpenThread) multicast address.
514      *
515      * For external address, the @p aAddress instance is not directly used (i.e., it can be temporary). It is copied
516      * into a local entry (allocated from an internal pool) before being added in the multicast address linked list.
517      * The maximum number of external addresses is specified by `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS`.
518      *
519      * @param[in]  aAddress  A reference to the multicast address.
520      *
521      * @retval kErrorNone          Successfully subscribed to @p aAddress.
522      * @retval kErrorAlready       The multicast address is already subscribed.
523      * @retval kErrorInvalidArgs   The address indicated by @p aAddress is an internal multicast address.
524      * @retval kErrorNoBufs        The maximum number of allowed external multicast addresses are already added.
525      *
526      */
527     Error SubscribeExternalMulticast(const Address &aAddress);
528 
529     /**
530      * This method unsubscribes the network interface to the external (to OpenThread) multicast address.
531      *
532      * @param[in]  aAddress  A reference to the multicast address.
533      *
534      * @retval kErrorNone         Successfully unsubscribed to the unicast address.
535      * @retval kErrorInvalidArgs  The address indicated by @p aAddress is an internal address.
536      * @retval kErrorNotFound     The multicast address was not found.
537      *
538      */
539     Error UnsubscribeExternalMulticast(const Address &aAddress);
540 
541     /**
542      * This method unsubscribes the network interface from all previously added external (to OpenThread) multicast
543      * addresses.
544      *
545      */
546     void UnsubscribeAllExternalMulticastAddresses(void);
547 
548     /**
549      * This method checks if multicast promiscuous mode is enabled on the network interface.
550      *
551      * @retval TRUE   If the multicast promiscuous mode is enabled.
552      * @retval FALSE  If the multicast promiscuous mode is disabled.
553      *
554      */
IsMulticastPromiscuousEnabled(void) const555     bool IsMulticastPromiscuousEnabled(void) const { return mMulticastPromiscuous; }
556 
557     /**
558      * This method enables multicast promiscuous mode on the network interface.
559      *
560      * @param[in]  aEnabled  TRUE if Multicast Promiscuous mode is enabled, FALSE otherwise.
561      *
562      */
SetMulticastPromiscuous(bool aEnabled)563     void SetMulticastPromiscuous(bool aEnabled) { mMulticastPromiscuous = aEnabled; }
564 
565     /**
566      * This method enables range-based `for` loop iteration over external multicast addresses on the Netif that matches
567      * a given IPv6 address type filter.
568      *
569      * This method should be used like follows: to iterate over all external multicast addresses
570      *
571      *     for (Ip6::Netif::ExternalMulticastAddress &addr : Get<ThreadNetif>().IterateExternalMulticastAddresses())
572      *     { ... }
573      *
574      * or to iterate over a subset of external multicast addresses determined by a given address type filter
575      *
576      *     for (Ip6::Netif::ExternalMulticastAddress &addr :
577      *          Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
578      *     { ... }
579      *
580      * @param[in] aFilter  The IPv6 address type filter.
581      *
582      * @returns An `ExternalMulticastAddress::Iterator::Builder` instance.
583      *
584      */
IterateExternalMulticastAddresses(Address::TypeFilter aFilter=Address::kTypeAny)585     ExternalMulticastAddress::Iterator::Builder IterateExternalMulticastAddresses(
586         Address::TypeFilter aFilter = Address::kTypeAny)
587     {
588         return ExternalMulticastAddress::Iterator::Builder(*this, aFilter);
589     }
590 
591     /**
592      * This method indicates whether or not the network interfaces is subscribed to any external multicast address.
593      *
594      * @retval TRUE  The network interface is subscribed to at least one external multicast address.
595      * @retval FALSE The network interface is not subscribed to any external multicast address.
596      *
597      */
HasAnyExternalMulticastAddress(void) const598     bool HasAnyExternalMulticastAddress(void) const { return !ExternalMulticastAddress::Iterator(*this).IsDone(); }
599 
600 protected:
601     /**
602      * This method subscribes the network interface to the realm-local all MPL forwarders, link-local, and realm-local
603      * all nodes address.
604      *
605      */
606     void SubscribeAllNodesMulticast(void);
607 
608     /**
609      * This method unsubscribes the network interface from the realm-local all MPL forwarders, link-local and
610      * realm-local all nodes address.
611      *
612      * @note This method MUST be called after `UnsubscribeAllRoutersMulticast()` or its behavior is undefined
613      *
614      */
615     void UnsubscribeAllNodesMulticast(void);
616 
617 private:
618     LinkedList<UnicastAddress>   mUnicastAddresses;
619     LinkedList<MulticastAddress> mMulticastAddresses;
620     bool                         mMulticastPromiscuous;
621 
622     otIp6AddressCallback mAddressCallback;
623     void *               mAddressCallbackContext;
624 
625     Pool<UnicastAddress, OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS>           mExtUnicastAddressPool;
626     Pool<ExternalMulticastAddress, OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS> mExtMulticastAddressPool;
627 
628     static const otNetifMulticastAddress kRealmLocalAllMplForwardersMulticastAddress;
629     static const otNetifMulticastAddress kLinkLocalAllNodesMulticastAddress;
630     static const otNetifMulticastAddress kRealmLocalAllNodesMulticastAddress;
631     static const otNetifMulticastAddress kLinkLocalAllRoutersMulticastAddress;
632     static const otNetifMulticastAddress kRealmLocalAllRoutersMulticastAddress;
633 };
634 
635 /**
636  * @}
637  *
638  */
639 
640 } // namespace Ip6
641 } // namespace ot
642 
643 #endif // NET_NETIF_HPP_
644