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