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