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.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