• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/const_cast.hpp"
37 #include "common/debug.hpp"
38 #include "common/string.hpp"
39 #include "meshcop/meshcop.hpp"
40 
41 namespace ot {
42 namespace MeshCoP {
43 
IsValid(const Tlv & aTlv)44 bool Tlv::IsValid(const Tlv &aTlv)
45 {
46     bool rval = true;
47 
48     switch (aTlv.GetType())
49     {
50     case Tlv::kChannel:
51         rval = As<ChannelTlv>(aTlv).IsValid();
52         break;
53 
54     case Tlv::kPanId:
55         rval = As<PanIdTlv>(aTlv).IsValid();
56         break;
57 
58     case Tlv::kExtendedPanId:
59         rval = As<ExtendedPanIdTlv>(aTlv).IsValid();
60         break;
61 
62     case Tlv::kNetworkName:
63         rval = As<NetworkNameTlv>(aTlv).IsValid();
64         break;
65 
66     case Tlv::kNetworkKey:
67         rval = As<NetworkKeyTlv>(aTlv).IsValid();
68         break;
69 
70     case Tlv::kPskc:
71         rval = As<PskcTlv>(aTlv).IsValid();
72         break;
73 
74     case Tlv::kMeshLocalPrefix:
75         rval = As<MeshLocalPrefixTlv>(aTlv).IsValid();
76         break;
77 
78     case Tlv::kSecurityPolicy:
79         rval = As<SecurityPolicyTlv>(aTlv).IsValid();
80         break;
81 
82     case Tlv::kChannelMask:
83         rval = As<ChannelMaskTlv>(aTlv).IsValid();
84         break;
85 
86     default:
87         break;
88     }
89 
90     return rval;
91 }
92 
FindTlv(const uint8_t * aTlvsStart,uint16_t aTlvsLength,Type aType)93 const Tlv *Tlv::FindTlv(const uint8_t *aTlvsStart, uint16_t aTlvsLength, Type aType)
94 {
95     const Tlv *tlv;
96     const Tlv *end = reinterpret_cast<const Tlv *>(aTlvsStart + aTlvsLength);
97 
98     for (tlv = reinterpret_cast<const Tlv *>(aTlvsStart); tlv < end; tlv = tlv->GetNext())
99     {
100         VerifyOrExit((tlv + 1) <= end, tlv = nullptr);
101         VerifyOrExit(!tlv->IsExtended() ||
102                          (reinterpret_cast<const ExtendedTlv *>(tlv) + 1 <= reinterpret_cast<const ExtendedTlv *>(end)),
103                      tlv = nullptr);
104         VerifyOrExit(tlv->GetNext() <= end, tlv = nullptr);
105 
106         if (tlv->GetType() == aType)
107         {
108             ExitNow();
109         }
110     }
111 
112     tlv = nullptr;
113 
114 exit:
115     return tlv;
116 }
117 
GetNetworkName(void) const118 NameData NetworkNameTlv::GetNetworkName(void) const
119 {
120     uint8_t len = GetLength();
121 
122     if (len > sizeof(mNetworkName))
123     {
124         len = sizeof(mNetworkName);
125     }
126 
127     return NameData(mNetworkName, len);
128 }
129 
SetNetworkName(const NameData & aNameData)130 void NetworkNameTlv::SetNetworkName(const NameData &aNameData)
131 {
132     uint8_t len;
133 
134     len = aNameData.CopyTo(mNetworkName, sizeof(mNetworkName));
135     SetLength(len);
136 }
137 
IsValid(void) const138 bool NetworkNameTlv::IsValid(void) const
139 {
140     return GetLength() >= 1 && IsValidUtf8String(mNetworkName, GetLength());
141 }
142 
CopyTo(SteeringData & aSteeringData) const143 void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const
144 {
145     aSteeringData.Init(GetSteeringDataLength());
146     memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength());
147 }
148 
IsValid(void) const149 bool SecurityPolicyTlv::IsValid(void) const
150 {
151     return GetLength() >= sizeof(mRotationTime) && 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 AsNonConst(AsConst(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(ChannelMaskEntry);
284 
285         entry = static_cast<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(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(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