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