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