1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "softbus_tlv_utils.h"
17
18 #include "securec.h"
19
20 #include "comm_log.h"
21 #include "softbus_adapter_mem.h"
22 #include "softbus_adapter_socket.h"
23 #include "softbus_error_code.h"
24
25 #define TLV_SIZE(obj, length) ((obj)->tSize + (obj)->lSize + (length))
26
NewTlvMember(uint32_t type,uint32_t length,const uint8_t * value)27 static TlvMember *NewTlvMember(uint32_t type, uint32_t length, const uint8_t *value)
28 {
29 TlvMember *tlv = (TlvMember *)SoftBusMalloc(sizeof(TlvMember) + length);
30 COMM_CHECK_AND_RETURN_RET_LOGW(tlv != NULL, NULL, COMM_UTILS, "malloc fail");
31 tlv->type = type;
32 tlv->length = length;
33 if (length > 0 && value != NULL) {
34 (void)memcpy_s(tlv->value, length, value, length);
35 }
36 return tlv;
37 }
38
DelTlvMember(TlvMember * tlv)39 static void DelTlvMember(TlvMember *tlv)
40 {
41 SoftBusFree(tlv);
42 }
43
CreateTlvObject(uint8_t tSize,uint8_t lSize)44 TlvObject *CreateTlvObject(uint8_t tSize, uint8_t lSize)
45 {
46 COMM_CHECK_AND_RETURN_RET_LOGW(tSize >= UINT8_T && tSize <= UINT32_T,
47 NULL, COMM_UTILS, "invalid tSize=%{public}u", tSize);
48 COMM_CHECK_AND_RETURN_RET_LOGW(lSize >= UINT8_T && lSize <= UINT32_T,
49 NULL, COMM_UTILS, "invalid lSize=%{public}u", lSize);
50 TlvObject *obj = (TlvObject *)SoftBusMalloc(sizeof(TlvObject));
51 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, NULL, COMM_UTILS, "malloc fail");
52 obj->tSize = tSize;
53 obj->lSize = lSize;
54 obj->size = 0;
55 ListInit(&obj->mList);
56 return obj;
57 }
58
DestroyTlvObject(TlvObject * obj)59 void DestroyTlvObject(TlvObject *obj)
60 {
61 COMM_CHECK_AND_RETURN_LOGW(obj != NULL, COMM_UTILS, "obj nullptr");
62 TlvMember *item = NULL;
63 TlvMember *next = NULL;
64 LIST_FOR_EACH_ENTRY_SAFE(item, next, &obj->mList, TlvMember, node) {
65 ListDelete(&item->node);
66 DelTlvMember(item);
67 }
68 SoftBusFree(obj);
69 }
70
AddTlvMember(TlvObject * obj,uint32_t type,uint32_t length,const uint8_t * value)71 int32_t AddTlvMember(TlvObject *obj, uint32_t type, uint32_t length, const uint8_t *value)
72 {
73 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "obj nullptr");
74 COMM_CHECK_AND_RETURN_RET_LOGW(((length > 0 && length < MAX_VALUE_LENGTH && value != NULL) || (length == 0)),
75 SOFTBUS_INVALID_PARAM, COMM_UTILS, "invalid param, length=%{public}u", length);
76 TlvMember *tlv = NewTlvMember(type, length, value);
77 COMM_CHECK_AND_RETURN_RET_LOGW(tlv != NULL, SOFTBUS_MALLOC_ERR, COMM_UTILS, "new tlv fail");
78 ListTailInsert(&obj->mList, &tlv->node);
79 obj->size += TLV_SIZE(obj, tlv->length);
80 return SOFTBUS_OK;
81 }
82
GetTlvMember(TlvObject * obj,uint32_t type,uint32_t * length,uint8_t ** value)83 int32_t GetTlvMember(TlvObject *obj, uint32_t type, uint32_t *length, uint8_t **value)
84 {
85 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "obj nullptr");
86 COMM_CHECK_AND_RETURN_RET_LOGW(length != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "length nullptr");
87 COMM_CHECK_AND_RETURN_RET_LOGW(value != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "value nullptr");
88 TlvMember *tlv = NULL;
89 LIST_FOR_EACH_ENTRY(tlv, &obj->mList, TlvMember, node) {
90 if (tlv->type == type) {
91 *length = tlv->length;
92 *value = tlv->value;
93 return SOFTBUS_OK;
94 }
95 }
96 COMM_LOGE(COMM_UTILS, "tlv not found by type(=%{public}u)", type);
97 return SOFTBUS_NOT_FIND;
98 }
99
PackTypeOrLength(uint8_t * buf,uint32_t size,uint32_t content,uint8_t contentSize)100 static int32_t PackTypeOrLength(uint8_t *buf, uint32_t size, uint32_t content, uint8_t contentSize)
101 {
102 errno_t err;
103 switch (contentSize) {
104 case UINT8_T: {
105 uint8_t type = (uint8_t)content;
106 err = memcpy_s(buf, size, &type, sizeof(type));
107 break;
108 }
109 case UINT16_T: {
110 uint16_t type = SoftBusHtoLs((uint16_t)content);
111 err = memcpy_s(buf, size, &type, sizeof(type));
112 break;
113 }
114 case UINT32_T: {
115 uint32_t type = SoftBusHtoLl(content);
116 err = memcpy_s(buf, size, &type, sizeof(type));
117 break;
118 }
119 default:
120 COMM_LOGW(COMM_UTILS, "unsupport type/length size(=%{public}u)", contentSize);
121 return SOFTBUS_NOT_IMPLEMENT;
122 }
123 return (err != EOK ? SOFTBUS_MEM_ERR : SOFTBUS_OK);
124 }
125
PackValue(uint8_t * buf,uint32_t size,const uint8_t * value,uint32_t vSize)126 static int32_t PackValue(uint8_t *buf, uint32_t size, const uint8_t *value, uint32_t vSize)
127 {
128 COMM_CHECK_AND_RETURN_RET_LOGW(vSize != 0, SOFTBUS_OK, COMM_UTILS, "tlv len=0! warning!");
129 errno_t err = memcpy_s(buf, size, value, vSize);
130 return (err != EOK ? SOFTBUS_MEM_ERR : SOFTBUS_OK);
131 }
132
PackTlvMember(const TlvObject * obj,const TlvMember * tlv,uint8_t * buffer,uint32_t size)133 static int32_t PackTlvMember(const TlvObject *obj, const TlvMember *tlv, uint8_t *buffer, uint32_t size)
134 {
135 COMM_CHECK_AND_RETURN_RET_LOGE(size >= TLV_SIZE(obj, tlv->length),
136 SOFTBUS_NO_ENOUGH_DATA, COMM_UTILS, "buffer not enough(size=%{public}u, len=%{public}u)", size, tlv->length);
137 uint32_t offset = 0;
138 int32_t ret = PackTypeOrLength(buffer, size, tlv->type, obj->tSize);
139 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "pack type fail(=%{public}d)", ret);
140 offset += obj->tSize;
141 ret = PackTypeOrLength(buffer + offset, size - offset, tlv->length, obj->lSize);
142 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "pack length fail(=%{public}d)", ret);
143 offset += obj->lSize;
144 ret = PackValue(buffer + offset, size - offset, tlv->value, tlv->length);
145 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "pack value fail(=%{public}d)", ret);
146 return SOFTBUS_OK;
147 }
148
GetTlvBinary(TlvObject * obj,uint8_t ** output,uint32_t * outputSize)149 int32_t GetTlvBinary(TlvObject *obj, uint8_t **output, uint32_t *outputSize)
150 {
151 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "obj nullptr");
152 COMM_CHECK_AND_RETURN_RET_LOGW(output != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "output nullptr");
153 COMM_CHECK_AND_RETURN_RET_LOGW(outputSize != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "outputSize nullptr");
154 COMM_CHECK_AND_RETURN_RET_LOGW(obj->size > 0, SOFTBUS_NOT_FIND, COMM_UTILS, "no tlv member");
155
156 uint8_t *buffer = (uint8_t *)SoftBusCalloc(obj->size);
157 COMM_CHECK_AND_RETURN_RET_LOGE(buffer != NULL, SOFTBUS_MALLOC_ERR, COMM_UTILS, "malloc buf fail");
158
159 int32_t ret;
160 uint32_t offset = 0;
161 TlvMember *tlv = NULL;
162 LIST_FOR_EACH_ENTRY(tlv, &obj->mList, TlvMember, node) {
163 ret = PackTlvMember(obj, tlv, buffer + offset, obj->size - offset);
164 if (ret != SOFTBUS_OK) {
165 SoftBusFree(buffer);
166 return ret;
167 }
168 offset += TLV_SIZE(obj, tlv->length);
169 }
170 *output = buffer;
171 *outputSize = offset;
172 return SOFTBUS_OK;
173 }
174
UnpackTypeOrLength(const uint8_t * buf,uint32_t size)175 static uint32_t UnpackTypeOrLength(const uint8_t *buf, uint32_t size)
176 {
177 switch (size) {
178 case UINT8_T: {
179 uint8_t type = *((uint8_t *)buf);
180 return (uint32_t)type;
181 }
182 case UINT16_T: {
183 uint16_t type = *((uint16_t *)buf);
184 return (uint32_t)SoftBusLtoHs(type);
185 }
186 case UINT32_T: {
187 uint32_t type = *((uint32_t *)buf);
188 return SoftBusLtoHl(type);
189 }
190 default:
191 COMM_LOGW(COMM_UTILS, "unsupport type/length size(=%{public}u)", size);
192 break;
193 }
194 return UINT32_MAX;
195 }
196
SetTlvBinary(TlvObject * obj,const uint8_t * input,uint32_t inputSize)197 int32_t SetTlvBinary(TlvObject *obj, const uint8_t *input, uint32_t inputSize)
198 {
199 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "obj nullptr");
200 COMM_CHECK_AND_RETURN_RET_LOGW(input != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "input nullptr");
201 COMM_CHECK_AND_RETURN_RET_LOGW(inputSize > 0 && inputSize < MAX_TLV_BINARY_LENGTH,
202 SOFTBUS_INVALID_DATA_HEAD, COMM_UTILS, "invalid inputSize(=%{public}u)", inputSize);
203 uint32_t offset = 0;
204 while (offset + TLV_SIZE(obj, 0) <= inputSize) {
205 uint32_t type = UnpackTypeOrLength(input + offset, obj->tSize);
206 uint32_t length = UnpackTypeOrLength(input + offset + obj->tSize, obj->lSize);
207 COMM_CHECK_AND_RETURN_RET_LOGE((type != UINT32_MAX && length != UINT32_MAX), SOFTBUS_NOT_IMPLEMENT,
208 COMM_UTILS, "invalid tSize(=%{public}u)/lSize(=%{public}u)", obj->tSize, obj->lSize);
209 COMM_CHECK_AND_RETURN_RET_LOGE(length < MAX_VALUE_LENGTH, SOFTBUS_INVALID_DATA_HEAD,
210 COMM_UTILS, "invalid length=%{public}u", length);
211 if (TLV_SIZE(obj, length) > inputSize - offset) {
212 COMM_LOGW(COMM_UTILS, "incomplete tlv, type=%{public}u, length=%{public}u", type, length);
213 return SOFTBUS_NO_ENOUGH_DATA;
214 }
215 int32_t ret = AddTlvMember(obj, type, length, input + offset + TLV_SIZE(obj, 0));
216 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "add tlv member fail(=%{public}d)", ret);
217 offset += TLV_SIZE(obj, length);
218 }
219 COMM_CHECK_AND_RETURN_RET_LOGW(offset > 0, SOFTBUS_NO_ENOUGH_DATA,
220 COMM_UTILS, "no tlv member, offset=%{public}u, length=%{public}u", offset, inputSize);
221 COMM_CHECK_AND_RETURN_RET_LOGW(offset == inputSize, SOFTBUS_OK,
222 COMM_UTILS, "TLV binary not be parsed completely, offset=%{public}u, length=%{public}u", offset, inputSize);
223 return SOFTBUS_OK;
224 }
225
GetTlvMemberWithSpecifiedBuffer(TlvObject * obj,uint32_t type,uint8_t * buffer,uint32_t size)226 int32_t GetTlvMemberWithSpecifiedBuffer(TlvObject *obj, uint32_t type, uint8_t *buffer, uint32_t size)
227 {
228 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "obj nullptr");
229 uint32_t length = 0;
230 uint8_t *value = NULL;
231 int32_t ret = GetTlvMember(obj, type, &length, &value);
232 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "get tlv fail(=%{public}d)", ret);
233 COMM_CHECK_AND_RETURN_RET_LOGE(length == size, SOFTBUS_INVALID_PARAM,
234 COMM_UTILS, "size(=%{public}u) not match length(=%{public}u)", size, length);
235 COMM_CHECK_AND_RETURN_RET_LOGW(length > 0, SOFTBUS_OK, COMM_UTILS, "tlv len==0! warning!");
236 COMM_CHECK_AND_RETURN_RET_LOGW(buffer != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "buffer nullptr");
237 errno_t err = memcpy_s(buffer, size, value, length);
238 return (err != EOK ? SOFTBUS_MEM_ERR : SOFTBUS_OK);
239 }
240
GetTlvMemberWithEstimatedBuffer(TlvObject * obj,uint32_t type,uint8_t * buffer,uint32_t * size)241 int32_t GetTlvMemberWithEstimatedBuffer(TlvObject *obj, uint32_t type, uint8_t *buffer, uint32_t *size)
242 {
243 COMM_CHECK_AND_RETURN_RET_LOGW(obj != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "obj nullptr");
244 COMM_CHECK_AND_RETURN_RET_LOGW(size != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "size nullptr");
245 COMM_CHECK_AND_RETURN_RET_LOGW(buffer != NULL, SOFTBUS_INVALID_PARAM, COMM_UTILS, "buffer nullptr");
246 uint32_t length = 0;
247 uint8_t *value = NULL;
248 int32_t ret = GetTlvMember(obj, type, &length, &value);
249 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "get tlv fail(=%{public}d)", ret);
250 if (length == 0) {
251 COMM_LOGW(COMM_UTILS, "tlv len==0! warning!");
252 *size = 0;
253 return SOFTBUS_OK;
254 }
255 errno_t err = memcpy_s(buffer, *size, value, length);
256 COMM_CHECK_AND_RETURN_RET_LOGE(err == EOK, SOFTBUS_MEM_ERR, COMM_UTILS, "copy value fail(=%{public}d)", ret);
257 *size = length;
258 return SOFTBUS_OK;
259 }
260
AddTlvMemberU8(TlvObject * obj,uint32_t type,uint8_t value)261 int32_t AddTlvMemberU8(TlvObject *obj, uint32_t type, uint8_t value)
262 {
263 return AddTlvMember(obj, type, sizeof(uint8_t), &value);
264 }
265
GetTlvMemberU8(TlvObject * obj,uint32_t type,uint8_t * value)266 int32_t GetTlvMemberU8(TlvObject *obj, uint32_t type, uint8_t *value)
267 {
268 return GetTlvMemberWithSpecifiedBuffer(obj, type, value, sizeof(uint8_t));
269 }
270
AddTlvMemberU16(TlvObject * obj,uint32_t type,uint16_t value)271 int32_t AddTlvMemberU16(TlvObject *obj, uint32_t type, uint16_t value)
272 {
273 value = SoftBusHtoLs(value);
274 return AddTlvMember(obj, type, sizeof(uint16_t), (const uint8_t *)&value);
275 }
276
GetTlvMemberU16(TlvObject * obj,uint32_t type,uint16_t * value)277 int32_t GetTlvMemberU16(TlvObject *obj, uint32_t type, uint16_t *value)
278 {
279 int32_t ret = GetTlvMemberWithSpecifiedBuffer(obj, type, (uint8_t *)value, sizeof(uint16_t));
280 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "get tlv fail(=%{public}d)", ret);
281 *value = SoftBusLtoHs(*value);
282 return SOFTBUS_OK;
283 }
284
AddTlvMemberU32(TlvObject * obj,uint32_t type,uint32_t value)285 int32_t AddTlvMemberU32(TlvObject *obj, uint32_t type, uint32_t value)
286 {
287 value = SoftBusHtoLl(value);
288 return AddTlvMember(obj, type, sizeof(uint32_t), (const uint8_t *)&value);
289 }
290
GetTlvMemberU32(TlvObject * obj,uint32_t type,uint32_t * value)291 int32_t GetTlvMemberU32(TlvObject *obj, uint32_t type, uint32_t *value)
292 {
293 int32_t ret = GetTlvMemberWithSpecifiedBuffer(obj, type, (uint8_t *)value, sizeof(uint32_t));
294 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "get tlv fail(=%{public}d)", ret);
295 *value = SoftBusLtoHl(*value);
296 return SOFTBUS_OK;
297 }
298
AddTlvMemberU64(TlvObject * obj,uint32_t type,uint64_t value)299 int32_t AddTlvMemberU64(TlvObject *obj, uint32_t type, uint64_t value)
300 {
301 value = SoftBusHtoLll(value);
302 return AddTlvMember(obj, type, sizeof(uint64_t), (const uint8_t *)&value);
303 }
304
GetTlvMemberU64(TlvObject * obj,uint32_t type,uint64_t * value)305 int32_t GetTlvMemberU64(TlvObject *obj, uint32_t type, uint64_t *value)
306 {
307 int32_t ret = GetTlvMemberWithSpecifiedBuffer(obj, type, (uint8_t *)value, sizeof(uint64_t));
308 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_UTILS, "get tlv fail(=%{public}d)", ret);
309 *value = SoftBusLtoHll(*value);
310 return SOFTBUS_OK;
311 }
312