3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://aws.amazon.com/freertos
23 * http://www.FreeRTOS.org
28 * Module which handles the TCP connections for FreeRTOS+TCP.
29 * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
32 * Endianness: in this module all ports and IP addresses are stored in
33 * host byte-order, except fields in the IP-packets
36 /* Standard includes. */
40 /* FreeRTOS includes. */
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_TCP_IP.h"
52 #include "FreeRTOS_DHCP.h"
53 #include "NetworkInterface.h"
54 #include "NetworkBufferManagement.h"
55 #include "FreeRTOS_ARP.h"
56 #include "FreeRTOS_TCP_WIN.h"
59 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
60 #if ipconfigUSE_TCP == 1
62 /* This compile-time test was moved to here because some macro's
63 were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether
64 the defined MTU size can contain at least a complete TCP packet. */
66 #if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )
67 #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.
71 * The meaning of the TCP flags:
73 #define ipTCP_FLAG_FIN 0x0001u /* No more data from sender */
74 #define ipTCP_FLAG_SYN 0x0002u /* Synchronize sequence numbers */
75 #define ipTCP_FLAG_RST 0x0004u /* Reset the connection */
76 #define ipTCP_FLAG_PSH 0x0008u /* Push function: please push buffered data to the recv application */
77 #define ipTCP_FLAG_ACK 0x0010u /* Acknowledgment field is significant */
78 #define ipTCP_FLAG_URG 0x0020u /* Urgent pointer field is significant */
79 #define ipTCP_FLAG_ECN 0x0040u /* ECN-Echo */
80 #define ipTCP_FLAG_CWR 0x0080u /* Congestion Window Reduced */
81 #define ipTCP_FLAG_NS 0x0100u /* ECN-nonce concealment protection */
82 #define ipTCP_FLAG_RSV 0x0E00u /* Reserved, keep 0 */
84 /* A mask to filter all protocol flags. */
85 #define ipTCP_FLAG_CTRL 0x001Fu
88 * A few values of the TCP options:
90 #define TCP_OPT_END 0u /* End of TCP options list */
91 #define TCP_OPT_NOOP 1u /* "No-operation" TCP option */
92 #define TCP_OPT_MSS 2u /* Maximum segment size TCP option */
93 #define TCP_OPT_WSOPT 3u /* TCP Window Scale Option (3-byte long) */
94 #define TCP_OPT_SACK_P 4u /* Advertize that SACK is permitted */
95 #define TCP_OPT_SACK_A 5u /* SACK option with first/last */
96 #define TCP_OPT_TIMESTAMP 8u /* Time-stamp option */
98 #define TCP_OPT_MSS_LEN 4u /* Length of TCP MSS option. */
99 #define TCP_OPT_WSOPT_LEN 3u /* Length of TCP WSOPT option. */
101 #define TCP_OPT_TIMESTAMP_LEN 10 /* fixed length of the time-stamp option */
103 #ifndef ipconfigTCP_ACK_EARLIER_PACKET
104 #define ipconfigTCP_ACK_EARLIER_PACKET 1
108 * The macro NOW_CONNECTED() is use to determine if the connection makes a
109 * transition from connected to non-connected and vice versa.
110 * NOW_CONNECTED() returns true when the status has one of these values:
111 * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
112 * Technically the connection status is closed earlier, but the library wants
113 * to prevent that the socket will be deleted before the last ACK has been
114 * and thus causing a 'RST' packet on either side.
116 #define NOW_CONNECTED( status )\
117 ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )
120 * The highest 4 bits in the TCP offset byte indicate the total length of the
121 * TCP header, divided by 4.
123 #define VALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0u )
126 * Acknowledgements to TCP data packets may be delayed as long as more is being expected.
127 * A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to
130 #define DELAYED_ACK_SHORT_DELAY_MS ( 2 )
131 #define DELAYED_ACK_LONGER_DELAY_MS ( 20 )
134 * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
135 * an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced
138 #define REDUCED_MSS_THROUGH_INTERNET ( 1400 )
141 * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
142 * the number 5 (words) in the higher niblle of the TCP-offset byte.
144 #define TCP_OFFSET_LENGTH_BITS ( 0xf0u )
145 #define TCP_OFFSET_STANDARD_LENGTH ( 0x50u )
148 * Each TCP socket is checked regularly to see if it can send data packets.
149 * By default, the maximum number of packets sent during one check is limited to 8.
150 * This amount may be further limited by setting the socket's TX window size.
152 #if( !defined( SEND_REPEATED_COUNT ) )
153 #define SEND_REPEATED_COUNT ( 8 )
154 #endif /* !defined( SEND_REPEATED_COUNT ) */
157 * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.
158 * When a TCP timer expires, retries and keep-alive messages will be checked.
160 #ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS
161 #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000u
165 * The names of the different TCP states may be useful in logging.
167 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
168 static const char *pcStateNames[] = {
183 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */
186 * Returns true if the socket must be checked. Non-active sockets are waiting
187 * for user action, either connect() or close().
189 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );
192 * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
194 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );
197 * Try to send a series of messages.
199 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
202 * Return or send a packet to the other party.
204 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
205 uint32_t ulLen, BaseType_t xReleaseAfterSend );
208 * Initialise the data structures which keep track of the TCP windowing system.
210 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );
213 * Let ARP look-up the MAC-address of the peer and initialise the first SYN
216 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );
218 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
220 * For logging and debugging: make a string showing the TCP flags.
222 static const char *prvTCPFlagMeaning( UBaseType_t xFlags);
223 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
226 * Parse the TCP option(s) received, if present.
228 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
231 * Identify and deal with a single TCP header option, advancing the pointer to
232 * the header. This function returns pdTRUE or pdFALSE depending on whether the
233 * caller should continue to parse more header options or break the loop.
235 static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow);
238 * Skip past TCP header options when doing Selective ACK, until there are no
241 static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const ppucLen );
244 * Set the initial properties in the options fields, like the preferred
245 * value of MSS and whether SACK allowed. Will be transmitted in the state
248 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );
251 * For anti-hang protection and TCP keep-alive messages. Called in two places:
252 * after receiving a packet and after a state change. The socket's alive timer
255 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );
258 * Prepare an outgoing message, if anything has to be sent.
260 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );
263 * Calculate when this socket needs to be checked to do (re-)transmissions.
265 static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );
268 * The API FreeRTOS_send() adds data to the TX stream. Add
269 * this data to the windowing system to it can be transmitted.
271 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );
274 * Called to handle the closure of a TCP connection.
276 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
279 * Called from prvTCPHandleState(). Find the TCP payload data and check and
282 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );
285 * Called from prvTCPHandleState(). Check if the payload data may be accepted.
286 * If so, it will be added to the socket's reception queue.
288 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
289 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );
292 * Set the TCP options (if any) for the outgoing packet.
294 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
297 * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
300 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
301 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
304 * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
306 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
307 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
310 * Called from prvTCPHandleState(). There is data to be sent.
311 * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
312 * be checked if it would better be postponed for efficiency.
314 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
315 uint32_t ulReceiveLength, BaseType_t xSendLength );
318 * The heart of all: check incoming packet for valid data and acks and do what
319 * is necessary in each state.
321 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
324 * Common code for sending a TCP protocol control packet (i.e. no options, no
325 * payload, just flags).
327 static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,
328 uint8_t ucTCPFlags );
331 * A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2,
332 * case #3. In summary, an RST was received with a sequence number that is
333 * unexpected but still within the window.
335 static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer );
338 * Reply to a peer with the RST flag on, in case a packet can not be handled.
340 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
343 * Set the initial value for MSS (Maximum Segment Size) to be used.
345 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
348 * Return either a newly created socket, or the current socket in a connected
349 * state (depends on the 'bReuseSocket' flag).
351 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
354 * After a listening socket receives a new connection, it may duplicate itself.
355 * The copying takes place in prvTCPSocketCopy.
357 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
360 * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
361 * state for too long. If so, the socket will be closed, and -1 will be
364 #if( ipconfigTCP_HANG_PROTECTION == 1 )
365 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
368 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
369 int32_t lDataLen, UBaseType_t uxOptionsLength );
371 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
372 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
375 #if( ipconfigUSE_TCP_WIN != 0 )
376 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
380 * Generate a randomized TCP Initial Sequence Number per RFC.
382 extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
383 uint16_t usSourcePort,
384 uint32_t ulDestinationAddress,
385 uint16_t usDestinationPort );
387 /*-----------------------------------------------------------*/
389 /* prvTCPSocketIsActive() returns true if the socket must be checked.
390 * Non-active sockets are waiting for user action, either connect()
392 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
406 /*-----------------------------------------------------------*/
408 #if( ipconfigTCP_HANG_PROTECTION == 1 )
410 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
413 switch( pxSocket->u.xTCP.ucTCPState )
416 /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
417 state ESTABLISHED can be protected using keep-alive messages. */
423 /* These 3 states may last for ever, up to the owner. */
427 /* All other (non-connected) states will get anti-hanging
432 if( xResult != pdFALSE )
434 /* How much time has past since the last active moment which is
435 defined as A) a state change or B) a packet has arrived. */
436 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
438 /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
439 if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
441 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
443 FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
444 pxSocket->usLocalPort,
445 pxSocket->u.xTCP.ulRemoteIP,
446 pxSocket->u.xTCP.usRemotePort,
447 FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
449 #endif /* ipconfigHAS_DEBUG_PRINTF */
451 /* Move to eCLOSE_WAIT, user may close the socket. */
452 vTCPStateChange( pxSocket, eCLOSE_WAIT );
454 /* When 'bPassQueued' true, this socket is an orphan until it
456 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
458 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
460 /* As it did not get connected, and the user can never
461 accept() it anymore, it will be deleted now. Called from
462 the IP-task, so it's safe to call the internal Close
463 function: vSocketClose(). */
464 vSocketClose( pxSocket );
466 /* Return a negative value to tell to inform the caller
468 that the socket got closed and may not be accessed anymore. */
475 /*-----------------------------------------------------------*/
480 * As soon as a TCP socket timer expires, this function xTCPSocketCheck
481 * will be called (from xTCPTimerCheck)
482 * It can send a delayed ACK or new data
483 * Sequence of calling (normally) :
485 * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
486 * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
487 * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
488 * prvTCPSendRepeated() // Send at most 8 messages on a row
489 * prvTCPReturnPacket() // Prepare for returning
490 * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
492 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
494 BaseType_t xResult = 0;
495 BaseType_t xReady = pdFALSE;
497 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
499 /* The API FreeRTOS_send() might have added data to the TX stream. Add
500 this data to the windowing system to it can be transmitted. */
501 prvTCPAddTxData( pxSocket );
504 #if ipconfigUSE_TCP_WIN == 1
506 if( pxSocket->u.xTCP.pxAckMessage != NULL )
508 /* The first task of this regular socket check is to send-out delayed
510 if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
512 /* Earlier data was received but not yet acknowledged. This
513 function is called when the TCP timer for the socket expires, the
514 ACK may be sent now. */
515 if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
517 if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
519 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
520 pxSocket->usLocalPort,
521 pxSocket->u.xTCP.usRemotePort,
522 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
523 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
524 ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
527 prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
529 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
531 /* The ownership has been passed to the SEND routine,
532 clear the pointer to it. */
533 pxSocket->u.xTCP.pxAckMessage = NULL;
535 #endif /* ipconfigZERO_COPY_TX_DRIVER */
537 if( prvTCPNextTimeout( pxSocket ) > 1 )
539 /* Tell the code below that this function is ready. */
545 /* The user wants to perform an active shutdown(), skip sending
546 the delayed ACK. The function prvTCPSendPacket() will send the
547 FIN along with the ACK's. */
550 if( pxSocket->u.xTCP.pxAckMessage != NULL )
552 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
553 pxSocket->u.xTCP.pxAckMessage = NULL;
557 #endif /* ipconfigUSE_TCP_WIN */
559 if( xReady == pdFALSE )
561 /* The second task of this regular socket check is sending out data. */
562 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
563 ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
565 prvTCPSendPacket( pxSocket );
568 /* Set the time-out for the next wakeup for this socket. */
569 prvTCPNextTimeout( pxSocket );
571 #if( ipconfigTCP_HANG_PROTECTION == 1 )
573 /* In all (non-connected) states in which keep-alive messages can not be sent
574 the anti-hang protocol will close sockets that are 'hanging'. */
575 xResult = prvTCPStatusAgeCheck( pxSocket );
582 /*-----------------------------------------------------------*/
585 * prvTCPSendPacket() will be called when the socket time-out has been reached.
586 * It is only called by xTCPSocketCheck().
588 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
591 UBaseType_t uxOptionsLength;
592 TCPPacket_t *pxTCPPacket;
593 NetworkBufferDescriptor_t *pxNetworkBuffer;
595 if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
597 /* The connection is in s state other than SYN. */
598 pxNetworkBuffer = NULL;
600 /* prvTCPSendRepeated() will only create a network buffer if necessary,
601 i.e. when data must be sent to the peer. */
602 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
604 if( pxNetworkBuffer != NULL )
606 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
611 if( pxSocket->u.xTCP.ucRepCount >= 3u )
613 /* The connection is in the SYN status. The packet will be repeated
614 to most 3 times. When there is no response, the socket get the
615 status 'eCLOSE_WAIT'. */
616 FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
617 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
618 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
619 vTCPStateChange( pxSocket, eCLOSE_WAIT );
621 else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
623 /* Or else, if the connection has been prepared, or can be prepared
624 now, proceed to send the packet with the SYN flag.
625 prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
626 the Ethernet address of the peer or the gateway is found. */
627 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
629 /* About to send a SYN packet. Call prvSetSynAckOptions() to set
630 the proper options: The size of MSS and whether SACK's are
632 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
634 /* Return the number of bytes to be sent. */
635 lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
637 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
638 uxOptionsLength is always a multiple of 4. The complete expression
640 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
641 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
643 /* Repeat Count is used for a connecting socket, to limit the number
645 pxSocket->u.xTCP.ucRepCount++;
647 /* Send the SYN message to make a connection. The messages is
648 stored in the socket field 'xPacket'. It will be wrapped in a
649 pseudo network buffer descriptor before it will be sent. */
650 prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
654 /* Return the total number of bytes sent. */
657 /*-----------------------------------------------------------*/
660 * prvTCPSendRepeated will try to send a series of messages, as long as there is
661 * data to be sent and as long as the transmit window isn't full.
663 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
667 UBaseType_t uxOptionsLength = 0u;
670 for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
672 /* prvTCPPrepareSend() might allocate a network buffer if there is data
674 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
675 if( xSendLength <= 0 )
680 /* And return the packet to the peer. */
681 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
683 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
685 *ppxNetworkBuffer = NULL;
687 #endif /* ipconfigZERO_COPY_TX_DRIVER */
689 lResult += xSendLength;
692 /* Return the total number of bytes sent. */
695 /*-----------------------------------------------------------*/
698 * Return (or send) a packet the the peer. The data is stored in pxBuffer,
699 * which may either point to a real network buffer or to a TCP socket field
700 * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
701 * the data to the NIC.
703 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
705 TCPPacket_t * pxTCPPacket;
706 IPHeader_t *pxIPHeader;
707 EthernetHeader_t *pxEthernetHeader;
708 uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
709 TCPWindow_t *pxTCPWindow;
710 NetworkBufferDescriptor_t xTempBuffer;
711 /* For sending, a pseudo network buffer will be used, as explained above. */
713 if( pxNetworkBuffer == NULL )
715 pxNetworkBuffer = &xTempBuffer;
717 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
719 xTempBuffer.pxNextBuffer = NULL;
722 xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
723 xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
724 xReleaseAfterSend = pdFALSE;
727 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
729 if( xReleaseAfterSend == pdFALSE )
731 pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
732 if( pxNetworkBuffer == NULL )
734 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
736 xReleaseAfterSend = pdTRUE;
739 #endif /* ipconfigZERO_COPY_TX_DRIVER */
741 if( pxNetworkBuffer != NULL )
743 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
744 pxIPHeader = &pxTCPPacket->xIPHeader;
745 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
747 /* Fill the packet, using hton translations. */
748 if( pxSocket != NULL )
750 /* Calculate the space in the RX buffer in order to advertise the
751 size of this socket's reception window. */
752 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
754 if( pxSocket->u.xTCP.rxStream != NULL )
756 /* An RX stream was created already, see how much space is
758 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
762 /* No RX stream has been created, the full stream size is
764 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
767 /* Take the minimum of the RX buffer space and the RX window size. */
768 ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace );
770 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
772 /* The low-water mark was reached, meaning there was little
773 space left. The socket will wait until the application has read
774 or flushed the incoming data, and 'zero-window' will be
779 /* If possible, advertise an RX window size of at least 1 MSS, otherwise
780 the peer might start 'zero window probing', i.e. sending small packets
781 (1, 2, 4, 8... bytes). */
782 if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
784 ulSpace = pxSocket->u.xTCP.usCurMSS;
787 /* Avoid overflow of the 16-bit win field. */
788 #if( ipconfigUSE_TCP_WIN != 0 )
790 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
797 if( ulWinSize > 0xfffcUL )
799 ulWinSize = 0xfffcUL;
802 pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
804 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
806 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
808 if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
812 if(pxSocket->u.xTCP.rxStream != NULL)
814 uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
821 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
822 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
823 pxSocket->u.xTCP.ulRemoteIP,
824 pxSocket->u.xTCP.usRemotePort,
825 pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
826 (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
830 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
832 /* The new window size has been advertised, switch off the flag. */
833 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
835 /* Later on, when deciding to delay an ACK, a precise estimate is needed
836 of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
837 highest sequence number minus 1 that the socket will accept. */
838 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
840 #if( ipconfigTCP_KEEP_ALIVE == 1 )
841 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
843 /* Sending a keep-alive packet, send the current sequence number
844 minus 1, which will be recognised as a keep-alive packet an
845 responded to by acknowledging the last byte. */
846 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
847 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
849 pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
850 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
855 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
857 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
859 /* Suppress FIN in case this packet carries earlier data to be
861 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
862 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
864 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
865 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
866 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
868 pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
873 /* Tell which sequence number is expected next time */
874 pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
878 /* Sending data without a socket, probably replying with a RST flag
879 Just swap the two sequence numbers. */
880 vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
883 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
884 pxIPHeader->usLength = FreeRTOS_htons( ulLen );
885 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
887 /* When pxSocket is NULL, this function is called by prvTCPSendReset()
888 and the IP-addresses must be swapped.
889 Also swap the IP-addresses in case the IP-tack doesn't have an
890 IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
891 ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
895 ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
897 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
898 pxIPHeader->ulSourceIPAddress = ulSourceAddress;
899 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
901 /* Just an increasing number. */
902 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
903 usPacketIdentifier++;
904 pxIPHeader->usFragmentOffset = 0u;
906 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
908 /* calculate the IP header checksum, in case the driver won't do that. */
909 pxIPHeader->usHeaderChecksum = 0x00u;
910 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
911 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
913 /* calculate the TCP checksum for an outgoing packet. */
914 usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
916 /* A calculated checksum of 0 must be inverted as 0 means the checksum
918 if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
920 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
925 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
926 pxNetworkBuffer->pxNextBuffer = NULL;
929 /* Important: tell NIC driver how many bytes must be sent. */
930 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
932 /* Fill in the destination MAC addresses. */
933 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
934 sizeof( pxEthernetHeader->xDestinationAddress ) );
936 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
937 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
939 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
941 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
945 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
947 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
949 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
955 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
957 if( xReleaseAfterSend == pdFALSE )
959 /* Swap-back some fields, as pxBuffer probably points to a socket field
960 containing the packet header. */
961 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
962 pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
963 memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
967 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
969 } /* if( pxNetworkBuffer != NULL ) */
971 /*-----------------------------------------------------------*/
974 * The SYN event is very important: the sequence numbers, which have a kind of
975 * random starting value, are being synchronised. The sliding window manager
976 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
979 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
981 if( xTCPWindowLoggingLevel )
982 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
983 pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
984 pxSocket->u.xTCP.uxLittleSpace ,
985 pxSocket->u.xTCP.uxEnoughSpace,
986 pxSocket->u.xTCP.uxRxStreamSize ) );
988 &pxSocket->u.xTCP.xTCPWindow,
989 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
990 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
991 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
992 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
993 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
995 /*-----------------------------------------------------------*/
998 * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
999 * the Ethernet address of the target will be found using ARP. In case the
1000 * target IP address is not within the netmask, the hardware address of the
1001 * gateway will be used.
1003 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
1005 TCPPacket_t *pxTCPPacket;
1006 IPHeader_t *pxIPHeader;
1007 eARPLookupResult_t eReturned;
1008 uint32_t ulRemoteIP;
1009 MACAddress_t xEthAddress;
1010 BaseType_t xReturn = pdTRUE;
1011 uint32_t ulInitialSequenceNumber = 0;
1013 #if( ipconfigHAS_PRINTF != 0 )
1015 /* Only necessary for nicer logging. */
1016 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
1018 #endif /* ipconfigHAS_PRINTF != 0 */
1020 ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
1022 /* Determine the ARP cache status for the requested IP address. */
1023 eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
1027 case eARPCacheHit: /* An ARP table lookup found a valid entry. */
1028 break; /* We can now prepare the SYN packet. */
1029 case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
1030 case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
1032 /* Count the number of times it couldn't find the ARP address. */
1033 pxSocket->u.xTCP.ucRepCount++;
1035 FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
1036 pxSocket->u.xTCP.ulRemoteIP,
1037 FreeRTOS_htonl( ulRemoteIP ),
1039 xEthAddress.ucBytes[ 0 ],
1040 xEthAddress.ucBytes[ 1 ],
1041 xEthAddress.ucBytes[ 2 ],
1042 xEthAddress.ucBytes[ 3 ],
1043 xEthAddress.ucBytes[ 4 ],
1044 xEthAddress.ucBytes[ 5 ] ) );
1046 /* And issue a (new) ARP request */
1047 FreeRTOS_OutputARPRequest( ulRemoteIP );
1052 if( xReturn != pdFALSE )
1054 /* Get a difficult-to-predict initial sequence number for this 4-tuple. */
1055 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
1056 pxSocket->usLocalPort,
1057 pxSocket->u.xTCP.ulRemoteIP,
1058 pxSocket->u.xTCP.usRemotePort );
1060 /* Check for a random number generation error. */
1061 if( 0 == ulInitialSequenceNumber )
1067 if( xReturn != pdFALSE )
1069 /* The MAC-address of the peer (or gateway) has been found,
1070 now prepare the initial TCP packet and some fields in the socket. */
1071 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
1072 pxIPHeader = &pxTCPPacket->xIPHeader;
1074 /* reset the retry counter to zero. */
1075 pxSocket->u.xTCP.ucRepCount = 0u;
1077 /* And remember that the connect/SYN data are prepared. */
1078 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
1080 /* Now that the Ethernet address is known, the initial packet can be
1082 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
1084 /* Write the Ethernet address in Source, because it will be swapped by
1085 prvTCPReturnPacket(). */
1086 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
1088 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
1089 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
1091 pxIPHeader->ucVersionHeaderLength = 0x45u;
1092 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
1093 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
1095 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
1097 /* Addresses and ports will be stored swapped because prvTCPReturnPacket
1098 will swap them back while replying. */
1099 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
1100 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
1102 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
1103 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
1105 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
1107 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
1109 /* Start with ISN (Initial Sequence Number). */
1110 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
1112 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
1113 the high nibble of the TCP offset field. */
1114 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
1116 /* Only set the SYN flag. */
1117 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
1119 /* Set the values of usInitMSS / usCurMSS for this socket. */
1120 prvSocketSetMSS( pxSocket );
1122 /* The initial sequence numbers at our side are known. Later
1123 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
1124 first wait for a SYN+ACK reply. */
1125 prvTCPCreateWindow( pxSocket );
1130 /*-----------------------------------------------------------*/
1132 /* For logging and debugging: make a string showing the TCP flags
1134 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1136 static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
1138 static char retString[10];
1139 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
1140 ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
1141 ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
1142 ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
1143 ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
1144 ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
1145 ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
1146 ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
1147 ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
1148 ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
1151 /*-----------------------------------------------------------*/
1153 #endif /* ipconfigHAS_DEBUG_PRINTF */
1156 * Parse the TCP option(s) received, if present. It has already been verified
1157 * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
1158 * is longer than the usual 20 (5 x 4) bytes.
1160 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
1162 TCPPacket_t * pxTCPPacket;
1163 TCPHeader_t * pxTCPHeader;
1164 const unsigned char *pucPtr;
1165 const unsigned char *pucLast;
1166 TCPWindow_t *pxTCPWindow;
1167 BaseType_t xShouldContinueLoop;
1169 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
1170 pxTCPHeader = &pxTCPPacket->xTCPHeader;
1172 /* A character pointer to iterate through the option data */
1173 pucPtr = pxTCPHeader->ucOptdata;
1174 pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
1175 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
1177 /* Validate options size calculation. */
1178 if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) )
1183 /* The comparison with pucLast is only necessary in case the option data are
1184 corrupted, we don't like to run into invalid memory and crash. */
1185 xShouldContinueLoop = pdTRUE;
1186 while( ( pucPtr < pucLast ) && ( xShouldContinueLoop == pdTRUE ) )
1188 xShouldContinueLoop = prvSingleStepTCPHeaderOptions( &pucPtr, &pucLast, &pxSocket, &pxTCPWindow );
1192 /*-----------------------------------------------------------*/
1194 static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow)
1196 UBaseType_t uxNewMSS;
1197 UBaseType_t xRemainingOptionsBytes = ( *ppucLast ) - ( *ppucPtr );
1198 unsigned char ucLen;
1200 if( ( *ppucPtr )[ 0 ] == TCP_OPT_END )
1202 /* End of options. */
1205 if( ( *ppucPtr )[ 0 ] == TCP_OPT_NOOP)
1207 /* NOP option, inserted to make the length a multiple of 4. */
1212 /* Any other well-formed option must be at least two bytes: the option
1213 type byte followed by a length byte. */
1214 if( xRemainingOptionsBytes < 2 )
1218 #if( ipconfigUSE_TCP_WIN != 0 )
1219 else if( ( *ppucPtr )[ 0 ] == TCP_OPT_WSOPT )
1221 /* Confirm that the option fits in the remaining buffer space. */
1222 if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( ( *ppucPtr )[ 1 ] != TCP_OPT_WSOPT_LEN ) )
1227 ( *ppxSocket )->u.xTCP.ucPeerWinScaleFactor = ( *ppucPtr )[ 2 ];
1228 ( *ppxSocket )->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
1229 ( *ppucPtr ) += TCP_OPT_WSOPT_LEN;
1231 #endif /* ipconfigUSE_TCP_WIN */
1232 else if( ( *ppucPtr )[ 0 ] == TCP_OPT_MSS )
1234 /* Confirm that the option fits in the remaining buffer space. */
1235 if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( ( *ppucPtr )[ 1 ] != TCP_OPT_MSS_LEN ) )
1240 /* An MSS option with the correct option length. FreeRTOS_htons()
1241 is not needed here because usChar2u16() already returns a host
1243 uxNewMSS = usChar2u16( ( *ppucPtr ) + 2 );
1245 if( ( *ppxSocket )->u.xTCP.usInitMSS != uxNewMSS )
1247 /* Perform a basic check on the the new MSS. */
1253 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", ( *ppxSocket )->u.xTCP.usInitMSS, uxNewMSS ) );
1256 if( ( *ppxSocket )->u.xTCP.usInitMSS > uxNewMSS )
1258 /* our MSS was bigger than the MSS of the other party: adapt it. */
1259 ( *ppxSocket )->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
1260 if( ( ( *ppxTCPWindow ) != NULL ) && ( ( *ppxSocket )->u.xTCP.usCurMSS > uxNewMSS ) )
1262 /* The peer advertises a smaller MSS than this socket was
1263 using. Use that as well. */
1264 FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", ( *ppxSocket )->u.xTCP.usCurMSS, uxNewMSS ) );
1265 ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
1267 ( *ppxTCPWindow )->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( ( *ppxTCPWindow )->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
1268 ( *ppxTCPWindow )->usMSSInit = ( uint16_t ) uxNewMSS;
1269 ( *ppxTCPWindow )->usMSS = ( uint16_t ) uxNewMSS;
1270 ( *ppxSocket )->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
1271 ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
1274 #if( ipconfigUSE_TCP_WIN != 1 )
1275 /* Without scaled windows, MSS is the only interesting option. */
1278 /* Or else we continue to check another option: selective ACK. */
1279 ( *ppucPtr ) += TCP_OPT_MSS_LEN;
1280 #endif /* ipconfigUSE_TCP_WIN != 1 */
1284 /* All other options have a length field, so that we easily
1285 can skip past them. */
1286 ucLen = ( *ppucPtr )[ 1 ];
1287 if( ( ucLen < 2 ) || ( ucLen > xRemainingOptionsBytes ) )
1289 /* If the length field is too small or too big, the options are
1290 * malformed, don't process them further.
1295 #if( ipconfigUSE_TCP_WIN == 1 )
1297 /* Selective ACK: the peer has received a packet but it is missing
1298 * earlier packets. At least this packet does not need retransmission
1299 * anymore. ulTCPWindowTxSack( ) takes care of this administration.
1301 if( ( *ppucPtr )[0] == TCP_OPT_SACK_A )
1308 prvSkipPastRemainingOptions( ppucPtr, ppxSocket, &ucLen );
1310 /* ucLen should be 0 by now. */
1313 #endif /* ipconfigUSE_TCP_WIN == 1 */
1315 ( *ppucPtr ) += ucLen;
1320 /*-----------------------------------------------------------*/
1322 static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const pucLen )
1324 uint32_t ulFirst = ulChar2u32( ( *ppucPtr ) );
1325 uint32_t ulLast = ulChar2u32( ( *ppucPtr ) + 4 );
1326 uint32_t ulCount = ulTCPWindowTxSack( &( *ppxSocket )->u.xTCP.xTCPWindow, ulFirst, ulLast );
1327 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
1328 * starting from the head position. Advance the tail pointer in txStream.
1330 if( ( ( *ppxSocket )->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
1332 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
1333 uxStreamBufferGet( ( *ppxSocket )->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
1334 ( *ppxSocket )->xEventBits |= eSOCKET_SEND;
1336 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
1338 if( ( *ppxSocket )->xSelectBits & eSELECT_WRITE )
1340 /* The field 'xEventBits' is used to store regular socket events
1341 * (at most 8), as well as 'select events', which will be left-shifted.
1343 ( *ppxSocket )->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
1348 /* In case the socket owner has installed an OnSent handler, call it now.
1350 #if( ipconfigUSE_CALLBACKS == 1 )
1352 if( ipconfigIS_VALID_PROG_ADDRESS( ( *ppxSocket )->u.xTCP.pxHandleSent ) )
1354 ( *ppxSocket )->u.xTCP.pxHandleSent( (Socket_t )( *ppxSocket ), ulCount );
1357 #endif /* ipconfigUSE_CALLBACKS == 1 */
1363 /*-----------------------------------------------------------*/
1365 #if( ipconfigUSE_TCP_WIN != 0 )
1367 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
1372 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
1373 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
1375 while( uxWinSize > 0xfffful )
1377 /* Divide by two and increase the binary factor by 1. */
1382 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
1383 pxSocket->u.xTCP.uxRxWinSize,
1384 pxSocket->u.xTCP.usInitMSS,
1391 /*-----------------------------------------------------------*/
1394 * When opening a TCP connection, while SYN's are being sent, the parties may
1395 * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
1396 * nett size of the payload, always smaller than MTU.
1398 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
1400 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
1401 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
1402 UBaseType_t uxOptionsLength;
1404 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
1406 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
1407 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
1408 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
1409 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
1411 #if( ipconfigUSE_TCP_WIN != 0 )
1413 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
1415 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
1416 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
1417 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
1418 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
1419 uxOptionsLength = 8u;
1423 uxOptionsLength = 4u;
1427 #if( ipconfigUSE_TCP_WIN == 0 )
1429 return uxOptionsLength;
1433 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
1434 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
1435 pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
1436 pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
1437 uxOptionsLength += 4u;
1439 return uxOptionsLength; /* bytes, not words. */
1441 #endif /* ipconfigUSE_TCP_WIN == 0 */
1445 * For anti-hanging protection and TCP keep-alive messages. Called in two
1446 * places: after receiving a packet and after a state change. The socket's
1447 * alive timer may be reset.
1449 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
1451 #if( ipconfigTCP_HANG_PROTECTION == 1 )
1453 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
1457 #if( ipconfigTCP_KEEP_ALIVE == 1 )
1459 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
1460 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
1461 pxSocket->u.xTCP.ucKeepRepCount = 0u;
1462 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
1468 /*-----------------------------------------------------------*/
1471 * Changing to a new state. Centralised here to do specific actions such as
1472 * resetting the alive timer, calling the user's OnConnect handler to notify
1473 * that a socket has got (dis)connected, and setting bit to unblock a call to
1476 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
1478 FreeRTOS_Socket_t *xParent = NULL;
1479 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
1480 BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
1481 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1482 BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
1484 #if( ipconfigUSE_CALLBACKS == 1 )
1485 FreeRTOS_Socket_t *xConnected = NULL;
1488 /* Has the connected status changed? */
1489 if( bBefore != bAfter )
1491 /* Is the socket connected now ? */
1492 if( bAfter != pdFALSE )
1494 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
1495 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
1497 /* Now that it is connected, find it's parent. */
1498 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
1504 xParent = pxSocket->u.xTCP.pxPeerSocket;
1505 configASSERT( xParent != NULL );
1507 if( xParent != NULL )
1509 if( xParent->u.xTCP.pxPeerSocket == NULL )
1511 xParent->u.xTCP.pxPeerSocket = pxSocket;
1514 xParent->xEventBits |= eSOCKET_ACCEPT;
1516 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
1518 /* Library support FreeRTOS_select(). Receiving a new
1519 connection is being translated as a READ event. */
1520 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
1522 xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
1527 #if( ipconfigUSE_CALLBACKS == 1 )
1529 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
1530 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
1532 /* The listening socket does not become connected itself, in stead
1533 a child socket is created.
1534 Postpone a call the OnConnect event until the end of this function. */
1535 xConnected = xParent;
1541 /* Don't need to access the parent socket anymore, so the
1542 reference 'pxPeerSocket' may be cleared. */
1543 pxSocket->u.xTCP.pxPeerSocket = NULL;
1544 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
1546 /* When true, this socket may be returned in a call to accept(). */
1547 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
1551 pxSocket->xEventBits |= eSOCKET_CONNECT;
1553 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
1555 if( pxSocket->xSelectBits & eSELECT_WRITE )
1557 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
1563 else /* bAfter == pdFALSE, connection is closed. */
1565 /* Notify/wake-up the socket-owner by setting a semaphore. */
1566 pxSocket->xEventBits |= eSOCKET_CLOSED;
1568 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
1570 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
1572 pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
1577 #if( ipconfigUSE_CALLBACKS == 1 )
1579 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
1581 /* The 'connected' state has changed, call the user handler. */
1582 xConnected = pxSocket;
1585 #endif /* ipconfigUSE_CALLBACKS */
1587 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
1589 /* Now the socket isn't in an active state anymore so it
1590 won't need further attention of the IP-task.
1591 Setting time-out to zero means that the socket won't get checked during
1593 pxSocket->u.xTCP.usTimeout = 0u;
1598 if( eTCPState == eCLOSED )
1600 /* Socket goes to status eCLOSED because of a RST.
1601 When nobody owns the socket yet, delete it. */
1602 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
1603 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
1605 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
1606 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
1608 FreeRTOS_closesocket( pxSocket );
1614 /* Fill in the new state. */
1615 pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
1617 /* touch the alive timers because moving to another state. */
1618 prvTCPTouchSocket( pxSocket );
1620 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
1622 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
1623 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
1624 pxSocket->usLocalPort,
1625 pxSocket->u.xTCP.ulRemoteIP,
1626 pxSocket->u.xTCP.usRemotePort,
1627 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
1628 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
1630 #endif /* ipconfigHAS_DEBUG_PRINTF */
1632 #if( ipconfigUSE_CALLBACKS == 1 )
1634 if( xConnected != NULL )
1636 /* The 'connected' state has changed, call the OnConnect handler of the parent. */
1637 xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter );
1641 if( xParent != NULL )
1643 vSocketWakeUpUser( xParent );
1646 /*-----------------------------------------------------------*/
1648 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
1649 int32_t lDataLen, UBaseType_t uxOptionsLength )
1651 NetworkBufferDescriptor_t *pxReturn;
1655 if( xBufferAllocFixedSize != pdFALSE )
1657 /* Network buffers are created with a fixed size and can hold the largest
1659 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
1660 /* and therefore, the buffer won't be too small.
1661 Only ask for a new network buffer in case none was supplied. */
1662 xResize = ( pxNetworkBuffer == NULL );
1666 /* Network buffers are created with a variable size. See if it must
1668 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
1669 ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
1670 /* In case we were called from a TCP timer event, a buffer must be
1671 created. Otherwise, test 'xDataLength' of the provided buffer. */
1672 xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded );
1675 if( xResize != pdFALSE )
1677 /* The caller didn't provide a network buffer or the provided buffer is
1678 too small. As we must send-out a data packet, a buffer will be created
1680 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
1682 if( pxReturn != NULL )
1684 /* Set the actual packet size, in case the returned buffer is larger. */
1685 pxReturn->xDataLength = lNeeded;
1687 /* Copy the existing data to the new created buffer. */
1688 if( pxNetworkBuffer )
1690 /* Either from the previous buffer... */
1691 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
1693 /* ...and release it. */
1694 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1698 /* Or from the socket field 'xTCP.xPacket'. */
1699 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
1705 /* xResize is false, the network buffer provided was big enough. */
1706 pxReturn = pxNetworkBuffer;
1708 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
1709 xDataLength member must get the correct length too! */
1710 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
1715 /*-----------------------------------------------------------*/
1718 * Prepare an outgoing message, in case anything has to be sent.
1720 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
1723 uint8_t *pucEthernetBuffer, *pucSendData;
1724 TCPPacket_t *pxTCPPacket;
1726 uint32_t ulDataGot, ulDistance;
1727 TCPWindow_t *pxTCPWindow;
1728 NetworkBufferDescriptor_t *pxNewBuffer;
1731 if( ( *ppxNetworkBuffer ) != NULL )
1733 /* A network buffer descriptor was already supplied */
1734 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
1738 /* For now let it point to the last packet header */
1739 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
1742 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
1743 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
1746 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
1748 if( pxSocket->u.xTCP.txStream != NULL )
1750 /* ulTCPWindowTxGet will return the amount of data which may be sent
1751 along with the position in the txStream.
1752 Why check for MSS > 1 ?
1753 Because some TCP-stacks (like uIP) use it for flow-control. */
1754 if( pxSocket->u.xTCP.usCurMSS > 1u )
1756 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
1761 /* Check if the current network buffer is big enough, if not,
1763 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
1765 if( pxNewBuffer != NULL )
1767 *ppxNetworkBuffer = pxNewBuffer;
1768 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
1769 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
1771 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
1773 /* Translate the position in txStream to an offset from the tail
1775 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
1777 /* Here data is copied from the txStream in 'peek' mode. Only
1778 when the packets are acked, the tail marker will be updated. */
1779 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
1781 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1783 if( ulDataGot != ( uint32_t ) lDataLen )
1785 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
1786 lStreamPos, uxOffset, ulDataGot, lDataLen ) );
1791 /* If the owner of the socket requests a closure, add the FIN
1792 flag to the last packet. */
1793 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
1795 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
1797 if( ulDistance == ulDataGot )
1799 #if (ipconfigHAS_DEBUG_PRINTF == 1)
1801 /* the order of volatile accesses is undefined
1802 so such workaround */
1803 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
1804 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
1805 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
1807 FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
1808 uxTail, uxMid, uxHead ) );
1811 /* Although the socket sends a FIN, it will stay in
1812 ESTABLISHED until all current data has been received or
1814 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
1815 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
1816 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
1827 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
1829 /* See if the socket owner wants to shutdown this connection. */
1830 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
1831 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
1833 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
1834 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
1835 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
1836 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
1837 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
1838 vTCPStateChange( pxSocket, eFIN_WAIT_1 );
1841 #if( ipconfigTCP_KEEP_ALIVE != 0 )
1843 if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
1845 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
1846 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
1847 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
1848 vTCPStateChange( pxSocket, eCLOSE_WAIT );
1851 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
1853 /* If there is no data to be sent, and no window-update message,
1854 we might want to send a keep-alive message. */
1855 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
1857 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
1858 if( pxSocket->u.xTCP.ucKeepRepCount )
1860 xMax = ( 3u * configTICK_RATE_HZ );
1864 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
1865 if( xTCPWindowLoggingLevel )
1866 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
1867 pxSocket->u.xTCP.ulRemoteIP,
1868 pxSocket->u.xTCP.usRemotePort,
1869 pxSocket->u.xTCP.ucKeepRepCount ) );
1870 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
1871 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
1872 pxSocket->u.xTCP.ucKeepRepCount++;
1876 #endif /* ipconfigTCP_KEEP_ALIVE */
1879 /* Anything to send, a change of the advertised window size, or maybe send a
1880 keep-alive message? */
1881 if( ( lDataLen > 0 ) ||
1882 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
1883 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
1885 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
1886 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
1888 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
1890 if( lDataLen != 0l )
1892 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
1895 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
1900 /*-----------------------------------------------------------*/
1903 * Calculate after how much time this socket needs to be checked again.
1905 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
1907 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
1909 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
1911 /* The socket is actively connecting to a peer. */
1912 if( pxSocket->u.xTCP.bits.bConnPrepared )
1914 /* Ethernet address has been found, use progressive timeout for
1915 active connect(). */
1916 if( pxSocket->u.xTCP.ucRepCount < 3u )
1918 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
1922 ulDelayMs = 11000UL;
1927 /* Still in the ARP phase: check every half second. */
1931 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
1932 pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
1933 pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
1934 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
1936 else if( pxSocket->u.xTCP.usTimeout == 0u )
1938 /* Let the sliding window mechanism decide what time-out is appropriate. */
1939 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
1940 if( ulDelayMs == 0u )
1942 if( xResult != ( BaseType_t )0 )
1948 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
1953 /* ulDelayMs contains the time to wait before a re-transmission. */
1955 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
1959 /* field '.usTimeout' has already been set (by the
1960 keep-alive/delayed-ACK mechanism). */
1963 /* Return the number of clock ticks before the timer expires. */
1964 return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
1966 /*-----------------------------------------------------------*/
1968 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
1970 int32_t lCount, lLength;
1972 /* A txStream has been created already, see if the socket has new data for
1975 uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It contains new
1976 Tx data which has not been passed to the sliding window yet. The oldest
1977 data not-yet-confirmed can be found at rxTail. */
1978 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
1982 /* All data between txMid and rxHead will now be passed to the sliding
1983 window manager, so it can start transmitting them.
1985 Hand over the new data to the sliding window handler. It will be
1986 split-up in chunks of 1460 bytes each (or less, depending on
1987 ipconfigTCP_MSS). */
1988 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
1989 ( uint32_t ) lLength,
1990 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
1991 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
1993 /* Move the rxMid pointer forward up to rxHead. */
1996 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
2000 /*-----------------------------------------------------------*/
2003 * prvTCPHandleFin() will be called to handle socket closure
2004 * The Closure starts when either a FIN has been received and accepted,
2005 * Or when the socket has sent a FIN flag to the peer
2006 * Before being called, it has been checked that both reception and transmission
2009 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
2011 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
2012 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
2013 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
2014 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
2015 BaseType_t xSendLength = 0;
2016 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
2018 if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
2020 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
2022 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
2024 /* We haven't yet replied with a FIN, do so now. */
2025 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
2026 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
2030 /* We did send a FIN already, see if it's ACK'd. */
2031 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
2033 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
2037 if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
2039 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
2040 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
2042 /* And wait for the final ACK. */
2043 vTCPStateChange( pxSocket, eLAST_ACK );
2047 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
2048 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
2049 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
2051 /* We have sent out a FIN but the peer hasn't replied with a FIN
2052 yet. Do nothing for the moment. */
2053 pxTCPHeader->ucTCPFlags = 0u;
2057 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
2059 /* This is the third of the three-way hand shake: the last
2061 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
2065 /* The other party started the closure, so we just wait for the
2067 pxTCPHeader->ucTCPFlags = 0u;
2070 /* And wait for the user to close this socket. */
2071 vTCPStateChange( pxSocket, eCLOSE_WAIT );
2075 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
2077 if( pxTCPHeader->ucTCPFlags != 0u )
2079 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
2082 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
2084 if( xTCPWindowLoggingLevel != 0 )
2086 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
2087 ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
2088 pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
2089 pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
2090 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
2091 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
2096 /*-----------------------------------------------------------*/
2099 * prvCheckRxData(): called from prvTCPHandleState()
2101 * The first thing that will be done is find the TCP payload data
2102 * and check the length of this data.
2104 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
2106 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
2107 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
2108 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
2110 /* Determine the length and the offset of the user-data sent to this
2113 The size of the TCP header is given in a multiple of 4-byte words (single
2114 byte, needs no ntoh() translation). A shift-right 2: is the same as
2115 (offset >> 4) * 4. */
2116 lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
2118 /* Let pucRecvData point to the first byte received. */
2119 *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
2121 /* Calculate lReceiveLength - the length of the TCP data received. This is
2122 equal to the total packet length minus:
2123 ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
2124 lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
2125 lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
2127 if( lReceiveLength > lLength )
2129 /* More bytes were received than the reported length, often because of
2130 padding bytes at the end. */
2131 lReceiveLength = lLength;
2134 /* Subtract the size of the TCP and IP headers and the actual data size is
2136 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
2138 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
2146 This field communicates the current value of the urgent pointer as a
2147 positive offset from the sequence number in this segment. The urgent
2148 pointer points to the sequence number of the octet following the urgent
2149 data. This field is only be interpreted in segments with the URG control
2151 if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
2153 /* Although we ignore the urgent data, we have to skip it. */
2154 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
2155 *ppucRecvData += lUrgentLength;
2156 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
2159 return ( BaseType_t ) lReceiveLength;
2161 /*-----------------------------------------------------------*/
2164 * prvStoreRxData(): called from prvTCPHandleState()
2166 * The second thing is to do is check if the payload data may be accepted
2167 * If so, they will be added to the reception queue.
2169 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
2170 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
2172 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
2173 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
2174 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
2175 uint32_t ulSequenceNumber, ulSpace;
2176 int32_t lOffset, lStored;
2177 BaseType_t xResult = 0;
2179 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
2181 if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
2183 /* See if way may accept the data contents and forward it to the socket
2186 If it can't be "accept"ed it may have to be stored and send a selective
2187 ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
2188 called later to store an out-of-order packet (in case lOffset is
2190 if ( pxSocket->u.xTCP.rxStream )
2192 ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
2196 ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
2199 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
2203 /* New data has arrived and may be made available to the user. See
2204 if the head marker in rxStream may be advanced, only if lOffset == 0.
2205 In case the low-water mark is reached, bLowWater will be set
2206 "low-water" here stands for "little space". */
2207 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
2209 if( lStored != ( int32_t ) ulReceiveLength )
2211 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
2213 /* Received data could not be stored. The socket's flag
2214 bMallocError has been set. The socket now has the status
2215 eCLOSE_WAIT and a RST packet will be sent back. */
2216 prvTCPSendReset( pxNetworkBuffer );
2221 /* After a missing packet has come in, higher packets may be passed to
2223 #if( ipconfigUSE_TCP_WIN == 1 )
2225 /* Now lTCPAddRxdata() will move the rxHead pointer forward
2226 so data becomes available to the user immediately
2227 In case the low-water mark is reached, bLowWater will be set. */
2228 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
2230 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
2231 pxTCPWindow->ulUserDataLength = 0;
2234 #endif /* ipconfigUSE_TCP_WIN */
2238 pxTCPWindow->ucOptionLength = 0u;
2243 /*-----------------------------------------------------------*/
2245 /* Set the TCP options (if any) for the outgoing packet. */
2246 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
2248 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
2249 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
2250 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
2251 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
2253 #if( ipconfigUSE_TCP_WIN == 1 )
2254 if( uxOptionsLength != 0u )
2256 /* TCP options must be sent because a packet which is out-of-order
2258 if( xTCPWindowLoggingLevel >= 0 )
2259 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
2260 pxSocket->usLocalPort,
2261 pxSocket->u.xTCP.usRemotePort,
2263 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
2264 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
2265 memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
2267 /* The header length divided by 4, goes into the higher nibble,
2268 effectively a shift-left 2. */
2269 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
2272 #endif /* ipconfigUSE_TCP_WIN */
2273 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
2275 /* TCP options must be sent because the MSS has changed. */
2276 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
2277 if( xTCPWindowLoggingLevel >= 0 )
2279 FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
2282 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
2283 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
2284 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
2285 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
2286 uxOptionsLength = 4u;
2287 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
2290 return uxOptionsLength;
2292 /*-----------------------------------------------------------*/
2295 * prvHandleSynReceived(): called from prvTCPHandleState()
2297 * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
2298 * If the flags received are correct, the socket will move to eESTABLISHED.
2300 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
2301 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
2303 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
2304 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
2305 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
2306 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
2307 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
2308 BaseType_t xSendLength = 0;
2310 /* Either expect a ACK or a SYN+ACK. */
2311 uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
2312 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
2314 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
2317 if( ( ucTCPFlags & 0x17u ) != usExpect )
2319 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
2320 /* eSYN_RECEIVED: flags ACK expected, not SYN. */
2321 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
2322 pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
2323 usExpect, ucTCPFlags ) );
2324 vTCPStateChange( pxSocket, eCLOSE_WAIT );
2325 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
2326 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
2327 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
2331 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
2332 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
2334 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
2336 TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
2338 /* Clear the SYN flag in lastPacket. */
2339 pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
2341 /* This socket was the one connecting actively so now perofmr the
2343 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
2344 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
2345 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
2346 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
2347 pxTCPWindow->ulNextTxSequenceNumber++;
2349 else if( ulReceiveLength == 0u )
2351 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
2354 /* The SYN+ACK has been confirmed, increase the next sequence number by
2356 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
2358 #if( ipconfigUSE_TCP_WIN == 1 )
2360 FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
2361 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
2362 pxSocket->usLocalPort,
2363 pxSocket->u.xTCP.ulRemoteIP,
2364 pxSocket->u.xTCP.usRemotePort,
2365 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
2367 #endif /* ipconfigUSE_TCP_WIN */
2369 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
2371 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
2372 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
2373 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
2375 #if( ipconfigUSE_TCP_WIN != 0 )
2377 if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
2379 /* The other party did not send a scaling factor.
2380 A shifting factor in this side must be canceled. */
2381 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
2382 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
2385 #endif /* ipconfigUSE_TCP_WIN */
2386 /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
2387 connection is established. */
2388 vTCPStateChange( pxSocket, eESTABLISHED );
2393 /*-----------------------------------------------------------*/
2396 * prvHandleEstablished(): called from prvTCPHandleState()
2398 * Called if the status is eESTABLISHED. Data reception has been handled
2399 * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
2400 * the code will check if it may be accepted, i.e. if all expected data has been
2401 * completely received.
2403 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
2404 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
2406 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
2407 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
2408 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
2409 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
2410 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
2411 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
2412 int32_t lDistance, lSendResult;
2414 /* Remember the window size the peer is advertising. */
2415 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
2416 #if( ipconfigUSE_TCP_WIN != 0 )
2418 pxSocket->u.xTCP.ulWindowSize =
2419 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
2423 if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
2425 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
2427 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
2428 starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
2430 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
2432 /* Just advancing the tail index, 'ulCount' bytes have been
2433 confirmed, and because there is new space in the txStream, the
2434 user/owner should be woken up. */
2435 /* _HT_ : only in case the socket's waiting? */
2436 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
2438 pxSocket->xEventBits |= eSOCKET_SEND;
2440 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
2442 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
2444 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
2448 /* In case the socket owner has installed an OnSent handler,
2450 #if( ipconfigUSE_CALLBACKS == 1 )
2452 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
2454 pxSocket->u.xTCP.pxHandleSent( ( Socket_t )pxSocket, ulCount );
2457 #endif /* ipconfigUSE_CALLBACKS == 1 */
2462 /* If this socket has a stream for transmission, add the data to the
2463 outgoing segment(s). */
2464 if( pxSocket->u.xTCP.txStream != NULL )
2466 prvTCPAddTxData( pxSocket );
2469 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
2471 if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
2473 /* Peer is requesting to stop, see if we're really finished. */
2476 /* Checks are only necessary if we haven't sent a FIN yet. */
2477 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
2479 /* xTCPWindowTxDone returns true when all Tx queues are empty. */
2480 bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
2481 bTxDone = xTCPWindowTxDone( pxTCPWindow );
2483 if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
2485 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
2486 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
2487 pxSocket->usLocalPort,
2488 pxSocket->u.xTCP.usRemotePort,
2489 bRxComplete, bTxDone ) );
2490 xMayClose = pdFALSE;
2494 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
2498 FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
2499 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
2500 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
2502 xMayClose = pdFALSE;
2507 if( xTCPWindowLoggingLevel > 0 )
2509 FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
2510 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
2511 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
2514 if( xMayClose != pdFALSE )
2516 pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
2517 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
2521 if( xMayClose == pdFALSE )
2523 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
2525 if( ulReceiveLength != 0u )
2527 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
2528 /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
2529 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
2531 if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
2533 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
2537 /* Now get data to be transmitted. */
2538 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
2539 can not send-out both TCP options and also a full packet. Sending
2540 options (SACK) is always more urgent than sending data, which can be
2542 if( uxOptionsLength == 0u )
2544 /* prvTCPPrepareSend might allocate a bigger network buffer, if
2546 lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
2547 if( lSendResult > 0 )
2549 xSendLength = ( BaseType_t ) lSendResult;
2556 /*-----------------------------------------------------------*/
2559 * Called from prvTCPHandleState(). There is data to be sent. If
2560 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
2561 * checked if it would better be postponed for efficiency.
2563 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
2564 uint32_t ulReceiveLength, BaseType_t xSendLength )
2566 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
2567 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
2568 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
2569 /* Find out what window size we may advertised. */
2571 #if( ipconfigUSE_TCP_WIN == 1 )
2572 #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
2573 const int32_t lMinLength = 0;
2579 /* Set the time-out field, so that we'll be called by the IP-task in case no
2580 next message will be received. */
2581 lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
2582 #if ipconfigUSE_TCP_WIN == 1
2585 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
2587 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
2589 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
2591 /* In case we're receiving data continuously, we might postpone sending
2592 an ACK to gain performance. */
2593 if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
2594 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
2595 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
2596 ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
2597 ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
2598 ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
2600 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
2602 /* There was still a delayed in queue, delete it. */
2603 if( pxSocket->u.xTCP.pxAckMessage != 0 )
2605 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
2608 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
2610 if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
2611 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
2613 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
2617 /* Normally a delayed ACK should wait 200 ms for a next incoming
2618 packet. Only wait 20 ms here to gain performance. A slow ACK
2619 for full-size message. */
2620 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
2623 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
2625 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
2626 pxSocket->usLocalPort,
2627 pxSocket->u.xTCP.usRemotePort,
2628 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
2629 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
2631 pxSocket->u.xTCP.usTimeout, lRxSpace ) );
2634 *ppxNetworkBuffer = NULL;
2637 else if( pxSocket->u.xTCP.pxAckMessage != NULL )
2639 /* As an ACK is not being delayed, remove any earlier delayed ACK
2641 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
2643 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
2646 pxSocket->u.xTCP.pxAckMessage = NULL;
2651 /* Remove compiler warnings. */
2652 ( void ) ulReceiveLength;
2653 ( void ) pxTCPHeader;
2656 #endif /* ipconfigUSE_TCP_WIN */
2658 if( xSendLength != 0 )
2660 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
2662 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
2663 pxSocket->usLocalPort,
2664 pxSocket->u.xTCP.usRemotePort,
2665 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
2666 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
2670 /* Set the parameter 'xReleaseAfterSend' to the value of
2671 ipconfigZERO_COPY_TX_DRIVER. */
2672 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
2673 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
2675 /* The driver has taken ownership of the Network Buffer. */
2676 *ppxNetworkBuffer = NULL;
2683 /*-----------------------------------------------------------*/
2686 * prvTCPHandleState()
2687 * is the most important function of this TCP stack
2688 * We've tried to keep it (relatively short) by putting a lot of code in
2689 * the static functions above:
2694 * prvHandleSynReceived()
2695 * prvHandleEstablished()
2698 * As these functions are declared static, and they're called from one location
2699 * only, most compilers will inline them, thus avoiding a call and return.
2701 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
2703 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
2704 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
2705 BaseType_t xSendLength = 0;
2706 uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
2707 uint8_t *pucRecvData;
2708 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
2710 /* uxOptionsLength: the size of the options to be sent (always a multiple of
2712 1. in the SYN phase, we shall communicate the MSS
2713 2. in case of a SACK, Selective ACK, ack a segment which comes in
2715 UBaseType_t uxOptionsLength = 0u;
2716 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
2717 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
2719 /* First get the length and the position of the received data, if any.
2720 pucRecvData will point to the first byte of the TCP payload. */
2721 ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
2723 if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
2725 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
2727 /* This is most probably a keep-alive message from peer. Setting
2728 'bWinChange' doesn't cause a window-size-change, the flag is used
2729 here to force sending an immediate ACK. */
2730 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
2734 /* Keep track of the highest sequence number that might be expected within
2736 if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
2738 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
2741 /* Storing data may result in a fatal error if malloc() fails. */
2742 if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
2748 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
2750 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
2752 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
2754 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
2755 'SYN+ACK' didn't arrive. Step back to the previous state in which
2756 a first incoming SYN is handled. The SYN was counted already so
2757 decrease it first. */
2758 vTCPStateChange( pxSocket, eSYN_FIRST );
2761 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
2763 /* It's the first time a FIN has been received, remember its
2765 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
2766 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
2768 /* Was peer the first one to send a FIN? */
2769 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
2771 /* If so, don't send the-last-ACK. */
2772 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
2776 switch (pxSocket->u.xTCP.ucTCPState)
2778 case eCLOSED: /* (server + client) no connection state at all. */
2779 /* Nothing to do for a closed socket, except waiting for the
2783 case eTCP_LISTEN: /* (server) waiting for a connection request from
2784 any remote TCP and port. */
2785 /* The listen state was handled in xProcessReceivedTCPPacket().
2786 Should not come here. */
2789 case eSYN_FIRST: /* (server) Just received a SYN request for a server
2792 /* A new socket has been created, reply with a SYN+ACK.
2793 Acknowledge with seq+1 because the SYN is seen as pseudo data
2795 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
2796 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
2798 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
2800 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
2801 uxOptionsLength is a multiple of 4. The complete expression is:
2802 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
2803 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
2804 vTCPStateChange( pxSocket, eSYN_RECEIVED );
2806 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
2807 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
2811 case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
2812 SYN, expect a SYN+ACK and send a ACK now. */
2814 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
2815 expect a ACK and do nothing. */
2816 xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
2819 case eESTABLISHED: /* (server + client) an open connection, data
2820 received can be delivered to the user. The normal
2821 state for the data transfer phase of the connection
2822 The closing states are also handled here with the
2823 use of some flags. */
2824 xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
2827 case eLAST_ACK: /* (server + client) waiting for an acknowledgement
2828 of the connection termination request previously
2829 sent to the remote TCP (which includes an
2830 acknowledgement of its connection termination
2833 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
2834 * or an acknowledgement of the connection termination request previously sent. */
2836 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
2837 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
2840 case eCLOSE_WAIT: /* (server + client) waiting for a connection
2841 termination request from the local user. Nothing to
2842 do, connection is closed, wait for owner to close
2846 case eCLOSING: /* (server + client) waiting for a connection
2847 termination request acknowledgement from the remote
2851 case eTIME_WAIT: /* (either server or client) waiting for enough time
2852 to pass to be sure the remote TCP received the
2853 acknowledgement of its connection termination
2854 request. [According to RFC 793 a connection can stay
2855 in TIME-WAIT for a maximum of four minutes known as
2856 a MSL (maximum segment lifetime).] These states are
2857 implemented implicitly by settings flags like
2858 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
2865 if( xSendLength > 0 )
2867 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
2872 /*-----------------------------------------------------------*/
2874 static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,
2875 uint8_t ucTCPFlags )
2877 #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
2879 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );
2880 const BaseType_t xSendLength = ( BaseType_t )
2881 ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
2883 pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags;
2884 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
2886 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE );
2888 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
2890 /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
2891 ( void )pxNetworkBuffer;
2894 /* The packet was not consumed. */
2897 /*-----------------------------------------------------------*/
2899 static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer )
2901 return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK );
2903 /*-----------------------------------------------------------*/
2905 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
2907 return prvTCPSendSpecialPacketHelper( pxNetworkBuffer,
2908 ipTCP_FLAG_ACK | ipTCP_FLAG_RST );
2910 /*-----------------------------------------------------------*/
2912 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
2914 uint32_t ulMSS = ipconfigTCP_MSS;
2916 if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
2918 /* Data for this peer will pass through a router, and maybe through
2919 the internet. Limit the MSS to 1400 bytes or less. */
2920 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
2923 FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
2925 pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
2927 /*-----------------------------------------------------------*/
2930 * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
2931 * xProcessReceivedTCPPacket()
2932 * prvTCPHandleState()
2933 * prvTCPPrepareSend()
2934 * prvTCPReturnPacket()
2935 * xNetworkInterfaceOutput() // Sends data to the NIC
2936 * prvTCPSendRepeated()
2937 * prvTCPReturnPacket() // Prepare for returning
2938 * xNetworkInterfaceOutput() // Sends data to the NIC
2940 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
2942 FreeRTOS_Socket_t *pxSocket;
2943 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
2944 uint16_t ucTCPFlags;
2946 uint16_t xLocalPort;
2947 uint32_t ulRemoteIP;
2948 uint16_t xRemotePort;
2949 uint32_t ulSequenceNumber;
2950 uint32_t ulAckNumber;
2951 BaseType_t xResult = pdPASS;
2952 configASSERT(pxNetworkBuffer);
2953 configASSERT(pxNetworkBuffer->pucEthernetBuffer);
2955 /* Check for a minimum packet size. */
2956 if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) )
2958 ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
2959 ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
2960 xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
2961 ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
2962 xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
2963 ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
2964 ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr );
2966 /* Find the destination socket, and if not found: return a socket listing to
2967 the destination PORT. */
2968 pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
2975 if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
2977 /* A TCP messages is received but either there is no socket with the
2978 given port number or the there is a socket, but it is in one of these
2979 non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
2982 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
2984 /* Send a RST to all packets that can not be handled. As a result
2985 the other party will get a ECONN error. There are two exceptions:
2986 1) A packet that already has the RST flag set.
2987 2) A packet that only has the ACK flag set.
2988 A packet with only the ACK flag set might be the last ACK in
2989 a three-way hand-shake that closes a connection. */
2990 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
2991 ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
2993 prvTCPSendReset( pxNetworkBuffer );
2996 /* The packet can't be handled. */
3001 pxSocket->u.xTCP.ucRepCount = 0u;
3003 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
3005 /* The matching socket is in a listening state. Test if the peer
3006 has set the SYN flag. */
3007 if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
3009 /* What happens: maybe after a reboot, a client doesn't know the
3010 connection had gone. Send a RST in order to get a new connect
3012 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
3014 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
3015 prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
3017 #endif /* ipconfigHAS_DEBUG_PRINTF */
3019 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
3021 prvTCPSendReset( pxNetworkBuffer );
3027 /* prvHandleListen() will either return a newly created socket
3028 (if bReuseSocket is false), otherwise it returns the current
3029 socket which will later get connected. */
3030 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
3032 if( pxSocket == NULL )
3037 } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
3040 /* This is not a socket in listening mode. Check for the RST
3042 if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
3044 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
3046 /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */
3047 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
3049 /* Per the above RFC, "In the SYN-SENT state ... the RST is
3050 acceptable if the ACK field acknowledges the SYN." */
3051 if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 )
3053 vTCPStateChange( pxSocket, eCLOSED );
3058 /* Check whether the packet matches the next expected sequence number. */
3059 if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber )
3061 vTCPStateChange( pxSocket, eCLOSED );
3063 /* Otherwise, check whether the packet is within the receive window. */
3064 else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber &&
3065 ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber +
3066 pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) )
3068 /* Send a challenge ACK. */
3069 prvTCPSendChallengeAck( pxNetworkBuffer );
3073 /* Otherwise, do nothing. In any case, the packet cannot be handled. */
3076 else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
3078 /* SYN flag while this socket is already connected. */
3079 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
3081 /* The packet cannot be handled. */
3086 /* Update the copy of the TCP header only (skipping eth and IP
3087 headers). It might be used later on, whenever data must be sent
3089 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
3090 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
3095 if( xResult != pdFAIL )
3097 /* Touch the alive timers because we received a message for this
3099 prvTCPTouchSocket( pxSocket );
3101 /* Parse the TCP option(s), if present. */
3102 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
3103 then we MUST assume an MSS size of 536 bytes for backward compatibility. */
3105 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
3106 the number 5 (words) in the higher niblle of the TCP-offset byte. */
3107 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
3109 prvCheckOptions( pxSocket, pxNetworkBuffer );
3113 #if( ipconfigUSE_TCP_WIN == 1 )
3115 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
3116 pxSocket->u.xTCP.ulWindowSize =
3117 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
3121 /* In prvTCPHandleState() the incoming messages will be handled
3122 depending on the current state of the connection. */
3123 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
3125 /* prvTCPHandleState() has sent a message, see if there are more to
3127 #if( ipconfigUSE_TCP_WIN == 1 )
3129 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
3131 #endif /* ipconfigUSE_TCP_WIN */
3134 if( pxNetworkBuffer != NULL )
3136 /* We must check if the buffer is unequal to NULL, because the
3137 socket might keep a reference to it in case a delayed ACK must be
3139 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
3140 pxNetworkBuffer = NULL;
3143 /* And finally, calculate when this socket wants to be woken up. */
3144 prvTCPNextTimeout ( pxSocket );
3145 /* Return pdPASS to tell that the network buffer is 'consumed'. */
3149 /* pdPASS being returned means the buffer has been consumed. */
3152 /*-----------------------------------------------------------*/
3154 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
3156 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
3157 FreeRTOS_Socket_t *pxReturn = NULL;
3158 uint32_t ulInitialSequenceNumber;
3160 /* Assume that a new Initial Sequence Number will be required. Request
3161 it now in order to fail out if necessary. */
3162 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
3163 pxSocket->usLocalPort,
3164 pxTCPPacket->xIPHeader.ulSourceIPAddress,
3165 pxTCPPacket->xTCPHeader.usSourcePort );
3167 /* A pure SYN (without ACK) has come in, create a new socket to answer
3169 if( 0 != ulInitialSequenceNumber )
3171 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
3173 /* The flag bReuseSocket indicates that the same instance of the
3174 listening socket should be used for the connection. */
3175 pxReturn = pxSocket;
3176 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
3177 pxSocket->u.xTCP.pxPeerSocket = pxSocket;
3181 /* The socket does not have the bReuseSocket flag set meaning create a
3182 new socket when a connection comes in. */
3185 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
3187 FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
3188 pxSocket->usLocalPort,
3189 pxSocket->u.xTCP.usChildCount,
3190 pxSocket->u.xTCP.usBacklog,
3191 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
3192 prvTCPSendReset( pxNetworkBuffer );
3196 FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * )
3197 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
3199 if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
3201 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
3202 prvTCPSendReset( pxNetworkBuffer );
3204 else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
3206 /* The socket will be connected immediately, no time for the
3207 owner to setsockopt's, therefore copy properties of the server
3208 socket to the new socket. Only the binding might fail (due to
3209 lack of resources). */
3210 pxReturn = pxNewSocket;
3216 if( ( 0 != ulInitialSequenceNumber ) && ( pxReturn != NULL ) )
3218 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
3219 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
3220 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
3222 /* Here is the SYN action. */
3223 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
3224 prvSocketSetMSS( pxReturn );
3226 prvTCPCreateWindow( pxReturn );
3228 vTCPStateChange( pxReturn, eSYN_FIRST );
3230 /* Make a copy of the header up to the TCP header. It is needed later
3231 on, whenever data must be sent to the peer. */
3232 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
3236 /*-----------------------------------------------------------*/
3239 * Duplicates a socket after a listening socket receives a connection.
3241 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
3243 struct freertos_sockaddr xAddress;
3245 pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
3246 pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
3247 pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
3248 pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
3249 pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
3250 pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
3251 pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
3252 pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
3253 pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
3255 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
3257 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
3259 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
3261 #if( ipconfigUSE_CALLBACKS == 1 )
3263 /* In case call-backs are used, copy them from parent to child. */
3264 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
3265 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
3266 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
3268 #endif /* ipconfigUSE_CALLBACKS */
3270 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
3272 /* Child socket of listening sockets will inherit the Socket Set
3273 Otherwise the owner has no chance of including it into the set. */
3274 if( pxSocket->pxSocketSet )
3276 pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
3277 pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
3280 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
3282 /* And bind it to the same local port as its parent. */
3283 xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
3284 xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
3286 #if( ipconfigTCP_HANG_PROTECTION == 1 )
3288 /* Only when there is anti-hanging protection, a socket may become an
3289 orphan temporarily. Once this socket is really connected, the owner of
3290 the server socket will be notified. */
3292 /* When bPassQueued is true, the socket is an orphan until it gets
3294 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
3295 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
3299 /* A reference to the new socket may be stored and the socket is marked
3302 /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to
3304 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
3305 if(pxSocket->u.xTCP.pxPeerSocket == NULL )
3307 pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
3312 pxSocket->u.xTCP.usChildCount++;
3314 FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
3315 pxSocket->usLocalPort,
3316 pxSocket->u.xTCP.usChildCount,
3317 pxSocket->u.xTCP.usBacklog,
3318 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
3320 /* Now bind the child socket to the same port as the listening socket. */
3321 if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
3323 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
3324 vSocketClose( pxNewSocket );
3330 /*-----------------------------------------------------------*/
3332 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
3334 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
3336 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
3338 ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
3340 return pcStateNames[ ulState ];
3343 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
3344 /*-----------------------------------------------------------*/
3347 * In the API accept(), the user asks is there is a new client? As API's can
3348 * not walk through the xBoundTCPSocketsList the IP-task will do this.
3350 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
3352 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
3353 ListItem_t *pxIterator;
3354 FreeRTOS_Socket_t *pxFound;
3355 BaseType_t xResult = pdFALSE;
3357 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
3359 for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
3360 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
3361 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
3363 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
3365 pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
3366 if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
3368 pxSocket->u.xTCP.pxPeerSocket = pxFound;
3369 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
3377 /*-----------------------------------------------------------*/
3379 #endif /* ipconfigUSE_TCP == 1 */
3381 /* Provide access to private members for testing. */
3382 #ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS
3383 #include "iot_freertos_tcp_test_access_tcp_define.h"
3386 /* Provide access to private members for verification. */
3387 #ifdef FREERTOS_TCP_ENABLE_VERIFICATION
3388 #include "aws_freertos_tcp_verification_access_tcp_define.h"