• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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