1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for managing Domain Unicast Address feature defined in Thread 1.2.
32  */
33 
34 #ifndef DUA_MANAGER_HPP_
35 #define DUA_MANAGER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
40 
41 #if OPENTHREAD_CONFIG_DUA_ENABLE && (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
42 #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_DUA_ENABLE"
43 #endif
44 
45 #include "backbone_router/bbr_leader.hpp"
46 #include "coap/coap.hpp"
47 #include "coap/coap_message.hpp"
48 #include "common/locator.hpp"
49 #include "common/non_copyable.hpp"
50 #include "common/notifier.hpp"
51 #include "common/tasklet.hpp"
52 #include "common/time.hpp"
53 #include "common/time_ticker.hpp"
54 #include "common/timer.hpp"
55 #include "net/netif.hpp"
56 #include "thread/thread_tlvs.hpp"
57 #include "thread/topology.hpp"
58 
59 namespace ot {
60 
61 /**
62  * @addtogroup core-dua
63  *
64  * @brief
65  *   This module includes definitions for generating, managing, registering Domain Unicast Address.
66  *
67  * @{
68  *
69  * @defgroup core-dua Dua
70  *
71  * @}
72  *
73  */
74 
75 /**
76  * This class implements managing DUA.
77  *
78  */
79 class DuaManager : public InstanceLocator, private NonCopyable
80 {
81     friend class ot::Notifier;
82     friend class ot::TimeTicker;
83 
84 public:
85     /**
86      * This constructor initializes the object.
87      *
88      * @param[in]  aInstance     A reference to the OpenThread instance.
89      *
90      */
91     explicit DuaManager(Instance &aInstance);
92 
93     /**
94      * This method notifies Domain Prefix status.
95      *
96      * @param[in]  aState  The Domain Prefix state or state change.
97      *
98      */
99     void HandleDomainPrefixUpdate(BackboneRouter::Leader::DomainPrefixState aState);
100 
101     /**
102      * This method notifies Primary Backbone Router status.
103      *
104      * @param[in]  aState   The state or state change of Primary Backbone Router.
105      * @param[in]  aConfig  The Primary Backbone Router service.
106      *
107      */
108     void HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State               aState,
109                                            const BackboneRouter::BackboneRouterConfig &aConfig);
110 
111 #if OPENTHREAD_CONFIG_DUA_ENABLE
112 
113     /**
114      * This method returns a reference to the Domain Unicast Address.
115      *
116      * @returns A reference to the Domain Unicast Address.
117      *
118      */
GetDomainUnicastAddress(void) const119     const Ip6::Address &GetDomainUnicastAddress(void) const { return mDomainUnicastAddress.GetAddress(); }
120 
121     /**
122      * This method sets the Interface Identifier manually specified for the Thread Domain Unicast Address.
123      *
124      * @param[in]  aIid        A reference to the Interface Identifier to set.
125      *
126      * @retval kErrorNone          Successfully set the Interface Identifier.
127      * @retval kErrorInvalidArgs   The specified Interface Identifier is reserved.
128      *
129      */
130     Error SetFixedDuaInterfaceIdentifier(const Ip6::InterfaceIdentifier &aIid);
131 
132     /**
133      * This method clears the Interface Identifier manually specified for the Thread Domain Unicast Address.
134      *
135      */
136     void ClearFixedDuaInterfaceIdentifier(void);
137 
138     /**
139      * This method indicates whether or not there is Interface Identifier manually specified for the Thread
140      * Domain Unicast Address.
141      *
142      * @retval true  If there is Interface Identifier manually specified.
143      * @retval false If there is no Interface Identifier manually specified.
144      *
145      */
IsFixedDuaInterfaceIdentifierSet(void)146     bool IsFixedDuaInterfaceIdentifierSet(void) { return !mFixedDuaInterfaceIdentifier.IsUnspecified(); }
147 
148     /**
149      * This method gets the Interface Identifier for the Thread Domain Unicast Address if manually specified.
150      *
151      * @returns A reference to the Interface Identifier.
152      *
153      */
GetFixedDuaInterfaceIdentifier(void) const154     const Ip6::InterfaceIdentifier &GetFixedDuaInterfaceIdentifier(void) const { return mFixedDuaInterfaceIdentifier; }
155 
156     /*
157      * This method restores duplicate address detection information from non-volatile memory.
158      *
159      */
160     void Restore(void);
161 
162     /**
163      * This method notifies duplicated Domain Unicast Address.
164      *
165      */
166     void NotifyDuplicateDomainUnicastAddress(void);
167 #endif
168 
169 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
170     void UpdateChildDomainUnicastAddress(const Child &aChild, Mle::ChildDuaState aState);
171 #endif
172 
173 private:
174     static constexpr uint8_t kNewRouterRegistrationDelay = 3; ///< Delay (in sec) to establish link for a new router.
175     static constexpr uint8_t kNewDuaRegistrationDelay    = 1; ///< Delay (in sec) for newly added DUA.
176 
177 #if OPENTHREAD_CONFIG_DUA_ENABLE
178     Error GenerateDomainUnicastAddressIid(void);
179     Error Store(void);
180 
181     void AddDomainUnicastAddress(void);
182     void RemoveDomainUnicastAddress(void);
183     void UpdateRegistrationDelay(uint8_t aDelay);
184 #endif
185 
186 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
187     void SendAddressNotification(Ip6::Address &aAddress, ThreadStatusTlv::DuaStatus aStatus, const Child &aChild);
188 #endif
189 
190     void HandleNotifierEvents(Events aEvents);
191 
192     void HandleTimeTick(void);
193 
194     static void HandleRegistrationTask(Tasklet &aTasklet);
195 
196     void UpdateTimeTickerRegistration(void);
197 
HandleDuaResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)198     static void HandleDuaResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, Error aResult)
199     {
200         static_cast<DuaManager *>(aContext)->HandleDuaResponse(
201             static_cast<Coap::Message *>(aMessage), static_cast<const Ip6::MessageInfo *>(aMessageInfo), aResult);
202     }
203 
204     void HandleDuaResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
205 
HandleDuaNotification(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)206     static void HandleDuaNotification(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
207     {
208         static_cast<DuaManager *>(aContext)->HandleDuaNotification(
209             *static_cast<Coap::Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
210     }
211 
212     void  HandleDuaNotification(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
213     Error ProcessDuaResponse(Coap::Message &aMessage);
214 
215     void PerformNextRegistration(void);
216     void UpdateReregistrationDelay(void);
217     void UpdateCheckDelay(uint8_t aDelay);
218 
219     Tasklet        mRegistrationTask;
220     Coap::Resource mDuaNotification;
221     Ip6::Address   mRegisteringDua;
222     bool           mIsDuaPending : 1;
223 
224 #if OPENTHREAD_CONFIG_DUA_ENABLE
225     enum DuaState : uint8_t
226     {
227         kNotExist,    ///< DUA is not available.
228         kToRegister,  ///< DUA is to be registered.
229         kRegistering, ///< DUA is being registered.
230         kRegistered,  ///< DUA is registered.
231     };
232 
233     DuaState  mDuaState;
234     uint8_t   mDadCounter;
235     TimeMilli mLastRegistrationTime; // The time (in milliseconds) when sent last DUA.req or received DUA.rsp.
236     Ip6::InterfaceIdentifier   mFixedDuaInterfaceIdentifier;
237     Ip6::Netif::UnicastAddress mDomainUnicastAddress;
238 #endif
239 
240     union
241     {
242         struct
243         {
244             uint16_t mReregistrationDelay; // Delay (in seconds) for DUA re-registration.
245             uint8_t  mCheckDelay;          // Delay (in seconds) for checking whether or not registration is required.
246 #if OPENTHREAD_CONFIG_DUA_ENABLE
247             uint8_t mRegistrationDelay; // Delay (in seconds) for DUA registration.
248 #endif
249         } mFields;
250         uint32_t mValue; // Non-zero indicates timer should start.
251     } mDelay;
252 
253 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
254     // TODO: (DUA) may re-evaluate the alternative option of distributing the flags into the child table:
255     //       - Child class itself have some padding - may save some RAM
256     //       - Avoid cross reference between a bit-vector and the child entry
257     ChildMask mChildDuaMask;             // Child Mask for child who registers DUA via Child Update Request.
258     ChildMask mChildDuaRegisteredMask;   // Child Mask for child's DUA that was registered by the parent on behalf.
259     uint16_t  mChildIndexDuaRegistering; // Child Index of the DUA being registered.
260 #endif
261 };
262 
263 } // namespace ot
264 
265 #endif // OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
266 #endif // DUA_MANAGER_HPP_
267