1 /* 2 * FreeRTOS+TCP <DEVELOPMENT BRANCH> 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 + uxIPHeaderSizePacket( 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 + ipSIZE_OF_TCP_HEADER; 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 = ( uint8_t ) ( ( ( 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 = ( uint8_t ) ( 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 = ( uint8_t ) ( 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 + uxIPHeaderSizePacket( 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 const size_t xIPHeaderLength = uxIPHeaderSizePacket( pxNetworkBuffer ); 443 uint16_t usLength; 444 uint8_t ucIntermediateResult = 0; 445 446 /* Determine the length and the offset of the user-data sent to this 447 * node. 448 * 449 * The size of the TCP header is given in a multiple of 4-byte words (single 450 * byte, needs no ntoh() translation). A shift-right 2: is the same as 451 * (offset >> 4) * 4. */ 452 ucIntermediateResult = ( pxTCPHeader->ucTCPOffset & tcpVALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2; 453 lTCPHeaderLength = ( int32_t ) ucIntermediateResult; 454 455 /* Let pucRecvData point to the first byte received. */ 456 *ppucRecvData = &( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderLength + ( size_t ) lTCPHeaderLength ] ); 457 458 /* Calculate lReceiveLength - the length of the TCP data received. This is 459 * equal to the total packet length minus: 460 * ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/ 461 lReceiveLength = ( int32_t ) pxNetworkBuffer->xDataLength; 462 lReceiveLength -= ( int32_t ) ipSIZE_OF_ETH_HEADER; 463 464 /* MISRA Ref 11.3.1 [Misaligned access] */ 465 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 466 /* coverity[misra_c_2012_rule_11_3_violation] */ 467 switch( ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer )->usFrameType ) 468 { 469 #if ( ipconfigUSE_IPv4 != 0 ) 470 case ipIPv4_FRAME_TYPE: 471 { 472 /* MISRA Ref 11.3.1 [Misaligned access] */ 473 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 474 /* coverity[misra_c_2012_rule_11_3_violation] */ 475 const IPHeader_t * pxIPHeader = ( ( IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) ); 476 477 usLength = FreeRTOS_htons( pxIPHeader->usLength ); 478 lLength = ( int32_t ) usLength; 479 } 480 break; 481 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 482 483 #if ( ipconfigUSE_IPv6 != 0 ) 484 case ipIPv6_FRAME_TYPE: 485 { 486 /* MISRA Ref 11.3.1 [Misaligned access] */ 487 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 488 /* coverity[misra_c_2012_rule_11_3_violation] */ 489 const IPHeader_IPv6_t * pxIPHeader = ( ( IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) ); 490 491 /* For Coverity: conversion and cast in 2 steps. */ 492 usLength = FreeRTOS_htons( pxIPHeader->usPayloadLength ); 493 lLength = ( int32_t ) usLength; 494 /* Add the length of the TCP-header, because that was not included in 'usPayloadLength'. */ 495 lLength += ( int32_t ) sizeof( IPHeader_IPv6_t ); 496 } 497 break; 498 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 499 500 default: 501 /* Shouldn't reach here */ 502 lLength = 0; 503 break; 504 } 505 506 if( lReceiveLength > lLength ) 507 { 508 /* More bytes were received than the reported length, often because of 509 * padding bytes at the end. */ 510 lReceiveLength = lLength; 511 } 512 513 /* Subtract the size of the TCP and IP headers and the actual data size is 514 * known. */ 515 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength ) ) 516 { 517 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength ); 518 } 519 else 520 { 521 lReceiveLength = 0; 522 } 523 524 /* Urgent Pointer: 525 * This field communicates the current value of the urgent pointer as a 526 * positive offset from the sequence number in this segment. The urgent 527 * pointer points to the sequence number of the octet following the urgent 528 * data. This field is only be interpreted in segments with the URG control 529 * bit set. */ 530 if( ( pxTCPHeader->ucTCPFlags & tcpTCP_FLAG_URG ) != 0U ) 531 { 532 /* Although we ignore the urgent data, we have to skip it. */ 533 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent ); 534 *ppucRecvData += lUrgentLength; 535 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength ); 536 } 537 538 return ( BaseType_t ) lReceiveLength; 539 } 540 /*-----------------------------------------------------------*/ 541 542 /** 543 * @brief prvStoreRxData(): called from prvTCPHandleState(). 544 * The second thing is to do is check if the payload data may 545 * be accepted. If so, they will be added to the reception queue. 546 * 547 * @param[in] pxSocket The socket owning the connection. 548 * @param[in] pucRecvData Pointer to received data. 549 * @param[in] pxNetworkBuffer The network buffer descriptor. 550 * @param[in] ulReceiveLength The length of the received data. 551 * 552 * @return 0 on success, -1 on failure of storing data. 553 */ prvStoreRxData(FreeRTOS_Socket_t * pxSocket,const uint8_t * pucRecvData,NetworkBufferDescriptor_t * pxNetworkBuffer,uint32_t ulReceiveLength)554 BaseType_t prvStoreRxData( FreeRTOS_Socket_t * pxSocket, 555 const uint8_t * pucRecvData, 556 NetworkBufferDescriptor_t * pxNetworkBuffer, 557 uint32_t ulReceiveLength ) 558 { 559 /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */ 560 size_t uxIPOffset = uxIPHeaderSizePacket( pxNetworkBuffer ); 561 /* MISRA Ref 11.3.1 [Misaligned access] */ 562 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 563 /* coverity[misra_c_2012_rule_11_3_violation] */ 564 const ProtocolHeaders_t * pxProtocolHeaders = ( ( const ProtocolHeaders_t * ) 565 &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPOffset ] ) ); 566 const TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader; 567 TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; 568 uint32_t ulSequenceNumber, ulSpace; 569 int32_t lOffset, lStored; 570 BaseType_t xResult = 0; 571 uint32_t ulRxLength = ulReceiveLength; 572 const uint8_t * pucRxBuffer = &( pucRecvData[ 0 ] ); 573 574 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ); 575 576 if( ( ulRxLength > 0U ) && ( pxSocket->u.xTCP.eTCPState >= eSYN_RECEIVED ) ) 577 { 578 uint32_t ulSkipCount = 0; 579 580 /* See if way may accept the data contents and forward it to the socket 581 * owner. 582 * 583 * If it can't be "accept"ed it may have to be stored and send a selective 584 * ack (SACK) option to confirm it. In that case, lTCPAddRxdata() will be 585 * called later to store an out-of-order packet (in case lOffset is 586 * negative). */ 587 if( pxSocket->u.xTCP.rxStream != NULL ) 588 { 589 ulSpace = ( uint32_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.rxStream ); 590 } 591 else 592 { 593 ulSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize; 594 } 595 596 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulRxLength, ulSpace, &( ulSkipCount ) ); 597 598 if( lOffset >= 0 ) 599 { 600 /* New data has arrived and may be made available to the user. See 601 * if the head marker in rxStream may be advanced, only if lOffset == 0. 602 * In case the low-water mark is reached, bLowWater will be set 603 * "low-water" here stands for "little space". */ 604 if( ulSkipCount != 0U ) 605 { 606 /* A packet was received that starts before 'ulCurrentSequenceNumber', 607 * and that ends after it. The first 'ulSkipCount' bytes shall be 608 * skipped. */ 609 ulRxLength -= ulSkipCount; 610 pucRxBuffer = &( pucRecvData[ ulSkipCount ] ); 611 } 612 613 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRxBuffer, ulRxLength ); 614 615 if( lStored != ( int32_t ) ulRxLength ) 616 { 617 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %d / %u bytes? ?\n", ( int ) lStored, ( unsigned ) ulRxLength ) ); 618 619 /* Received data could not be stored. The socket's flag 620 * bMallocError has been set. The socket now has the status 621 * eCLOSE_WAIT and a RST packet will be sent back. */ 622 ( void ) prvTCPSendReset( pxNetworkBuffer ); 623 xResult = -1; 624 } 625 } 626 627 /* After a missing packet has come in, higher packets may be passed to 628 * the user. */ 629 #if ( ipconfigUSE_TCP_WIN == 1 ) 630 { 631 /* Now lTCPAddRxdata() will move the rxHead pointer forward 632 * so data becomes available to the user immediately 633 * In case the low-water mark is reached, bLowWater will be set. */ 634 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0U ) ) 635 { 636 ( void ) lTCPAddRxdata( pxSocket, 0U, NULL, pxTCPWindow->ulUserDataLength ); 637 pxTCPWindow->ulUserDataLength = 0; 638 } 639 } 640 #endif /* ipconfigUSE_TCP_WIN */ 641 } 642 else 643 { 644 pxTCPWindow->ucOptionLength = 0U; 645 } 646 647 return xResult; 648 } 649 /*-----------------------------------------------------------*/ 650 651 #endif /* ipconfigUSE_TCP == 1 */ 652