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 implements transmissions of SVR_DATA.ntf messages to the Leader.
32  */
33 
34 #include "network_data_notifier.hpp"
35 
36 #if OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
37 
38 #include "common/code_utils.hpp"
39 #include "common/instance.hpp"
40 #include "common/locator_getters.hpp"
41 #include "thread/network_data_leader.hpp"
42 #include "thread/network_data_local.hpp"
43 
44 namespace ot {
45 namespace NetworkData {
46 
Notifier(Instance & aInstance)47 Notifier::Notifier(Instance &aInstance)
48     : InstanceLocator(aInstance)
49     , mTimer(aInstance, Notifier::HandleTimer)
50     , mNextDelay(0)
51     , mWaitingForResponse(false)
52 {
53 }
54 
HandleServerDataUpdated(void)55 void Notifier::HandleServerDataUpdated(void)
56 {
57     mNextDelay = 0;
58     SynchronizeServerData();
59 }
60 
SynchronizeServerData(void)61 void Notifier::SynchronizeServerData(void)
62 {
63     Error error = kErrorNotFound;
64 
65     VerifyOrExit(Get<Mle::MleRouter>().IsAttached() && !mWaitingForResponse);
66 
67     VerifyOrExit((mNextDelay == 0) || !mTimer.IsRunning());
68 
69 #if OPENTHREAD_FTD
70     mNextDelay = kDelayRemoveStaleChildren;
71     error      = Get<Leader>().RemoveStaleChildEntries(&Notifier::HandleCoapResponse, this);
72     VerifyOrExit(error == kErrorNotFound);
73 #endif
74 
75 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
76     mNextDelay = kDelaySynchronizeServerData;
77     error      = Get<Local>().UpdateInconsistentServerData(&Notifier::HandleCoapResponse, this);
78     VerifyOrExit(error == kErrorNotFound);
79 #endif
80 
81 exit:
82     switch (error)
83     {
84     case kErrorNone:
85         mWaitingForResponse = true;
86         break;
87     case kErrorNoBufs:
88         mTimer.Start(kDelayNoBufs);
89         break;
90 #if OPENTHREAD_FTD
91     case kErrorInvalidState:
92         mTimer.Start(Time::SecToMsec(Get<Mle::MleRouter>().GetRouterSelectionJitterTimeout() + 1));
93         break;
94 #endif
95     case kErrorNotFound:
96         break;
97     default:
98         OT_ASSERT(false);
99         OT_UNREACHABLE_CODE(break);
100     }
101 }
102 
HandleNotifierEvents(Events aEvents)103 void Notifier::HandleNotifierEvents(Events aEvents)
104 {
105     if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadChildRemoved))
106     {
107         mNextDelay = 0;
108     }
109 
110     if (aEvents.ContainsAny(kEventThreadNetdataChanged | kEventThreadRoleChanged | kEventThreadChildRemoved))
111     {
112         SynchronizeServerData();
113     }
114 }
115 
HandleTimer(Timer & aTimer)116 void Notifier::HandleTimer(Timer &aTimer)
117 {
118     aTimer.Get<Notifier>().HandleTimer();
119 }
120 
HandleTimer(void)121 void Notifier::HandleTimer(void)
122 {
123     SynchronizeServerData();
124 }
125 
HandleCoapResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)126 void Notifier::HandleCoapResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, Error aResult)
127 {
128     OT_UNUSED_VARIABLE(aMessage);
129     OT_UNUSED_VARIABLE(aMessageInfo);
130 
131     static_cast<Notifier *>(aContext)->HandleCoapResponse(aResult);
132 }
133 
HandleCoapResponse(Error aResult)134 void Notifier::HandleCoapResponse(Error aResult)
135 {
136     mWaitingForResponse = false;
137 
138     switch (aResult)
139     {
140     case kErrorNone:
141         mTimer.Start(mNextDelay + 1);
142         break;
143 
144     case kErrorResponseTimeout:
145     case kErrorAbort:
146         SynchronizeServerData();
147         break;
148 
149     default:
150         OT_ASSERT(false);
151         OT_UNREACHABLE_CODE(break);
152     }
153 }
154 
155 } // namespace NetworkData
156 } // namespace ot
157 
158 #endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
159