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 , mTimer(aInstance)
61 , mDelayTimerMinimal(DelayTimerTlv::kDelayTimerMinimal)
62 , mSessionId(Random::NonCrypto::GetUint16())
63 {
64 }
65
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)66 template <> void Leader::HandleTmf<kUriLeaderPetition>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
67 {
68 OT_UNUSED_VARIABLE(aMessageInfo);
69
70 CommissioningData data;
71 CommissionerIdTlv commissionerId;
72 StateTlv::State state = StateTlv::kReject;
73
74 LogInfo("Received %s", UriToString<kUriLeaderPetition>());
75
76 VerifyOrExit(Get<Mle::MleRouter>().IsRoutingLocator(aMessageInfo.GetPeerAddr()));
77 SuccessOrExit(Tlv::FindTlv(aMessage, commissionerId));
78
79 if (mTimer.IsRunning())
80 {
81 VerifyOrExit((commissionerId.GetCommissionerIdLength() == mCommissionerId.GetCommissionerIdLength()) &&
82 (!strncmp(commissionerId.GetCommissionerId(), mCommissionerId.GetCommissionerId(),
83 commissionerId.GetCommissionerIdLength())));
84
85 ResignCommissioner();
86 }
87
88 data.mBorderAgentLocator.Init();
89 data.mBorderAgentLocator.SetBorderAgentLocator(aMessageInfo.GetPeerAddr().GetIid().GetLocator());
90
91 data.mCommissionerSessionId.Init();
92 data.mCommissionerSessionId.SetCommissionerSessionId(++mSessionId);
93
94 data.mSteeringData.Init();
95 data.mSteeringData.SetLength(1);
96 data.mSteeringData.Clear();
97
98 SuccessOrExit(
99 Get<NetworkData::Leader>().SetCommissioningData(reinterpret_cast<uint8_t *>(&data), data.GetLength()));
100
101 mCommissionerId = commissionerId;
102
103 if (mCommissionerId.GetLength() > CommissionerIdTlv::kMaxLength)
104 {
105 mCommissionerId.SetLength(CommissionerIdTlv::kMaxLength);
106 }
107
108 state = StateTlv::kAccept;
109 mTimer.Start(Time::SecToMsec(kTimeoutLeaderPetition));
110
111 exit:
112 SendPetitionResponse(aMessage, aMessageInfo, state);
113 }
114
SendPetitionResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,StateTlv::State aState)115 void Leader::SendPetitionResponse(const Coap::Message &aRequest,
116 const Ip6::MessageInfo &aMessageInfo,
117 StateTlv::State aState)
118 {
119 Error error = kErrorNone;
120 Coap::Message *message;
121
122 message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
123 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
124
125 SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
126
127 if (mTimer.IsRunning())
128 {
129 SuccessOrExit(error = mCommissionerId.AppendTo(*message));
130 }
131
132 if (aState == StateTlv::kAccept)
133 {
134 SuccessOrExit(error = Tlv::Append<CommissionerSessionIdTlv>(*message, mSessionId));
135 }
136
137 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
138
139 LogInfo("Sent %s response", UriToString<kUriLeaderPetition>());
140
141 exit:
142 FreeMessageOnError(message, error);
143 LogError("send petition response", error);
144 }
145
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)146 template <> void Leader::HandleTmf<kUriLeaderKeepAlive>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
147 {
148 uint8_t state;
149 uint16_t sessionId;
150 BorderAgentLocatorTlv *borderAgentLocator;
151 StateTlv::State responseState;
152
153 LogInfo("Received %s", UriToString<kUriLeaderKeepAlive>());
154
155 SuccessOrExit(Tlv::Find<StateTlv>(aMessage, state));
156
157 SuccessOrExit(Tlv::Find<CommissionerSessionIdTlv>(aMessage, sessionId));
158
159 borderAgentLocator =
160 As<BorderAgentLocatorTlv>(Get<NetworkData::Leader>().GetCommissioningDataSubTlv(Tlv::kBorderAgentLocator));
161
162 if ((borderAgentLocator == nullptr) || (sessionId != mSessionId))
163 {
164 responseState = StateTlv::kReject;
165 }
166 else if (state != StateTlv::kAccept)
167 {
168 responseState = StateTlv::kReject;
169 ResignCommissioner();
170 }
171 else
172 {
173 uint16_t rloc = aMessageInfo.GetPeerAddr().GetIid().GetLocator();
174
175 if (borderAgentLocator->GetBorderAgentLocator() != rloc)
176 {
177 borderAgentLocator->SetBorderAgentLocator(rloc);
178 Get<NetworkData::Leader>().IncrementVersion();
179 }
180
181 responseState = StateTlv::kAccept;
182 mTimer.Start(Time::SecToMsec(kTimeoutLeaderPetition));
183 }
184
185 SendKeepAliveResponse(aMessage, aMessageInfo, responseState);
186
187 exit:
188 return;
189 }
190
SendKeepAliveResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,StateTlv::State aState)191 void Leader::SendKeepAliveResponse(const Coap::Message &aRequest,
192 const Ip6::MessageInfo &aMessageInfo,
193 StateTlv::State aState)
194 {
195 Error error = kErrorNone;
196 Coap::Message *message;
197
198 message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
199 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
200
201 SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
202
203 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
204
205 LogInfo("Sent %s response", UriToString<kUriLeaderKeepAlive>());
206
207 exit:
208 FreeMessageOnError(message, error);
209 LogError("send keep alive response", error);
210 }
211
SendDatasetChanged(const Ip6::Address & aAddress)212 void Leader::SendDatasetChanged(const Ip6::Address &aAddress)
213 {
214 Error error = kErrorNone;
215 Tmf::MessageInfo messageInfo(GetInstance());
216 Coap::Message *message;
217
218 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriDatasetChanged);
219 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
220
221 messageInfo.SetSockAddrToRlocPeerAddrTo(aAddress);
222 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
223
224 LogInfo("Sent %s", UriToString<kUriDatasetChanged>());
225
226 exit:
227 FreeMessageOnError(message, error);
228 LogError("send dataset changed", error);
229 }
230
SetDelayTimerMinimal(uint32_t aDelayTimerMinimal)231 Error Leader::SetDelayTimerMinimal(uint32_t aDelayTimerMinimal)
232 {
233 Error error = kErrorNone;
234 VerifyOrExit((aDelayTimerMinimal != 0 && aDelayTimerMinimal < DelayTimerTlv::kDelayTimerDefault),
235 error = kErrorInvalidArgs);
236 mDelayTimerMinimal = aDelayTimerMinimal;
237
238 exit:
239 return error;
240 }
241
GetDelayTimerMinimal(void) const242 uint32_t Leader::GetDelayTimerMinimal(void) const { return mDelayTimerMinimal; }
243
HandleTimer(void)244 void Leader::HandleTimer(void)
245 {
246 VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
247
248 ResignCommissioner();
249
250 exit:
251 return;
252 }
253
SetEmptyCommissionerData(void)254 void Leader::SetEmptyCommissionerData(void)
255 {
256 CommissionerSessionIdTlv mCommissionerSessionId;
257
258 mCommissionerSessionId.Init();
259 mCommissionerSessionId.SetCommissionerSessionId(++mSessionId);
260
261 IgnoreError(Get<NetworkData::Leader>().SetCommissioningData(reinterpret_cast<uint8_t *>(&mCommissionerSessionId),
262 sizeof(Tlv) + mCommissionerSessionId.GetLength()));
263 }
264
ResignCommissioner(void)265 void Leader::ResignCommissioner(void)
266 {
267 mTimer.Stop();
268 SetEmptyCommissionerData();
269
270 LogInfo("commissioner inactive");
271 }
272
273 } // namespace MeshCoP
274 } // namespace ot
275
276 #endif // OPENTHREAD_FTD
277