• 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 a MeshCoP Leader.
32  */
33 
34 #include "meshcop_leader.hpp"
35 
36 #if OPENTHREAD_FTD
37 
38 #include <stdio.h>
39 
40 #include "coap/coap_message.hpp"
41 #include "common/as_core_type.hpp"
42 #include "common/code_utils.hpp"
43 #include "common/instance.hpp"
44 #include "common/locator_getters.hpp"
45 #include "common/log.hpp"
46 #include "common/random.hpp"
47 #include "meshcop/meshcop.hpp"
48 #include "meshcop/meshcop_tlvs.hpp"
49 #include "thread/thread_netif.hpp"
50 #include "thread/thread_tlvs.hpp"
51 #include "thread/uri_paths.hpp"
52 
53 namespace ot {
54 namespace MeshCoP {
55 
56 RegisterLogModule("MeshCoPLeader");
57 
Leader(Instance & aInstance)58 Leader::Leader(Instance &aInstance)
59     : InstanceLocator(aInstance)
60     , mPetition(UriPath::kLeaderPetition, Leader::HandlePetition, this)
61     , mKeepAlive(UriPath::kLeaderKeepAlive, Leader::HandleKeepAlive, this)
62     , mTimer(aInstance, HandleTimer)
63     , mDelayTimerMinimal(DelayTimerTlv::kDelayTimerMinimal)
64     , mSessionId(Random::NonCrypto::GetUint16())
65 {
66     Get<Tmf::Agent>().AddResource(mPetition);
67     Get<Tmf::Agent>().AddResource(mKeepAlive);
68 }
69 
HandlePetition(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)70 void Leader::HandlePetition(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
71 {
72     static_cast<Leader *>(aContext)->HandlePetition(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
73 }
74 
HandlePetition(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)75 void Leader::HandlePetition(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
76 {
77     OT_UNUSED_VARIABLE(aMessageInfo);
78 
79     CommissioningData data;
80     CommissionerIdTlv commissionerId;
81     StateTlv::State   state = StateTlv::kReject;
82 
83     LogInfo("received petition");
84 
85     VerifyOrExit(Get<Mle::MleRouter>().IsRoutingLocator(aMessageInfo.GetPeerAddr()));
86     SuccessOrExit(Tlv::FindTlv(aMessage, commissionerId));
87 
88     if (mTimer.IsRunning())
89     {
90         VerifyOrExit((commissionerId.GetCommissionerIdLength() == mCommissionerId.GetCommissionerIdLength()) &&
91                      (!strncmp(commissionerId.GetCommissionerId(), mCommissionerId.GetCommissionerId(),
92                                commissionerId.GetCommissionerIdLength())));
93 
94         ResignCommissioner();
95     }
96 
97     data.mBorderAgentLocator.Init();
98     data.mBorderAgentLocator.SetBorderAgentLocator(aMessageInfo.GetPeerAddr().GetIid().GetLocator());
99 
100     data.mCommissionerSessionId.Init();
101     data.mCommissionerSessionId.SetCommissionerSessionId(++mSessionId);
102 
103     data.mSteeringData.Init();
104     data.mSteeringData.SetLength(1);
105     data.mSteeringData.Clear();
106 
107     SuccessOrExit(
108         Get<NetworkData::Leader>().SetCommissioningData(reinterpret_cast<uint8_t *>(&data), data.GetLength()));
109 
110     mCommissionerId = commissionerId;
111 
112     if (mCommissionerId.GetLength() > CommissionerIdTlv::kMaxLength)
113     {
114         mCommissionerId.SetLength(CommissionerIdTlv::kMaxLength);
115     }
116 
117     state = StateTlv::kAccept;
118     mTimer.Start(Time::SecToMsec(kTimeoutLeaderPetition));
119 
120 exit:
121     SendPetitionResponse(aMessage, aMessageInfo, state);
122 }
123 
SendPetitionResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,StateTlv::State aState)124 void Leader::SendPetitionResponse(const Coap::Message &   aRequest,
125                                   const Ip6::MessageInfo &aMessageInfo,
126                                   StateTlv::State         aState)
127 {
128     Error          error = kErrorNone;
129     Coap::Message *message;
130 
131     message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
132     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
133 
134     SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
135 
136     if (mTimer.IsRunning())
137     {
138         SuccessOrExit(error = mCommissionerId.AppendTo(*message));
139     }
140 
141     if (aState == StateTlv::kAccept)
142     {
143         SuccessOrExit(error = Tlv::Append<CommissionerSessionIdTlv>(*message, mSessionId));
144     }
145 
146     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
147 
148     LogInfo("sent petition response");
149 
150 exit:
151     FreeMessageOnError(message, error);
152     LogError("send petition response", error);
153 }
154 
HandleKeepAlive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)155 void Leader::HandleKeepAlive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
156 {
157     static_cast<Leader *>(aContext)->HandleKeepAlive(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
158 }
159 
HandleKeepAlive(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)160 void Leader::HandleKeepAlive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
161 {
162     uint8_t                state;
163     uint16_t               sessionId;
164     BorderAgentLocatorTlv *borderAgentLocator;
165     StateTlv::State        responseState;
166 
167     LogInfo("received keep alive");
168 
169     SuccessOrExit(Tlv::Find<StateTlv>(aMessage, state));
170 
171     SuccessOrExit(Tlv::Find<CommissionerSessionIdTlv>(aMessage, sessionId));
172 
173     borderAgentLocator =
174         As<BorderAgentLocatorTlv>(Get<NetworkData::Leader>().GetCommissioningDataSubTlv(Tlv::kBorderAgentLocator));
175 
176     if ((borderAgentLocator == nullptr) || (sessionId != mSessionId))
177     {
178         responseState = StateTlv::kReject;
179     }
180     else if (state != StateTlv::kAccept)
181     {
182         responseState = StateTlv::kReject;
183         ResignCommissioner();
184     }
185     else
186     {
187         uint16_t rloc = aMessageInfo.GetPeerAddr().GetIid().GetLocator();
188 
189         if (borderAgentLocator->GetBorderAgentLocator() != rloc)
190         {
191             borderAgentLocator->SetBorderAgentLocator(rloc);
192             Get<NetworkData::Leader>().IncrementVersion();
193         }
194 
195         responseState = StateTlv::kAccept;
196         mTimer.Start(Time::SecToMsec(kTimeoutLeaderPetition));
197     }
198 
199     SendKeepAliveResponse(aMessage, aMessageInfo, responseState);
200 
201 exit:
202     return;
203 }
204 
SendKeepAliveResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,StateTlv::State aState)205 void Leader::SendKeepAliveResponse(const Coap::Message &   aRequest,
206                                    const Ip6::MessageInfo &aMessageInfo,
207                                    StateTlv::State         aState)
208 {
209     Error          error = kErrorNone;
210     Coap::Message *message;
211 
212     message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
213     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
214 
215     SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
216 
217     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
218 
219     LogInfo("sent keep alive response");
220 
221 exit:
222     FreeMessageOnError(message, error);
223     LogError("send keep alive response", error);
224 }
225 
SendDatasetChanged(const Ip6::Address & aAddress)226 void Leader::SendDatasetChanged(const Ip6::Address &aAddress)
227 {
228     Error            error = kErrorNone;
229     Tmf::MessageInfo messageInfo(GetInstance());
230     Coap::Message *  message;
231 
232     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kDatasetChanged);
233     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
234 
235     messageInfo.SetSockAddrToRlocPeerAddrTo(aAddress);
236     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
237 
238     LogInfo("sent dataset changed");
239 
240 exit:
241     FreeMessageOnError(message, error);
242     LogError("send dataset changed", error);
243 }
244 
SetDelayTimerMinimal(uint32_t aDelayTimerMinimal)245 Error Leader::SetDelayTimerMinimal(uint32_t aDelayTimerMinimal)
246 {
247     Error error = kErrorNone;
248     VerifyOrExit((aDelayTimerMinimal != 0 && aDelayTimerMinimal < DelayTimerTlv::kDelayTimerDefault),
249                  error = kErrorInvalidArgs);
250     mDelayTimerMinimal = aDelayTimerMinimal;
251 
252 exit:
253     return error;
254 }
255 
GetDelayTimerMinimal(void) const256 uint32_t Leader::GetDelayTimerMinimal(void) const
257 {
258     return mDelayTimerMinimal;
259 }
260 
HandleTimer(Timer & aTimer)261 void Leader::HandleTimer(Timer &aTimer)
262 {
263     aTimer.Get<Leader>().HandleTimer();
264 }
265 
HandleTimer(void)266 void Leader::HandleTimer(void)
267 {
268     VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
269 
270     ResignCommissioner();
271 
272 exit:
273     return;
274 }
275 
SetEmptyCommissionerData(void)276 void Leader::SetEmptyCommissionerData(void)
277 {
278     CommissionerSessionIdTlv mCommissionerSessionId;
279 
280     mCommissionerSessionId.Init();
281     mCommissionerSessionId.SetCommissionerSessionId(++mSessionId);
282 
283     IgnoreError(Get<NetworkData::Leader>().SetCommissioningData(reinterpret_cast<uint8_t *>(&mCommissionerSessionId),
284                                                                 sizeof(Tlv) + mCommissionerSessionId.GetLength()));
285 }
286 
ResignCommissioner(void)287 void Leader::ResignCommissioner(void)
288 {
289     mTimer.Stop();
290     SetEmptyCommissionerData();
291 
292     LogInfo("commissioner inactive");
293 }
294 
295 } // namespace MeshCoP
296 } // namespace ot
297 
298 #endif // OPENTHREAD_FTD
299