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