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