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