xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_TCP_Reception.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_TCP_Reception.c
30  * @brief Module which processes the packet received from a socket for FreeRTOS+TCP.
31  *
32  * Endianness: in this module all ports and IP addresses are stored in
33  * host byte-order, except fields in the IP-packets
34  */
35 
36 /* Standard includes. */
37 #include <stdint.h>
38 #include <stdio.h>
39 
40 /* FreeRTOS includes. */
41 #include "FreeRTOS.h"
42 #include "task.h"
43 #include "queue.h"
44 #include "semphr.h"
45 
46 /* FreeRTOS+TCP includes. */
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_UDP_IP.h"
51 #include "FreeRTOS_DHCP.h"
52 #include "NetworkInterface.h"
53 #include "NetworkBufferManagement.h"
54 #include "FreeRTOS_ARP.h"
55 #include "FreeRTOS_TCP_Transmission.h"
56 #include "FreeRTOS_TCP_Reception.h"
57 
58 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
59 #if ipconfigUSE_TCP == 1
60 
61 /*
62  * Identify and deal with a single TCP header option, advancing the pointer to
63  * the header. This function returns pdTRUE or pdFALSE depending on whether the
64  * caller should continue to parse more header options or break the loop.
65  */
66     static int32_t prvSingleStepTCPHeaderOptions( const uint8_t * const pucPtr,
67                                                   size_t uxTotalLength,
68                                                   FreeRTOS_Socket_t * const pxSocket,
69                                                   BaseType_t xHasSYNFlag );
70 
71     #if ( ipconfigUSE_TCP_WIN == 1 )
72 
73 /*
74  * Skip past TCP header options when doing Selective ACK, until there are no
75  * more options left.
76  */
77         static void prvReadSackOption( const uint8_t * const pucPtr,
78                                        size_t uxIndex,
79                                        FreeRTOS_Socket_t * const pxSocket );
80     #endif /* ( ipconfigUSE_TCP_WIN == 1 ) */
81 
82 /**
83  * @brief Parse the TCP option(s) received, if present.
84  *
85  * @param[in] pxSocket: The socket handling the connection.
86  * @param[in] pxNetworkBuffer: The network buffer containing the TCP
87  *                             packet.
88  *
89  * @return: If the options are well formed and processed successfully
90  *          then pdPASS is returned; else a pdFAIL is returned.
91  *
92  * @note It has already been verified that:
93  *       ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that
94  *       the TP header is longer than the usual 20 (5 x 4) bytes.
95  */
prvCheckOptions(FreeRTOS_Socket_t * pxSocket,const NetworkBufferDescriptor_t * pxNetworkBuffer)96     BaseType_t prvCheckOptions( FreeRTOS_Socket_t * pxSocket,
97                                 const NetworkBufferDescriptor_t * pxNetworkBuffer )
98     {
99         size_t uxTCPHeaderOffset = ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer );
100 
101         /* MISRA Ref 11.3.1 [Misaligned access] */
102 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
103         /* coverity[misra_c_2012_rule_11_3_violation] */
104         const ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
105                                                         &( pxNetworkBuffer->pucEthernetBuffer[ uxTCPHeaderOffset ] ) );
106         const TCPHeader_t * pxTCPHeader;
107         const uint8_t * pucPtr;
108         BaseType_t xHasSYNFlag;
109         BaseType_t xReturn = pdPASS;
110         /* Offset in the network packet where the first option byte is stored. */
111         size_t uxOptionOffset = uxTCPHeaderOffset + ( sizeof( TCPHeader_t ) - sizeof( pxTCPHeader->ucOptdata ) );
112         size_t uxOptionsLength;
113         int32_t lResult;
114         uint8_t ucLength;
115 
116         pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
117 
118 
119         /* A character pointer to iterate through the option data */
120         pucPtr = pxTCPHeader->ucOptdata;
121 
122         if( pxTCPHeader->ucTCPOffset <= ( 5U << 4U ) )
123         {
124             /* Avoid integer underflow in computation of ucLength. */
125         }
126         else
127         {
128             ucLength = ( ( ( pxTCPHeader->ucTCPOffset >> 4U ) - 5U ) << 2U );
129             uxOptionsLength = ( size_t ) ucLength;
130 
131             if( pxNetworkBuffer->xDataLength > uxOptionOffset )
132             {
133                 /* Validate options size calculation. */
134                 if( uxOptionsLength <= ( pxNetworkBuffer->xDataLength - uxOptionOffset ) )
135                 {
136                     if( ( pxTCPHeader->ucTCPFlags & tcpTCP_FLAG_SYN ) != ( uint8_t ) 0U )
137                     {
138                         xHasSYNFlag = pdTRUE;
139                     }
140                     else
141                     {
142                         xHasSYNFlag = pdFALSE;
143                     }
144 
145                     /* The length check is only necessary in case the option data are
146                      *  corrupted, we don't like to run into invalid memory and crash. */
147                     for( ; ; )
148                     {
149                         if( uxOptionsLength == 0U )
150                         {
151                             /* coverity[break_stmt] : Break statement terminating the loop */
152                             break;
153                         }
154 
155                         lResult = prvSingleStepTCPHeaderOptions( pucPtr, uxOptionsLength, pxSocket, xHasSYNFlag );
156 
157                         if( lResult < 0 )
158                         {
159                             xReturn = pdFAIL;
160                             break;
161                         }
162 
163                         if( lResult == 0 )
164                         {
165                             break;
166                         }
167 
168                         uxOptionsLength -= ( size_t ) lResult;
169                         pucPtr = &( pucPtr[ lResult ] );
170                     }
171                 }
172             }
173         }
174 
175         return xReturn;
176     }
177     /*-----------------------------------------------------------*/
178 
179 /**
180  * @brief Identify and deal with a single TCP header option, advancing the pointer to
181  *        the header.
182  *
183  * @param[in] pucPtr: Pointer to the TCP packet options.
184  * @param[in] uxTotalLength: Length of the TCP packet options.
185  * @param[in] pxSocket: Socket handling the connection.
186  * @param[in] xHasSYNFlag: Whether the header has SYN flag or not.
187  *
188  * @return This function returns index of the next option if the current option is
189  *         successfully processed and it is not the end of options whereafter the caller
190  *         should continue to process more options.
191  *         If the options have ended, this function will return a zero whereafter the
192  *         caller should stop parsing options and continue further processing.
193  *         If the current option has erroneous value, then the function returns a
194  *         negative value wherein the calling function should not process this packet any
195  *         further and drop it.
196  */
prvSingleStepTCPHeaderOptions(const uint8_t * const pucPtr,size_t uxTotalLength,FreeRTOS_Socket_t * const pxSocket,BaseType_t xHasSYNFlag)197     static int32_t prvSingleStepTCPHeaderOptions( const uint8_t * const pucPtr,
198                                                   size_t uxTotalLength,
199                                                   FreeRTOS_Socket_t * const pxSocket,
200                                                   BaseType_t xHasSYNFlag )
201     {
202         UBaseType_t uxNewMSS;
203         size_t uxRemainingOptionsBytes = uxTotalLength;
204         uint8_t ucLen;
205         int32_t lIndex = 0;
206         TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
207         BaseType_t xReturn = pdFALSE;
208 
209         if( pucPtr[ 0U ] == tcpTCP_OPT_END )
210         {
211             /* End of options. */
212             lIndex = 0;
213         }
214         else if( pucPtr[ 0U ] == tcpTCP_OPT_NOOP )
215         {
216             /* NOP option, inserted to make the length a multiple of 4. */
217             lIndex = 1;
218         }
219         else if( uxRemainingOptionsBytes < 2U )
220         {
221             /* Any other well-formed option must be at least two bytes: the option
222              * type byte followed by a length byte. */
223             lIndex = -1;
224         }
225 
226         #if ( ipconfigUSE_TCP_WIN != 0 )
227             else if( pucPtr[ 0 ] == tcpTCP_OPT_WSOPT )
228             {
229                 /* The TCP Window Scale Option. */
230                 /* Confirm that the option fits in the remaining buffer space. */
231                 if( ( uxRemainingOptionsBytes < tcpTCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != tcpTCP_OPT_WSOPT_LEN ) )
232                 {
233                     lIndex = -1;
234                 }
235                 else
236                 {
237                     /* Option is only valid in SYN phase. */
238                     if( xHasSYNFlag != 0 )
239                     {
240                         pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
241                         pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
242                     }
243 
244                     lIndex = ( int32_t ) tcpTCP_OPT_WSOPT_LEN;
245                 }
246             }
247         #endif /* ipconfigUSE_TCP_WIN */
248         else if( pucPtr[ 0 ] == tcpTCP_OPT_MSS )
249         {
250             /* Confirm that the option fits in the remaining buffer space. */
251             if( ( uxRemainingOptionsBytes < tcpTCP_OPT_MSS_LEN ) || ( pucPtr[ 1 ] != tcpTCP_OPT_MSS_LEN ) )
252             {
253                 lIndex = -1;
254             }
255             else
256             {
257                 /* An MSS option with the correct option length.  FreeRTOS_htons()
258                  * is not needed here because usChar2u16() already returns a host
259                  * endian number. */
260                 uxNewMSS = usChar2u16( &( pucPtr[ 2 ] ) );
261 
262                 if( pxSocket->u.xTCP.usMSS != uxNewMSS )
263                 {
264                     /* Perform a basic check on the the new MSS. */
265                     if( uxNewMSS == 0U )
266                     {
267                         lIndex = -1;
268 
269                         /* Return Condition found. */
270                         xReturn = pdTRUE;
271                     }
272                     else
273                     {
274                         FreeRTOS_debug_printf( ( "MSS change %u -> %u\n", pxSocket->u.xTCP.usMSS, ( unsigned ) uxNewMSS ) );
275                     }
276                 }
277 
278                 /* If a 'return' condition has not been found. */
279                 if( xReturn == pdFALSE )
280                 {
281                     /* Restrict the minimum value of segment length to the ( Minimum IP MTU (576) - IP header(20) - TCP Header(20) ).
282                      * See "RFC 791 section 3.1 Total Length" for more details. */
283                     if( uxNewMSS < tcpMINIMUM_SEGMENT_LENGTH )
284                     {
285                         uxNewMSS = tcpMINIMUM_SEGMENT_LENGTH;
286                     }
287 
288                     if( pxSocket->u.xTCP.usMSS > uxNewMSS )
289                     {
290                         /* our MSS was bigger than the MSS of the other party: adapt it. */
291                         pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
292 
293                         if( pxSocket->u.xTCP.usMSS > uxNewMSS )
294                         {
295                             /* The peer advertises a smaller MSS than this socket was
296                              * using.  Use that as well. */
297                             FreeRTOS_debug_printf( ( "Change mss %d => %u\n", pxSocket->u.xTCP.usMSS, ( unsigned ) uxNewMSS ) );
298                         }
299 
300                         pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
301                         pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
302                         pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
303                         pxSocket->u.xTCP.usMSS = ( uint16_t ) uxNewMSS;
304                     }
305 
306                     lIndex = ( int32_t ) tcpTCP_OPT_MSS_LEN;
307                 }
308             }
309         }
310         else
311         {
312             /* All other options have a length field, so that we easily
313              * can skip past them. */
314             ucLen = pucPtr[ 1 ];
315             lIndex = 0;
316 
317             if( ( ucLen < ( uint8_t ) 2U ) || ( uxRemainingOptionsBytes < ( size_t ) ucLen ) )
318             {
319                 /* If the length field is too small or too big, the options are
320                  * malformed, don't process them further.
321                  */
322                 lIndex = -1;
323             }
324             else
325             {
326                 #if ( ipconfigUSE_TCP_WIN == 1 )
327                     {
328                         /* Selective ACK: the peer has received a packet but it is missing
329                          * earlier packets. At least this packet does not need retransmission
330                          * anymore. ulTCPWindowTxSack( ) takes care of this administration.
331                          */
332                         if( pucPtr[ 0U ] == tcpTCP_OPT_SACK_A )
333                         {
334                             ucLen -= 2U;
335                             lIndex += 2;
336 
337                             while( ucLen >= ( uint8_t ) 8U )
338                             {
339                                 prvReadSackOption( pucPtr, ( size_t ) lIndex, pxSocket );
340                                 lIndex += 8;
341                                 ucLen -= 8U;
342                             }
343 
344                             /* ucLen should be 0 by now. */
345                         }
346                     }
347                 #endif /* ipconfigUSE_TCP_WIN == 1 */
348 
349                 lIndex += ( int32_t ) ucLen;
350             }
351         }
352 
353         #if ( ipconfigUSE_TCP_WIN == 0 )
354             /* Avoid compiler warnings when TCP window is not used. */
355             ( void ) xHasSYNFlag;
356         #endif
357 
358         return lIndex;
359     }
360     /*-----------------------------------------------------------*/
361 
362     #if ( ipconfigUSE_TCP_WIN == 1 )
363 
364 /**
365  * @brief Skip past TCP header options when doing Selective ACK, until there are no
366  *        more options left.
367  *
368  * @param[in] pucPtr: Pointer to the TCP packet options.
369  * @param[in] uxIndex: Index of options in the TCP packet options.
370  * @param[in] pxSocket: Socket handling the TCP connection.
371  */
prvReadSackOption(const uint8_t * const pucPtr,size_t uxIndex,FreeRTOS_Socket_t * const pxSocket)372         static void prvReadSackOption( const uint8_t * const pucPtr,
373                                        size_t uxIndex,
374                                        FreeRTOS_Socket_t * const pxSocket )
375         {
376             uint32_t ulFirst = ulChar2u32( &( pucPtr[ uxIndex ] ) );
377             uint32_t ulLast = ulChar2u32( &( pucPtr[ uxIndex + 4U ] ) );
378             uint32_t ulCount = ulTCPWindowTxSack( &( pxSocket->u.xTCP.xTCPWindow ), ulFirst, ulLast );
379 
380             /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
381              * starting from the head position.  Advance the tail pointer in txStream.
382              */
383             if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0U ) )
384             {
385                 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
386                 ( void ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
387                 pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_SEND;
388 
389                 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
390                     {
391                         if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_WRITE ) != 0U )
392                         {
393                             /* The field 'xEventBits' is used to store regular socket events
394                              * (at most 8), as well as 'select events', which will be left-shifted.
395                              */
396                             pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_WRITE ) << SOCKET_EVENT_BIT_COUNT;
397                         }
398                     }
399                 #endif
400 
401                 /* In case the socket owner has installed an OnSent handler,
402                  * call it now. */
403                 #if ( ipconfigUSE_CALLBACKS == 1 )
404                     {
405                         if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
406                         {
407                             pxSocket->u.xTCP.pxHandleSent( pxSocket, ulCount );
408                         }
409                     }
410                 #endif /* ipconfigUSE_CALLBACKS == 1  */
411             }
412         }
413 
414     #endif /* ( ipconfigUSE_TCP_WIN != 0 ) */
415     /*-----------------------------------------------------------*/
416 
417 /**
418  * @brief prvCheckRxData(): called from prvTCPHandleState(). The
419  *        first thing that will be done is find the TCP payload data
420  *        and check the length of this data.
421  *
422  * @param[in] pxNetworkBuffer: The network buffer holding the received data.
423  * @param[out] ppucRecvData: It will point to first byte of the TCP payload.
424  *
425  * @return Length of the received buffer.
426  */
prvCheckRxData(const NetworkBufferDescriptor_t * pxNetworkBuffer,uint8_t ** ppucRecvData)427     BaseType_t prvCheckRxData( const NetworkBufferDescriptor_t * pxNetworkBuffer,
428                                uint8_t ** ppucRecvData )
429     {
430         /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
431 
432         /* MISRA Ref 11.3.1 [Misaligned access] */
433 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
434         /* coverity[misra_c_2012_rule_11_3_violation] */
435         const ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
436                                                         &( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
437         const TCPHeader_t * pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
438         int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
439 
440         /* Map the buffer onto an IPHeader_t struct for easy access to fields. */
441 
442         /* MISRA Ref 11.3.1 [Misaligned access] */
443 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
444         /* coverity[misra_c_2012_rule_11_3_violation] */
445         const IPHeader_t * pxIPHeader = ( ( const IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
446         const size_t xIPHeaderLength = ipSIZE_OF_IPv4_HEADER;
447         uint16_t usLength;
448         uint8_t ucIntermediateResult = 0;
449 
450         /* Determine the length and the offset of the user-data sent to this
451          * node.
452          *
453          * The size of the TCP header is given in a multiple of 4-byte words (single
454          * byte, needs no ntoh() translation).  A shift-right 2: is the same as
455          * (offset >> 4) * 4. */
456         ucIntermediateResult = ( pxTCPHeader->ucTCPOffset & tcpVALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2;
457         lTCPHeaderLength = ( int32_t ) ucIntermediateResult;
458 
459         /* Let pucRecvData point to the first byte received. */
460         *ppucRecvData = &( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderLength + ( size_t ) lTCPHeaderLength ] );
461 
462         /* Calculate lReceiveLength - the length of the TCP data received.  This is
463          * equal to the total packet length minus:
464          * ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
465         lReceiveLength = ( int32_t ) pxNetworkBuffer->xDataLength;
466         lReceiveLength -= ( int32_t ) ipSIZE_OF_ETH_HEADER;
467 
468         usLength = FreeRTOS_htons( pxIPHeader->usLength );
469         lLength = ( int32_t ) usLength;
470 
471         if( lReceiveLength > lLength )
472         {
473             /* More bytes were received than the reported length, often because of
474              * padding bytes at the end. */
475             lReceiveLength = lLength;
476         }
477 
478         /* Subtract the size of the TCP and IP headers and the actual data size is
479          * known. */
480         if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength ) )
481         {
482             lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength );
483         }
484         else
485         {
486             lReceiveLength = 0;
487         }
488 
489         /* Urgent Pointer:
490          * This field communicates the current value of the urgent pointer as a
491          * positive offset from the sequence number in this segment.  The urgent
492          * pointer points to the sequence number of the octet following the urgent
493          * data.  This field is only be interpreted in segments with the URG control
494          * bit set. */
495         if( ( pxTCPHeader->ucTCPFlags & tcpTCP_FLAG_URG ) != 0U )
496         {
497             /* Although we ignore the urgent data, we have to skip it. */
498             lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
499             *ppucRecvData += lUrgentLength;
500             lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
501         }
502 
503         return ( BaseType_t ) lReceiveLength;
504     }
505     /*-----------------------------------------------------------*/
506 
507 /**
508  * @brief prvStoreRxData(): called from prvTCPHandleState().
509  *        The second thing is to do is check if the payload data may
510  *        be accepted. If so, they will be added to the reception queue.
511  *
512  * @param[in] pxSocket: The socket owning the connection.
513  * @param[in] pucRecvData: Pointer to received data.
514  * @param[in] pxNetworkBuffer: The network buffer descriptor.
515  * @param[in] ulReceiveLength: The length of the received data.
516  *
517  * @return 0 on success, -1 on failure of storing data.
518  */
prvStoreRxData(FreeRTOS_Socket_t * pxSocket,const uint8_t * pucRecvData,NetworkBufferDescriptor_t * pxNetworkBuffer,uint32_t ulReceiveLength)519     BaseType_t prvStoreRxData( FreeRTOS_Socket_t * pxSocket,
520                                const uint8_t * pucRecvData,
521                                NetworkBufferDescriptor_t * pxNetworkBuffer,
522                                uint32_t ulReceiveLength )
523     {
524         /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
525 
526         /* MISRA Ref 11.3.1 [Misaligned access] */
527 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
528         /* coverity[misra_c_2012_rule_11_3_violation] */
529         const ProtocolHeaders_t * pxProtocolHeaders = ( ( const ProtocolHeaders_t * )
530                                                         &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
531         const TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
532         TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
533         uint32_t ulSequenceNumber, ulSpace;
534         int32_t lOffset, lStored;
535         BaseType_t xResult = 0;
536         uint32_t ulRxLength = ulReceiveLength;
537         const uint8_t * pucRxBuffer = &( pucRecvData[ 0 ] );
538 
539         ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
540 
541         if( ( ulRxLength > 0U ) && ( pxSocket->u.xTCP.eTCPState >= eSYN_RECEIVED ) )
542         {
543             uint32_t ulSkipCount = 0;
544 
545             /* See if way may accept the data contents and forward it to the socket
546              * owner.
547              *
548              * If it can't be "accept"ed it may have to be stored and send a selective
549              * ack (SACK) option to confirm it.  In that case, lTCPAddRxdata() will be
550              * called later to store an out-of-order packet (in case lOffset is
551              * negative). */
552             if( pxSocket->u.xTCP.rxStream != NULL )
553             {
554                 ulSpace = ( uint32_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.rxStream );
555             }
556             else
557             {
558                 ulSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
559             }
560 
561             lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulRxLength, ulSpace, &( ulSkipCount ) );
562 
563             if( lOffset >= 0 )
564             {
565                 /* New data has arrived and may be made available to the user.  See
566                  * if the head marker in rxStream may be advanced, only if lOffset == 0.
567                  * In case the low-water mark is reached, bLowWater will be set
568                  * "low-water" here stands for "little space". */
569                 if( ulSkipCount != 0U )
570                 {
571                     /* A packet was received that starts before 'ulCurrentSequenceNumber',
572                      * and that ends after it.  The first 'ulSkipCount' bytes shall be
573                      * skipped. */
574                     ulRxLength -= ulSkipCount;
575                     pucRxBuffer = &( pucRecvData[ ulSkipCount ] );
576                 }
577 
578                 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRxBuffer, ulRxLength );
579 
580                 if( lStored != ( int32_t ) ulRxLength )
581                 {
582                     FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %d / %u bytes? ?\n", ( int ) lStored, ( unsigned ) ulRxLength ) );
583 
584                     /* Received data could not be stored.  The socket's flag
585                      * bMallocError has been set.  The socket now has the status
586                      * eCLOSE_WAIT and a RST packet will be sent back. */
587                     ( void ) prvTCPSendReset( pxNetworkBuffer );
588                     xResult = -1;
589                 }
590             }
591 
592             /* After a missing packet has come in, higher packets may be passed to
593              * the user. */
594             #if ( ipconfigUSE_TCP_WIN == 1 )
595                 {
596                     /* Now lTCPAddRxdata() will move the rxHead pointer forward
597                      * so data becomes available to the user immediately
598                      * In case the low-water mark is reached, bLowWater will be set. */
599                     if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0U ) )
600                     {
601                         ( void ) lTCPAddRxdata( pxSocket, 0U, NULL, pxTCPWindow->ulUserDataLength );
602                         pxTCPWindow->ulUserDataLength = 0;
603                     }
604                 }
605             #endif /* ipconfigUSE_TCP_WIN */
606         }
607         else
608         {
609             pxTCPWindow->ucOptionLength = 0U;
610         }
611 
612         return xResult;
613     }
614     /*-----------------------------------------------------------*/
615 
616 #endif /* ipconfigUSE_TCP == 1 */
617