• 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 "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