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