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