2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
60 * Module which handles the TCP connections for FreeRTOS+TCP.
\r
61 * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
\r
64 * Endianness: in this module all ports and IP addresses are stored in
\r
65 * host byte-order, except fields in the IP-packets
\r
68 /* Standard includes. */
\r
72 /* FreeRTOS includes. */
\r
73 #include "FreeRTOS.h"
\r
78 /* FreeRTOS+TCP includes. */
\r
79 #include "FreeRTOS_IP.h"
\r
80 #include "FreeRTOS_Sockets.h"
\r
81 #include "FreeRTOS_IP_Private.h"
\r
82 #include "FreeRTOS_UDP_IP.h"
\r
83 #include "FreeRTOS_TCP_IP.h"
\r
84 #include "FreeRTOS_DHCP.h"
\r
85 #include "NetworkInterface.h"
\r
86 #include "NetworkBufferManagement.h"
\r
87 #include "FreeRTOS_ARP.h"
\r
88 #include "FreeRTOS_TCP_WIN.h"
\r
91 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
\r
92 #if ipconfigUSE_TCP == 1
\r
94 /* This compile-time test was moved to here because some macro's
\r
95 were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether
\r
96 the defined MTU size can contain at ;east a complete TCP packet. */
\r
98 #if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )
\r
99 #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.
\r
103 * The meaning of the TCP flags:
\r
105 #define ipTCP_FLAG_FIN 0x0001u /* No more data from sender */
\r
106 #define ipTCP_FLAG_SYN 0x0002u /* Synchronize sequence numbers */
\r
107 #define ipTCP_FLAG_RST 0x0004u /* Reset the connection */
\r
108 #define ipTCP_FLAG_PSH 0x0008u /* Push function: please push buffered data to the recv application */
\r
109 #define ipTCP_FLAG_ACK 0x0010u /* Acknowledgment field is significant */
\r
110 #define ipTCP_FLAG_URG 0x0020u /* Urgent pointer field is significant */
\r
111 #define ipTCP_FLAG_ECN 0x0040u /* ECN-Echo */
\r
112 #define ipTCP_FLAG_CWR 0x0080u /* Congestion Window Reduced */
\r
113 #define ipTCP_FLAG_NS 0x0100u /* ECN-nonce concealment protection */
\r
114 #define ipTCP_FLAG_RSV 0x0E00u /* Reserved, keep 0 */
\r
116 /* A mask to filter all protocol flags. */
\r
117 #define ipTCP_FLAG_CTRL 0x001Fu
\r
120 * A few values of the TCP options:
\r
122 #define TCP_OPT_END 0u /* End of TCP options list */
\r
123 #define TCP_OPT_NOOP 1u /* "No-operation" TCP option */
\r
124 #define TCP_OPT_MSS 2u /* Maximum segment size TCP option */
\r
125 #define TCP_OPT_WSOPT 3u /* TCP Window Scale Option (3-byte long) */
\r
126 #define TCP_OPT_SACK_P 4u /* Advertize that SACK is permitted */
\r
127 #define TCP_OPT_SACK_A 5u /* SACK option with first/last */
\r
128 #define TCP_OPT_TIMESTAMP 8u /* Time-stamp option */
\r
130 #define TCP_OPT_MSS_LEN 4u /* Length of TCP MSS option. */
\r
131 #define TCP_OPT_WSOPT_LEN 3u /* Length of TCP WSOPT option. */
\r
133 #define TCP_OPT_TIMESTAMP_LEN 10 /* fixed length of the time-stamp option */
\r
135 #ifndef ipconfigTCP_ACK_EARLIER_PACKET
\r
136 #define ipconfigTCP_ACK_EARLIER_PACKET 1
\r
140 * The macro NOW_CONNECTED() is use to determine if the connection makes a
\r
141 * transition from connected to non-connected and vice versa.
\r
142 * NOW_CONNECTED() returns true when the status has one of these values:
\r
143 * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
\r
144 * Technically the connection status is closed earlier, but the library wants
\r
145 * to prevent that the socket will be deleted before the last ACK has been
\r
146 * and thus causing a 'RST' packet on either side.
\r
148 #define NOW_CONNECTED( status )\
\r
149 ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )
\r
152 * The highest 4 bits in the TCP offset byte indicate the total length of the
\r
153 * TCP header, divided by 4.
\r
155 #define VALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0u )
\r
158 * Acknowledgements to TCP data packets may be delayed as long as more is being expected.
\r
159 * A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to
\r
160 * gain performance.
\r
162 #define DELAYED_ACK_SHORT_DELAY_MS ( 2 )
\r
163 #define DELAYED_ACK_LONGER_DELAY_MS ( 20 )
\r
166 * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
\r
167 * an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced
\r
170 #define REDUCED_MSS_THROUGH_INTERNET ( 1400 )
\r
173 * Each time a new TCP connection is being made, a new Initial Sequence Number shall be used.
\r
174 * The variable 'ulNextInitialSequenceNumber' will be incremented with a recommended value
\r
177 #define INITIAL_SEQUENCE_NUMBER_INCREMENT ( 0x102UL )
\r
180 * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
181 * the number 5 (words) in the higher niblle of the TCP-offset byte.
\r
183 #define TCP_OFFSET_LENGTH_BITS ( 0xf0u )
\r
184 #define TCP_OFFSET_STANDARD_LENGTH ( 0x50u )
\r
187 * Each TCP socket is checked regularly to see if it can send data packets.
\r
188 * By default, the maximum number of packets sent during one check is limited to 8.
\r
189 * This amount may be further limited by setting the socket's TX window size.
\r
191 #if( !defined( SEND_REPEATED_COUNT ) )
\r
192 #define SEND_REPEATED_COUNT ( 8 )
\r
193 #endif /* !defined( SEND_REPEATED_COUNT ) */
\r
196 * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.
\r
197 * When a TCP timer expires, retries and keep-alive messages will be checked.
\r
199 #ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS
\r
200 #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000u
\r
204 * The names of the different TCP states may be useful in logging.
\r
206 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
207 static const char *pcStateNames[] = {
\r
222 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */
\r
225 * Returns true if the socket must be checked. Non-active sockets are waiting
\r
226 * for user action, either connect() or close().
\r
228 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );
\r
231 * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
\r
233 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );
\r
236 * Try to send a series of messages.
\r
238 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
\r
241 * Return or send a packet to the other party.
\r
243 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
244 uint32_t ulLen, BaseType_t xReleaseAfterSend );
\r
247 * Initialise the data structures which keep track of the TCP windowing system.
\r
249 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );
\r
252 * Let ARP look-up the MAC-address of the peer and initialise the first SYN
\r
255 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );
\r
257 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
259 * For logging and debugging: make a string showing the TCP flags.
\r
261 static const char *prvTCPFlagMeaning( UBaseType_t xFlags);
\r
262 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
265 * Parse the TCP option(s) received, if present.
\r
267 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
270 * Set the initial properties in the options fields, like the preferred
\r
271 * value of MSS and whether SACK allowed. Will be transmitted in the state
\r
274 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );
\r
277 * For anti-hang protection and TCP keep-alive messages. Called in two places:
\r
278 * after receiving a packet and after a state change. The socket's alive timer
\r
281 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );
\r
284 * Prepare an outgoing message, if anything has to be sent.
\r
286 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );
\r
289 * Calculate when this socket needs to be checked to do (re-)transmissions.
\r
291 static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );
\r
294 * The API FreeRTOS_send() adds data to the TX stream. Add
\r
295 * this data to the windowing system to it can be transmitted.
\r
297 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );
\r
300 * Called to handle the closure of a TCP connection.
\r
302 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
304 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
\r
305 static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader );
\r
309 * Called from prvTCPHandleState(). Find the TCP payload data and check and
\r
310 * return its length.
\r
312 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );
\r
315 * Called from prvTCPHandleState(). Check if the payload data may be accepted.
\r
316 * If so, it will be added to the socket's reception queue.
\r
318 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
319 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );
\r
322 * Set the TCP options (if any) for the outgoing packet.
\r
324 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
327 * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
\r
330 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
331 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
\r
334 * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
\r
336 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
337 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
\r
340 * Called from prvTCPHandleState(). There is data to be sent.
\r
341 * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
\r
342 * be checked if it would better be postponed for efficiency.
\r
344 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
345 uint32_t ulReceiveLength, BaseType_t xSendLength );
\r
348 * The heart of all: check incoming packet for valid data and acks and do what
\r
349 * is necessary in each state.
\r
351 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
\r
354 * Reply to a peer with the RST flag on, in case a packet can not be handled.
\r
356 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
359 * Set the initial value for MSS (Maximum Segment Size) to be used.
\r
361 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
\r
364 * Return either a newly created socket, or the current socket in a connected
\r
365 * state (depends on the 'bReuseSocket' flag).
\r
367 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
370 * After a listening socket receives a new connection, it may duplicate itself.
\r
371 * The copying takes place in prvTCPSocketCopy.
\r
373 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
\r
376 * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
\r
377 * state for too long. If so, the socket will be closed, and -1 will be
\r
380 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
381 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
\r
384 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
385 int32_t lDataLen, UBaseType_t uxOptionsLength );
\r
387 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
388 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
\r
391 #if( ipconfigUSE_TCP_WIN != 0 )
\r
392 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
\r
395 /*-----------------------------------------------------------*/
\r
397 /* Initial Sequence Number, i.e. the next initial sequence number that will be
\r
398 used when a new connection is opened. The value should be randomized to prevent
\r
399 attacks from outside (spoofing). */
\r
400 uint32_t ulNextInitialSequenceNumber = 0ul;
\r
402 /*-----------------------------------------------------------*/
\r
404 /* prvTCPSocketIsActive() returns true if the socket must be checked.
\r
405 * Non-active sockets are waiting for user action, either connect()
\r
407 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
\r
421 /*-----------------------------------------------------------*/
\r
423 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
425 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
\r
427 BaseType_t xResult;
\r
428 switch( pxSocket->u.xTCP.ucTCPState )
\r
431 /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
\r
432 state ESTABLISHED can be protected using keep-alive messages. */
\r
438 /* These 3 states may last for ever, up to the owner. */
\r
442 /* All other (non-connected) states will get anti-hanging
\r
447 if( xResult != pdFALSE )
\r
449 /* How much time has past since the last active moment which is
\r
450 defined as A) a state change or B) a packet has arrived. */
\r
451 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
\r
453 /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
\r
454 if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
\r
456 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
458 FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
\r
459 pxSocket->usLocalPort,
\r
460 pxSocket->u.xTCP.ulRemoteIP,
\r
461 pxSocket->u.xTCP.usRemotePort,
\r
462 FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
\r
464 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
466 /* Move to eCLOSE_WAIT, user may close the socket. */
\r
467 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
469 /* When 'bPassQueued' true, this socket is an orphan until it
\r
471 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
473 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
475 /* As it did not get connected, and the user can never
\r
476 accept() it anymore, it will be deleted now. Called from
\r
477 the IP-task, so it's safe to call the internal Close
\r
478 function: vSocketClose(). */
\r
479 vSocketClose( pxSocket );
\r
481 /* Return a negative value to tell to inform the caller
\r
483 that the socket got closed and may not be accessed anymore. */
\r
490 /*-----------------------------------------------------------*/
\r
495 * As soon as a TCP socket timer expires, this function xTCPSocketCheck
\r
496 * will be called (from xTCPTimerCheck)
\r
497 * It can send a delayed ACK or new data
\r
498 * Sequence of calling (normally) :
\r
500 * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
\r
501 * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
\r
502 * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
\r
503 * prvTCPSendRepeated() // Send at most 8 messages on a row
\r
504 * prvTCPReturnPacket() // Prepare for returning
\r
505 * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
\r
507 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
\r
509 BaseType_t xResult = 0;
\r
510 BaseType_t xReady = pdFALSE;
\r
512 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
\r
514 /* The API FreeRTOS_send() might have added data to the TX stream. Add
\r
515 this data to the windowing system so it can be transmitted. */
\r
516 prvTCPAddTxData( pxSocket );
\r
519 #if( ipconfigUSE_TCP_WIN == 1 )
\r
521 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
523 /* The first task of this regular socket check is to send-out delayed
\r
525 if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
\r
527 /* Earlier data was received but not yet acknowledged. This
\r
528 function is called when the TCP timer for the socket expires, the
\r
529 ACK may be sent now. */
\r
530 if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
\r
532 if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
\r
534 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
\r
535 pxSocket->usLocalPort,
\r
536 pxSocket->u.xTCP.usRemotePort,
\r
537 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
538 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
\r
539 ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
\r
542 prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
\r
544 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
546 /* The ownership has been passed to the SEND routine,
\r
547 clear the pointer to it. */
\r
548 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
550 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
552 if( prvTCPNextTimeout( pxSocket ) > 1 )
\r
554 /* Tell the code below that this function is ready. */
\r
560 /* The user wants to perform an active shutdown(), skip sending
\r
561 the delayed ACK. The function prvTCPSendPacket() will send the
\r
562 FIN along with the ACK's. */
\r
565 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
567 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
568 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
572 #endif /* ipconfigUSE_TCP_WIN */
\r
574 if( xReady == pdFALSE )
\r
576 /* The second task of this regular socket check is sending out data. */
\r
577 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
\r
578 ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
\r
580 prvTCPSendPacket( pxSocket );
\r
583 /* Set the time-out for the next wakeup for this socket. */
\r
584 prvTCPNextTimeout( pxSocket );
\r
586 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
588 /* In all (non-connected) states in which keep-alive messages can not be sent
\r
589 the anti-hang protocol will close sockets that are 'hanging'. */
\r
590 xResult = prvTCPStatusAgeCheck( pxSocket );
\r
597 /*-----------------------------------------------------------*/
\r
600 * prvTCPSendPacket() will be called when the socket time-out has been reached.
\r
601 * It is only called by xTCPSocketCheck().
\r
603 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
\r
605 int32_t lResult = 0;
\r
606 UBaseType_t uxOptionsLength;
\r
607 TCPPacket_t *pxTCPPacket;
\r
608 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
610 if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
\r
612 /* The connection is in a state other than SYN. */
\r
613 pxNetworkBuffer = NULL;
\r
615 /* prvTCPSendRepeated() will only create a network buffer if necessary,
\r
616 i.e. when data must be sent to the peer. */
\r
617 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
619 if( pxNetworkBuffer != NULL )
\r
621 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
626 if( pxSocket->u.xTCP.ucRepCount >= 3u )
\r
628 /* The connection is in the SYN status. The packet will be repeated
\r
629 to most 3 times. When there is no response, the socket get the
\r
630 status 'eCLOSE_WAIT'. */
\r
631 FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
\r
632 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
633 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
634 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
636 else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
\r
638 /* Or else, if the connection has been prepared, or can be prepared
\r
639 now, proceed to send the packet with the SYN flag.
\r
640 prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
\r
641 the Ethernet address of the peer or the gateway is found. */
\r
642 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
644 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
\r
646 /* When TCP time stamps are enabled, but they will only be applied
\r
647 if the peer is outside the netmask, usually on the internet.
\r
648 Packages sent on a LAN are usually too big to carry time stamps. */
\r
649 if( ( ( pxSocket->u.xTCP.ulRemoteIP ^ FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ) & xNetworkAddressing.ulNetMask ) != 0ul )
\r
651 pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;
\r
656 /* About to send a SYN packet. Call prvSetSynAckOptions() to set
\r
657 the proper options: The size of MSS and whether SACK's are
\r
659 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
661 /* Return the number of bytes to be sent. */
\r
662 lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
664 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
665 uxOptionsLength is always a multiple of 4. The complete expression
\r
667 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
668 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
670 /* Repeat Count is used for a connecting socket, to limit the number
\r
672 pxSocket->u.xTCP.ucRepCount++;
\r
674 /* Send the SYN message to make a connection. The messages is
\r
675 stored in the socket field 'xPacket'. It will be wrapped in a
\r
676 pseudo network buffer descriptor before it will be sent. */
\r
677 prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
\r
681 /* Return the total number of bytes sent. */
\r
684 /*-----------------------------------------------------------*/
\r
687 * prvTCPSendRepeated will try to send a series of messages, as long as there is
\r
688 * data to be sent and as long as the transmit window isn't full.
\r
690 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
692 UBaseType_t uxIndex;
\r
693 int32_t lResult = 0;
\r
694 UBaseType_t uxOptionsLength = 0u;
\r
695 int32_t xSendLength;
\r
697 for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
\r
699 /* prvTCPPrepareSend() might allocate a network buffer if there is data
\r
701 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
702 if( xSendLength <= 0 )
\r
707 /* And return the packet to the peer. */
\r
708 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
710 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
712 *ppxNetworkBuffer = NULL;
\r
714 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
716 lResult += xSendLength;
\r
719 /* Return the total number of bytes sent. */
\r
722 /*-----------------------------------------------------------*/
\r
725 * Return (or send) a packet the the peer. The data is stored in pxBuffer,
\r
726 * which may either point to a real network buffer or to a TCP socket field
\r
727 * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
\r
728 * the data to the NIC.
\r
730 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
\r
732 TCPPacket_t * pxTCPPacket;
\r
733 IPHeader_t *pxIPHeader;
\r
734 EthernetHeader_t *pxEthernetHeader;
\r
735 uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
\r
736 TCPWindow_t *pxTCPWindow;
\r
737 NetworkBufferDescriptor_t xTempBuffer;
\r
738 /* For sending, a pseudo network buffer will be used, as explained above. */
\r
740 if( pxNetworkBuffer == NULL )
\r
742 memset( &xTempBuffer, '\0', sizeof( xTempBuffer ) );
\r
743 pxNetworkBuffer = &xTempBuffer;
\r
745 xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
746 xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
747 /* A pseudo network buffer can not be released. */
\r
748 xReleaseAfterSend = pdFALSE;
\r
751 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
753 if( xReleaseAfterSend == pdFALSE )
\r
755 pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
\r
756 if( pxNetworkBuffer == NULL )
\r
758 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
\r
760 xReleaseAfterSend = pdTRUE;
\r
763 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
765 if( pxNetworkBuffer != NULL )
\r
767 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
768 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
769 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
\r
771 /* Fill the packet, using hton translations. */
\r
772 if( pxSocket != NULL )
\r
774 /* Calculate the space in the RX buffer in order to advertise the
\r
775 size of this socket's reception window. */
\r
776 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
778 if( pxSocket->u.xTCP.rxStream != NULL )
\r
780 /* An RX stream was created already, see how much space is
\r
782 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
786 /* No RX stream has been created, the full stream size is
\r
788 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
791 /* Take the minimum of the RX buffer space and the RX window size. */
\r
792 ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );
\r
794 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
\r
796 /* The low-water mark was reached, meaning there was little
\r
797 space left. The socket will wait until the application has read
\r
798 or flushed the incoming data, and 'zero-window' will be
\r
803 /* If possible, advertise an RX window size of at least 1 MSS, otherwise
\r
804 the peer might start 'zero window probing', i.e. sending small packets
\r
805 (1, 2, 4, 8... bytes). */
\r
806 if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
\r
808 ulSpace = pxSocket->u.xTCP.usCurMSS;
\r
811 /* Avoid overflow of the 16-bit win field. */
\r
812 #if( ipconfigUSE_TCP_WIN != 0 )
\r
814 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
\r
818 ulWinSize = ulSpace;
\r
821 if( ulWinSize > 0xfffcUL )
\r
823 ulWinSize = 0xfffcUL;
\r
826 pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
\r
828 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
830 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
\r
832 if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
\r
834 size_t uxFrontSpace;
\r
836 if(pxSocket->u.xTCP.rxStream != NULL)
\r
838 uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
\r
845 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
\r
846 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
\r
847 pxSocket->u.xTCP.ulRemoteIP,
\r
848 pxSocket->u.xTCP.usRemotePort,
\r
849 pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
\r
850 (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
\r
854 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
856 /* The new window size has been advertised, switch off the flag. */
\r
857 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
\r
859 /* Later on, when deciding to delay an ACK, a precise estimate is needed
\r
860 of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
\r
861 highest sequence number minus 1 that the socket will accept. */
\r
862 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
\r
864 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
865 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
\r
867 /* Sending a keep-alive packet, send the current sequence number
\r
868 minus 1, which will be recognised as a keep-alive packet an
\r
869 responded to by acknowledging the last byte. */
\r
870 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
871 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
\r
873 pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
\r
874 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
879 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
\r
881 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
\r
883 /* Suppress FIN in case this packet carries earlier data to be
\r
885 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
\r
886 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
\r
888 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
\r
889 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
\r
890 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
892 pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
\r
897 /* Tell which sequence number is expected next time */
\r
898 pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
902 /* Sending data without a socket, probably replying with a RST flag
\r
903 Just swap the two sequence numbers. */
\r
904 vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
\r
907 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
908 pxIPHeader->usLength = FreeRTOS_htons( ulLen );
\r
909 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
\r
911 /* When pxSocket is NULL, this function is called by prvTCPSendReset()
\r
912 and the IP-addresses must be swapped.
\r
913 Also swap the IP-addresses in case the IP-tack doesn't have an
\r
914 IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
\r
915 ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
\r
919 ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
921 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
922 pxIPHeader->ulSourceIPAddress = ulSourceAddress;
\r
923 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
\r
925 /* Just an increasing number. */
\r
926 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
927 usPacketIdentifier++;
\r
928 pxIPHeader->usFragmentOffset = 0u;
\r
930 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
932 /* calculate the IP header checksum, in case the driver won't do that. */
\r
933 pxIPHeader->usHeaderChecksum = 0x00u;
\r
934 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
935 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
937 /* calculate the TCP checksum for an outgoing packet. */
\r
938 usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pdTRUE );
\r
940 /* A calculated checksum of 0 must be inverted as 0 means the checksum
\r
942 if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
\r
944 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
\r
949 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
951 pxNetworkBuffer->pxNextBuffer = NULL;
\r
955 /* Important: tell NIC driver how many bytes must be sent. */
\r
956 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
\r
958 /* Fill in the destination MAC addresses. */
\r
959 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
\r
960 sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
962 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
\r
963 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
965 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
967 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
971 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
973 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
975 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
981 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
\r
983 if( xReleaseAfterSend == pdFALSE )
\r
985 /* Swap-back some fields, as pxBuffer probably points to a socket field
\r
986 containing the packet header. */
\r
987 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
\r
988 pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
\r
989 memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
993 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
\r
995 } /* if( pxNetworkBuffer != NULL ) */
\r
997 /*-----------------------------------------------------------*/
\r
1000 * The SYN event is very important: the sequence numbers, which have a kind of
\r
1001 * random starting value, are being synchronised. The sliding window manager
\r
1002 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
\r
1003 * Size (MSS) in use.
\r
1005 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
\r
1007 if( xTCPWindowLoggingLevel )
\r
1008 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
\r
1009 pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
\r
1010 pxSocket->u.xTCP.uxLittleSpace ,
\r
1011 pxSocket->u.xTCP.uxEnoughSpace,
\r
1012 pxSocket->u.xTCP.uxRxStreamSize ) );
\r
1014 &pxSocket->u.xTCP.xTCPWindow,
\r
1015 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
\r
1016 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
\r
1017 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
\r
1018 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
\r
1019 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
\r
1021 /*-----------------------------------------------------------*/
\r
1024 * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
\r
1025 * the Ethernet address of the target will be found using ARP. In case the
\r
1026 * target IP address is not within the netmask, the hardware address of the
\r
1027 * gateway will be used.
\r
1029 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
\r
1031 TCPPacket_t *pxTCPPacket;
\r
1032 IPHeader_t *pxIPHeader;
\r
1033 eARPLookupResult_t eReturned;
\r
1034 uint32_t ulRemoteIP;
\r
1035 MACAddress_t xEthAddress;
\r
1036 BaseType_t xReturn = pdTRUE;
\r
1038 #if( ipconfigHAS_PRINTF != 0 )
\r
1040 /* Only necessary for nicer logging. */
\r
1041 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
\r
1043 #endif /* ipconfigHAS_PRINTF != 0 */
\r
1045 ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1047 /* Determine the ARP cache status for the requested IP address. */
\r
1048 eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
\r
1050 switch( eReturned )
\r
1052 case eARPCacheHit: /* An ARP table lookup found a valid entry. */
\r
1053 break; /* We can now prepare the SYN packet. */
\r
1054 case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
\r
1055 case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
\r
1057 /* Count the number of times it couldn't find the ARP address. */
\r
1058 pxSocket->u.xTCP.ucRepCount++;
\r
1060 FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
\r
1061 pxSocket->u.xTCP.ulRemoteIP,
\r
1062 FreeRTOS_htonl( ulRemoteIP ),
\r
1064 xEthAddress.ucBytes[ 0 ],
\r
1065 xEthAddress.ucBytes[ 1 ],
\r
1066 xEthAddress.ucBytes[ 2 ],
\r
1067 xEthAddress.ucBytes[ 3 ],
\r
1068 xEthAddress.ucBytes[ 4 ],
\r
1069 xEthAddress.ucBytes[ 5 ] ) );
\r
1071 /* And issue a (new) ARP request */
\r
1072 FreeRTOS_OutputARPRequest( ulRemoteIP );
\r
1074 xReturn = pdFALSE;
\r
1078 if( xReturn != pdFALSE )
\r
1080 /* The MAC-address of the peer (or gateway) has been found,
\r
1081 now prepare the initial TCP packet and some fields in the socket. */
\r
1082 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1083 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
1085 /* Reset the retry counter to zero... */
\r
1086 pxSocket->u.xTCP.ucRepCount = 0u;
\r
1088 /* ...and remember that the connect/SYN data are prepared. */
\r
1089 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
\r
1091 /* Now that the Ethernet address is known, the initial packet can be
\r
1093 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1095 /* Write the Ethernet address in Source, because it will be swapped by
\r
1096 prvTCPReturnPacket(). */
\r
1097 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
\r
1099 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
\r
1100 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
\r
1102 pxIPHeader->ucVersionHeaderLength = 0x45u;
\r
1103 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
\r
1104 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
1106 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
\r
1108 /* Addresses and ports will be stored swapped because prvTCPReturnPacket
\r
1109 will swap them back while replying. */
\r
1110 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1111 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1113 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
\r
1114 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
1116 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
\r
1117 isn't known yet. */
\r
1118 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
\r
1120 /* Start with ISN (Initial Sequence Number). */
\r
1121 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;
\r
1123 /* And increment it with 268 for the next new connection, which is
\r
1124 recommended value. */
\r
1125 ulNextInitialSequenceNumber += 0x102UL;
\r
1127 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
\r
1128 the high nibble of the TCP offset field. */
\r
1129 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
\r
1131 /* Only set the SYN flag. */
\r
1132 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
\r
1134 /* Set the values of usInitMSS / usCurMSS for this socket. */
\r
1135 prvSocketSetMSS( pxSocket );
\r
1137 /* For now this is also the advertised window size. */
\r
1138 pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;
\r
1140 /* The initial sequence numbers at our side are known. Later
\r
1141 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
\r
1142 first wait for a SYN+ACK reply. */
\r
1143 prvTCPCreateWindow( pxSocket );
\r
1148 /*-----------------------------------------------------------*/
\r
1150 /* For logging and debugging: make a string showing the TCP flags
\r
1152 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1154 static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
\r
1156 static char retString[10];
\r
1157 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
\r
1158 ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
\r
1159 ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
\r
1160 ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
\r
1161 ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
\r
1162 ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
\r
1163 ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
\r
1164 ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
\r
1165 ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
\r
1166 ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
\r
1169 /*-----------------------------------------------------------*/
\r
1171 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1174 * Parse the TCP option(s) received, if present. It has already been verified
\r
1175 * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
\r
1176 * is longer than the usual 20 (5 x 4) bytes.
\r
1178 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1180 TCPPacket_t * pxTCPPacket;
\r
1181 TCPHeader_t * pxTCPHeader;
\r
1182 const unsigned char *pucPtr;
\r
1183 const unsigned char *pucLast;
\r
1184 TCPWindow_t *pxTCPWindow;
\r
1185 UBaseType_t uxNewMSS;
\r
1187 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1188 pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1190 /* A character pointer to iterate through the option data */
\r
1191 pucPtr = pxTCPHeader->ucOptdata;
\r
1192 pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
\r
1193 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1195 /* The comparison with pucLast is only necessary in case the option data are
\r
1196 corrupted, we don't like to run into invalid memory and crash. */
\r
1197 while( pucPtr < pucLast )
\r
1199 if( pucPtr[ 0 ] == TCP_OPT_END )
\r
1201 /* End of options. */
\r
1204 if( pucPtr[ 0 ] == TCP_OPT_NOOP)
\r
1208 /* NOP option, inserted to make the length a multiple of 4. */
\r
1210 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1211 else if( ( pucPtr[ 0 ] == TCP_OPT_WSOPT ) && ( pucPtr[ 1 ] == TCP_OPT_WSOPT_LEN ) )
\r
1213 pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
\r
1214 pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
\r
1215 pucPtr += TCP_OPT_WSOPT_LEN;
\r
1217 #endif /* ipconfigUSE_TCP_WIN */
\r
1218 else if( ( pucPtr[ 0 ] == TCP_OPT_MSS ) && ( pucPtr[ 1 ] == TCP_OPT_MSS_LEN ) )
\r
1220 /* An MSS option with the correct option length. FreeRTOS_htons()
\r
1221 is not needed here because usChar2u16() already returns a host
\r
1223 uxNewMSS = usChar2u16( pucPtr + 2 );
\r
1225 if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
\r
1227 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
\r
1230 if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
\r
1232 /* our MSS was bigger than the MSS of the other party: adapt it. */
\r
1233 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
\r
1234 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )
\r
1236 /* The peer advertises a smaller MSS than this socket was
\r
1237 using. Use that as well. */
\r
1238 FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
\r
1239 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1241 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
\r
1242 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
\r
1243 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
\r
1244 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
\r
1245 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1248 #if( ipconfigUSE_TCP_WIN != 1 )
\r
1249 /* Without scaled windows, MSS is the only interesting option. */
\r
1252 /* Or else we continue to check another option: selective ACK. */
\r
1253 pucPtr += TCP_OPT_MSS_LEN;
\r
1254 #endif /* ipconfigUSE_TCP_WIN != 1 */
\r
1258 /* All other options have a length field, so that we easily
\r
1259 can skip past them. */
\r
1260 int len = ( int )pucPtr[ 1 ];
\r
1263 /* If the length field is zero, the options are malformed
\r
1264 and we don't process them further. */
\r
1268 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1270 /* Selective ACK: the peer has received a packet but it is missing earlier
\r
1271 packets. At least this packet does not need retransmission anymore
\r
1272 ulTCPWindowTxSack( ) takes care of this administration. */
\r
1273 if( pucPtr[0] == TCP_OPT_SACK_A )
\r
1280 uint32_t ulFirst = ulChar2u32( pucPtr );
\r
1281 uint32_t ulLast = ulChar2u32( pucPtr + 4 );
\r
1282 uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );
\r
1283 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
\r
1284 starting from the head position.
\r
1285 Advance the tail pointer in txStream. */
\r
1286 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
\r
1288 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
\r
1289 uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
\r
1290 pxSocket->xEventBits |= eSOCKET_SEND;
\r
1292 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
1294 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1296 /* The field 'xEventBits' is used to store regular socket events (at most 8),
\r
1297 as well as 'select events', which will be left-shifted */
\r
1298 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1303 /* In case the socket owner has installed an OnSent handler,
\r
1305 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1307 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
1309 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
1312 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
1317 /* len should be 0 by now. */
\r
1319 #if ipconfigUSE_TCP_TIMESTAMPS == 1
\r
1320 else if( pucPtr[0] == TCP_OPT_TIMESTAMP )
\r
1322 len -= 2; /* Skip option and length byte. */
\r
1324 pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;
\r
1325 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = ulChar2u32( pucPtr );
\r
1326 pxSocket->u.xTCP.xTCPWindow.tx.ulTimeStamp = ulChar2u32( pucPtr + 4 );
\r
1328 #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */
\r
1330 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1336 /*-----------------------------------------------------------*/
\r
1338 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1340 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
\r
1345 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
\r
1346 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
\r
1348 while( uxWinSize > 0xfffful )
\r
1350 /* Divide by two and increase the binary factor by 1. */
\r
1355 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
\r
1356 pxSocket->u.xTCP.uxRxWinSize,
\r
1357 pxSocket->u.xTCP.usInitMSS,
\r
1364 /*-----------------------------------------------------------*/
\r
1367 * When opening a TCP connection, while SYN's are being sent, the parties may
\r
1368 * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
\r
1369 * nett size of the payload, always smaller than MTU.
\r
1371 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
\r
1373 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1374 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
\r
1375 UBaseType_t uxOptionsLength;
\r
1377 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
\r
1379 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
\r
1380 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
\r
1381 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
\r
1382 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
\r
1384 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1386 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
\r
1388 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
\r
1389 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
\r
1390 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
\r
1391 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
\r
1392 uxOptionsLength = 8u;
\r
1396 uxOptionsLength = 4u;
\r
1400 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1402 return uxOptionsLength;
\r
1406 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
\r
1407 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
\r
1409 uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, &pxTCPPacket->xTCPHeader );
\r
1410 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1411 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = 2u;
\r
1412 uxOptionsLength += 2u;
\r
1417 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
\r
1418 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
\r
1419 pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1420 pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
\r
1421 uxOptionsLength += 4u;
\r
1423 return uxOptionsLength; /* bytes, not words. */
\r
1425 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1429 * For anti-hanging protection and TCP keep-alive messages. Called in two
\r
1430 * places: after receiving a packet and after a state change. The socket's
\r
1431 * alive timer may be reset.
\r
1433 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
\r
1435 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
1437 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
\r
1441 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
1443 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
\r
1444 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
1445 pxSocket->u.xTCP.ucKeepRepCount = 0u;
\r
1446 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
\r
1450 ( void ) pxSocket;
\r
1452 /*-----------------------------------------------------------*/
\r
1455 * Changing to a new state. Centralised here to do specific actions such as
\r
1456 * resetting the alive timer, calling the user's OnConnect handler to notify
\r
1457 * that a socket has got (dis)connected, and setting bit to unblock a call to
\r
1458 * FreeRTOS_select()
\r
1460 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
\r
1462 FreeRTOS_Socket_t *xParent = NULL;
\r
1463 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
\r
1464 BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
\r
1465 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1466 BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
\r
1468 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1469 FreeRTOS_Socket_t *xConnected = NULL;
\r
1472 /* Has the connected status changed? */
\r
1473 if( bBefore != bAfter )
\r
1475 /* Is the socket connected now ? */
\r
1476 if( bAfter != pdFALSE )
\r
1478 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
\r
1479 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
1481 /* Now that it is connected, find it's parent. */
\r
1482 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
1484 xParent = pxSocket;
\r
1488 xParent = pxSocket->u.xTCP.pxPeerSocket;
\r
1489 configASSERT( xParent != NULL );
\r
1491 if( xParent != NULL )
\r
1493 if( xParent->u.xTCP.pxPeerSocket == NULL )
\r
1495 xParent->u.xTCP.pxPeerSocket = pxSocket;
\r
1498 xParent->xEventBits |= eSOCKET_ACCEPT;
\r
1500 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1502 /* Library support FreeRTOS_select(). Receiving a new
\r
1503 connection is being translated as a READ event. */
\r
1504 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
\r
1506 xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
\r
1511 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1513 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
\r
1514 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
\r
1516 /* The listening socket does not become connected itself, in stead
\r
1517 a child socket is created.
\r
1518 Postpone a call the OnConnect event until the end of this function. */
\r
1519 xConnected = xParent;
\r
1525 /* Don't need to access the parent socket anymore, so the
\r
1526 reference 'pxPeerSocket' may be cleared. */
\r
1527 pxSocket->u.xTCP.pxPeerSocket = NULL;
\r
1528 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
\r
1530 /* When true, this socket may be returned in a call to accept(). */
\r
1531 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
1535 pxSocket->xEventBits |= eSOCKET_CONNECT;
\r
1537 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1539 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1541 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1547 else /* bAfter == pdFALSE, connection is closed. */
\r
1549 /* Notify/wake-up the socket-owner by setting a semaphore. */
\r
1550 pxSocket->xEventBits |= eSOCKET_CLOSED;
\r
1552 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1554 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
\r
1556 pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
\r
1561 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1563 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
\r
1565 /* The 'connected' state has changed, call the user handler. */
\r
1566 xConnected = pxSocket;
\r
1569 #endif /* ipconfigUSE_CALLBACKS */
\r
1571 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
\r
1573 /* Now the socket isn't in an active state anymore so it
\r
1574 won't need further attention of the IP-task.
\r
1575 Setting time-out to zero means that the socket won't get checked during
\r
1577 pxSocket->u.xTCP.usTimeout = 0u;
\r
1582 if( eTCPState == eCLOSED )
\r
1584 /* Socket goes to status eCLOSED because of a RST.
\r
1585 When nobody owns the socket yet, delete it. */
\r
1586 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
\r
1587 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
1589 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
\r
1590 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
1592 FreeRTOS_closesocket( pxSocket );
\r
1598 /* Fill in the new state. */
\r
1599 pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
\r
1601 /* Touch the alive timers because moving to another state. */
\r
1602 prvTCPTouchSocket( pxSocket );
\r
1604 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
1606 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
1607 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
\r
1608 pxSocket->usLocalPort,
\r
1609 pxSocket->u.xTCP.ulRemoteIP,
\r
1610 pxSocket->u.xTCP.usRemotePort,
\r
1611 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
\r
1612 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
\r
1614 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1616 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1618 if( xConnected != NULL )
\r
1620 /* The 'connected' state has changed, call the OnConnect handler of the parent. */
\r
1621 xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );
\r
1625 if( xParent != NULL )
\r
1627 vSocketWakeUpUser( xParent );
\r
1630 /*-----------------------------------------------------------*/
\r
1632 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
1633 int32_t lDataLen, UBaseType_t uxOptionsLength )
\r
1635 NetworkBufferDescriptor_t *pxReturn;
\r
1637 BaseType_t xResize;
\r
1639 if( xBufferAllocFixedSize != pdFALSE )
\r
1641 /* Network buffers are created with a fixed size and can hold the largest
\r
1643 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
\r
1644 /* and therefore, the buffer won't be too small.
\r
1645 Only ask for a new network buffer in case none was supplied. */
\r
1646 xResize = ( pxNetworkBuffer == NULL );
\r
1650 /* Network buffers are created with a variable size. See if it must
\r
1652 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
\r
1653 ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
\r
1654 /* In case we were called from a TCP timer event, a buffer must be
\r
1655 created. Otherwise, test 'xDataLength' of the provided buffer. */
\r
1656 if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) )
\r
1662 xResize = pdFALSE;
\r
1666 if( xResize != pdFALSE )
\r
1668 /* The caller didn't provide a network buffer or the provided buffer is
\r
1669 too small. As we must send-out a data packet, a buffer will be created
\r
1671 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
\r
1673 if( pxReturn != NULL )
\r
1675 /* Copy the existing data to the new created buffer. */
\r
1676 if( pxNetworkBuffer )
\r
1678 /* Either from the previous buffer... */
\r
1679 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
1681 /* ...and release it. */
\r
1682 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1686 /* Or from the socket field 'xTCP.xPacket'. */
\r
1687 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1693 /* xResize is false, the network buffer provided was big enough. */
\r
1694 pxReturn = pxNetworkBuffer;
\r
1696 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
\r
1697 xDataLength member must get the correct length too! */
\r
1698 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
\r
1703 /*-----------------------------------------------------------*/
\r
1706 * Prepare an outgoing message, in case anything has to be sent.
\r
1708 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
\r
1711 uint8_t *pucEthernetBuffer, *pucSendData;
\r
1712 TCPPacket_t *pxTCPPacket;
\r
1714 uint32_t ulDataGot, ulDistance;
\r
1715 TCPWindow_t *pxTCPWindow;
\r
1716 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1717 int32_t lStreamPos;
\r
1719 if( ( *ppxNetworkBuffer ) != NULL )
\r
1721 /* A network buffer descriptor was already supplied */
\r
1722 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
\r
1726 /* For now let it point to the last packet header */
\r
1727 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1730 pxTCPPacket = ( TCPPacket_t * ) pucEthernetBuffer;
\r
1731 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
1734 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
\r
1736 if( pxSocket->u.xTCP.txStream != NULL )
\r
1738 /* ulTCPWindowTxGet will return the amount of data which may be sent
\r
1739 along with the position in the txStream.
\r
1740 Why check for MSS > 1 ?
\r
1741 Because some TCP-stacks (like uIP) use it for flow-control. */
\r
1742 if( pxSocket->u.xTCP.usCurMSS > 1u )
\r
1744 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
\r
1747 if( lDataLen > 0 )
\r
1749 /* Check if the current network buffer is big enough, if not,
\r
1751 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
\r
1753 if( pxNewBuffer != NULL )
\r
1755 *ppxNetworkBuffer = pxNewBuffer;
\r
1756 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
\r
1757 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1759 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
\r
1761 /* Translate the position in txStream to an offset from the tail
\r
1763 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
\r
1765 /* Here data is copied from the txStream in 'peek' mode. Only
\r
1766 when the packets are acked, the tail marker will be updated. */
\r
1767 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
\r
1769 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1771 if( ulDataGot != ( uint32_t ) lDataLen )
\r
1773 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
\r
1774 lStreamPos, uxOffset, ulDataGot, lDataLen ) );
\r
1779 /* If the owner of the socket requests a closure, add the FIN
\r
1780 flag to the last packet. */
\r
1781 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
\r
1783 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
\r
1785 if( ulDistance == ulDataGot )
\r
1787 #if (ipconfigHAS_DEBUG_PRINTF == 1)
\r
1789 /* the order of volatile accesses is undefined
\r
1790 so such workaround */
\r
1791 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
\r
1792 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
\r
1793 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
\r
1795 FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
\r
1796 uxTail, uxMid, uxHead ) );
\r
1799 /* Although the socket sends a FIN, it will stay in
\r
1800 ESTABLISHED until all current data has been received or
\r
1802 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1803 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
\r
1804 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1815 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
\r
1817 /* See if the socket owner wants to shutdown this connection. */
\r
1818 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
\r
1819 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
\r
1821 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
\r
1822 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1823 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1824 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
1825 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1826 vTCPStateChange( pxSocket, eFIN_WAIT_1 );
\r
1829 #if( ipconfigTCP_KEEP_ALIVE != 0 )
\r
1831 if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
\r
1833 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
\r
1834 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
1835 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
1836 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
1839 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
\r
1841 /* If there is no data to be sent, and no window-update message,
\r
1842 we might want to send a keep-alive message. */
\r
1843 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
\r
1845 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
\r
1846 if( pxSocket->u.xTCP.ucKeepRepCount )
\r
1848 xMax = ( 3u * configTICK_RATE_HZ );
\r
1852 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
\r
1853 if( xTCPWindowLoggingLevel )
\r
1854 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
\r
1855 pxSocket->u.xTCP.ulRemoteIP,
\r
1856 pxSocket->u.xTCP.usRemotePort,
\r
1857 pxSocket->u.xTCP.ucKeepRepCount ) );
\r
1858 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
\r
1859 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
\r
1860 pxSocket->u.xTCP.ucKeepRepCount++;
\r
1864 #endif /* ipconfigTCP_KEEP_ALIVE */
\r
1867 /* Anything to send, a change of the advertised window size, or maybe send a
\r
1868 keep-alive message? */
\r
1869 if( ( lDataLen > 0 ) ||
\r
1870 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
\r
1871 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
\r
1873 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
\r
1874 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
1876 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
\r
1878 if( lDataLen != 0l )
\r
1880 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
\r
1883 #if ipconfigUSE_TCP_TIMESTAMPS == 1
\r
1885 if( uxOptionsLength == 0u )
\r
1887 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
\r
1889 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1890 uxOptionsLength = prvTCPSetTimeStamp( 0, pxSocket, &pxTCPPacket->xTCPHeader );
\r
1896 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
1901 /*-----------------------------------------------------------*/
\r
1904 * Calculate after how much time this socket needs to be checked again.
\r
1906 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
\r
1908 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1910 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
1912 /* The socket is actively connecting to a peer. */
\r
1913 if( pxSocket->u.xTCP.bits.bConnPrepared )
\r
1915 /* Ethernet address has been found, use progressive timeout for
\r
1916 active connect(). */
\r
1917 if( pxSocket->u.xTCP.ucRepCount < 3u )
\r
1919 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
\r
1923 ulDelayMs = 11000UL;
\r
1928 /* Still in the ARP phase: check every half second. */
\r
1929 ulDelayMs = 500UL;
\r
1932 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
\r
1933 pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
\r
1934 pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
\r
1935 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1937 else if( pxSocket->u.xTCP.usTimeout == 0u )
\r
1939 /* Let the sliding window mechanism decide what time-out is appropriate. */
\r
1940 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
\r
1941 if( ulDelayMs == 0u )
\r
1943 if( xResult != ( BaseType_t )0 )
\r
1949 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1954 /* ulDelayMs contains the time to wait before a re-transmission. */
\r
1956 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1960 /* field '.usTimeout' has already been set (by the
\r
1961 keep-alive/delayed-ACK mechanism). */
\r
1964 /* Return the number of clock ticks before the timer expires. */
\r
1965 return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
\r
1967 /*-----------------------------------------------------------*/
\r
1969 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
\r
1971 int32_t lCount, lLength;
\r
1973 /* A txStream has been created already, see if the socket has new data for
\r
1974 the sliding window.
\r
1976 uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It
\r
1977 contains new Tx data which has not been passed to the sliding window yet.
\r
1978 The oldest data not-yet-confirmed can be found at rxTail. */
\r
1979 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
\r
1983 /* All data between txMid and rxHead will now be passed to the sliding
\r
1984 window manager, so it can start transmitting them.
\r
1986 Hand over the new data to the sliding window handler. It will be
\r
1987 split-up in chunks of 1460 bytes each (or less, depending on
\r
1988 ipconfigTCP_MSS). */
\r
1989 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
\r
1990 ( uint32_t ) lLength,
\r
1991 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
\r
1992 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
\r
1994 /* Move the rxMid pointer forward up to rxHead. */
\r
1997 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
\r
2001 /*-----------------------------------------------------------*/
\r
2004 * prvTCPHandleFin() will be called to handle socket closure
\r
2005 * The Closure starts when either a FIN has been received and accepted,
\r
2006 * Or when the socket has sent a FIN flag to the peer
\r
2007 * Before being called, it has been checked that both reception and transmission
\r
2010 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2012 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2013 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2014 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2015 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2016 BaseType_t xSendLength = 0;
\r
2017 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
\r
2019 if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
\r
2021 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
\r
2023 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2025 /* We haven't yet replied with a FIN, do so now. */
\r
2026 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2027 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
2031 /* We did send a FIN already, see if it's ACK'd. */
\r
2032 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
\r
2034 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
\r
2038 if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
\r
2040 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2041 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
\r
2043 /* And wait for the final ACK. */
\r
2044 vTCPStateChange( pxSocket, eLAST_ACK );
\r
2048 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
\r
2049 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
\r
2050 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
\r
2052 /* We have sent out a FIN but the peer hasn't replied with a FIN
\r
2053 yet. Do nothing for the moment. */
\r
2054 pxTCPHeader->ucTCPFlags = 0u;
\r
2058 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
\r
2060 /* This is the third of the three-way hand shake: the last
\r
2062 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2066 /* The other party started the closure, so we just wait for the
\r
2068 pxTCPHeader->ucTCPFlags = 0u;
\r
2071 /* And wait for the user to close this socket. */
\r
2072 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2076 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2078 if( pxTCPHeader->ucTCPFlags != 0u )
\r
2080 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
\r
2083 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
\r
2085 if( xTCPWindowLoggingLevel != 0 )
\r
2087 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
\r
2088 ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2089 pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2090 pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2091 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2092 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2095 return xSendLength;
\r
2097 /*-----------------------------------------------------------*/
\r
2099 #if ipconfigUSE_TCP_TIMESTAMPS == 1
\r
2101 static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader )
\r
2103 uint32_t ulTimes[2];
\r
2104 uint8_t *ucOptdata = &( pxTCPHeader->ucOptdata[ lOffset ] );
\r
2106 ulTimes[0] = ( xTaskGetTickCount ( ) * 1000u ) / configTICK_RATE_HZ;
\r
2107 ulTimes[0] = FreeRTOS_htonl( ulTimes[0] );
\r
2108 ulTimes[1] = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp );
\r
2109 ucOptdata[0] = ( uint8_t ) TCP_OPT_TIMESTAMP;
\r
2110 ucOptdata[1] = ( uint8_t ) TCP_OPT_TIMESTAMP_LEN;
\r
2111 memcpy( &(ucOptdata[2] ), ulTimes, 8u );
\r
2112 ucOptdata[10] = ( uint8_t ) TCP_OPT_NOOP;
\r
2113 ucOptdata[11] = ( uint8_t ) TCP_OPT_NOOP;
\r
2114 /* Do not return the same timestamps 2 times. */
\r
2115 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = 0ul;
\r
2120 /*-----------------------------------------------------------*/
\r
2123 * prvCheckRxData(): called from prvTCPHandleState()
\r
2125 * The first thing that will be done is find the TCP payload data
\r
2126 * and check the length of this data.
\r
2128 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
\r
2130 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2131 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2132 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
\r
2134 /* Determine the length and the offset of the user-data sent to this
\r
2137 The size of the TCP header is given in a multiple of 4-byte words (single
\r
2138 byte, needs no ntoh() translation). A shift-right 2: is the same as
\r
2139 (offset >> 4) * 4. */
\r
2140 lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
\r
2142 /* Let pucRecvData point to the first byte received. */
\r
2143 *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
\r
2145 /* Calculate lReceiveLength - the length of the TCP data received. This is
\r
2146 equal to the total packet length minus:
\r
2147 ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
\r
2148 lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
\r
2149 lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
\r
2151 if( lReceiveLength > lLength )
\r
2153 /* More bytes were received than the reported length, often because of
\r
2154 padding bytes at the end. */
\r
2155 lReceiveLength = lLength;
\r
2158 /* Subtract the size of the TCP and IP headers and the actual data size is
\r
2160 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
\r
2162 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
\r
2166 lReceiveLength = 0;
\r
2169 /* Urgent Pointer:
\r
2170 This field communicates the current value of the urgent pointer as a
\r
2171 positive offset from the sequence number in this segment. The urgent
\r
2172 pointer points to the sequence number of the octet following the urgent
\r
2173 data. This field is only be interpreted in segments with the URG control
\r
2175 if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
\r
2177 /* Although we ignore the urgent data, we have to skip it. */
\r
2178 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
\r
2179 *ppucRecvData += lUrgentLength;
\r
2180 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
\r
2183 return ( BaseType_t ) lReceiveLength;
\r
2185 /*-----------------------------------------------------------*/
\r
2188 * prvStoreRxData(): called from prvTCPHandleState()
\r
2190 * The second thing is to do is check if the payload data may be accepted
\r
2191 * If so, they will be added to the reception queue.
\r
2193 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
2194 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
\r
2196 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2197 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2198 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2199 uint32_t ulSequenceNumber, ulSpace;
\r
2200 int32_t lOffset, lStored;
\r
2201 BaseType_t xResult = 0;
\r
2203 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2205 if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
\r
2207 /* See if way may accept the data contents and forward it to the socket
\r
2210 If it can't be "accept"ed it may have to be stored and send a selective
\r
2211 ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
\r
2212 called later to store an out-of-order packet (in case lOffset is
\r
2214 if ( pxSocket->u.xTCP.rxStream )
\r
2216 ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
\r
2220 ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
\r
2223 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
\r
2225 if( lOffset >= 0 )
\r
2227 /* New data has arrived and may be made available to the user. See
\r
2228 if the head marker in rxStream may be advanced, only if lOffset == 0.
\r
2229 In case the low-water mark is reached, bLowWater will be set
\r
2230 "low-water" here stands for "little space". */
\r
2231 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
\r
2233 if( lStored != ( int32_t ) ulReceiveLength )
\r
2235 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
\r
2237 /* Received data could not be stored. The socket's flag
\r
2238 bMallocError has been set. The socket now has the status
\r
2239 eCLOSE_WAIT and a RST packet will be sent back. */
\r
2240 prvTCPSendReset( pxNetworkBuffer );
\r
2245 /* After a missing packet has come in, higher packets may be passed to
\r
2247 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2249 /* Now lTCPAddRxdata() will move the rxHead pointer forward
\r
2250 so data becomes available to the user immediately
\r
2251 In case the low-water mark is reached, bLowWater will be set. */
\r
2252 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
\r
2254 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
\r
2255 pxTCPWindow->ulUserDataLength = 0;
\r
2258 #endif /* ipconfigUSE_TCP_WIN */
\r
2262 pxTCPWindow->ucOptionLength = 0u;
\r
2267 /*-----------------------------------------------------------*/
\r
2269 /* Set the TCP options (if any) for the outgoing packet. */
\r
2270 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2272 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2273 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2274 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2275 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
\r
2277 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2278 if( uxOptionsLength != 0u )
\r
2280 /* TCP options must be sent because a packet which is out-of-order
\r
2282 if( xTCPWindowLoggingLevel >= 0 )
\r
2283 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
\r
2284 pxSocket->usLocalPort,
\r
2285 pxSocket->u.xTCP.usRemotePort,
\r
2287 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
2288 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
\r
2289 memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
\r
2291 /* The header length divided by 4, goes into the higher nibble,
\r
2292 effectively a shift-left 2. */
\r
2293 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2296 #endif /* ipconfigUSE_TCP_WIN */
\r
2297 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
\r
2299 /* TCP options must be sent because the MSS has changed. */
\r
2300 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
\r
2301 if( xTCPWindowLoggingLevel >= 0 )
\r
2303 FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
\r
2306 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
\r
2307 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
\r
2308 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
\r
2309 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
\r
2310 uxOptionsLength = 4u;
\r
2311 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2314 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
\r
2316 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
\r
2318 uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, pxTCPHeader );
\r
2321 #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */
\r
2323 return uxOptionsLength;
\r
2325 /*-----------------------------------------------------------*/
\r
2328 * prvHandleSynReceived(): called from prvTCPHandleState()
\r
2330 * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
\r
2331 * If the flags received are correct, the socket will move to eESTABLISHED.
\r
2333 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2334 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2336 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2337 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2338 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2339 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2340 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2341 BaseType_t xSendLength = 0;
\r
2343 /* Either expect a ACK or a SYN+ACK. */
\r
2344 uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
\r
2345 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2347 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
\r
2350 if( ( ucTCPFlags & 0x17u ) != usExpect )
\r
2352 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
\r
2353 /* eSYN_RECEIVED: flags ACK expected, not SYN. */
\r
2354 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
\r
2355 pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
\r
2356 usExpect, ucTCPFlags ) );
\r
2357 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2358 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
\r
2359 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2360 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2364 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
\r
2365 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
\r
2367 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2369 TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
2371 /* Clear the SYN flag in lastPacket. */
\r
2372 pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
\r
2374 /* This socket was the one connecting actively so now perofmr the
\r
2375 synchronisation. */
\r
2376 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
\r
2377 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2378 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2379 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
\r
2380 pxTCPWindow->ulNextTxSequenceNumber++;
\r
2382 else if( ulReceiveLength == 0u )
\r
2384 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
2387 /* The SYN+ACK has been confirmed, increase the next sequence number by
\r
2389 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
\r
2391 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2393 FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
\r
2394 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
\r
2395 pxSocket->usLocalPort,
\r
2396 pxSocket->u.xTCP.ulRemoteIP,
\r
2397 pxSocket->u.xTCP.usRemotePort,
\r
2398 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
\r
2400 #endif /* ipconfigUSE_TCP_WIN */
\r
2402 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
\r
2404 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2405 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2406 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2408 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2410 if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
\r
2412 /* The other party did not send a scaling factor.
\r
2413 A shifting factor in this side must be canceled. */
\r
2414 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
\r
2415 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
\r
2418 #endif /* ipconfigUSE_TCP_WIN */
\r
2419 /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
\r
2420 connection is established. */
\r
2421 vTCPStateChange( pxSocket, eESTABLISHED );
\r
2424 return xSendLength;
\r
2426 /*-----------------------------------------------------------*/
\r
2429 * prvHandleEstablished(): called from prvTCPHandleState()
\r
2431 * Called if the status is eESTABLISHED. Data reception has been handled
\r
2432 * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
\r
2433 * the code will check if it may be accepted, i.e. if all expected data has been
\r
2434 * completely received.
\r
2436 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2437 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2439 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2440 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2441 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2442 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2443 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
\r
2444 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
\r
2445 int32_t lDistance, lSendResult;
\r
2447 /* Remember the window size the peer is advertising. */
\r
2448 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
\r
2449 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2451 pxSocket->u.xTCP.ulWindowSize =
\r
2452 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
2456 if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
\r
2458 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
\r
2460 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
\r
2461 starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
\r
2463 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
\r
2465 /* Just advancing the tail index, 'ulCount' bytes have been
\r
2466 confirmed, and because there is new space in the txStream, the
\r
2467 user/owner should be woken up. */
\r
2468 /* _HT_ : only in case the socket's waiting? */
\r
2469 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
\r
2471 pxSocket->xEventBits |= eSOCKET_SEND;
\r
2473 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
2475 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
\r
2477 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
2481 /* In case the socket owner has installed an OnSent handler,
\r
2483 #if( ipconfigUSE_CALLBACKS == 1 )
\r
2485 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
2487 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
2490 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
2495 /* If this socket has a stream for transmission, add the data to the
\r
2496 outgoing segment(s). */
\r
2497 if( pxSocket->u.xTCP.txStream != NULL )
\r
2499 prvTCPAddTxData( pxSocket );
\r
2502 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2504 if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
\r
2506 /* Peer is requesting to stop, see if we're really finished. */
\r
2507 xMayClose = pdTRUE;
\r
2509 /* Checks are only necessary if we haven't sent a FIN yet. */
\r
2510 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2512 /* xTCPWindowTxDone returns true when all Tx queues are empty. */
\r
2513 bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
\r
2514 bTxDone = xTCPWindowTxDone( pxTCPWindow );
\r
2516 if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
\r
2518 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
\r
2519 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
\r
2520 pxSocket->usLocalPort,
\r
2521 pxSocket->u.xTCP.usRemotePort,
\r
2522 bRxComplete, bTxDone ) );
\r
2523 xMayClose = pdFALSE;
\r
2527 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2529 if( lDistance > 1 )
\r
2531 FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
\r
2532 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2533 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2535 xMayClose = pdFALSE;
\r
2540 if( xTCPWindowLoggingLevel > 0 )
\r
2542 FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
\r
2543 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
\r
2544 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
\r
2547 if( xMayClose != pdFALSE )
\r
2549 pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
\r
2550 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2554 if( xMayClose == pdFALSE )
\r
2556 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2558 if( ulReceiveLength != 0u )
\r
2560 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2561 /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
\r
2562 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2564 if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
\r
2566 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2570 /* Now get data to be transmitted. */
\r
2571 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
\r
2572 can not send-out both TCP options and also a full packet. Sending
\r
2573 options (SACK) is always more urgent than sending data, which can be
\r
2575 if( uxOptionsLength == 0u )
\r
2577 /* prvTCPPrepareSend might allocate a bigger network buffer, if
\r
2579 lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
2580 if( lSendResult > 0 )
\r
2582 xSendLength = ( BaseType_t ) lSendResult;
\r
2587 return xSendLength;
\r
2589 /*-----------------------------------------------------------*/
\r
2592 * Called from prvTCPHandleState(). There is data to be sent. If
\r
2593 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
\r
2594 * checked if it would better be postponed for efficiency.
\r
2596 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2597 uint32_t ulReceiveLength, BaseType_t xSendLength )
\r
2599 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2600 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2601 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2602 /* Find out what window size we may advertised. */
\r
2603 uint32_t ulFrontSpace;
\r
2605 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2606 #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
\r
2607 const int32_t lMinLength = 0;
\r
2609 int32_t lMinLength;
\r
2612 pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -
\r
2613 ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2615 /* Free space in rxStream. */
\r
2616 if( pxSocket->u.xTCP.rxStream != NULL )
\r
2618 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
2622 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
2625 pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );
\r
2627 /* Set the time-out field, so that we'll be called by the IP-task in case no
\r
2628 next message will be received. */
\r
2629 lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2630 #if ipconfigUSE_TCP_WIN == 1
\r
2633 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
\r
2635 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2637 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
\r
2639 /* In case we're receiving data continuously, we might postpone sending
\r
2640 an ACK to gain performance. */
\r
2641 if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
\r
2642 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
\r
2643 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
\r
2644 ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
\r
2645 ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
\r
2646 ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
\r
2648 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2650 /* There was still a delayed in queue, delete it. */
\r
2651 if( pxSocket->u.xTCP.pxAckMessage != 0 )
\r
2653 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2656 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
\r
2658 if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
\r
2659 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
\r
2661 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
\r
2665 /* Normally a delayed ACK should wait 200 ms for a next incoming
\r
2666 packet. Only wait 20 ms here to gain performance. A slow ACK
\r
2667 for full-size message. */
\r
2668 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
\r
2671 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2673 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
\r
2674 pxSocket->usLocalPort,
\r
2675 pxSocket->u.xTCP.usRemotePort,
\r
2676 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2677 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2679 pxSocket->u.xTCP.usTimeout, lRxSpace ) );
\r
2682 *ppxNetworkBuffer = NULL;
\r
2685 else if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
2687 /* As an ACK is not being delayed, remove any earlier delayed ACK
\r
2689 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2691 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2694 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
2699 /* Remove compiler warnings. */
\r
2700 ( void ) ulReceiveLength;
\r
2701 ( void ) pxTCPHeader;
\r
2702 ( void ) lRxSpace;
\r
2704 #endif /* ipconfigUSE_TCP_WIN */
\r
2706 if( xSendLength != 0 )
\r
2708 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2710 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
\r
2711 pxSocket->usLocalPort,
\r
2712 pxSocket->u.xTCP.usRemotePort,
\r
2713 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2714 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2718 /* Set the parameter 'xReleaseAfterSend' to the value of
\r
2719 ipconfigZERO_COPY_TX_DRIVER. */
\r
2720 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
2721 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
2723 /* The driver has taken ownership of the Network Buffer. */
\r
2724 *ppxNetworkBuffer = NULL;
\r
2729 return xSendLength;
\r
2731 /*-----------------------------------------------------------*/
\r
2734 * prvTCPHandleState()
\r
2735 * is the most important function of this TCP stack
\r
2736 * We've tried to keep it (relatively short) by putting a lot of code in
\r
2737 * the static functions above:
\r
2739 * prvCheckRxData()
\r
2740 * prvStoreRxData()
\r
2742 * prvHandleSynReceived()
\r
2743 * prvHandleEstablished()
\r
2746 * As these functions are declared static, and they're called from one location
\r
2747 * only, most compilers will inline them, thus avoiding a call and return.
\r
2749 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
2751 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2752 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2753 BaseType_t xSendLength = 0;
\r
2754 uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
\r
2755 uint8_t *pucRecvData;
\r
2756 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
\r
2758 /* uxOptionsLength: the size of the options to be sent (always a multiple of
\r
2760 1. in the SYN phase, we shall communicate the MSS
\r
2761 2. in case of a SACK, Selective ACK, ack a segment which comes in
\r
2763 UBaseType_t uxOptionsLength = 0u;
\r
2764 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2765 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
2767 /* First get the length and the position of the received data, if any.
\r
2768 pucRecvData will point to the first byte of the TCP payload. */
\r
2769 ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
\r
2771 if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
\r
2773 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
\r
2775 /* This is most probably a keep-alive message from peer. Setting
\r
2776 'bWinChange' doesn't cause a window-size-change, the flag is used
\r
2777 here to force sending an immediate ACK. */
\r
2778 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
2782 /* Keep track of the highest sequence number that might be expected within
\r
2783 this connection. */
\r
2784 if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
\r
2786 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2789 /* Storing data may result in a fatal error if malloc() fails. */
\r
2790 if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
\r
2796 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
\r
2798 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
\r
2800 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
\r
2802 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
\r
2803 'SYN+ACK' didn't arrive. Step back to the previous state in which
\r
2804 a first incoming SYN is handled. The SYN was counted already so
\r
2805 decrease it first. */
\r
2806 vTCPStateChange( pxSocket, eSYN_FIRST );
\r
2809 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
\r
2811 /* It's the first time a FIN has been received, remember its
\r
2812 sequence number. */
\r
2813 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2814 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
\r
2816 /* Was peer the first one to send a FIN? */
\r
2817 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2819 /* If so, don't send the-last-ACK. */
\r
2820 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
\r
2824 switch (pxSocket->u.xTCP.ucTCPState)
\r
2826 case eCLOSED: /* (server + client) no connection state at all. */
\r
2827 /* Nothing to do for a closed socket, except waiting for the
\r
2831 case eTCP_LISTEN: /* (server) waiting for a connection request from
\r
2832 any remote TCP and port. */
\r
2833 /* The listen state was handled in xProcessReceivedTCPPacket().
\r
2834 Should not come here. */
\r
2837 case eSYN_FIRST: /* (server) Just received a SYN request for a server
\r
2840 /* A new socket has been created, reply with a SYN+ACK.
\r
2841 Acknowledge with seq+1 because the SYN is seen as pseudo data
\r
2843 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
2844 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
\r
2846 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2848 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
2849 uxOptionsLength is a multiple of 4. The complete expression is:
\r
2850 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
2851 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2852 vTCPStateChange( pxSocket, eSYN_RECEIVED );
\r
2854 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2855 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
\r
2859 case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
\r
2860 SYN, expect a SYN+ACK and send a ACK now. */
\r
2861 /* Fall through */
\r
2862 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
\r
2863 expect a ACK and do nothing. */
\r
2864 xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2867 case eESTABLISHED: /* (server + client) an open connection, data
\r
2868 received can be delivered to the user. The normal
\r
2869 state for the data transfer phase of the connection
\r
2870 The closing states are also handled here with the
\r
2871 use of some flags. */
\r
2872 xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2875 case eLAST_ACK: /* (server + client) waiting for an acknowledgement
\r
2876 of the connection termination request previously
\r
2877 sent to the remote TCP (which includes an
\r
2878 acknowledgement of its connection termination
\r
2880 /* Fall through */
\r
2881 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
\r
2882 * or an acknowledgement of the connection termination request previously sent. */
\r
2883 /* Fall through */
\r
2884 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
\r
2885 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2888 case eCLOSE_WAIT: /* (server + client) waiting for a connection
\r
2889 termination request from the local user. Nothing to
\r
2890 do, connection is closed, wait for owner to close
\r
2894 case eCLOSING: /* (server + client) waiting for a connection
\r
2895 termination request acknowledgement from the remote
\r
2899 case eTIME_WAIT: /* (either server or client) waiting for enough time
\r
2900 to pass to be sure the remote TCP received the
\r
2901 acknowledgement of its connection termination
\r
2902 request. [According to RFC 793 a connection can stay
\r
2903 in TIME-WAIT for a maximum of four minutes known as
\r
2904 a MSL (maximum segment lifetime).] These states are
\r
2905 implemented implicitly by settings flags like
\r
2906 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
\r
2913 if( xSendLength > 0 )
\r
2915 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
\r
2918 return xSendLength;
\r
2920 /*-----------------------------------------------------------*/
\r
2922 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2924 #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
\r
2926 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2927 const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
\r
2929 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;
\r
2930 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
\r
2932 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );
\r
2934 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
\r
2936 /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
\r
2937 ( void ) pxNetworkBuffer;
\r
2939 /* The packet was not consumed. */
\r
2942 /*-----------------------------------------------------------*/
\r
2944 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
\r
2946 uint32_t ulMSS = ipconfigTCP_MSS;
\r
2948 if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
\r
2950 /* Data for this peer will pass through a router, and maybe through
\r
2951 the internet. Limit the MSS to 1400 bytes or less. */
\r
2952 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
\r
2955 FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
\r
2957 pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
\r
2959 /*-----------------------------------------------------------*/
\r
2962 * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
\r
2963 * xProcessReceivedTCPPacket()
\r
2964 * prvTCPHandleState()
\r
2965 * prvTCPPrepareSend()
\r
2966 * prvTCPReturnPacket()
\r
2967 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2968 * prvTCPSendRepeated()
\r
2969 * prvTCPReturnPacket() // Prepare for returning
\r
2970 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2972 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2974 FreeRTOS_Socket_t *pxSocket;
\r
2975 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2976 uint16_t ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
\r
2977 uint32_t ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
\r
2978 uint16_t xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
\r
2979 uint32_t ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
2980 uint16_t xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
2981 BaseType_t xResult = pdPASS;
\r
2983 /* Find the destination socket, and if not found: return a socket listing to
\r
2984 the destination PORT. */
\r
2985 pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
\r
2987 if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
\r
2989 /* A TCP messages is received but either there is no socket with the
\r
2990 given port number or the there is a socket, but it is in one of these
\r
2991 non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
\r
2994 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
\r
2996 /* Send a RST to all packets that can not be handled. As a result
\r
2997 the other party will get a ECONN error. There are two exceptions:
\r
2998 1) A packet that already has the RST flag set.
\r
2999 2) A packet that only has the ACK flag set.
\r
3000 A packet with only the ACK flag set might be the last ACK in
\r
3001 a three-way hand-shake that closes a connection. */
\r
3002 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
\r
3003 ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
\r
3005 prvTCPSendReset( pxNetworkBuffer );
\r
3008 /* The packet can't be handled. */
\r
3013 pxSocket->u.xTCP.ucRepCount = 0u;
\r
3015 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
\r
3017 /* The matching socket is in a listening state. Test if the peer
\r
3018 has set the SYN flag. */
\r
3019 if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
\r
3021 /* What happens: maybe after a reboot, a client doesn't know the
\r
3022 connection had gone. Send a RST in order to get a new connect
\r
3024 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
3026 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
\r
3027 prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
\r
3029 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
3031 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
\r
3033 prvTCPSendReset( pxNetworkBuffer );
\r
3039 /* prvHandleListen() will either return a newly created socket
\r
3040 (if bReuseSocket is false), otherwise it returns the current
\r
3041 socket which will later get connected. */
\r
3042 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
\r
3044 if( pxSocket == NULL )
\r
3049 } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
\r
3052 /* This is not a socket in listening mode. Check for the RST
\r
3054 if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
\r
3056 /* The target socket is not in a listening state, any RST packet
\r
3057 will cause the socket to be closed. */
\r
3058 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
\r
3059 /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */
\r
3060 vTCPStateChange( pxSocket, eCLOSED );
\r
3062 /* The packet cannot be handled. */
\r
3065 else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
\r
3067 /* SYN flag while this socket is already connected. */
\r
3068 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
\r
3070 /* The packet cannot be handled. */
\r
3075 /* Update the copy of the TCP header only (skipping eth and IP
\r
3076 headers). It might be used later on, whenever data must be sent
\r
3078 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
\r
3079 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
\r
3084 if( xResult != pdFAIL )
\r
3086 /* Touch the alive timers because we received a message for this
\r
3088 prvTCPTouchSocket( pxSocket );
\r
3090 /* Parse the TCP option(s), if present. */
\r
3091 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
\r
3092 then we MUST assume an MSS size of 536 bytes for backward compatibility. */
\r
3094 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
3095 the number 5 (words) in the higher niblle of the TCP-offset byte. */
\r
3096 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
\r
3098 prvCheckOptions( pxSocket, pxNetworkBuffer );
\r
3102 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3104 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
\r
3105 pxSocket->u.xTCP.ulWindowSize =
\r
3106 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
3110 /* In prvTCPHandleState() the incoming messages will be handled
\r
3111 depending on the current state of the connection. */
\r
3112 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
\r
3114 /* prvTCPHandleState() has sent a message, see if there are more to
\r
3115 be transmitted. */
\r
3116 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3118 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
3120 #endif /* ipconfigUSE_TCP_WIN */
\r
3123 if( pxNetworkBuffer != NULL )
\r
3125 /* We must check if the buffer is unequal to NULL, because the
\r
3126 socket might keep a reference to it in case a delayed ACK must be
\r
3128 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
3129 pxNetworkBuffer = NULL;
\r
3132 /* And finally, calculate when this socket wants to be woken up. */
\r
3133 prvTCPNextTimeout ( pxSocket );
\r
3134 /* Return pdPASS to tell that the network buffer is 'consumed'. */
\r
3138 /* pdPASS being returned means the buffer has been consumed. */
\r
3141 /*-----------------------------------------------------------*/
\r
3143 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
3145 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
3146 FreeRTOS_Socket_t *pxReturn;
\r
3148 /* A pure SYN (without ACK) has come in, create a new socket to answer
\r
3150 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
3152 /* The flag bReuseSocket indicates that the same instance of the
\r
3153 listening socket should be used for the connection. */
\r
3154 pxReturn = pxSocket;
\r
3155 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3156 pxSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3160 /* The socket does not have the bReuseSocket flag set meaning create a
\r
3161 new socket when a connection comes in. */
\r
3164 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
\r
3166 FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
\r
3167 pxSocket->usLocalPort,
\r
3168 pxSocket->u.xTCP.usChildCount,
\r
3169 pxSocket->u.xTCP.usBacklog,
\r
3170 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
\r
3171 prvTCPSendReset( pxNetworkBuffer );
\r
3175 FreeRTOS_Socket_t *pxNewSocket = (FreeRTOS_Socket_t *)
\r
3176 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
3178 if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
\r
3180 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
\r
3181 prvTCPSendReset( pxNetworkBuffer );
\r
3183 else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
\r
3185 /* The socket will be connected immediately, no time for the
\r
3186 owner to setsockopt's, therefore copy properties of the server
\r
3187 socket to the new socket. Only the binding might fail (due to
\r
3188 lack of resources). */
\r
3189 pxReturn = pxNewSocket;
\r
3194 if( pxReturn != NULL )
\r
3196 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
3197 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
3198 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;
\r
3200 /* Here is the SYN action. */
\r
3201 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
3202 prvSocketSetMSS( pxReturn );
\r
3204 prvTCPCreateWindow( pxReturn );
\r
3206 /* It is recommended to increase the ISS for each new connection with a value of 0x102. */
\r
3207 ulNextInitialSequenceNumber += INITIAL_SEQUENCE_NUMBER_INCREMENT;
\r
3209 vTCPStateChange( pxReturn, eSYN_FIRST );
\r
3211 /* Make a copy of the header up to the TCP header. It is needed later
\r
3212 on, whenever data must be sent to the peer. */
\r
3213 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
\r
3217 /*-----------------------------------------------------------*/
\r
3220 * Duplicates a socket after a listening socket receives a connection.
\r
3222 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
\r
3224 struct freertos_sockaddr xAddress;
\r
3226 pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
\r
3227 pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
\r
3228 pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
\r
3229 pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
\r
3230 pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
\r
3231 pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
\r
3232 pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
\r
3233 pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
\r
3234 pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
\r
3236 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
\r
3238 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
\r
3240 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
\r
3242 #if( ipconfigUSE_CALLBACKS == 1 )
\r
3244 /* In case call-backs are used, copy them from parent to child. */
\r
3245 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
\r
3246 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
\r
3247 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
\r
3249 #endif /* ipconfigUSE_CALLBACKS */
\r
3251 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
3253 /* Child socket of listening sockets will inherit the Socket Set
\r
3254 Otherwise the owner has no chance of including it into the set. */
\r
3255 if( pxSocket->pxSocketSet )
\r
3257 pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
\r
3258 pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
\r
3261 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
3263 /* And bind it to the same local port as its parent. */
\r
3264 xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
\r
3265 xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3267 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
3269 /* Only when there is anti-hanging protection, a socket may become an
\r
3270 orphan temporarily. Once this socket is really connected, the owner of
\r
3271 the server socket will be notified. */
\r
3273 /* When bPassQueued is true, the socket is an orphan until it gets
\r
3275 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3276 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3280 /* A reference to the new socket may be stored and the socket is marked
\r
3283 /* When bPassAccept is true, this socket may be returned in a call to
\r
3285 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
3286 if(pxSocket->u.xTCP.pxPeerSocket == NULL )
\r
3288 pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
\r
3293 pxSocket->u.xTCP.usChildCount++;
\r
3295 FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
\r
3296 pxSocket->usLocalPort,
\r
3297 pxSocket->u.xTCP.usChildCount,
\r
3298 pxSocket->u.xTCP.usBacklog,
\r
3299 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
\r
3301 /* Now bind the child socket to the same port as the listening socket. */
\r
3302 if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
\r
3304 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
\r
3305 vSocketClose( pxNewSocket );
\r
3311 /*-----------------------------------------------------------*/
\r
3313 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
3315 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
\r
3317 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
\r
3319 ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
\r
3321 return pcStateNames[ ulState ];
\r
3324 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
\r
3325 /*-----------------------------------------------------------*/
\r
3328 * In the API accept(), the user asks is there is a new client? As API's can
\r
3329 * not walk through the xBoundTCPSocketsList the IP-task will do this.
\r
3331 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
\r
3333 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3334 ListItem_t *pxIterator;
\r
3335 FreeRTOS_Socket_t *pxFound;
\r
3336 BaseType_t xResult = pdFALSE;
\r
3338 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
\r
3339 who has access. */
\r
3340 for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
\r
3341 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
\r
3342 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
3344 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
\r
3346 pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
3347 if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
3349 pxSocket->u.xTCP.pxPeerSocket = pxFound;
\r
3350 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
\r
3358 /*-----------------------------------------------------------*/
\r
3360 #endif /* ipconfigUSE_TCP == 1 */
\r