• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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