Coverage Report

Created: 2025-05-12 06:47

/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.48k
{
44
5.48k
    return IsExtended() ? sizeof(ExtendedTlv) + As<ExtendedTlv>(this)->GetLength() : sizeof(Tlv) + GetLength();
45
5.48k
}
46
47
uint8_t *Tlv::GetValue(void)
48
0
{
49
0
    return reinterpret_cast<uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv));
50
0
}
51
52
const uint8_t *Tlv::GetValue(void) const
53
0
{
54
0
    return reinterpret_cast<const uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv));
55
0
}
56
57
5.48k
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
396
{
61
396
    uint16_t offset;
62
63
396
    return FindTlv(aMessage, aType, aMaxSize, aTlv, offset);
64
396
}
65
66
Error Tlv::FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv, uint16_t &aOffset)
67
396
{
68
396
    Error      error;
69
396
    ParsedInfo info;
70
71
396
    SuccessOrExit(error = info.FindIn(aMessage, aType));
72
73
384
    info.mTlvOffsetRange.ShrinkLength(aMaxSize);
74
384
    aMessage.ReadBytes(info.mTlvOffsetRange, &aTlv);
75
384
    aOffset = info.mTlvOffsetRange.GetOffset();
76
77
396
exit:
78
396
    return error;
79
384
}
80
81
Error Tlv::FindTlvValueOffsetRange(const Message &aMessage, uint8_t aType, OffsetRange &aOffsetRange)
82
1.91k
{
83
1.91k
    Error      error;
84
1.91k
    ParsedInfo info;
85
86
1.91k
    SuccessOrExit(error = info.FindIn(aMessage, aType));
87
1.60k
    aOffsetRange = info.mValueOffsetRange;
88
89
1.91k
exit:
90
1.91k
    return error;
91
1.60k
}
92
93
Error Tlv::ParsedInfo::ParseFrom(const Message &aMessage, uint16_t aOffset)
94
1.19k
{
95
1.19k
    OffsetRange offsetRange;
96
97
1.19k
    offsetRange.InitFromRange(aOffset, aMessage.GetLength());
98
1.19k
    return ParseFrom(aMessage, offsetRange);
99
1.19k
}
100
101
Error Tlv::ParsedInfo::ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange)
102
12.5k
{
103
12.5k
    Error       error;
104
12.5k
    Tlv         tlv;
105
12.5k
    ExtendedTlv extTlv;
106
12.5k
    uint32_t    headerSize;
107
12.5k
    uint32_t    size;
108
109
12.5k
    SuccessOrExit(error = aMessage.Read(aOffsetRange, tlv));
110
111
11.8k
    mType = tlv.GetType();
112
113
11.8k
    if (!tlv.IsExtended())
114
11.7k
    {
115
11.7k
        mIsExtended = false;
116
11.7k
        headerSize  = sizeof(Tlv);
117
11.7k
        size        = headerSize + tlv.GetLength();
118
11.7k
    }
119
104
    else
120
104
    {
121
104
        SuccessOrExit(error = aMessage.Read(aOffsetRange, extTlv));
122
123
99
        mIsExtended = true;
124
99
        headerSize  = sizeof(ExtendedTlv);
125
99
        size        = headerSize + extTlv.GetLength();
126
99
    }
127
128
11.8k
    mTlvOffsetRange = aOffsetRange;
129
11.8k
    VerifyOrExit(mTlvOffsetRange.Contains(size), error = kErrorParse);
130
11.8k
    mTlvOffsetRange.ShrinkLength(static_cast<uint16_t>(size));
131
132
11.8k
    VerifyOrExit(mTlvOffsetRange.GetEndOffset() <= aMessage.GetLength(), error = kErrorParse);
133
134
11.8k
    mValueOffsetRange = mTlvOffsetRange;
135
11.8k
    mValueOffsetRange.AdvanceOffset(headerSize);
136
137
12.5k
exit:
138
12.5k
    return error;
139
11.8k
}
140
141
Error Tlv::ParsedInfo::FindIn(const Message &aMessage, uint8_t aType)
142
3.83k
{
143
3.83k
    Error       error = kErrorNotFound;
144
3.83k
    OffsetRange offsetRange;
145
146
3.83k
    offsetRange.InitFromMessageOffsetToEnd(aMessage);
147
148
11.0k
    while (true)
149
11.0k
    {
150
11.0k
        SuccessOrExit(ParseFrom(aMessage, offsetRange));
151
152
10.3k
        if (mType == aType)
153
3.14k
        {
154
3.14k
            error = kErrorNone;
155
3.14k
            ExitNow();
156
3.14k
        }
157
158
7.25k
        offsetRange.AdvanceOffset(mTlvOffsetRange.GetLength());
159
7.25k
    }
160
161
3.83k
exit:
162
3.83k
    return error;
163
3.83k
}
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
1.15k
{
182
1.15k
    Error error;
183
184
1.15k
    SuccessOrExit(error = ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue)));
185
1.14k
    aValue = BigEndian::HostSwap<UintType>(aValue);
186
187
1.15k
exit:
188
1.15k
    return error;
189
1.14k
}
otError ot::Tlv::ReadUintTlv<unsigned char>(ot::Message const&, unsigned short, unsigned char&)
Line
Count
Source
181
335
{
182
335
    Error error;
183
184
335
    SuccessOrExit(error = ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue)));
185
334
    aValue = BigEndian::HostSwap<UintType>(aValue);
186
187
335
exit:
188
335
    return error;
189
334
}
otError ot::Tlv::ReadUintTlv<unsigned short>(ot::Message const&, unsigned short, unsigned short&)
Line
Count
Source
181
819
{
182
819
    Error error;
183
184
819
    SuccessOrExit(error = ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue)));
185
813
    aValue = BigEndian::HostSwap<UintType>(aValue);
186
187
819
exit:
188
819
    return error;
189
813
}
otError ot::Tlv::ReadUintTlv<unsigned int>(ot::Message const&, unsigned short, unsigned int&)
Line
Count
Source
181
5
{
182
5
    Error error;
183
184
5
    SuccessOrExit(error = ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue)));
185
2
    aValue = BigEndian::HostSwap<UintType>(aValue);
186
187
5
exit:
188
5
    return error;
189
2
}
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
1.19k
{
198
1.19k
    Error      error;
199
1.19k
    ParsedInfo info;
200
201
1.19k
    SuccessOrExit(error = info.ParseFrom(aMessage, aOffset));
202
203
1.19k
    VerifyOrExit(info.mValueOffsetRange.Contains(aMinLength), error = kErrorParse);
204
1.18k
    info.mValueOffsetRange.ShrinkLength(aMinLength);
205
206
1.18k
    aMessage.ReadBytes(info.mValueOffsetRange, aValue);
207
208
1.19k
exit:
209
1.19k
    return error;
210
1.18k
}
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
1.52k
{
226
1.52k
    Error      error;
227
1.52k
    ParsedInfo info;
228
229
1.52k
    SuccessOrExit(error = info.FindIn(aMessage, aType));
230
1.15k
    error = ReadUintTlv<UintType>(aMessage, info.mTlvOffsetRange.GetOffset(), aValue);
231
232
1.52k
exit:
233
1.52k
    return error;
234
1.15k
}
otError ot::Tlv::FindUintTlv<unsigned char>(ot::Message const&, unsigned char, unsigned char&)
Line
Count
Source
225
353
{
226
353
    Error      error;
227
353
    ParsedInfo info;
228
229
353
    SuccessOrExit(error = info.FindIn(aMessage, aType));
230
335
    error = ReadUintTlv<UintType>(aMessage, info.mTlvOffsetRange.GetOffset(), aValue);
231
232
353
exit:
233
353
    return error;
234
335
}
otError ot::Tlv::FindUintTlv<unsigned short>(ot::Message const&, unsigned char, unsigned short&)
Line
Count
Source
225
1.14k
{
226
1.14k
    Error      error;
227
1.14k
    ParsedInfo info;
228
229
1.14k
    SuccessOrExit(error = info.FindIn(aMessage, aType));
230
819
    error = ReadUintTlv<UintType>(aMessage, info.mTlvOffsetRange.GetOffset(), aValue);
231
232
1.14k
exit:
233
1.14k
    return error;
234
819
}
otError ot::Tlv::FindUintTlv<unsigned int>(ot::Message const&, unsigned char, unsigned int&)
Line
Count
Source
225
33
{
226
33
    Error      error;
227
33
    ParsedInfo info;
228
229
33
    SuccessOrExit(error = info.FindIn(aMessage, aType));
230
5
    error = ReadUintTlv<UintType>(aMessage, info.mTlvOffsetRange.GetOffset(), aValue);
231
232
33
exit:
233
33
    return error;
234
5
}
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
476
{
243
476
    Error       error;
244
476
    OffsetRange offsetRange;
245
246
476
    SuccessOrExit(error = FindTlvValueOffsetRange(aMessage, aType, offsetRange));
247
442
    error = aMessage.Read(offsetRange, aValue, aLength);
248
249
476
exit:
250
476
    return error;
251
442
}
252
253
Error Tlv::AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, const char *aValue)
254
1.01k
{
255
1.01k
    uint16_t length = (aValue == nullptr) ? 0 : StringLength(aValue, aMaxStringLength);
256
257
1.01k
    return AppendTlv(aMessage, aType, aValue, static_cast<uint8_t>(length));
258
1.01k
}
259
260
template <typename UintType> Error Tlv::AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue)
261
622k
{
262
622k
    UintType value = BigEndian::HostSwap<UintType>(aValue);
263
264
622k
    return AppendTlv(aMessage, aType, &value, sizeof(UintType));
265
622k
}
otError ot::Tlv::AppendUintTlv<unsigned char>(ot::Message&, unsigned char, unsigned char)
Line
Count
Source
261
152k
{
262
152k
    UintType value = BigEndian::HostSwap<UintType>(aValue);
263
264
152k
    return AppendTlv(aMessage, aType, &value, sizeof(UintType));
265
152k
}
otError ot::Tlv::AppendUintTlv<unsigned short>(ot::Message&, unsigned char, unsigned short)
Line
Count
Source
261
469k
{
262
469k
    UintType value = BigEndian::HostSwap<UintType>(aValue);
263
264
469k
    return AppendTlv(aMessage, aType, &value, sizeof(UintType));
265
469k
}
otError ot::Tlv::AppendUintTlv<unsigned int>(ot::Message&, unsigned char, unsigned int)
Line
Count
Source
261
25
{
262
25
    UintType value = BigEndian::HostSwap<UintType>(aValue);
263
264
25
    return AppendTlv(aMessage, aType, &value, sizeof(UintType));
265
25
}
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
1.09M
{
274
1.09M
    Error       error = kErrorNone;
275
1.09M
    ExtendedTlv extTlv;
276
1.09M
    Tlv         tlv;
277
278
1.09M
    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
1.09M
    else
285
1.09M
    {
286
1.09M
        tlv.SetType(aType);
287
1.09M
        tlv.SetLength(static_cast<uint8_t>(aLength));
288
1.09M
        SuccessOrExit(error = aMessage.Append(tlv));
289
1.09M
    }
290
291
1.09M
    VerifyOrExit(aLength > 0);
292
1.09M
    error = aMessage.AppendBytes(aValue, aLength);
293
294
1.09M
exit:
295
1.09M
    return error;
296
1.09M
}
297
298
const Tlv *Tlv::FindTlv(const void *aTlvsStart, uint16_t aTlvsLength, uint8_t aType)
299
0
{
300
0
    const Tlv *tlv;
301
0
    const Tlv *end = reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(aTlvsStart) + aTlvsLength);
302
303
0
    for (tlv = reinterpret_cast<const Tlv *>(aTlvsStart); tlv < end; tlv = tlv->GetNext())
304
0
    {
305
0
        VerifyOrExit((tlv + 1) <= end, tlv = nullptr);
306
307
0
        if (tlv->IsExtended())
308
0
        {
309
0
            VerifyOrExit((As<ExtendedTlv>(tlv) + 1) <= As<ExtendedTlv>(end), tlv = nullptr);
310
0
        }
311
312
0
        VerifyOrExit(tlv->GetNext() <= end, tlv = nullptr);
313
314
0
        if (tlv->GetType() == aType)
315
0
        {
316
0
            ExitNow();
317
0
        }
318
0
    }
319
320
0
    tlv = nullptr;
321
322
0
exit:
323
0
    return tlv;
324
0
}
325
326
} // namespace ot