1 /*
2  *  Copyright (c) 2016-2017, 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 MechCop TLV helper functions.
32  */
33 
34 #include "meshcop_tlvs.hpp"
35 
36 #include "common/debug.hpp"
37 #include "common/string.hpp"
38 #include "meshcop/meshcop.hpp"
39 
40 namespace ot {
41 namespace MeshCoP {
42 
IsValid(const Tlv & aTlv)43 bool Tlv::IsValid(const Tlv &aTlv)
44 {
45     bool rval = true;
46 
47     switch (aTlv.GetType())
48     {
49     case Tlv::kChannel:
50         rval = static_cast<const ChannelTlv &>(aTlv).IsValid();
51         break;
52 
53     case Tlv::kPanId:
54         rval = static_cast<const PanIdTlv &>(aTlv).IsValid();
55         break;
56 
57     case Tlv::kExtendedPanId:
58         rval = static_cast<const ExtendedPanIdTlv &>(aTlv).IsValid();
59         break;
60 
61     case Tlv::kNetworkName:
62         rval = static_cast<const NetworkNameTlv &>(aTlv).IsValid();
63         break;
64 
65     case Tlv::kNetworkKey:
66         rval = static_cast<const NetworkKeyTlv &>(aTlv).IsValid();
67         break;
68 
69     case Tlv::kPskc:
70         rval = static_cast<const PskcTlv &>(aTlv).IsValid();
71         break;
72 
73     case Tlv::kMeshLocalPrefix:
74         rval = static_cast<const MeshLocalPrefixTlv &>(aTlv).IsValid();
75         break;
76 
77     case Tlv::kSecurityPolicy:
78         rval = static_cast<const SecurityPolicyTlv &>(aTlv).IsValid();
79         break;
80 
81     case Tlv::kChannelMask:
82         rval = static_cast<const ChannelMaskTlv &>(aTlv).IsValid();
83         break;
84 
85     default:
86         break;
87     }
88 
89     return rval;
90 }
91 
FindTlv(const uint8_t * aTlvsStart,uint16_t aTlvsLength,Type aType)92 const Tlv *Tlv::FindTlv(const uint8_t *aTlvsStart, uint16_t aTlvsLength, Type aType)
93 {
94     const Tlv *tlv;
95     const Tlv *end = reinterpret_cast<const Tlv *>(aTlvsStart + aTlvsLength);
96 
97     for (tlv = reinterpret_cast<const Tlv *>(aTlvsStart); tlv < end; tlv = tlv->GetNext())
98     {
99         VerifyOrExit((tlv + 1) <= end, tlv = nullptr);
100         VerifyOrExit(!tlv->IsExtended() ||
101                          (reinterpret_cast<const ExtendedTlv *>(tlv) + 1 <= reinterpret_cast<const ExtendedTlv *>(end)),
102                      tlv = nullptr);
103         VerifyOrExit(tlv->GetNext() <= end, tlv = nullptr);
104 
105         if (tlv->GetType() == aType)
106         {
107             ExitNow();
108         }
109     }
110 
111     tlv = nullptr;
112 
113 exit:
114     return tlv;
115 }
116 
GetNetworkName(void) const117 Mac::NameData NetworkNameTlv::GetNetworkName(void) const
118 {
119     uint8_t len = GetLength();
120 
121     if (len > sizeof(mNetworkName))
122     {
123         len = sizeof(mNetworkName);
124     }
125 
126     return Mac::NameData(mNetworkName, len);
127 }
128 
SetNetworkName(const Mac::NameData & aNameData)129 void NetworkNameTlv::SetNetworkName(const Mac::NameData &aNameData)
130 {
131     uint8_t len;
132 
133     len = aNameData.CopyTo(mNetworkName, sizeof(mNetworkName));
134     SetLength(len);
135 }
136 
IsValid(void) const137 bool NetworkNameTlv::IsValid(void) const
138 {
139     return IsValidUtf8String(mNetworkName, GetLength());
140 }
141 
CopyTo(SteeringData & aSteeringData) const142 void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const
143 {
144     aSteeringData.Init(GetSteeringDataLength());
145     memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength());
146 }
147 
IsValid(void) const148 bool SecurityPolicyTlv::IsValid(void) const
149 {
150     return GetLength() >= sizeof(mRotationTime) && GetRotationTime() >= SecurityPolicy::kMinKeyRotationTime &&
151            GetFlagsLength() >= kThread11FlagsLength;
152 }
153 
GetSecurityPolicy(void) const154 SecurityPolicy SecurityPolicyTlv::GetSecurityPolicy(void) const
155 {
156     SecurityPolicy securityPolicy;
157     uint8_t        length = OT_MIN(static_cast<uint8_t>(sizeof(mFlags)), GetFlagsLength());
158 
159     securityPolicy.mRotationTime = GetRotationTime();
160     securityPolicy.SetFlags(mFlags, length);
161 
162     return securityPolicy;
163 }
164 
SetSecurityPolicy(const SecurityPolicy & aSecurityPolicy)165 void SecurityPolicyTlv::SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy)
166 {
167     SetRotationTime(aSecurityPolicy.mRotationTime);
168     aSecurityPolicy.GetFlags(mFlags, sizeof(mFlags));
169 }
170 
IsValid(void) const171 bool ChannelTlv::IsValid(void) const
172 {
173     bool ret = false;
174 
175     VerifyOrExit(GetLength() == sizeof(*this) - sizeof(Tlv));
176     VerifyOrExit(mChannelPage < sizeof(uint32_t) * CHAR_BIT);
177     VerifyOrExit((1U << mChannelPage) & Radio::kSupportedChannelPages);
178     VerifyOrExit(Radio::kChannelMin <= GetChannel() && GetChannel() <= Radio::kChannelMax);
179     ret = true;
180 
181 exit:
182     return ret;
183 }
184 
SetChannel(uint16_t aChannel)185 void ChannelTlv::SetChannel(uint16_t aChannel)
186 {
187     uint8_t channelPage = OT_RADIO_CHANNEL_PAGE_0;
188 
189 #if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
190     if ((OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN <= aChannel) && (aChannel <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX))
191     {
192         channelPage = OT_RADIO_CHANNEL_PAGE_0;
193     }
194 #endif
195 
196 #if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
197     if ((OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN <= aChannel) && (aChannel <= OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX))
198     {
199         channelPage = OT_RADIO_CHANNEL_PAGE_2;
200     }
201 #endif
202 
203 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
204     if ((OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN == aChannel) ||
205         ((OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN < aChannel) &&
206          (aChannel <= OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX)))
207     {
208         channelPage = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE;
209     }
210 #endif
211 
212     SetChannelPage(channelPage);
213     mChannel = HostSwap16(aChannel);
214 }
215 
IsValid(void) const216 bool ChannelMaskBaseTlv::IsValid(void) const
217 {
218     const ChannelMaskEntryBase *cur = GetFirstEntry();
219     const ChannelMaskEntryBase *end = reinterpret_cast<const ChannelMaskEntryBase *>(GetNext());
220     bool                        ret = false;
221 
222     VerifyOrExit(cur != nullptr);
223 
224     while (cur < end)
225     {
226         uint8_t channelPage;
227 
228         VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end);
229 
230         channelPage = cur->GetChannelPage();
231 
232 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
233         if (channelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE)
234 #else
235         if ((channelPage == OT_RADIO_CHANNEL_PAGE_0) || (channelPage == OT_RADIO_CHANNEL_PAGE_2))
236 #endif
237         {
238             VerifyOrExit(static_cast<const ChannelMaskEntry *>(cur)->IsValid());
239         }
240 
241         cur = cur->GetNext();
242     }
243 
244     ret = true;
245 
246 exit:
247     return ret;
248 }
249 
GetFirstEntry(void) const250 const ChannelMaskEntryBase *ChannelMaskBaseTlv::GetFirstEntry(void) const
251 {
252     const ChannelMaskEntryBase *entry = nullptr;
253 
254     VerifyOrExit(GetLength() >= sizeof(ChannelMaskEntryBase));
255 
256     entry = reinterpret_cast<const ChannelMaskEntryBase *>(GetValue());
257     VerifyOrExit(GetLength() >= entry->GetEntrySize(), entry = nullptr);
258 
259 exit:
260     return entry;
261 }
262 
GetFirstEntry(void)263 ChannelMaskEntryBase *ChannelMaskBaseTlv::GetFirstEntry(void)
264 {
265     return const_cast<ChannelMaskEntryBase *>(static_cast<const ChannelMaskBaseTlv *>(this)->GetFirstEntry());
266 }
267 
SetChannelMask(uint32_t aChannelMask)268 void ChannelMaskTlv::SetChannelMask(uint32_t aChannelMask)
269 {
270     uint8_t           length = 0;
271     ChannelMaskEntry *entry;
272 
273     entry = static_cast<ChannelMaskEntry *>(GetFirstEntry());
274 
275 #if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
276     if (aChannelMask & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK)
277     {
278         OT_ASSERT(entry != nullptr);
279         entry->Init();
280         entry->SetChannelPage(OT_RADIO_CHANNEL_PAGE_2);
281         entry->SetMask(aChannelMask & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK);
282 
283         length += sizeof(MeshCoP::ChannelMaskEntry);
284 
285         entry = static_cast<MeshCoP::ChannelMaskEntry *>(entry->GetNext());
286     }
287 #endif
288 
289 #if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
290     if (aChannelMask & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK)
291     {
292         OT_ASSERT(entry != nullptr);
293         entry->Init();
294         entry->SetChannelPage(OT_RADIO_CHANNEL_PAGE_0);
295         entry->SetMask(aChannelMask & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK);
296 
297         length += sizeof(MeshCoP::ChannelMaskEntry);
298     }
299 #endif
300 
301 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
302     if (aChannelMask & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK)
303     {
304         OT_ASSERT(entry != nullptr);
305         entry->Init();
306         entry->SetChannelPage(OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE);
307         entry->SetMask(aChannelMask & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK);
308 
309         length += sizeof(MeshCoP::ChannelMaskEntry);
310     }
311 #endif
312 
313     SetLength(length);
314 }
315 
GetChannelMask(void) const316 uint32_t ChannelMaskTlv::GetChannelMask(void) const
317 {
318     const ChannelMaskEntryBase *cur  = GetFirstEntry();
319     const ChannelMaskEntryBase *end  = reinterpret_cast<const ChannelMaskEntryBase *>(GetNext());
320     uint32_t                    mask = 0;
321 
322     VerifyOrExit(cur != nullptr);
323 
324     while (cur < end)
325     {
326         uint8_t channelPage;
327 
328         VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end);
329 
330         channelPage = cur->GetChannelPage();
331 
332 #if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
333         if (channelPage == OT_RADIO_CHANNEL_PAGE_2)
334         {
335             mask |= static_cast<const ChannelMaskEntry *>(cur)->GetMask() & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
336         }
337 #endif
338 
339 #if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
340         if (channelPage == OT_RADIO_CHANNEL_PAGE_0)
341         {
342             mask |= static_cast<const ChannelMaskEntry *>(cur)->GetMask() & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
343         }
344 #endif
345 
346 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
347         if (channelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE)
348         {
349             mask |= static_cast<const ChannelMaskEntry *>(cur)->GetMask() &
350                     OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
351         }
352 #endif
353 
354         cur = cur->GetNext();
355     }
356 
357 exit:
358     return mask;
359 }
360 
GetChannelMask(const Message & aMessage)361 uint32_t ChannelMaskTlv::GetChannelMask(const Message &aMessage)
362 {
363     uint32_t mask = 0;
364     uint16_t offset;
365     uint16_t end;
366 
367     SuccessOrExit(FindTlvValueOffset(aMessage, kChannelMask, offset, end));
368     end += offset;
369 
370     while (offset + sizeof(ChannelMaskEntryBase) <= end)
371     {
372         ChannelMaskEntry entry;
373 
374         IgnoreError(aMessage.Read(offset, entry));
375         VerifyOrExit(offset + entry.GetEntrySize() <= end);
376 
377         switch (entry.GetChannelPage())
378         {
379 #if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
380         case OT_RADIO_CHANNEL_PAGE_0:
381             IgnoreError(aMessage.Read(offset, entry));
382             mask |= entry.GetMask() & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
383             break;
384 #endif
385 
386 #if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
387         case OT_RADIO_CHANNEL_PAGE_2:
388             IgnoreError(aMessage.Read(offset, entry));
389             mask |= entry.GetMask() & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
390             break;
391 #endif
392 
393 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
394         case OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE:
395             IgnoreError(aMessage.Read(offset, entry));
396             mask |= entry.GetMask() & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
397             break;
398 #endif
399         }
400         offset += entry.GetEntrySize();
401     }
402 
403 exit:
404     return mask;
405 }
406 
407 } // namespace MeshCoP
408 } // namespace ot
409