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