/src/openthread/src/core/common/tlvs.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016, 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 common methods for manipulating MLE TLVs. |
32 | | */ |
33 | | |
34 | | #include "tlvs.hpp" |
35 | | |
36 | | #include "common/code_utils.hpp" |
37 | | #include "common/debug.hpp" |
38 | | #include "common/message.hpp" |
39 | | |
40 | | namespace ot { |
41 | | |
42 | | uint32_t Tlv::GetSize(void) const |
43 | 5.49k | { |
44 | 5.49k | return IsExtended() ? sizeof(ExtendedTlv) + As<ExtendedTlv>(this)->GetLength() : sizeof(Tlv) + GetLength(); |
45 | 5.49k | } |
46 | | |
47 | | uint8_t *Tlv::GetValue(void) |
48 | 184 | { |
49 | 184 | return reinterpret_cast<uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv)); |
50 | 184 | } |
51 | | |
52 | | const uint8_t *Tlv::GetValue(void) const |
53 | 75 | { |
54 | 75 | return reinterpret_cast<const uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv)); |
55 | 75 | } |
56 | | |
57 | 14 | Error Tlv::AppendTo(Message &aMessage) const { return aMessage.AppendBytes(this, static_cast<uint16_t>(GetSize())); } |
58 | | |
59 | | Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv) |
60 | 0 | { |
61 | 0 | uint16_t offset; |
62 | |
|
63 | 0 | return FindTlv(aMessage, aType, aMaxSize, aTlv, offset); |
64 | 0 | } |
65 | | |
66 | | Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv, uint16_t &aOffset) |
67 | 0 | { |
68 | 0 | Error error; |
69 | 0 | ParsedInfo info; |
70 | |
|
71 | 0 | SuccessOrExit(error = info.FindIn(aMessage, aType)); |
72 | | |
73 | 0 | info.mTlvOffsetRange.ShrinkLength(aMaxSize); |
74 | 0 | aMessage.ReadBytes(info.mTlvOffsetRange, &aTlv); |
75 | 0 | aOffset = info.mTlvOffsetRange.GetOffset(); |
76 | |
|
77 | 0 | exit: |
78 | 0 | return error; |
79 | 0 | } |
80 | | |
81 | | Error Tlv::FindTlvValueOffsetRange(const Message &aMessage, uint8_t aType, OffsetRange &aOffsetRange) |
82 | 0 | { |
83 | 0 | Error error; |
84 | 0 | ParsedInfo info; |
85 | |
|
86 | 0 | SuccessOrExit(error = info.FindIn(aMessage, aType)); |
87 | 0 | aOffsetRange = info.mValueOffsetRange; |
88 | |
|
89 | 0 | exit: |
90 | 0 | return error; |
91 | 0 | } |
92 | | |
93 | | Error Tlv::ParsedInfo::ParseFrom(const Message &aMessage, uint16_t aOffset) |
94 | 0 | { |
95 | 0 | OffsetRange offsetRange; |
96 | |
|
97 | 0 | offsetRange.InitFromRange(aOffset, aMessage.GetLength()); |
98 | 0 | return ParseFrom(aMessage, offsetRange); |
99 | 0 | } |
100 | | |
101 | | Error Tlv::ParsedInfo::ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange) |
102 | 0 | { |
103 | 0 | Error error; |
104 | 0 | Tlv tlv; |
105 | 0 | ExtendedTlv extTlv; |
106 | 0 | uint32_t headerSize; |
107 | 0 | uint32_t size; |
108 | |
|
109 | 0 | SuccessOrExit(error = aMessage.Read(aOffsetRange, tlv)); |
110 | | |
111 | 0 | mType = tlv.GetType(); |
112 | |
|
113 | 0 | if (!tlv.IsExtended()) |
114 | 0 | { |
115 | 0 | mIsExtended = false; |
116 | 0 | headerSize = sizeof(Tlv); |
117 | 0 | size = headerSize + tlv.GetLength(); |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | SuccessOrExit(error = aMessage.Read(aOffsetRange, extTlv)); |
122 | | |
123 | 0 | mIsExtended = true; |
124 | 0 | headerSize = sizeof(ExtendedTlv); |
125 | 0 | size = headerSize + extTlv.GetLength(); |
126 | 0 | } |
127 | | |
128 | 0 | mTlvOffsetRange = aOffsetRange; |
129 | 0 | VerifyOrExit(mTlvOffsetRange.Contains(size), error = kErrorParse); |
130 | 0 | mTlvOffsetRange.ShrinkLength(static_cast<uint16_t>(size)); |
131 | |
|
132 | 0 | VerifyOrExit(mTlvOffsetRange.GetEndOffset() <= aMessage.GetLength(), error = kErrorParse); |
133 | | |
134 | 0 | mValueOffsetRange = mTlvOffsetRange; |
135 | 0 | mValueOffsetRange.AdvanceOffset(headerSize); |
136 | |
|
137 | 0 | exit: |
138 | 0 | return error; |
139 | 0 | } |
140 | | |
141 | | Error Tlv::ParsedInfo::FindIn(const Message &aMessage, uint8_t aType) |
142 | 0 | { |
143 | 0 | Error error = kErrorNotFound; |
144 | 0 | OffsetRange offsetRange; |
145 | |
|
146 | 0 | offsetRange.InitFromMessageOffsetToEnd(aMessage); |
147 | |
|
148 | 0 | while (true) |
149 | 0 | { |
150 | 0 | SuccessOrExit(ParseFrom(aMessage, offsetRange)); |
151 | | |
152 | 0 | if (mType == aType) |
153 | 0 | { |
154 | 0 | error = kErrorNone; |
155 | 0 | ExitNow(); |
156 | 0 | } |
157 | | |
158 | 0 | offsetRange.AdvanceOffset(mTlvOffsetRange.GetLength()); |
159 | 0 | } |
160 | | |
161 | 0 | exit: |
162 | 0 | return error; |
163 | 0 | } |
164 | | |
165 | | Error Tlv::ReadStringTlv(const Message &aMessage, uint16_t aOffset, uint8_t aMaxStringLength, char *aValue) |
166 | 0 | { |
167 | 0 | Error error = kErrorNone; |
168 | 0 | ParsedInfo info; |
169 | |
|
170 | 0 | SuccessOrExit(error = info.ParseFrom(aMessage, aOffset)); |
171 | | |
172 | 0 | info.mValueOffsetRange.ShrinkLength(aMaxStringLength); |
173 | 0 | aMessage.ReadBytes(info.mValueOffsetRange, aValue); |
174 | 0 | aValue[info.mValueOffsetRange.GetLength()] = kNullChar; |
175 | |
|
176 | 0 | exit: |
177 | 0 | return error; |
178 | 0 | } |
179 | | |
180 | | template <typename UintType> Error Tlv::ReadUintTlv(const Message &aMessage, uint16_t aOffset, UintType &aValue) |
181 | 0 | { |
182 | 0 | Error error; |
183 | |
|
184 | 0 | SuccessOrExit(error = ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue))); |
185 | 0 | aValue = BigEndian::HostSwap<UintType>(aValue); |
186 | |
|
187 | 0 | exit: |
188 | 0 | return error; |
189 | 0 | } Unexecuted instantiation: otError ot::Tlv::ReadUintTlv<unsigned char>(ot::Message const&, unsigned short, unsigned char&) Unexecuted instantiation: otError ot::Tlv::ReadUintTlv<unsigned short>(ot::Message const&, unsigned short, unsigned short&) Unexecuted instantiation: otError ot::Tlv::ReadUintTlv<unsigned int>(ot::Message const&, unsigned short, unsigned int&) |
190 | | |
191 | | // Explicit instantiations of `ReadUintTlv<>()` |
192 | | template Error Tlv::ReadUintTlv<uint8_t>(const Message &aMessage, uint16_t aOffset, uint8_t &aValue); |
193 | | template Error Tlv::ReadUintTlv<uint16_t>(const Message &aMessage, uint16_t aOffset, uint16_t &aValue); |
194 | | template Error Tlv::ReadUintTlv<uint32_t>(const Message &aMessage, uint16_t aOffset, uint32_t &aValue); |
195 | | |
196 | | Error Tlv::ReadTlvValue(const Message &aMessage, uint16_t aOffset, void *aValue, uint8_t aMinLength) |
197 | 0 | { |
198 | 0 | Error error; |
199 | 0 | ParsedInfo info; |
200 | |
|
201 | 0 | SuccessOrExit(error = info.ParseFrom(aMessage, aOffset)); |
202 | | |
203 | 0 | VerifyOrExit(info.mValueOffsetRange.Contains(aMinLength), error = kErrorParse); |
204 | 0 | info.mValueOffsetRange.ShrinkLength(aMinLength); |
205 | |
|
206 | 0 | aMessage.ReadBytes(info.mValueOffsetRange, aValue); |
207 | |
|
208 | 0 | exit: |
209 | 0 | return error; |
210 | 0 | } |
211 | | |
212 | | Error Tlv::FindStringTlv(const Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, char *aValue) |
213 | 0 | { |
214 | 0 | Error error; |
215 | 0 | ParsedInfo info; |
216 | |
|
217 | 0 | SuccessOrExit(error = info.FindIn(aMessage, aType)); |
218 | 0 | error = ReadStringTlv(aMessage, info.mTlvOffsetRange.GetOffset(), aMaxStringLength, aValue); |
219 | |
|
220 | 0 | exit: |
221 | 0 | return error; |
222 | 0 | } |
223 | | |
224 | | template <typename UintType> Error Tlv::FindUintTlv(const Message &aMessage, uint8_t aType, UintType &aValue) |
225 | 0 | { |
226 | 0 | Error error; |
227 | 0 | ParsedInfo info; |
228 | |
|
229 | 0 | SuccessOrExit(error = info.FindIn(aMessage, aType)); |
230 | 0 | error = ReadUintTlv<UintType>(aMessage, info.mTlvOffsetRange.GetOffset(), aValue); |
231 | |
|
232 | 0 | exit: |
233 | 0 | return error; |
234 | 0 | } Unexecuted instantiation: otError ot::Tlv::FindUintTlv<unsigned char>(ot::Message const&, unsigned char, unsigned char&) Unexecuted instantiation: otError ot::Tlv::FindUintTlv<unsigned short>(ot::Message const&, unsigned char, unsigned short&) Unexecuted instantiation: otError ot::Tlv::FindUintTlv<unsigned int>(ot::Message const&, unsigned char, unsigned int&) |
235 | | |
236 | | // Explicit instantiations of `FindUintTlv<>()` |
237 | | template Error Tlv::FindUintTlv<uint8_t>(const Message &aMessage, uint8_t aType, uint8_t &aValue); |
238 | | template Error Tlv::FindUintTlv<uint16_t>(const Message &aMessage, uint8_t aType, uint16_t &aValue); |
239 | | template Error Tlv::FindUintTlv<uint32_t>(const Message &aMessage, uint8_t aType, uint32_t &aValue); |
240 | | |
241 | | Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, void *aValue, uint16_t aLength) |
242 | 0 | { |
243 | 0 | Error error; |
244 | 0 | OffsetRange offsetRange; |
245 | |
|
246 | 0 | SuccessOrExit(error = FindTlvValueOffsetRange(aMessage, aType, offsetRange)); |
247 | 0 | error = aMessage.Read(offsetRange, aValue, aLength); |
248 | |
|
249 | 0 | exit: |
250 | 0 | return error; |
251 | 0 | } |
252 | | |
253 | | Error Tlv::AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, const char *aValue) |
254 | 0 | { |
255 | 0 | uint16_t length = (aValue == nullptr) ? 0 : StringLength(aValue, aMaxStringLength); |
256 | |
|
257 | 0 | return AppendTlv(aMessage, aType, aValue, static_cast<uint8_t>(length)); |
258 | 0 | } |
259 | | |
260 | | template <typename UintType> Error Tlv::AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue) |
261 | 210k | { |
262 | 210k | UintType value = BigEndian::HostSwap<UintType>(aValue); |
263 | | |
264 | 210k | return AppendTlv(aMessage, aType, &value, sizeof(UintType)); |
265 | 210k | } otError ot::Tlv::AppendUintTlv<unsigned char>(ot::Message&, unsigned char, unsigned char) Line | Count | Source | 261 | 140k | { | 262 | 140k | UintType value = BigEndian::HostSwap<UintType>(aValue); | 263 | | | 264 | 140k | return AppendTlv(aMessage, aType, &value, sizeof(UintType)); | 265 | 140k | } |
otError ot::Tlv::AppendUintTlv<unsigned short>(ot::Message&, unsigned char, unsigned short) Line | Count | Source | 261 | 70.2k | { | 262 | 70.2k | UintType value = BigEndian::HostSwap<UintType>(aValue); | 263 | | | 264 | 70.2k | return AppendTlv(aMessage, aType, &value, sizeof(UintType)); | 265 | 70.2k | } |
Unexecuted instantiation: otError ot::Tlv::AppendUintTlv<unsigned int>(ot::Message&, unsigned char, unsigned int) |
266 | | |
267 | | // Explicit instantiations of `AppendUintTlv<>()` |
268 | | template Error Tlv::AppendUintTlv<uint8_t>(Message &aMessage, uint8_t aType, uint8_t aValue); |
269 | | template Error Tlv::AppendUintTlv<uint16_t>(Message &aMessage, uint8_t aType, uint16_t aValue); |
270 | | template Error Tlv::AppendUintTlv<uint32_t>(Message &aMessage, uint8_t aType, uint32_t aValue); |
271 | | |
272 | | Error Tlv::AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint16_t aLength) |
273 | 281k | { |
274 | 281k | Error error = kErrorNone; |
275 | 281k | ExtendedTlv extTlv; |
276 | 281k | Tlv tlv; |
277 | | |
278 | 281k | if (aLength > kBaseTlvMaxLength) |
279 | 0 | { |
280 | 0 | extTlv.SetType(aType); |
281 | 0 | extTlv.SetLength(aLength); |
282 | 0 | SuccessOrExit(error = aMessage.Append(extTlv)); |
283 | 0 | } |
284 | 281k | else |
285 | 281k | { |
286 | 281k | tlv.SetType(aType); |
287 | 281k | tlv.SetLength(static_cast<uint8_t>(aLength)); |
288 | 281k | SuccessOrExit(error = aMessage.Append(tlv)); |
289 | 281k | } |
290 | | |
291 | 281k | VerifyOrExit(aLength > 0); |
292 | 281k | error = aMessage.AppendBytes(aValue, aLength); |
293 | | |
294 | 281k | exit: |
295 | 281k | return error; |
296 | 281k | } |
297 | | |
298 | | const Tlv *Tlv::FindTlv(const void *aTlvsStart, uint16_t aTlvsLength, uint8_t aType) |
299 | 665 | { |
300 | 665 | const Tlv *tlv; |
301 | 665 | const Tlv *end = reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(aTlvsStart) + aTlvsLength); |
302 | | |
303 | 2.88k | for (tlv = reinterpret_cast<const Tlv *>(aTlvsStart); tlv < end; tlv = tlv->GetNext()) |
304 | 2.36k | { |
305 | 2.36k | VerifyOrExit((tlv + 1) <= end, tlv = nullptr); |
306 | | |
307 | 2.36k | if (tlv->IsExtended()) |
308 | 0 | { |
309 | 0 | VerifyOrExit((As<ExtendedTlv>(tlv) + 1) <= As<ExtendedTlv>(end), tlv = nullptr); |
310 | 0 | } |
311 | | |
312 | 2.36k | VerifyOrExit(tlv->GetNext() <= end, tlv = nullptr); |
313 | | |
314 | 2.36k | if (tlv->GetType() == aType) |
315 | 143 | { |
316 | 143 | ExitNow(); |
317 | 143 | } |
318 | 2.36k | } |
319 | | |
320 | 522 | tlv = nullptr; |
321 | | |
322 | 665 | exit: |
323 | 665 | return tlv; |
324 | 522 | } |
325 | | |
326 | | } // namespace ot |