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/num_utils.hpp"
39 #include "common/numeric_limits.hpp"
40 #include "common/string.hpp"
41 #include "meshcop/meshcop.hpp"
42
43 namespace ot {
44 namespace MeshCoP {
45
GetNetworkName(void) const46 NameData NetworkNameTlv::GetNetworkName(void) const
47 {
48 uint8_t len = GetLength();
49
50 if (len > sizeof(mNetworkName))
51 {
52 len = sizeof(mNetworkName);
53 }
54
55 return NameData(mNetworkName, len);
56 }
57
SetNetworkName(const NameData & aNameData)58 void NetworkNameTlv::SetNetworkName(const NameData &aNameData)
59 {
60 uint8_t len;
61
62 len = aNameData.CopyTo(mNetworkName, sizeof(mNetworkName));
63 SetLength(len);
64 }
65
IsValid(void) const66 bool NetworkNameTlv::IsValid(void) const { return IsValidUtf8String(mNetworkName, GetLength()); }
67
CopyTo(SteeringData & aSteeringData) const68 void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const
69 {
70 aSteeringData.Init(GetSteeringDataLength());
71 memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength());
72 }
73
IsValid(void) const74 bool SecurityPolicyTlv::IsValid(void) const
75 {
76 return GetLength() >= sizeof(mRotationTime) && GetFlagsLength() >= kThread11FlagsLength;
77 }
78
GetSecurityPolicy(void) const79 SecurityPolicy SecurityPolicyTlv::GetSecurityPolicy(void) const
80 {
81 SecurityPolicy securityPolicy;
82 uint8_t length = Min(static_cast<uint8_t>(sizeof(mFlags)), GetFlagsLength());
83
84 securityPolicy.mRotationTime = GetRotationTime();
85 securityPolicy.SetFlags(mFlags, length);
86
87 return securityPolicy;
88 }
89
SetSecurityPolicy(const SecurityPolicy & aSecurityPolicy)90 void SecurityPolicyTlv::SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy)
91 {
92 SetRotationTime(aSecurityPolicy.mRotationTime);
93 aSecurityPolicy.GetFlags(mFlags, sizeof(mFlags));
94 }
95
StateToString(State aState)96 const char *StateTlv::StateToString(State aState)
97 {
98 static const char *const kStateStrings[] = {
99 "Pending", // (0) kPending,
100 "Accept", // (1) kAccept
101 "Reject", // (2) kReject,
102 };
103
104 static_assert(0 == kPending, "kPending value is incorrect");
105 static_assert(1 == kAccept, "kAccept value is incorrect");
106
107 return aState == kReject ? kStateStrings[2] : kStateStrings[aState];
108 }
109
CalculateRemainingDelay(const Tlv & aDelayTimerTlv,TimeMilli aUpdateTime)110 uint32_t DelayTimerTlv::CalculateRemainingDelay(const Tlv &aDelayTimerTlv, TimeMilli aUpdateTime)
111 {
112 uint32_t delay = Min(aDelayTimerTlv.ReadValueAs<DelayTimerTlv>(), kMaxDelay);
113 uint32_t elapsed = TimerMilli::GetNow() - aUpdateTime;
114
115 if (delay > elapsed)
116 {
117 delay -= elapsed;
118 }
119 else
120 {
121 delay = 0;
122 }
123
124 return delay;
125 }
126
IsValid(void) const127 bool ChannelMaskTlv::IsValid(void) const
128 {
129 uint32_t channelMask;
130
131 return (ReadChannelMask(channelMask) == kErrorNone);
132 }
133
ReadChannelMask(uint32_t & aChannelMask) const134 Error ChannelMaskTlv::ReadChannelMask(uint32_t &aChannelMask) const
135 {
136 EntriesData entriesData;
137
138 entriesData.Clear();
139 entriesData.mData = &mEntriesStart;
140 entriesData.mOffsetRange.Init(0, GetLength());
141
142 return entriesData.Parse(aChannelMask);
143 }
144
FindIn(const Message & aMessage,uint32_t & aChannelMask)145 Error ChannelMaskTlv::FindIn(const Message &aMessage, uint32_t &aChannelMask)
146 {
147 Error error;
148 EntriesData entriesData;
149 OffsetRange offsetRange;
150
151 entriesData.Clear();
152 entriesData.mMessage = &aMessage;
153
154 SuccessOrExit(error = FindTlvValueOffsetRange(aMessage, Tlv::kChannelMask, offsetRange));
155 entriesData.mOffsetRange = offsetRange;
156 error = entriesData.Parse(aChannelMask);
157
158 exit:
159 return error;
160 }
161
Parse(uint32_t & aChannelMask)162 Error ChannelMaskTlv::EntriesData::Parse(uint32_t &aChannelMask)
163 {
164 // Validates and parses the Channel Mask TLV entries for each
165 // channel page and if successful updates `aChannelMask` to
166 // return the combined mask for all channel pages supported by
167 // radio. The entries can be either contained in `mMessage`
168 // (when `mMessage` is non-null) or be in a buffer `mData`.
169
170 Error error = kErrorParse;
171 Entry readEntry;
172 const Entry *entry;
173 uint16_t size;
174
175 aChannelMask = 0;
176
177 VerifyOrExit(!mOffsetRange.IsEmpty()); // At least one entry.
178
179 while (!mOffsetRange.IsEmpty())
180 {
181 VerifyOrExit(mOffsetRange.Contains(kEntryHeaderSize));
182
183 if (mMessage != nullptr)
184 {
185 // We first read the entry's header only and after
186 // validating the entry and that the entry's channel page
187 // is supported by radio, we read the full `Entry`.
188
189 mMessage->ReadBytes(mOffsetRange.GetOffset(), &readEntry, kEntryHeaderSize);
190 entry = &readEntry;
191 }
192 else
193 {
194 entry = reinterpret_cast<const Entry *>(&mData[mOffsetRange.GetOffset()]);
195 }
196
197 size = kEntryHeaderSize + entry->GetMaskLength();
198
199 VerifyOrExit(mOffsetRange.Contains(size));
200
201 if (Radio::SupportsChannelPage(entry->GetChannelPage()))
202 {
203 // Currently supported channel pages all use `uint32_t`
204 // channel mask.
205
206 VerifyOrExit(entry->GetMaskLength() == kMaskLength);
207
208 if (mMessage != nullptr)
209 {
210 IgnoreError(mMessage->Read(mOffsetRange, readEntry));
211 }
212
213 aChannelMask |= (entry->GetMask() & Radio::ChannelMaskForPage(entry->GetChannelPage()));
214 }
215
216 mOffsetRange.AdvanceOffset(size);
217 }
218
219 error = kErrorNone;
220
221 exit:
222 return error;
223 }
224
PrepareValue(Value & aValue,uint32_t aChannelMask)225 void ChannelMaskTlv::PrepareValue(Value &aValue, uint32_t aChannelMask)
226 {
227 Entry *entry = reinterpret_cast<Entry *>(aValue.mData);
228
229 aValue.mLength = 0;
230
231 for (uint8_t page : Radio::kSupportedChannelPages)
232 {
233 uint32_t mask = (Radio::ChannelMaskForPage(page) & aChannelMask);
234
235 if (mask != 0)
236 {
237 entry->SetChannelPage(page);
238 entry->SetMaskLength(kMaskLength);
239 entry->SetMask(mask);
240
241 aValue.mLength += sizeof(Entry);
242 entry++;
243 }
244 }
245 }
246
AppendTo(Message & aMessage,uint32_t aChannelMask)247 Error ChannelMaskTlv::AppendTo(Message &aMessage, uint32_t aChannelMask)
248 {
249 Value value;
250
251 PrepareValue(value, aChannelMask);
252 return Tlv::Append<ChannelMaskTlv>(aMessage, value.mData, value.mLength);
253 }
254
255 } // namespace MeshCoP
256 } // namespace ot
257