1 /*
2 * Copyright (C) 2021 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 "nstackx_dfile_frame.h"
17 #include "nstackx_util.h"
18 #include "nstackx_error.h"
19 #include "nstackx_dfile.h"
20 #include "nstackx_dfile_log.h"
21 #include "nstackx_dfile_config.h"
22 #include "nstackx_dev.h"
23 #include "securec.h"
24
25 #define TAG "nStackXDFile"
26
GetFrameName(DFileFrameType frameType)27 const char *GetFrameName(DFileFrameType frameType)
28 {
29 uint32_t i;
30
31 static const char *frameNameList[] = {
32 [NSTACKX_DFILE_FILE_HEADER_FRAME] = "FILE_HEADER_FRAME",
33 [NSTACKX_DFILE_FILE_HEADER_CONFIRM_FRAME] = "FILE_HEADER_CONFIRM_FRAME",
34 [NSTACKX_DFILE_FILE_TRANSFER_REQ_FRAME] = "FILE_TRANSFER_REQ_FRAME",
35 [NSTACKX_DFILE_FILE_DATA_FRAME] = "FILE_DATA_FRAME",
36 [NSTACKX_DFILE_FILE_TRANSFER_DONE_FRAME] = "FILE_TRANSFER_DONE_FRAME",
37 [NSTACKX_DFILE_FILE_TRANSFER_DONE_ACK_FRAME] = "FILE_TRANSFER_DONE_ACK_FRAME",
38 [NSTACKX_DFILE_SETTING_FRAME] = "SETTING_FRAME",
39 [NSTACKX_DFILE_RST_FRAME] = "RST_FRAME",
40 };
41
42 for (i = 0; i < sizeof(frameNameList) / sizeof(frameNameList[0]); i++) {
43 if (i == frameType) {
44 return frameNameList[i];
45 }
46 }
47
48 return "unknown";
49 }
50
GetTarTotalBlockLength(FileList * fileList)51 uint64_t GetTarTotalBlockLength(FileList *fileList)
52 {
53 char pathSeparator = '/';
54 uint64_t tarFilesTotalLen = 0;
55 uint64_t blockCnt;
56 uint32_t i;
57 int32_t ret;
58 struct stat statInfo;
59 char *path = NULL;
60
61 for (i = 0; i < fileList->num; i++) {
62 tarFilesTotalLen += BLOCK_LEN;
63
64 path = fileList->list[i].fullFileName;
65 if (strlen(path) > MAX_NAME_LEN) {
66 // +1 because of the string end '\0'
67 tarFilesTotalLen += BLOCK_LEN +
68 (((strlen(path) + 1 - (long long)(path[0] == pathSeparator) + BLOCK_LEN - 1) / BLOCK_LEN) * BLOCK_LEN);
69 }
70
71 ret = stat(path, &statInfo);
72 if (ret != NSTACKX_EOK) {
73 DFILE_LOGE(TAG, "get stat error: %d", ret);
74 return 0;
75 }
76
77 // file body length
78 blockCnt = (uint64_t)((statInfo.st_size + BLOCK_LEN - 1) / BLOCK_LEN);
79 tarFilesTotalLen += (blockCnt * BLOCK_LEN);
80 }
81
82 // file tail paddings length
83 tarFilesTotalLen += BLOCK_LEN;
84
85 return tarFilesTotalLen;
86 }
87
EncodeFileInfo(FileList * fileList,uint16_t fileId,uint8_t * buffer,size_t length,size_t * fileInfoSize)88 static int32_t EncodeFileInfo(FileList *fileList, uint16_t fileId, uint8_t *buffer, size_t length,
89 size_t *fileInfoSize)
90 {
91 FileInfoUnit *fileInfoUnit = (FileInfoUnit *)buffer;
92 const char *fileName = NULL;
93 uint16_t fileNameLen;
94 size_t remainLength;
95 uint64_t filesTotalLen;
96
97 if (fileId == 0) {
98 if (fileList->packedUserData != NULL) {
99 fileName = (char *)fileList->packedUserData;
100 fileNameLen = fileList->packedUserDataLen;
101 } else {
102 fileName = fileList->userData;
103 fileNameLen = (uint16_t)strlen(fileName);
104 }
105 filesTotalLen = 0;
106 } else {
107 fileName = FileListGetRemotePath(fileList, fileId);
108 if (fileName == NULL) {
109 fileName = FileListGetFileName(fileList, fileId);
110 }
111 fileNameLen = (uint16_t)strlen(fileName);
112 if (fileList->tarFlag == NSTACKX_FALSE) {
113 filesTotalLen = FileListGetFileSize(fileList, fileId);
114 } else {
115 filesTotalLen = GetTarTotalBlockLength(fileList);
116 }
117 }
118
119 if (length <= offsetof(FileInfoUnit, fileName)) {
120 /* Running out of buffer */
121 DFILE_LOGE(TAG, "buffer length %zu is not enough", length);
122 return NSTACKX_EAGAIN;
123 }
124 remainLength = length - offsetof(FileInfoUnit, fileName);
125 if (memcpy_s(fileInfoUnit->fileName, remainLength, fileName, fileNameLen) != EOK) {
126 /* Running out of buffer */
127 DFILE_LOGE(TAG, "memcpy_s fileName error. remain length %zu, fileNameLen %hu", remainLength, fileNameLen);
128 return NSTACKX_EAGAIN;
129 }
130 fileInfoUnit->fileId = htons(fileId);
131 fileInfoUnit->fileSize = htobe64(filesTotalLen);
132 fileInfoUnit->fileNameLength = htons(fileNameLen);
133 *fileInfoSize = offsetof(FileInfoUnit, fileName) + fileNameLen;
134 return NSTACKX_EOK;
135 }
136
137 /* Caller should make sure that "length" can cover the minimum header length */
EncodeFileHeaderFrameSp(FileList * fileList,int32_t * fileId,uint8_t * buffer,size_t length,size_t * frameLength)138 void EncodeFileHeaderFrameSp(FileList *fileList, int32_t *fileId, uint8_t *buffer, size_t length,
139 size_t *frameLength)
140 {
141 FileHeaderFrame *headerFrame = (FileHeaderFrame *)buffer;
142 size_t offset = 0;
143 size_t fileInfoSize = 0;
144 size_t bufferLength = length;
145 int32_t nextFileId;
146 int32_t lastAddedFileId = *fileId;
147 uint32_t fileNum;
148
149 /* Remaining buffer length for fileInfoUnit */
150 bufferLength -= (sizeof(uint16_t) + DFILE_FRAME_HEADER_LEN);
151
152 if (fileList->tarFlag == NSTACKX_TRUE) {
153 fileNum = 1;
154 } else {
155 fileNum = FileListGetNum(fileList);
156 }
157
158 do {
159 if (lastAddedFileId == (int32_t)fileNum || bufferLength <= offset) {
160 break;
161 }
162
163 nextFileId = lastAddedFileId + 1;
164 if (FileListGetFileNameAcked(fileList, (uint16_t)nextFileId) ||
165 (nextFileId == 0 && fileList->userData == NULL && fileList->packedUserData == NULL)) {
166 DFILE_LOGI(TAG, "SKIP FILE ID %d", nextFileId);
167 lastAddedFileId = nextFileId;
168 continue;
169 }
170
171 if (EncodeFileInfo(fileList, (uint16_t)nextFileId, &headerFrame->fileInfoUnit[offset],
172 bufferLength - offset, &fileInfoSize) != NSTACKX_EOK) {
173 DFILE_LOGE(TAG, "EncodeFileInfo fileId %d failed", nextFileId);
174 break;
175 }
176
177 offset += fileInfoSize;
178 lastAddedFileId = nextFileId;
179 } while (NSTACKX_TRUE);
180
181 headerFrame->header.type = NSTACKX_DFILE_FILE_HEADER_FRAME;
182 if (fileList->userData != NULL) {
183 SetDfileFrameUserDataFlag(&headerFrame->header);
184 }
185
186 if (fileList->pathType > 0) {
187 SetDfileFramePathTypeFlag(&headerFrame->header);
188 }
189 /* set no sync flag */
190 if (fileList->noSyncFlag) {
191 SetDfileFrameNoSyncFlag(&headerFrame->header);
192 }
193 /* Add "node number" */
194 offset += sizeof(uint16_t);
195 headerFrame->header.length = htons((uint16_t)offset);
196 headerFrame->nodeNumber = htons((uint16_t)fileNum);
197 /* Update internal buffer length */
198 *frameLength = DFILE_FRAME_HEADER_LEN + offset;
199 *fileId = lastAddedFileId;
200 }
201
EncodeFileHeaderFrame(FileList * fileList,int32_t * fileId,uint8_t * buffer,size_t length,size_t * frameLength)202 void EncodeFileHeaderFrame(FileList *fileList, int32_t *fileId, uint8_t *buffer, size_t length,
203 size_t *frameLength)
204 {
205 EncodeFileHeaderFrameSp(fileList, fileId, buffer, length, frameLength);
206 }
207
208 /* Caller should make sure that "length" can cover the minimum header length */
EncodeFileHeaderConfirmFrame(FileList * fileList,uint16_t * fileId,uint8_t * buffer,size_t length,size_t * frameLength)209 void EncodeFileHeaderConfirmFrame(FileList *fileList, uint16_t *fileId, uint8_t *buffer, size_t length,
210 size_t *frameLength)
211 {
212 FileHeaderConfirmFrame *confirmFrame = (FileHeaderConfirmFrame *)buffer;
213 size_t bufferLength = length;
214 uint16_t payloadLength;
215 uint16_t nextFileId;
216 uint16_t lastAckedFileId = *fileId;
217 uint16_t i = 0;
218
219 /* Remaining buffer length for payload */
220 bufferLength -= DFILE_FRAME_HEADER_LEN;
221
222 if ((fileList->userDataFlag & NSTACKX_DFILE_HEADER_FRAME_USER_DATA_FLAG) &&
223 (fileList->userDataFlag & NSTACKX_FLAGS_FILE_NAME_RECEIVED)) {
224 confirmFrame->fileId[i] = 0;
225 i++;
226 }
227
228 do {
229 if (lastAckedFileId == FileListGetNum(fileList)) {
230 break;
231 }
232
233 nextFileId = lastAckedFileId + 1;
234 if (!FileListGetFileNameReceived(fileList, nextFileId)) {
235 lastAckedFileId = nextFileId;
236 DFILE_LOGE(TAG, "fileId %u is not acked yet", nextFileId);
237 continue;
238 }
239 if (i >= (bufferLength >> 1)) {
240 break;
241 }
242 confirmFrame->fileId[i++] = htons(nextFileId);
243 lastAckedFileId = nextFileId;
244 } while (NSTACKX_TRUE);
245
246 payloadLength = (uint16_t)(i * sizeof(uint16_t)); /* length should be within MTU to avoid overflow */
247 confirmFrame->header.type = NSTACKX_DFILE_FILE_HEADER_CONFIRM_FRAME;
248 /* Don't have to set flag for ACK frame */
249 confirmFrame->header.flag = 0;
250 confirmFrame->header.length = htons(payloadLength);
251
252 /* Update internal buffer length */
253 *frameLength = DFILE_FRAME_HEADER_LEN + payloadLength;
254 *fileId = lastAckedFileId;
255 }
256
257 /* Caller should make sure that "length" can cover the minimum header length */
EncodeFileTransferDoneFrame(uint8_t * buffer,size_t length,uint16_t fileIdList[],uint32_t fileIdNum,size_t * frameLength)258 void EncodeFileTransferDoneFrame(uint8_t *buffer, size_t length, uint16_t fileIdList[], uint32_t fileIdNum,
259 size_t *frameLength)
260 {
261 uint32_t i;
262 uint32_t maxIdNum;
263 uint16_t payloadLength;
264 FileTransferDoneFrame *transferDoneFrame = (FileTransferDoneFrame *)buffer;
265
266 maxIdNum = (uint32_t)((length - DFILE_FRAME_HEADER_LEN) / sizeof(uint16_t));
267 if (maxIdNum > fileIdNum) {
268 maxIdNum = fileIdNum;
269 }
270
271 for (i = 0; i < maxIdNum; i++) {
272 transferDoneFrame->fileId[i] = htons(fileIdList[i]);
273 }
274
275 transferDoneFrame->header.type = NSTACKX_DFILE_FILE_TRANSFER_DONE_FRAME;
276
277 payloadLength = (uint16_t)(maxIdNum * sizeof(uint16_t));
278 transferDoneFrame->header.length = htons(payloadLength);
279
280 *frameLength = DFILE_FRAME_HEADER_LEN + payloadLength;
281 }
282
283 /* Caller should make sure that "length" can cover the minimum header length */
EncodeSettingFrame(uint8_t * buffer,size_t length,size_t * frameLength,const SettingFrame * settingFramePara)284 void EncodeSettingFrame(uint8_t *buffer, size_t length, size_t *frameLength, const SettingFrame *settingFramePara)
285 {
286 SettingFrame *settingFrame = (SettingFrame *)buffer;
287
288 *frameLength = sizeof(SettingFrame);
289 if (*frameLength > length) {
290 return;
291 }
292 settingFrame->header.type = NSTACKX_DFILE_SETTING_FRAME;
293 settingFrame->header.flag = 0;
294 settingFrame->header.sessionId = 0;
295 settingFrame->header.transId = 0;
296 settingFrame->mtu = htons(settingFramePara->mtu);
297 settingFrame->connType = htons(settingFramePara->connType);
298 settingFrame->dFileVersion = htonl(NSTACKX_DFILE_VERSION);
299 settingFrame->abmCapability = 0;
300 settingFrame->header.length = htons(*frameLength - DFILE_FRAME_HEADER_LEN);
301 settingFrame->capability = htonl(settingFramePara->capability);
302 settingFrame->dataFrameSize = htonl(settingFramePara->dataFrameSize);
303 settingFrame->capsCheck = htonl(settingFramePara->capsCheck);
304 settingFrame->cipherCapability = htonl(settingFramePara->cipherCapability);
305 }
306
307 /* Caller should make sure that "length" can cover the minimum header length */
EncodeRstFrame(uint8_t * buffer,size_t length,size_t * frameLength,uint16_t transId,uint16_t errCode)308 void EncodeRstFrame(uint8_t *buffer, size_t length, size_t *frameLength, uint16_t transId, uint16_t errCode)
309 {
310 RstFrame *rstFrame = (RstFrame *)buffer;
311 uint16_t payloadLength;
312
313 payloadLength = sizeof(uint16_t);
314 *frameLength = DFILE_FRAME_HEADER_LEN + payloadLength;
315 if (*frameLength > length) {
316 return;
317 }
318 rstFrame->header.type = NSTACKX_DFILE_RST_FRAME;
319 rstFrame->header.flag = 0;
320 rstFrame->header.sessionId = 0;
321 rstFrame->header.transId = htons(transId);
322 rstFrame->code = htons(errCode);
323 rstFrame->header.length = htons(payloadLength);
324 }
325
EncodeBackPressFrame(uint8_t * buffer,size_t length,size_t * frameLength,uint8_t recvListOverIo)326 void EncodeBackPressFrame(uint8_t *buffer, size_t length, size_t *frameLength, uint8_t recvListOverIo)
327 {
328 BackPressureFrame *backPressFrame = (BackPressureFrame *)buffer;
329 uint16_t payloadLength;
330
331 payloadLength = sizeof(DataBackPressure);
332 *frameLength = DFILE_FRAME_HEADER_LEN + payloadLength;
333 if (*frameLength > length) {
334 return;
335 }
336
337 backPressFrame->header.type = NSTACKX_DFILE_FILE_BACK_PRESSURE_FRAME;
338 backPressFrame->header.flag = 0;
339 backPressFrame->header.sessionId = 0;
340 backPressFrame->header.transId = 0;
341 backPressFrame->header.length = htons(payloadLength);
342 backPressFrame->backPressure.recvListOverIo = recvListOverIo;
343 backPressFrame->backPressure.recvBufThreshold = 0;
344 backPressFrame->backPressure.stopSendPeriod = htonl(0);
345 }
346
347 /* Caller should make sure that "length" can cover the minimum header length */
EncodeFileTransferDoneAckFrame(uint8_t * buffer,size_t length,uint16_t transId,size_t * frameLength)348 void EncodeFileTransferDoneAckFrame(uint8_t *buffer, size_t length, uint16_t transId, size_t *frameLength)
349 {
350 FileTransferDoneAckFrame *transferDoneAckFrame = (FileTransferDoneAckFrame *)buffer;
351
352 *frameLength = DFILE_FRAME_HEADER_LEN;
353 if (*frameLength > length) {
354 return;
355 }
356 transferDoneAckFrame->header.type = NSTACKX_DFILE_FILE_TRANSFER_DONE_ACK_FRAME;
357 transferDoneAckFrame->header.transId = htons(transId);
358 }
359
DecodeDFileFrame(const uint8_t * buffer,size_t bufferLength,DFileFrame ** frame)360 int32_t DecodeDFileFrame(const uint8_t *buffer, size_t bufferLength, DFileFrame **frame)
361 {
362 DFileFrame *dFileFrame = (DFileFrame *)buffer;
363 uint16_t payloadLength;
364
365 if (bufferLength < DFILE_FRAME_HEADER_LEN) {
366 DFILE_LOGE(TAG, "drop malformed frame");
367 return NSTACKX_EFAILED;
368 }
369
370 payloadLength = ntohs(dFileFrame->header.length);
371 if (bufferLength - DFILE_FRAME_HEADER_LEN != payloadLength) {
372 DFILE_LOGE(TAG, "drop malformed frame");
373 return NSTACKX_EFAILED;
374 }
375
376 *frame = dFileFrame;
377 return NSTACKX_EOK;
378 }
379
SetDfileHeaderFrameUserDataFlag(FileList * fileList)380 static inline void SetDfileHeaderFrameUserDataFlag(FileList *fileList)
381 {
382 fileList->userDataFlag = fileList->userDataFlag | NSTACKX_DFILE_HEADER_FRAME_USER_DATA_FLAG;
383 }
384
CheckDfileHeaderFrameUserDataFlag(uint8_t flag)385 static inline uint8_t CheckDfileHeaderFrameUserDataFlag(uint8_t flag)
386 {
387 return flag & NSTACKX_DFILE_HEADER_FRAME_USER_DATA_FLAG;
388 }
389
CheckDfileHeaderFramePathTypeFlag(uint8_t flag)390 static inline uint8_t CheckDfileHeaderFramePathTypeFlag(uint8_t flag)
391 {
392 return flag & NSTACKX_DFILE_HEADER_FRAME_PATH_TYPE_FLAG;
393 }
394
CheckDfileHeaderFrameNoSyncFlag(uint8_t flag)395 static inline uint8_t CheckDfileHeaderFrameNoSyncFlag(uint8_t flag)
396 {
397 return flag & NSTACKX_DFILE_HEADER_FRAME_NO_SYNC_FLAG;
398 }
399
DecodeFileHeaderFrameSp(FileList * fileList,FileHeaderFrame * headerFrame)400 int32_t DecodeFileHeaderFrameSp(FileList *fileList, FileHeaderFrame *headerFrame)
401 {
402 FileInfoUnit *fileInfoUnit = NULL;
403 size_t offset = 0;
404 if (ntohs(headerFrame->header.length) <= sizeof(uint16_t)) {
405 return NSTACKX_EFAILED;
406 }
407 uint8_t *buffer = (uint8_t *)headerFrame->fileInfoUnit;
408 uint16_t length = ntohs(headerFrame->header.length) - sizeof(uint16_t);
409 uint16_t nodeNumber = ntohs(headerFrame->nodeNumber);
410 int32_t ret;
411 if (FileListSetNum(fileList, nodeNumber) != NSTACKX_EOK) {
412 return NSTACKX_EFAILED;
413 }
414 if (CheckDfileHeaderFrameUserDataFlag(headerFrame->header.flag) != 0 ||
415 (CheckDfileHeaderFramePathTypeFlag(headerFrame->header.flag) != 0)) {
416 SetDfileHeaderFrameUserDataFlag(fileList);
417 }
418 if (CheckDfileHeaderFrameNoSyncFlag(headerFrame->header.flag) != 0) {
419 fileList->noSyncFlag = NSTACKX_TRUE;
420 }
421 while (offset < length) {
422 fileInfoUnit = (FileInfoUnit *)&buffer[offset];
423 if (length - offset <= offsetof(FileInfoUnit, fileName)) {
424 DFILE_LOGE(TAG, "length %u is too small", length);
425 return NSTACKX_EFAILED;
426 }
427 size_t fileNameLength = ntohs(fileInfoUnit->fileNameLength);
428 uint16_t fileId = ntohs(fileInfoUnit->fileId);
429 if ((fileId == 0) && !(CheckDfileHeaderFrameUserDataFlag(headerFrame->header.flag)) &&
430 !(CheckDfileHeaderFramePathTypeFlag(headerFrame->header.flag))) {
431 /* Invalid file id, discard the whole frame. */
432 return NSTACKX_EFAILED;
433 }
434 /*
435 * fileNameLength validation:
436 * 1) Minimum value:
437 * For normal file name (file id != 0), it should be > 0;
438 * For user data (file id = 0), 0 is allowed.
439 * 2) Maximum value: should be <= remaining buffer - offsetof(FileInfoUnit, fileName)
440 */
441 if ((fileId != 0 && fileNameLength == 0) ||
442 (fileNameLength > (length - offset - offsetof(FileInfoUnit, fileName)))) {
443 return NSTACKX_EFAILED;
444 }
445 if (fileId == 0) {
446 ret = FileListAddUserData(fileList, fileInfoUnit->fileName, fileNameLength, headerFrame->header.flag);
447 } else {
448 uint64_t fileSize = be64toh(fileInfoUnit->fileSize);
449 ret = FileListAddFile(fileList, fileId, fileInfoUnit->fileName, fileNameLength, fileSize);
450 }
451 if (ret != NSTACKX_EOK) {
452 return NSTACKX_EFAILED;
453 }
454 offset += (offsetof(FileInfoUnit, fileName) + fileNameLength);
455 }
456
457 return NSTACKX_EOK;
458 }
459
DecodeFileHeaderFrame(FileList * fileList,FileHeaderFrame * headerFrame)460 int32_t DecodeFileHeaderFrame(FileList *fileList, FileHeaderFrame *headerFrame)
461 {
462 return DecodeFileHeaderFrameSp(fileList, headerFrame);
463 }
464
DecodeFileHeaderConfirmFrame(FileList * fileList,FileHeaderConfirmFrame * confirmFrame)465 int32_t DecodeFileHeaderConfirmFrame(FileList *fileList, FileHeaderConfirmFrame *confirmFrame)
466 {
467 uint16_t fileId;
468 uint16_t i;
469 size_t length = ntohs(confirmFrame->header.length);
470 DFILE_LOGI(TAG, "header confirm frame length %u", length);
471 /* Make sure payload buffer should contain valid number of file ID. */
472 if (length == 0 || length % sizeof(uint16_t) != 0) {
473 return NSTACKX_EFAILED;
474 }
475 uint16_t *fileIdList = confirmFrame->fileId;
476 uint16_t fileIdCount = (uint16_t)(length >> 1);
477
478 for (i = 0; i < fileIdCount; i++) {
479 fileId = ntohs(fileIdList[i]);
480 if (fileId > FileListGetNum(fileList)) {
481 DFILE_LOGE(TAG, "Invalid file ID %u", fileId);
482 continue;
483 }
484 FileListSetFileNameAcked(fileList, fileId);
485 }
486
487 return NSTACKX_EOK;
488 }
489
GetFileIdFromFileDataFrame(const FileList * fileList,const FileDataFrame * dataFrame)490 int16_t GetFileIdFromFileDataFrame(const FileList *fileList, const FileDataFrame *dataFrame)
491 {
492 uint16_t fileId;
493
494 fileId = ntohs(dataFrame->fileId);
495 if (fileId == NSTACKX_RESERVED_FILE_ID || fileId > FileListGetNum(fileList)) {
496 return 0;
497 }
498
499 return (int16_t)fileId;
500 }
501
DecodeFileTransferDoneFrame(FileList * fileList,FileTransferDoneFrame * transferDoneFrame)502 int32_t DecodeFileTransferDoneFrame(FileList *fileList, FileTransferDoneFrame *transferDoneFrame)
503 {
504 uint32_t i;
505 uint32_t fileIdNum;
506 uint16_t fileId;
507
508 uint16_t length = ntohs(transferDoneFrame->header.length);
509 if (length == 0 || length % sizeof(uint16_t) != 0) {
510 return NSTACKX_EFAILED;
511 }
512 fileIdNum = length / sizeof(uint16_t);
513
514 DFILE_LOGI(TAG, "transId %u, FileTransferDone:fileIdNum %u, file number %u",
515 ntohs(transferDoneFrame->header.transId), fileIdNum, FileListGetNum(fileList));
516 for (i = 0; i < fileIdNum; i++) {
517 fileId = ntohs(transferDoneFrame->fileId[i]);
518 if (fileId == 0 || fileId > FileListGetNum(fileList)) {
519 continue;
520 }
521 FileListSetFileSendSuccess(fileList, fileId);
522 }
523 return NSTACKX_EOK;
524 }
525
IsSettingFrameLengthValid(const SettingFrame * hostSettingFrame,uint16_t payloadLength)526 static uint8_t IsSettingFrameLengthValid(const SettingFrame *hostSettingFrame, uint16_t payloadLength)
527 {
528 /*
529 * From dfile with historical version NSTACKX_DFILE_VERSION_0, whose setting frame is composed of header,
530 * mtu and connType.
531 */
532 size_t hostFrameLength = 0;
533 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->mtu) + sizeof(hostSettingFrame->connType))) {
534 return NSTACKX_TRUE;
535 }
536
537 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->dFileVersion))) {
538 return NSTACKX_TRUE;
539 }
540
541 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->abmCapability))) {
542 return NSTACKX_TRUE;
543 }
544
545 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->capability))) {
546 return NSTACKX_TRUE;
547 }
548
549 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->dataFrameSize))) {
550 return NSTACKX_TRUE;
551 }
552
553 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->capsCheck))) {
554 return NSTACKX_TRUE;
555 }
556
557 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->productVersion))) {
558 return NSTACKX_TRUE;
559 }
560
561 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->isSupport160M))) {
562 return NSTACKX_TRUE;
563 }
564
565 if (payloadLength ==
566 (hostFrameLength += sizeof(hostSettingFrame->isSupportMtp) + sizeof(hostSettingFrame->mtpPort))) {
567 return NSTACKX_TRUE;
568 }
569
570 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->headerEnc))) {
571 return NSTACKX_TRUE;
572 }
573
574 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->mtpCapability))) {
575 return NSTACKX_TRUE;
576 }
577
578 if (payloadLength == (hostFrameLength += sizeof(hostSettingFrame->cipherCapability))) {
579 return NSTACKX_TRUE;
580 }
581 /*
582 * From dfile with the same version with local dfile.
583 */
584 if (payloadLength >= sizeof(SettingFrame) - DFILE_FRAME_HEADER_LEN) {
585 return NSTACKX_TRUE;
586 }
587
588 return NSTACKX_FALSE;
589 }
590
IsSettingFrameMtuAndTypeValid(const SettingFrame * netSettingFrame)591 static uint8_t IsSettingFrameMtuAndTypeValid(const SettingFrame *netSettingFrame)
592 {
593 if (ntohs(netSettingFrame->mtu) < NSTACKX_MIN_MTU_SIZE ||
594 ntohs(netSettingFrame->connType) == CONNECT_TYPE_NONE ||
595 ntohs(netSettingFrame->connType) >= CONNECT_TYPE_MAX) {
596 return NSTACKX_FALSE;
597 }
598 return NSTACKX_TRUE;
599 }
600
DecodeSettingFrameDfxPayload(uint16_t payloadLength,SettingFrame * netSettingFrame,SettingFrame * hostSettingFrame)601 static void DecodeSettingFrameDfxPayload(uint16_t payloadLength, SettingFrame *netSettingFrame,
602 SettingFrame *hostSettingFrame)
603 {
604 if (payloadLength > (sizeof(hostSettingFrame->mtu) + sizeof(hostSettingFrame->connType) +
605 sizeof(hostSettingFrame->dFileVersion) + sizeof(hostSettingFrame->abmCapability) +
606 sizeof(hostSettingFrame->capability) + sizeof(hostSettingFrame->dataFrameSize) +
607 sizeof(hostSettingFrame->capsCheck))) {
608 if (strnlen(netSettingFrame->productVersion, VERSION_STR_LEN) == VERSION_STR_LEN) {
609 (void)memset_s(hostSettingFrame->productVersion, VERSION_STR_LEN, 0, VERSION_STR_LEN);
610 DFILE_LOGD(TAG, "DFX, remote productVersion is wrong");
611 } else {
612 DFILE_LOGD(TAG, "DFX, remote productVersion: %s", netSettingFrame->productVersion);
613 if (strncpy_s(hostSettingFrame->productVersion, VERSION_STR_LEN,
614 netSettingFrame->productVersion, strlen(netSettingFrame->productVersion)) != 0) {
615 DFILE_LOGW(TAG, "DFX, Decode strncpy ProductVersion fail");
616 }
617 }
618 }
619
620 if (payloadLength > (sizeof(hostSettingFrame->mtu) + sizeof(hostSettingFrame->connType) +
621 sizeof(hostSettingFrame->dFileVersion) + sizeof(hostSettingFrame->abmCapability) +
622 sizeof(hostSettingFrame->capability) + sizeof(hostSettingFrame->dataFrameSize) +
623 sizeof(hostSettingFrame->capsCheck) + sizeof(hostSettingFrame->productVersion))) {
624 hostSettingFrame->isSupport160M = netSettingFrame->isSupport160M;
625 DFILE_LOGD(TAG, "DFX, DecodeSettingFrame, isSupport160M:%d", hostSettingFrame->isSupport160M);
626 }
627 }
628
DecodeSettingFrameInner(uint16_t payloadLength,SettingFrame * netSettingFrame,SettingFrame * hostSettingFrame)629 static void DecodeSettingFrameInner(uint16_t payloadLength, SettingFrame *netSettingFrame,
630 SettingFrame *hostSettingFrame)
631 {
632 size_t hostFrameLength = 0;
633
634 hostSettingFrame->dFileVersion = ntohl(netSettingFrame->dFileVersion);
635 hostSettingFrame->abmCapability = ntohl(netSettingFrame->abmCapability);
636 hostFrameLength += sizeof(hostSettingFrame->mtu) + sizeof(hostSettingFrame->connType) +
637 sizeof(hostSettingFrame->dFileVersion) + sizeof(hostSettingFrame->abmCapability);
638
639 if (payloadLength > hostFrameLength) {
640 hostSettingFrame->capability = ntohl(netSettingFrame->capability);
641 }
642 hostFrameLength += sizeof(hostSettingFrame->capability);
643
644 if (payloadLength > hostFrameLength) {
645 hostSettingFrame->dataFrameSize = ntohl(netSettingFrame->dataFrameSize);
646 }
647 hostFrameLength += sizeof(hostSettingFrame->dataFrameSize);
648
649 if (payloadLength > hostFrameLength) {
650 hostSettingFrame->capsCheck = ntohl(netSettingFrame->capsCheck);
651 }
652
653 /* DFX */
654 DecodeSettingFrameDfxPayload(payloadLength, netSettingFrame, hostSettingFrame);
655 hostFrameLength += sizeof(hostSettingFrame->capsCheck) + sizeof(hostSettingFrame->productVersion) +
656 sizeof(hostSettingFrame->isSupport160M);
657
658 if (payloadLength > hostFrameLength) {
659 hostSettingFrame->isSupportMtp = netSettingFrame->isSupportMtp;
660 hostSettingFrame->mtpPort = netSettingFrame->mtpPort;
661 }
662 hostFrameLength += sizeof(hostSettingFrame->isSupportMtp) + sizeof(hostSettingFrame->mtpPort);
663
664 if (payloadLength > hostFrameLength) {
665 hostSettingFrame->headerEnc = netSettingFrame->headerEnc;
666 }
667 hostFrameLength += sizeof(hostSettingFrame->headerEnc);
668
669 if (payloadLength > hostFrameLength) {
670 hostSettingFrame->mtpCapability = ntohl(netSettingFrame->mtpCapability);
671 }
672 hostFrameLength += sizeof(hostSettingFrame->mtpCapability);
673
674 if (payloadLength > hostFrameLength) {
675 hostSettingFrame->cipherCapability = ntohl(netSettingFrame->cipherCapability);
676 }
677 hostFrameLength += sizeof(hostSettingFrame->cipherCapability);
678 }
679
DFileCheckSettingFrame(SettingFrame * netSettingFrame,SettingFrame * hostSettingFrame)680 static int32_t DFileCheckSettingFrame(SettingFrame *netSettingFrame, SettingFrame *hostSettingFrame)
681 {
682 if (netSettingFrame->header.sessionId != 0 || netSettingFrame->header.transId != 0) {
683 DFILE_LOGE(TAG, "error transId for Setting Frame");
684 return NSTACKX_EFAILED;
685 }
686 uint16_t payloadLength = ntohs(netSettingFrame->header.length);
687 if (!IsSettingFrameLengthValid(hostSettingFrame, payloadLength)) {
688 DFILE_LOGE(TAG, "illegal setting frame length %u", payloadLength);
689 return NSTACKX_EFAILED;
690 }
691 if (!IsSettingFrameMtuAndTypeValid(netSettingFrame)) {
692 DFILE_LOGE(TAG, "illegal setting frame mtu or type");
693 return NSTACKX_EFAILED;
694 }
695 return NSTACKX_EOK;
696 }
697
698 /*
699 * Note: netSettingFrame is a malloced buffer with length reading from network, so it is not reliable and its length
700 * may be shorter than sizeof(SettingFrame).
701 */
DecodeSettingFrame(SettingFrame * netSettingFrame,SettingFrame * hostSettingFrame)702 int32_t DecodeSettingFrame(SettingFrame *netSettingFrame, SettingFrame *hostSettingFrame)
703 {
704 if (DFileCheckSettingFrame(netSettingFrame, hostSettingFrame) != NSTACKX_EOK) {
705 return NSTACKX_EFAILED;
706 }
707 uint16_t payloadLength = ntohs(netSettingFrame->header.length);
708 hostSettingFrame->header.sessionId = netSettingFrame->header.sessionId;
709 hostSettingFrame->mtu = ntohs(netSettingFrame->mtu);
710 hostSettingFrame->connType = ntohs(netSettingFrame->connType);
711
712 if (payloadLength == sizeof(hostSettingFrame->mtu) + sizeof(hostSettingFrame->connType)) {
713 /*
714 * In this condition, this netSettingFrame is from an old version and doesn't have the member dFileVersion.
715 * Then the dFileVersion will be set to zero by defulat.
716 * Note that the usage of netSettingFrame->dFileVersion is illegal in this condition.
717 */
718 DFILE_LOGI(TAG, "this setting frame is from an old version whose setting frame doesn't "
719 "have the member dFileVersion");
720 hostSettingFrame->dFileVersion = 0;
721 } else if (payloadLength == sizeof(hostSettingFrame->mtu) + sizeof(hostSettingFrame->connType) +
722 sizeof(hostSettingFrame->dFileVersion)) {
723 hostSettingFrame->dFileVersion = ntohl(netSettingFrame->dFileVersion);
724 hostSettingFrame->abmCapability = 0;
725 } else {
726 DecodeSettingFrameInner(payloadLength, netSettingFrame, hostSettingFrame);
727 }
728 DFILE_LOGI(TAG, "local version is %u, remote version is %u capability 0x%x dataFrameSize %u capsCheck 0x%x "
729 "cipherCaps 0x%x",
730 NSTACKX_DFILE_VERSION, hostSettingFrame->dFileVersion, hostSettingFrame->capability,
731 hostSettingFrame->dataFrameSize, hostSettingFrame->capsCheck,
732 hostSettingFrame->cipherCapability);
733 return NSTACKX_EOK;
734 }
735
DecodeRstFrame(RstFrame * rstFrame,uint16_t * code,uint16_t ** fileIdList,uint16_t * listCount)736 int32_t DecodeRstFrame(RstFrame *rstFrame, uint16_t *code, uint16_t **fileIdList, uint16_t *listCount)
737 {
738 uint16_t payloadLen = ntohs(rstFrame->header.length);
739 if (payloadLen < sizeof(uint16_t) || (payloadLen - sizeof(uint16_t)) % sizeof(uint16_t) != 0) {
740 return NSTACKX_EFAILED;
741 }
742 *code = ntohs(rstFrame->code);
743
744 if (fileIdList != NULL && listCount != NULL) {
745 *fileIdList = rstFrame->fileId;
746 *listCount = (payloadLen - sizeof(uint16_t)) / sizeof(uint16_t);
747 }
748 return NSTACKX_EOK;
749 }
750
DecodeBackPressFrame(const BackPressureFrame * backPressFrame,DataBackPressure * backPressInfo)751 int32_t DecodeBackPressFrame(const BackPressureFrame *backPressFrame, DataBackPressure *backPressInfo)
752 {
753 uint16_t payloadLen = ntohs(backPressFrame->header.length);
754 if (payloadLen < sizeof(BackPressureFrame) - sizeof(DFileFrameHeader)) {
755 return NSTACKX_EFAILED;
756 }
757
758 backPressInfo->recvListOverIo = backPressFrame->backPressure.recvListOverIo;
759 backPressInfo->recvBufThreshold = backPressFrame->backPressure.recvBufThreshold;
760 backPressInfo->stopSendPeriod = ntohl(backPressFrame->backPressure.stopSendPeriod);
761
762 return NSTACKX_EOK;
763 }
764