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
749 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
751 if( xReleaseAfterSend == pdFALSE )
\r
753 pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
\r
754 if( pxNetworkBuffer == NULL )
\r
756 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
\r
758 xReleaseAfterSend = pdTRUE;
\r
761 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
763 if( pxNetworkBuffer != NULL )
\r
765 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
766 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
767 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
\r
769 /* Fill the packet, using hton translations. */
\r
770 if( pxSocket != NULL )
\r
772 /* Calculate the space in the RX buffer in order to advertise the
\r
773 size of this socket's reception window. */
\r
774 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
776 if( pxSocket->u.xTCP.rxStream != NULL )
\r
778 /* An RX stream was created already, see how much space is
\r
780 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
784 /* No RX stream has been created, the full stream size is
\r
786 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
789 /* Take the minimum of the RX buffer space and the RX window size. */
\r
790 ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );
\r
792 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
\r
794 /* The low-water mark was reached, meaning there was little
\r
795 space left. The socket will wait until the application has read
\r
796 or flushed the incoming data, and 'zero-window' will be
\r
801 /* If possible, advertise an RX window size of at least 1 MSS, otherwise
\r
802 the peer might start 'zero window probing', i.e. sending small packets
\r
803 (1, 2, 4, 8... bytes). */
\r
804 if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
\r
806 ulSpace = pxSocket->u.xTCP.usCurMSS;
\r
809 /* Avoid overflow of the 16-bit win field. */
\r
810 #if( ipconfigUSE_TCP_WIN != 0 )
\r
812 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
\r
816 ulWinSize = ulSpace;
\r
819 if( ulWinSize > 0xfffcUL )
\r
821 ulWinSize = 0xfffcUL;
\r
824 pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
\r
826 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
828 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
\r
830 if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
\r
832 size_t uxFrontSpace;
\r
834 if(pxSocket->u.xTCP.rxStream != NULL)
\r
836 uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
\r
843 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
\r
844 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
\r
845 pxSocket->u.xTCP.ulRemoteIP,
\r
846 pxSocket->u.xTCP.usRemotePort,
\r
847 pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
\r
848 (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
\r
852 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
854 /* The new window size has been advertised, switch off the flag. */
\r
855 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
\r
857 /* Later on, when deciding to delay an ACK, a precise estimate is needed
\r
858 of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
\r
859 highest sequence number minus 1 that the socket will accept. */
\r
860 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
\r
862 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
863 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
\r
865 /* Sending a keep-alive packet, send the current sequence number
\r
866 minus 1, which will be recognised as a keep-alive packet an
\r
867 responded to by acknowledging the last byte. */
\r
868 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
869 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
\r
871 pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
\r
872 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
877 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
\r
879 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
\r
881 /* Suppress FIN in case this packet carries earlier data to be
\r
883 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
\r
884 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
\r
886 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
\r
887 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
\r
888 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
890 pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
\r
895 /* Tell which sequence number is expected next time */
\r
896 pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
900 /* Sending data without a socket, probably replying with a RST flag
\r
901 Just swap the two sequence numbers. */
\r
902 vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
\r
905 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
906 pxIPHeader->usLength = FreeRTOS_htons( ulLen );
\r
907 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
\r
909 /* When pxSocket is NULL, this function is called by prvTCPSendReset()
\r
910 and the IP-addresses must be swapped.
\r
911 Also swap the IP-addresses in case the IP-tack doesn't have an
\r
912 IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
\r
913 ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
\r
917 ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
919 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
920 pxIPHeader->ulSourceIPAddress = ulSourceAddress;
\r
921 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
\r
923 /* Just an increasing number. */
\r
924 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
925 usPacketIdentifier++;
\r
926 pxIPHeader->usFragmentOffset = 0u;
\r
928 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
930 /* calculate the IP header checksum, in case the driver won't do that. */
\r
931 pxIPHeader->usHeaderChecksum = 0x00u;
\r
932 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
933 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
935 /* calculate the TCP checksum for an outgoing packet. */
\r
936 usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pdTRUE );
\r
938 /* A calculated checksum of 0 must be inverted as 0 means the checksum
\r
940 if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
\r
942 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
\r
947 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
949 pxNetworkBuffer->pxNextBuffer = NULL;
\r
953 /* Important: tell NIC driver how many bytes must be sent. */
\r
954 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
\r
956 /* Fill in the destination MAC addresses. */
\r
957 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
\r
958 sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
960 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
\r
961 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
963 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
965 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
969 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
971 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
973 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
979 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
\r
981 if( xReleaseAfterSend == pdFALSE )
\r
983 /* Swap-back some fields, as pxBuffer probably points to a socket field
\r
984 containing the packet header. */
\r
985 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
\r
986 pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
\r
987 memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
991 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
\r
993 } /* if( pxNetworkBuffer != NULL ) */
\r
995 /*-----------------------------------------------------------*/
\r
998 * The SYN event is very important: the sequence numbers, which have a kind of
\r
999 * random starting value, are being synchronised. The sliding window manager
\r
1000 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
\r
1001 * Size (MSS) in use.
\r
1003 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
\r
1005 if( xTCPWindowLoggingLevel )
\r
1006 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
\r
1007 pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
\r
1008 pxSocket->u.xTCP.uxLittleSpace ,
\r
1009 pxSocket->u.xTCP.uxEnoughSpace,
\r
1010 pxSocket->u.xTCP.uxRxStreamSize ) );
\r
1012 &pxSocket->u.xTCP.xTCPWindow,
\r
1013 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
\r
1014 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
\r
1015 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
\r
1016 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
\r
1017 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
\r
1019 /*-----------------------------------------------------------*/
\r
1022 * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
\r
1023 * the Ethernet address of the target will be found using ARP. In case the
\r
1024 * target IP address is not within the netmask, the hardware address of the
\r
1025 * gateway will be used.
\r
1027 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
\r
1029 TCPPacket_t *pxTCPPacket;
\r
1030 IPHeader_t *pxIPHeader;
\r
1031 eARPLookupResult_t eReturned;
\r
1032 uint32_t ulRemoteIP;
\r
1033 MACAddress_t xEthAddress;
\r
1034 BaseType_t xReturn = pdTRUE;
\r
1036 #if( ipconfigHAS_PRINTF != 0 )
\r
1038 /* Only necessary for nicer logging. */
\r
1039 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
\r
1041 #endif /* ipconfigHAS_PRINTF != 0 */
\r
1043 ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1045 /* Determine the ARP cache status for the requested IP address. */
\r
1046 eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
\r
1048 switch( eReturned )
\r
1050 case eARPCacheHit: /* An ARP table lookup found a valid entry. */
\r
1051 break; /* We can now prepare the SYN packet. */
\r
1052 case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
\r
1053 case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
\r
1055 /* Count the number of times it couldn't find the ARP address. */
\r
1056 pxSocket->u.xTCP.ucRepCount++;
\r
1058 FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
\r
1059 pxSocket->u.xTCP.ulRemoteIP,
\r
1060 FreeRTOS_htonl( ulRemoteIP ),
\r
1062 xEthAddress.ucBytes[ 0 ],
\r
1063 xEthAddress.ucBytes[ 1 ],
\r
1064 xEthAddress.ucBytes[ 2 ],
\r
1065 xEthAddress.ucBytes[ 3 ],
\r
1066 xEthAddress.ucBytes[ 4 ],
\r
1067 xEthAddress.ucBytes[ 5 ] ) );
\r
1069 /* And issue a (new) ARP request */
\r
1070 FreeRTOS_OutputARPRequest( ulRemoteIP );
\r
1072 xReturn = pdFALSE;
\r
1076 if( xReturn != pdFALSE )
\r
1078 /* The MAC-address of the peer (or gateway) has been found,
\r
1079 now prepare the initial TCP packet and some fields in the socket. */
\r
1080 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1081 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
1083 /* Reset the retry counter to zero... */
\r
1084 pxSocket->u.xTCP.ucRepCount = 0u;
\r
1086 /* ...and remember that the connect/SYN data are prepared. */
\r
1087 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
\r
1089 /* Now that the Ethernet address is known, the initial packet can be
\r
1091 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1093 /* Write the Ethernet address in Source, because it will be swapped by
\r
1094 prvTCPReturnPacket(). */
\r
1095 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
\r
1097 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
\r
1098 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
\r
1100 pxIPHeader->ucVersionHeaderLength = 0x45u;
\r
1101 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
\r
1102 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
1104 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
\r
1106 /* Addresses and ports will be stored swapped because prvTCPReturnPacket
\r
1107 will swap them back while replying. */
\r
1108 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1109 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1111 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
\r
1112 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
1114 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
\r
1115 isn't known yet. */
\r
1116 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
\r
1118 /* Start with ISN (Initial Sequence Number). */
\r
1119 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;
\r
1121 /* And increment it with 268 for the next new connection, which is
\r
1122 recommended value. */
\r
1123 ulNextInitialSequenceNumber += 0x102UL;
\r
1125 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
\r
1126 the high nibble of the TCP offset field. */
\r
1127 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
\r
1129 /* Only set the SYN flag. */
\r
1130 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
\r
1132 /* Set the values of usInitMSS / usCurMSS for this socket. */
\r
1133 prvSocketSetMSS( pxSocket );
\r
1135 /* For now this is also the advertised window size. */
\r
1136 pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;
\r
1138 /* The initial sequence numbers at our side are known. Later
\r
1139 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
\r
1140 first wait for a SYN+ACK reply. */
\r
1141 prvTCPCreateWindow( pxSocket );
\r
1146 /*-----------------------------------------------------------*/
\r
1148 /* For logging and debugging: make a string showing the TCP flags
\r
1150 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1152 static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
\r
1154 static char retString[10];
\r
1155 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
\r
1156 ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
\r
1157 ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
\r
1158 ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
\r
1159 ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
\r
1160 ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
\r
1161 ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
\r
1162 ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
\r
1163 ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
\r
1164 ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
\r
1167 /*-----------------------------------------------------------*/
\r
1169 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1172 * Parse the TCP option(s) received, if present. It has already been verified
\r
1173 * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
\r
1174 * is longer than the usual 20 (5 x 4) bytes.
\r
1176 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1178 TCPPacket_t * pxTCPPacket;
\r
1179 TCPHeader_t * pxTCPHeader;
\r
1180 const unsigned char *pucPtr;
\r
1181 const unsigned char *pucLast;
\r
1182 TCPWindow_t *pxTCPWindow;
\r
1183 UBaseType_t uxNewMSS;
\r
1185 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1186 pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1188 /* A character pointer to iterate through the option data */
\r
1189 pucPtr = pxTCPHeader->ucOptdata;
\r
1190 pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
\r
1191 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1193 /* The comparison with pucLast is only necessary in case the option data are
\r
1194 corrupted, we don't like to run into invalid memory and crash. */
\r
1195 while( pucPtr < pucLast )
\r
1197 if( pucPtr[ 0 ] == TCP_OPT_END )
\r
1199 /* End of options. */
\r
1202 if( pucPtr[ 0 ] == TCP_OPT_NOOP)
\r
1206 /* NOP option, inserted to make the length a multiple of 4. */
\r
1208 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1209 else if( ( pucPtr[ 0 ] == TCP_OPT_WSOPT ) && ( pucPtr[ 1 ] == TCP_OPT_WSOPT_LEN ) )
\r
1211 pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
\r
1212 pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
\r
1213 pucPtr += TCP_OPT_WSOPT_LEN;
\r
1215 #endif /* ipconfigUSE_TCP_WIN */
\r
1216 else if( ( pucPtr[ 0 ] == TCP_OPT_MSS ) && ( pucPtr[ 1 ] == TCP_OPT_MSS_LEN ) )
\r
1218 /* An MSS option with the correct option length. FreeRTOS_htons()
\r
1219 is not needed here because usChar2u16() already returns a host
\r
1221 uxNewMSS = usChar2u16( pucPtr + 2 );
\r
1223 if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
\r
1225 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
\r
1228 if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
\r
1230 /* our MSS was bigger than the MSS of the other party: adapt it. */
\r
1231 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
\r
1232 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )
\r
1234 /* The peer advertises a smaller MSS than this socket was
\r
1235 using. Use that as well. */
\r
1236 FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
\r
1237 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1239 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
\r
1240 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
\r
1241 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
\r
1242 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
\r
1243 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1246 #if( ipconfigUSE_TCP_WIN != 1 )
\r
1247 /* Without scaled windows, MSS is the only interesting option. */
\r
1250 /* Or else we continue to check another option: selective ACK. */
\r
1251 pucPtr += TCP_OPT_MSS_LEN;
\r
1252 #endif /* ipconfigUSE_TCP_WIN != 1 */
\r
1256 /* All other options have a length field, so that we easily
\r
1257 can skip past them. */
\r
1258 int len = ( int )pucPtr[ 1 ];
\r
1261 /* If the length field is zero, the options are malformed
\r
1262 and we don't process them further. */
\r
1266 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1268 /* Selective ACK: the peer has received a packet but it is missing earlier
\r
1269 packets. At least this packet does not need retransmission anymore
\r
1270 ulTCPWindowTxSack( ) takes care of this administration. */
\r
1271 if( pucPtr[0] == TCP_OPT_SACK_A )
\r
1278 uint32_t ulFirst = ulChar2u32( pucPtr );
\r
1279 uint32_t ulLast = ulChar2u32( pucPtr + 4 );
\r
1280 uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );
\r
1281 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
\r
1282 starting from the head position.
\r
1283 Advance the tail pointer in txStream. */
\r
1284 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
\r
1286 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
\r
1287 uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
\r
1288 pxSocket->xEventBits |= eSOCKET_SEND;
\r
1290 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
1292 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1294 /* The field 'xEventBits' is used to store regular socket events (at most 8),
\r
1295 as well as 'select events', which will be left-shifted */
\r
1296 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1301 /* In case the socket owner has installed an OnSent handler,
\r
1303 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1305 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
1307 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
1310 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
1315 /* len should be 0 by now. */
\r
1317 #if ipconfigUSE_TCP_TIMESTAMPS == 1
\r
1318 else if( pucPtr[0] == TCP_OPT_TIMESTAMP )
\r
1320 len -= 2; /* Skip option and length byte. */
\r
1322 pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;
\r
1323 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = ulChar2u32( pucPtr );
\r
1324 pxSocket->u.xTCP.xTCPWindow.tx.ulTimeStamp = ulChar2u32( pucPtr + 4 );
\r
1326 #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */
\r
1328 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1334 /*-----------------------------------------------------------*/
\r
1336 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1338 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
\r
1343 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
\r
1344 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
\r
1346 while( uxWinSize > 0xfffful )
\r
1348 /* Divide by two and increase the binary factor by 1. */
\r
1353 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
\r
1354 pxSocket->u.xTCP.uxRxWinSize,
\r
1355 pxSocket->u.xTCP.usInitMSS,
\r
1362 /*-----------------------------------------------------------*/
\r
1365 * When opening a TCP connection, while SYN's are being sent, the parties may
\r
1366 * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
\r
1367 * nett size of the payload, always smaller than MTU.
\r
1369 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
\r
1371 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1372 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
\r
1373 UBaseType_t uxOptionsLength;
\r
1375 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
\r
1377 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
\r
1378 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
\r
1379 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
\r
1380 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
\r
1382 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1384 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
\r
1386 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
\r
1387 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
\r
1388 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
\r
1389 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
\r
1390 uxOptionsLength = 8u;
\r
1394 uxOptionsLength = 4u;
\r
1398 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1400 return uxOptionsLength;
\r
1404 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
\r
1405 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
\r
1407 uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, &pxTCPPacket->xTCPHeader );
\r
1408 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1409 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = 2u;
\r
1410 uxOptionsLength += 2u;
\r
1415 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
\r
1416 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
\r
1417 pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1418 pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
\r
1419 uxOptionsLength += 4u;
\r
1421 return uxOptionsLength; /* bytes, not words. */
\r
1423 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1427 * For anti-hanging protection and TCP keep-alive messages. Called in two
\r
1428 * places: after receiving a packet and after a state change. The socket's
\r
1429 * alive timer may be reset.
\r
1431 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
\r
1433 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
1435 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
\r
1439 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
1441 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
\r
1442 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
1443 pxSocket->u.xTCP.ucKeepRepCount = 0u;
\r
1444 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
\r
1448 ( void ) pxSocket;
\r
1450 /*-----------------------------------------------------------*/
\r
1453 * Changing to a new state. Centralised here to do specific actions such as
\r
1454 * resetting the alive timer, calling the user's OnConnect handler to notify
\r
1455 * that a socket has got (dis)connected, and setting bit to unblock a call to
\r
1456 * FreeRTOS_select()
\r
1458 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
\r
1460 FreeRTOS_Socket_t *xParent = NULL;
\r
1461 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
\r
1462 BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
\r
1463 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1464 BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
\r
1466 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1467 FreeRTOS_Socket_t *xConnected = NULL;
\r
1470 /* Has the connected status changed? */
\r
1471 if( bBefore != bAfter )
\r
1473 /* Is the socket connected now ? */
\r
1474 if( bAfter != pdFALSE )
\r
1476 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
\r
1477 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
1479 /* Now that it is connected, find it's parent. */
\r
1480 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
1482 xParent = pxSocket;
\r
1486 xParent = pxSocket->u.xTCP.pxPeerSocket;
\r
1487 configASSERT( xParent != NULL );
\r
1489 if( xParent != NULL )
\r
1491 if( xParent->u.xTCP.pxPeerSocket == NULL )
\r
1493 xParent->u.xTCP.pxPeerSocket = pxSocket;
\r
1496 xParent->xEventBits |= eSOCKET_ACCEPT;
\r
1498 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1500 /* Library support FreeRTOS_select(). Receiving a new
\r
1501 connection is being translated as a READ event. */
\r
1502 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
\r
1504 xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
\r
1509 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1511 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
\r
1512 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
\r
1514 /* The listening socket does not become connected itself, in stead
\r
1515 a child socket is created.
\r
1516 Postpone a call the OnConnect event until the end of this function. */
\r
1517 xConnected = xParent;
\r
1523 /* Don't need to access the parent socket anymore, so the
\r
1524 reference 'pxPeerSocket' may be cleared. */
\r
1525 pxSocket->u.xTCP.pxPeerSocket = NULL;
\r
1526 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
\r
1528 /* When true, this socket may be returned in a call to accept(). */
\r
1529 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
1533 pxSocket->xEventBits |= eSOCKET_CONNECT;
\r
1535 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1537 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1539 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1545 else /* bAfter == pdFALSE, connection is closed. */
\r
1547 /* Notify/wake-up the socket-owner by setting a semaphore. */
\r
1548 pxSocket->xEventBits |= eSOCKET_CLOSED;
\r
1550 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1552 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
\r
1554 pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
\r
1559 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1561 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
\r
1563 /* The 'connected' state has changed, call the user handler. */
\r
1564 xConnected = pxSocket;
\r
1567 #endif /* ipconfigUSE_CALLBACKS */
\r
1569 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
\r
1571 /* Now the socket isn't in an active state anymore so it
\r
1572 won't need further attention of the IP-task.
\r
1573 Setting time-out to zero means that the socket won't get checked during
\r
1575 pxSocket->u.xTCP.usTimeout = 0u;
\r
1580 if( eTCPState == eCLOSED )
\r
1582 /* Socket goes to status eCLOSED because of a RST.
\r
1583 When nobody owns the socket yet, delete it. */
\r
1584 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
\r
1585 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
1587 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
\r
1588 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
1590 FreeRTOS_closesocket( pxSocket );
\r
1596 /* Fill in the new state. */
\r
1597 pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
\r
1599 /* Touch the alive timers because moving to another state. */
\r
1600 prvTCPTouchSocket( pxSocket );
\r
1602 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
1604 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
1605 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
\r
1606 pxSocket->usLocalPort,
\r
1607 pxSocket->u.xTCP.ulRemoteIP,
\r
1608 pxSocket->u.xTCP.usRemotePort,
\r
1609 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
\r
1610 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
\r
1612 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1614 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1616 if( xConnected != NULL )
\r
1618 /* The 'connected' state has changed, call the OnConnect handler of the parent. */
\r
1619 xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );
\r
1623 if( xParent != NULL )
\r
1625 vSocketWakeUpUser( xParent );
\r
1628 /*-----------------------------------------------------------*/
\r
1630 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
1631 int32_t lDataLen, UBaseType_t uxOptionsLength )
\r
1633 NetworkBufferDescriptor_t *pxReturn;
\r
1635 BaseType_t xResize;
\r
1637 if( xBufferAllocFixedSize != pdFALSE )
\r
1639 /* Network buffers are created with a fixed size and can hold the largest
\r
1641 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
\r
1642 /* and therefore, the buffer won't be too small.
\r
1643 Only ask for a new network buffer in case none was supplied. */
\r
1644 xResize = ( pxNetworkBuffer == NULL );
\r
1648 /* Network buffers are created with a variable size. See if it must
\r
1650 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
\r
1651 ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
\r
1652 /* In case we were called from a TCP timer event, a buffer must be
\r
1653 created. Otherwise, test 'xDataLength' of the provided buffer. */
\r
1654 if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) )
\r
1660 xResize = pdFALSE;
\r
1664 if( xResize != pdFALSE )
\r
1666 /* The caller didn't provide a network buffer or the provided buffer is
\r
1667 too small. As we must send-out a data packet, a buffer will be created
\r
1669 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
\r
1671 if( pxReturn != NULL )
\r
1673 /* Copy the existing data to the new created buffer. */
\r
1674 if( pxNetworkBuffer )
\r
1676 /* Either from the previous buffer... */
\r
1677 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
1679 /* ...and release it. */
\r
1680 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1684 /* Or from the socket field 'xTCP.xPacket'. */
\r
1685 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1691 /* xResize is false, the network buffer provided was big enough. */
\r
1692 pxReturn = pxNetworkBuffer;
\r
1694 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
\r
1695 xDataLength member must get the correct length too! */
\r
1696 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
\r
1701 /*-----------------------------------------------------------*/
\r
1704 * Prepare an outgoing message, in case anything has to be sent.
\r
1706 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
\r
1709 uint8_t *pucEthernetBuffer, *pucSendData;
\r
1710 TCPPacket_t *pxTCPPacket;
\r
1712 uint32_t ulDataGot, ulDistance;
\r
1713 TCPWindow_t *pxTCPWindow;
\r
1714 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1715 int32_t lStreamPos;
\r
1717 if( ( *ppxNetworkBuffer ) != NULL )
\r
1719 /* A network buffer descriptor was already supplied */
\r
1720 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
\r
1724 /* For now let it point to the last packet header */
\r
1725 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1728 pxTCPPacket = ( TCPPacket_t * ) pucEthernetBuffer;
\r
1729 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
1732 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
\r
1734 if( pxSocket->u.xTCP.txStream != NULL )
\r
1736 /* ulTCPWindowTxGet will return the amount of data which may be sent
\r
1737 along with the position in the txStream.
\r
1738 Why check for MSS > 1 ?
\r
1739 Because some TCP-stacks (like uIP) use it for flow-control. */
\r
1740 if( pxSocket->u.xTCP.usCurMSS > 1u )
\r
1742 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
\r
1745 if( lDataLen > 0 )
\r
1747 /* Check if the current network buffer is big enough, if not,
\r
1749 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
\r
1751 if( pxNewBuffer != NULL )
\r
1753 *ppxNetworkBuffer = pxNewBuffer;
\r
1754 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
\r
1755 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1757 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
\r
1759 /* Translate the position in txStream to an offset from the tail
\r
1761 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
\r
1763 /* Here data is copied from the txStream in 'peek' mode. Only
\r
1764 when the packets are acked, the tail marker will be updated. */
\r
1765 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
\r
1767 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1769 if( ulDataGot != ( uint32_t ) lDataLen )
\r
1771 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
\r
1772 lStreamPos, uxOffset, ulDataGot, lDataLen ) );
\r
1777 /* If the owner of the socket requests a closure, add the FIN
\r
1778 flag to the last packet. */
\r
1779 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
\r
1781 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
\r
1783 if( ulDistance == ulDataGot )
\r
1785 #if (ipconfigHAS_DEBUG_PRINTF == 1)
\r
1787 /* the order of volatile accesses is undefined
\r
1788 so such workaround */
\r
1789 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
\r
1790 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
\r
1791 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
\r
1793 FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
\r
1794 uxTail, uxMid, uxHead ) );
\r
1797 /* Although the socket sends a FIN, it will stay in
\r
1798 ESTABLISHED until all current data has been received or
\r
1800 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1801 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
\r
1802 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1813 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
\r
1815 /* See if the socket owner wants to shutdown this connection. */
\r
1816 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
\r
1817 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
\r
1819 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
\r
1820 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1821 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1822 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
1823 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1824 vTCPStateChange( pxSocket, eFIN_WAIT_1 );
\r
1827 #if( ipconfigTCP_KEEP_ALIVE != 0 )
\r
1829 if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
\r
1831 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
\r
1832 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
1833 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
1834 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
1837 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
\r
1839 /* If there is no data to be sent, and no window-update message,
\r
1840 we might want to send a keep-alive message. */
\r
1841 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
\r
1843 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
\r
1844 if( pxSocket->u.xTCP.ucKeepRepCount )
\r
1846 xMax = ( 3u * configTICK_RATE_HZ );
\r
1850 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
\r
1851 if( xTCPWindowLoggingLevel )
\r
1852 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
\r
1853 pxSocket->u.xTCP.ulRemoteIP,
\r
1854 pxSocket->u.xTCP.usRemotePort,
\r
1855 pxSocket->u.xTCP.ucKeepRepCount ) );
\r
1856 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
\r
1857 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
\r
1858 pxSocket->u.xTCP.ucKeepRepCount++;
\r
1862 #endif /* ipconfigTCP_KEEP_ALIVE */
\r
1865 /* Anything to send, a change of the advertised window size, or maybe send a
\r
1866 keep-alive message? */
\r
1867 if( ( lDataLen > 0 ) ||
\r
1868 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
\r
1869 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
\r
1871 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
\r
1872 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
1874 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
\r
1876 if( lDataLen != 0l )
\r
1878 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
\r
1881 #if ipconfigUSE_TCP_TIMESTAMPS == 1
\r
1883 if( uxOptionsLength == 0u )
\r
1885 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
\r
1887 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1888 uxOptionsLength = prvTCPSetTimeStamp( 0, pxSocket, &pxTCPPacket->xTCPHeader );
\r
1894 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
1899 /*-----------------------------------------------------------*/
\r
1902 * Calculate after how much time this socket needs to be checked again.
\r
1904 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
\r
1906 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1908 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
1910 /* The socket is actively connecting to a peer. */
\r
1911 if( pxSocket->u.xTCP.bits.bConnPrepared )
\r
1913 /* Ethernet address has been found, use progressive timeout for
\r
1914 active connect(). */
\r
1915 if( pxSocket->u.xTCP.ucRepCount < 3u )
\r
1917 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
\r
1921 ulDelayMs = 11000UL;
\r
1926 /* Still in the ARP phase: check every half second. */
\r
1927 ulDelayMs = 500UL;
\r
1930 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
\r
1931 pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
\r
1932 pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
\r
1933 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1935 else if( pxSocket->u.xTCP.usTimeout == 0u )
\r
1937 /* Let the sliding window mechanism decide what time-out is appropriate. */
\r
1938 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
\r
1939 if( ulDelayMs == 0u )
\r
1941 if( xResult != ( BaseType_t )0 )
\r
1947 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1952 /* ulDelayMs contains the time to wait before a re-transmission. */
\r
1954 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1958 /* field '.usTimeout' has already been set (by the
\r
1959 keep-alive/delayed-ACK mechanism). */
\r
1962 /* Return the number of clock ticks before the timer expires. */
\r
1963 return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
\r
1965 /*-----------------------------------------------------------*/
\r
1967 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
\r
1969 int32_t lCount, lLength;
\r
1971 /* A txStream has been created already, see if the socket has new data for
\r
1972 the sliding window.
\r
1974 uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It
\r
1975 contains new Tx data which has not been passed to the sliding window yet.
\r
1976 The oldest data not-yet-confirmed can be found at rxTail. */
\r
1977 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
\r
1981 /* All data between txMid and rxHead will now be passed to the sliding
\r
1982 window manager, so it can start transmitting them.
\r
1984 Hand over the new data to the sliding window handler. It will be
\r
1985 split-up in chunks of 1460 bytes each (or less, depending on
\r
1986 ipconfigTCP_MSS). */
\r
1987 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
\r
1988 ( uint32_t ) lLength,
\r
1989 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
\r
1990 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
\r
1992 /* Move the rxMid pointer forward up to rxHead. */
\r
1995 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
\r
1999 /*-----------------------------------------------------------*/
\r
2002 * prvTCPHandleFin() will be called to handle socket closure
\r
2003 * The Closure starts when either a FIN has been received and accepted,
\r
2004 * Or when the socket has sent a FIN flag to the peer
\r
2005 * Before being called, it has been checked that both reception and transmission
\r
2008 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2010 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2011 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2012 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2013 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2014 BaseType_t xSendLength = 0;
\r
2015 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
\r
2017 if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
\r
2019 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
\r
2021 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2023 /* We haven't yet replied with a FIN, do so now. */
\r
2024 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2025 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
2029 /* We did send a FIN already, see if it's ACK'd. */
\r
2030 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
\r
2032 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
\r
2036 if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
\r
2038 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2039 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
\r
2041 /* And wait for the final ACK. */
\r
2042 vTCPStateChange( pxSocket, eLAST_ACK );
\r
2046 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
\r
2047 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
\r
2048 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
\r
2050 /* We have sent out a FIN but the peer hasn't replied with a FIN
\r
2051 yet. Do nothing for the moment. */
\r
2052 pxTCPHeader->ucTCPFlags = 0u;
\r
2056 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
\r
2058 /* This is the third of the three-way hand shake: the last
\r
2060 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2064 /* The other party started the closure, so we just wait for the
\r
2066 pxTCPHeader->ucTCPFlags = 0u;
\r
2069 /* And wait for the user to close this socket. */
\r
2070 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2074 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2076 if( pxTCPHeader->ucTCPFlags != 0u )
\r
2078 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
\r
2081 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
\r
2083 if( xTCPWindowLoggingLevel != 0 )
\r
2085 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
\r
2086 ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2087 pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2088 pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2089 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2090 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2093 return xSendLength;
\r
2095 /*-----------------------------------------------------------*/
\r
2097 #if ipconfigUSE_TCP_TIMESTAMPS == 1
\r
2099 static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader )
\r
2101 uint32_t ulTimes[2];
\r
2102 uint8_t *ucOptdata = &( pxTCPHeader->ucOptdata[ lOffset ] );
\r
2104 ulTimes[0] = ( xTaskGetTickCount ( ) * 1000u ) / configTICK_RATE_HZ;
\r
2105 ulTimes[0] = FreeRTOS_htonl( ulTimes[0] );
\r
2106 ulTimes[1] = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp );
\r
2107 ucOptdata[0] = ( uint8_t ) TCP_OPT_TIMESTAMP;
\r
2108 ucOptdata[1] = ( uint8_t ) TCP_OPT_TIMESTAMP_LEN;
\r
2109 memcpy( &(ucOptdata[2] ), ulTimes, 8u );
\r
2110 ucOptdata[10] = ( uint8_t ) TCP_OPT_NOOP;
\r
2111 ucOptdata[11] = ( uint8_t ) TCP_OPT_NOOP;
\r
2112 /* Do not return the same timestamps 2 times. */
\r
2113 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = 0ul;
\r
2118 /*-----------------------------------------------------------*/
\r
2121 * prvCheckRxData(): called from prvTCPHandleState()
\r
2123 * The first thing that will be done is find the TCP payload data
\r
2124 * and check the length of this data.
\r
2126 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
\r
2128 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2129 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2130 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
\r
2132 /* Determine the length and the offset of the user-data sent to this
\r
2135 The size of the TCP header is given in a multiple of 4-byte words (single
\r
2136 byte, needs no ntoh() translation). A shift-right 2: is the same as
\r
2137 (offset >> 4) * 4. */
\r
2138 lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
\r
2140 /* Let pucRecvData point to the first byte received. */
\r
2141 *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
\r
2143 /* Calculate lReceiveLength - the length of the TCP data received. This is
\r
2144 equal to the total packet length minus:
\r
2145 ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
\r
2146 lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
\r
2147 lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
\r
2149 if( lReceiveLength > lLength )
\r
2151 /* More bytes were received than the reported length, often because of
\r
2152 padding bytes at the end. */
\r
2153 lReceiveLength = lLength;
\r
2156 /* Subtract the size of the TCP and IP headers and the actual data size is
\r
2158 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
\r
2160 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
\r
2164 lReceiveLength = 0;
\r
2167 /* Urgent Pointer:
\r
2168 This field communicates the current value of the urgent pointer as a
\r
2169 positive offset from the sequence number in this segment. The urgent
\r
2170 pointer points to the sequence number of the octet following the urgent
\r
2171 data. This field is only be interpreted in segments with the URG control
\r
2173 if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
\r
2175 /* Although we ignore the urgent data, we have to skip it. */
\r
2176 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
\r
2177 *ppucRecvData += lUrgentLength;
\r
2178 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
\r
2181 return ( BaseType_t ) lReceiveLength;
\r
2183 /*-----------------------------------------------------------*/
\r
2186 * prvStoreRxData(): called from prvTCPHandleState()
\r
2188 * The second thing is to do is check if the payload data may be accepted
\r
2189 * If so, they will be added to the reception queue.
\r
2191 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
2192 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
\r
2194 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2195 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2196 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2197 uint32_t ulSequenceNumber, ulSpace;
\r
2198 int32_t lOffset, lStored;
\r
2199 BaseType_t xResult = 0;
\r
2201 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2203 if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
\r
2205 /* See if way may accept the data contents and forward it to the socket
\r
2208 If it can't be "accept"ed it may have to be stored and send a selective
\r
2209 ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
\r
2210 called later to store an out-of-order packet (in case lOffset is
\r
2212 if ( pxSocket->u.xTCP.rxStream )
\r
2214 ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
\r
2218 ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
\r
2221 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
\r
2223 if( lOffset >= 0 )
\r
2225 /* New data has arrived and may be made available to the user. See
\r
2226 if the head marker in rxStream may be advanced, only if lOffset == 0.
\r
2227 In case the low-water mark is reached, bLowWater will be set
\r
2228 "low-water" here stands for "little space". */
\r
2229 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
\r
2231 if( lStored != ( int32_t ) ulReceiveLength )
\r
2233 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
\r
2235 /* Received data could not be stored. The socket's flag
\r
2236 bMallocError has been set. The socket now has the status
\r
2237 eCLOSE_WAIT and a RST packet will be sent back. */
\r
2238 prvTCPSendReset( pxNetworkBuffer );
\r
2243 /* After a missing packet has come in, higher packets may be passed to
\r
2245 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2247 /* Now lTCPAddRxdata() will move the rxHead pointer forward
\r
2248 so data becomes available to the user immediately
\r
2249 In case the low-water mark is reached, bLowWater will be set. */
\r
2250 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
\r
2252 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
\r
2253 pxTCPWindow->ulUserDataLength = 0;
\r
2256 #endif /* ipconfigUSE_TCP_WIN */
\r
2260 pxTCPWindow->ucOptionLength = 0u;
\r
2265 /*-----------------------------------------------------------*/
\r
2267 /* Set the TCP options (if any) for the outgoing packet. */
\r
2268 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2270 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2271 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2272 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2273 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
\r
2275 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2276 if( uxOptionsLength != 0u )
\r
2278 /* TCP options must be sent because a packet which is out-of-order
\r
2280 if( xTCPWindowLoggingLevel >= 0 )
\r
2281 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
\r
2282 pxSocket->usLocalPort,
\r
2283 pxSocket->u.xTCP.usRemotePort,
\r
2285 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
2286 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
\r
2287 memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
\r
2289 /* The header length divided by 4, goes into the higher nibble,
\r
2290 effectively a shift-left 2. */
\r
2291 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2294 #endif /* ipconfigUSE_TCP_WIN */
\r
2295 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
\r
2297 /* TCP options must be sent because the MSS has changed. */
\r
2298 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
\r
2299 if( xTCPWindowLoggingLevel >= 0 )
\r
2301 FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
\r
2304 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
\r
2305 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
\r
2306 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
\r
2307 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
\r
2308 uxOptionsLength = 4u;
\r
2309 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2312 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
\r
2314 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
\r
2316 uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, pxTCPHeader );
\r
2319 #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */
\r
2321 return uxOptionsLength;
\r
2323 /*-----------------------------------------------------------*/
\r
2326 * prvHandleSynReceived(): called from prvTCPHandleState()
\r
2328 * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
\r
2329 * If the flags received are correct, the socket will move to eESTABLISHED.
\r
2331 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2332 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2334 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2335 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2336 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2337 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2338 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2339 BaseType_t xSendLength = 0;
\r
2341 /* Either expect a ACK or a SYN+ACK. */
\r
2342 uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
\r
2343 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2345 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
\r
2348 if( ( ucTCPFlags & 0x17u ) != usExpect )
\r
2350 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
\r
2351 /* eSYN_RECEIVED: flags ACK expected, not SYN. */
\r
2352 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
\r
2353 pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
\r
2354 usExpect, ucTCPFlags ) );
\r
2355 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2356 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
\r
2357 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2358 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2362 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
\r
2363 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
\r
2365 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2367 TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
2369 /* Clear the SYN flag in lastPacket. */
\r
2370 pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
\r
2372 /* This socket was the one connecting actively so now perofmr the
\r
2373 synchronisation. */
\r
2374 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
\r
2375 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2376 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2377 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
\r
2378 pxTCPWindow->ulNextTxSequenceNumber++;
\r
2380 else if( ulReceiveLength == 0u )
\r
2382 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
2385 /* The SYN+ACK has been confirmed, increase the next sequence number by
\r
2387 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
\r
2389 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2391 FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
\r
2392 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
\r
2393 pxSocket->usLocalPort,
\r
2394 pxSocket->u.xTCP.ulRemoteIP,
\r
2395 pxSocket->u.xTCP.usRemotePort,
\r
2396 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
\r
2398 #endif /* ipconfigUSE_TCP_WIN */
\r
2400 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
\r
2402 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2403 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2404 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2406 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2408 if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
\r
2410 /* The other party did not send a scaling factor.
\r
2411 A shifting factor in this side must be canceled. */
\r
2412 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
\r
2413 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
\r
2416 #endif /* ipconfigUSE_TCP_WIN */
\r
2417 /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
\r
2418 connection is established. */
\r
2419 vTCPStateChange( pxSocket, eESTABLISHED );
\r
2422 return xSendLength;
\r
2424 /*-----------------------------------------------------------*/
\r
2427 * prvHandleEstablished(): called from prvTCPHandleState()
\r
2429 * Called if the status is eESTABLISHED. Data reception has been handled
\r
2430 * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
\r
2431 * the code will check if it may be accepted, i.e. if all expected data has been
\r
2432 * completely received.
\r
2434 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2435 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2437 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2438 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2439 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2440 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2441 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
\r
2442 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
\r
2443 int32_t lDistance, lSendResult;
\r
2445 /* Remember the window size the peer is advertising. */
\r
2446 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
\r
2447 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2449 pxSocket->u.xTCP.ulWindowSize =
\r
2450 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
2454 if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
\r
2456 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
\r
2458 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
\r
2459 starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
\r
2461 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
\r
2463 /* Just advancing the tail index, 'ulCount' bytes have been
\r
2464 confirmed, and because there is new space in the txStream, the
\r
2465 user/owner should be woken up. */
\r
2466 /* _HT_ : only in case the socket's waiting? */
\r
2467 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
\r
2469 pxSocket->xEventBits |= eSOCKET_SEND;
\r
2471 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
2473 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
\r
2475 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
2479 /* In case the socket owner has installed an OnSent handler,
\r
2481 #if( ipconfigUSE_CALLBACKS == 1 )
\r
2483 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
2485 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
2488 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
2493 /* If this socket has a stream for transmission, add the data to the
\r
2494 outgoing segment(s). */
\r
2495 if( pxSocket->u.xTCP.txStream != NULL )
\r
2497 prvTCPAddTxData( pxSocket );
\r
2500 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2502 if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
\r
2504 /* Peer is requesting to stop, see if we're really finished. */
\r
2505 xMayClose = pdTRUE;
\r
2507 /* Checks are only necessary if we haven't sent a FIN yet. */
\r
2508 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2510 /* xTCPWindowTxDone returns true when all Tx queues are empty. */
\r
2511 bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
\r
2512 bTxDone = xTCPWindowTxDone( pxTCPWindow );
\r
2514 if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
\r
2516 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
\r
2517 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
\r
2518 pxSocket->usLocalPort,
\r
2519 pxSocket->u.xTCP.usRemotePort,
\r
2520 bRxComplete, bTxDone ) );
\r
2521 xMayClose = pdFALSE;
\r
2525 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2527 if( lDistance > 1 )
\r
2529 FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
\r
2530 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2531 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2533 xMayClose = pdFALSE;
\r
2538 if( xTCPWindowLoggingLevel > 0 )
\r
2540 FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
\r
2541 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
\r
2542 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
\r
2545 if( xMayClose != pdFALSE )
\r
2547 pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
\r
2548 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2552 if( xMayClose == pdFALSE )
\r
2554 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2556 if( ulReceiveLength != 0u )
\r
2558 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2559 /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
\r
2560 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2562 if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
\r
2564 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2568 /* Now get data to be transmitted. */
\r
2569 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
\r
2570 can not send-out both TCP options and also a full packet. Sending
\r
2571 options (SACK) is always more urgent than sending data, which can be
\r
2573 if( uxOptionsLength == 0u )
\r
2575 /* prvTCPPrepareSend might allocate a bigger network buffer, if
\r
2577 lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
2578 if( lSendResult > 0 )
\r
2580 xSendLength = ( BaseType_t ) lSendResult;
\r
2585 return xSendLength;
\r
2587 /*-----------------------------------------------------------*/
\r
2590 * Called from prvTCPHandleState(). There is data to be sent. If
\r
2591 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
\r
2592 * checked if it would better be postponed for efficiency.
\r
2594 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2595 uint32_t ulReceiveLength, BaseType_t xSendLength )
\r
2597 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2598 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2599 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2600 /* Find out what window size we may advertised. */
\r
2601 uint32_t ulFrontSpace;
\r
2603 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2604 #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
\r
2605 const int32_t lMinLength = 0;
\r
2607 int32_t lMinLength;
\r
2610 pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -
\r
2611 ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2613 /* Free space in rxStream. */
\r
2614 if( pxSocket->u.xTCP.rxStream != NULL )
\r
2616 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
2620 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
2623 pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );
\r
2625 /* Set the time-out field, so that we'll be called by the IP-task in case no
\r
2626 next message will be received. */
\r
2627 lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2628 #if ipconfigUSE_TCP_WIN == 1
\r
2631 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
\r
2633 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2635 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
\r
2637 /* In case we're receiving data continuously, we might postpone sending
\r
2638 an ACK to gain performance. */
\r
2639 if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
\r
2640 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
\r
2641 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
\r
2642 ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
\r
2643 ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
\r
2644 ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
\r
2646 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2648 /* There was still a delayed in queue, delete it. */
\r
2649 if( pxSocket->u.xTCP.pxAckMessage != 0 )
\r
2651 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2654 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
\r
2656 if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
\r
2657 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
\r
2659 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
\r
2663 /* Normally a delayed ACK should wait 200 ms for a next incoming
\r
2664 packet. Only wait 20 ms here to gain performance. A slow ACK
\r
2665 for full-size message. */
\r
2666 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
\r
2669 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2671 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
\r
2672 pxSocket->usLocalPort,
\r
2673 pxSocket->u.xTCP.usRemotePort,
\r
2674 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2675 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2677 pxSocket->u.xTCP.usTimeout, lRxSpace ) );
\r
2680 *ppxNetworkBuffer = NULL;
\r
2683 else if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
2685 /* As an ACK is not being delayed, remove any earlier delayed ACK
\r
2687 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2689 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2692 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
2697 /* Remove compiler warnings. */
\r
2698 ( void ) ulReceiveLength;
\r
2699 ( void ) pxTCPHeader;
\r
2700 ( void ) lRxSpace;
\r
2702 #endif /* ipconfigUSE_TCP_WIN */
\r
2704 if( xSendLength != 0 )
\r
2706 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2708 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
\r
2709 pxSocket->usLocalPort,
\r
2710 pxSocket->u.xTCP.usRemotePort,
\r
2711 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2712 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2716 /* Set the parameter 'xReleaseAfterSend' to the value of
\r
2717 ipconfigZERO_COPY_TX_DRIVER. */
\r
2718 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
2719 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
2721 /* The driver has taken ownership of the Network Buffer. */
\r
2722 *ppxNetworkBuffer = NULL;
\r
2727 return xSendLength;
\r
2729 /*-----------------------------------------------------------*/
\r
2732 * prvTCPHandleState()
\r
2733 * is the most important function of this TCP stack
\r
2734 * We've tried to keep it (relatively short) by putting a lot of code in
\r
2735 * the static functions above:
\r
2737 * prvCheckRxData()
\r
2738 * prvStoreRxData()
\r
2740 * prvHandleSynReceived()
\r
2741 * prvHandleEstablished()
\r
2744 * As these functions are declared static, and they're called from one location
\r
2745 * only, most compilers will inline them, thus avoiding a call and return.
\r
2747 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
2749 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2750 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2751 BaseType_t xSendLength = 0;
\r
2752 uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
\r
2753 uint8_t *pucRecvData;
\r
2754 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
\r
2756 /* uxOptionsLength: the size of the options to be sent (always a multiple of
\r
2758 1. in the SYN phase, we shall communicate the MSS
\r
2759 2. in case of a SACK, Selective ACK, ack a segment which comes in
\r
2761 UBaseType_t uxOptionsLength = 0u;
\r
2762 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2763 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
2765 /* First get the length and the position of the received data, if any.
\r
2766 pucRecvData will point to the first byte of the TCP payload. */
\r
2767 ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
\r
2769 if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
\r
2771 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
\r
2773 /* This is most probably a keep-alive message from peer. Setting
\r
2774 'bWinChange' doesn't cause a window-size-change, the flag is used
\r
2775 here to force sending an immediate ACK. */
\r
2776 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
2780 /* Keep track of the highest sequence number that might be expected within
\r
2781 this connection. */
\r
2782 if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
\r
2784 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2787 /* Storing data may result in a fatal error if malloc() fails. */
\r
2788 if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
\r
2794 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
\r
2796 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
\r
2798 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
\r
2800 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
\r
2801 'SYN+ACK' didn't arrive. Step back to the previous state in which
\r
2802 a first incoming SYN is handled. The SYN was counted already so
\r
2803 decrease it first. */
\r
2804 vTCPStateChange( pxSocket, eSYN_FIRST );
\r
2807 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
\r
2809 /* It's the first time a FIN has been received, remember its
\r
2810 sequence number. */
\r
2811 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2812 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
\r
2814 /* Was peer the first one to send a FIN? */
\r
2815 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2817 /* If so, don't send the-last-ACK. */
\r
2818 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
\r
2822 switch (pxSocket->u.xTCP.ucTCPState)
\r
2824 case eCLOSED: /* (server + client) no connection state at all. */
\r
2825 /* Nothing to do for a closed socket, except waiting for the
\r
2829 case eTCP_LISTEN: /* (server) waiting for a connection request from
\r
2830 any remote TCP and port. */
\r
2831 /* The listen state was handled in xProcessReceivedTCPPacket().
\r
2832 Should not come here. */
\r
2835 case eSYN_FIRST: /* (server) Just received a SYN request for a server
\r
2838 /* A new socket has been created, reply with a SYN+ACK.
\r
2839 Acknowledge with seq+1 because the SYN is seen as pseudo data
\r
2841 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
2842 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
\r
2844 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2846 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
2847 uxOptionsLength is a multiple of 4. The complete expression is:
\r
2848 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
2849 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2850 vTCPStateChange( pxSocket, eSYN_RECEIVED );
\r
2852 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2853 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
\r
2857 case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
\r
2858 SYN, expect a SYN+ACK and send a ACK now. */
\r
2859 /* Fall through */
\r
2860 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
\r
2861 expect a ACK and do nothing. */
\r
2862 xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2865 case eESTABLISHED: /* (server + client) an open connection, data
\r
2866 received can be delivered to the user. The normal
\r
2867 state for the data transfer phase of the connection
\r
2868 The closing states are also handled here with the
\r
2869 use of some flags. */
\r
2870 xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2873 case eLAST_ACK: /* (server + client) waiting for an acknowledgement
\r
2874 of the connection termination request previously
\r
2875 sent to the remote TCP (which includes an
\r
2876 acknowledgement of its connection termination
\r
2878 /* Fall through */
\r
2879 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
\r
2880 * or an acknowledgement of the connection termination request previously sent. */
\r
2881 /* Fall through */
\r
2882 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
\r
2883 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2886 case eCLOSE_WAIT: /* (server + client) waiting for a connection
\r
2887 termination request from the local user. Nothing to
\r
2888 do, connection is closed, wait for owner to close
\r
2892 case eCLOSING: /* (server + client) waiting for a connection
\r
2893 termination request acknowledgement from the remote
\r
2897 case eTIME_WAIT: /* (either server or client) waiting for enough time
\r
2898 to pass to be sure the remote TCP received the
\r
2899 acknowledgement of its connection termination
\r
2900 request. [According to RFC 793 a connection can stay
\r
2901 in TIME-WAIT for a maximum of four minutes known as
\r
2902 a MSL (maximum segment lifetime).] These states are
\r
2903 implemented implicitly by settings flags like
\r
2904 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
\r
2911 if( xSendLength > 0 )
\r
2913 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
\r
2916 return xSendLength;
\r
2918 /*-----------------------------------------------------------*/
\r
2920 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2922 #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
\r
2924 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2925 const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
\r
2927 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;
\r
2928 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
\r
2930 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );
\r
2932 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
\r
2934 /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
\r
2935 ( void ) pxNetworkBuffer;
\r
2937 /* The packet was not consumed. */
\r
2940 /*-----------------------------------------------------------*/
\r
2942 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
\r
2944 uint32_t ulMSS = ipconfigTCP_MSS;
\r
2946 if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
\r
2948 /* Data for this peer will pass through a router, and maybe through
\r
2949 the internet. Limit the MSS to 1400 bytes or less. */
\r
2950 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
\r
2953 FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
\r
2955 pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
\r
2957 /*-----------------------------------------------------------*/
\r
2960 * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
\r
2961 * xProcessReceivedTCPPacket()
\r
2962 * prvTCPHandleState()
\r
2963 * prvTCPPrepareSend()
\r
2964 * prvTCPReturnPacket()
\r
2965 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2966 * prvTCPSendRepeated()
\r
2967 * prvTCPReturnPacket() // Prepare for returning
\r
2968 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2970 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2972 FreeRTOS_Socket_t *pxSocket;
\r
2973 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2974 uint16_t ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
\r
2975 uint32_t ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
\r
2976 uint16_t xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
\r
2977 uint32_t ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
2978 uint16_t xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
2979 BaseType_t xResult = pdPASS;
\r
2981 /* Find the destination socket, and if not found: return a socket listing to
\r
2982 the destination PORT. */
\r
2983 pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
\r
2985 if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
\r
2987 /* A TCP messages is received but either there is no socket with the
\r
2988 given port number or the there is a socket, but it is in one of these
\r
2989 non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
\r
2992 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
\r
2994 /* Send a RST to all packets that can not be handled. As a result
\r
2995 the other party will get a ECONN error. There are two exceptions:
\r
2996 1) A packet that already has the RST flag set.
\r
2997 2) A packet that only has the ACK flag set.
\r
2998 A packet with only the ACK flag set might be the last ACK in
\r
2999 a three-way hand-shake that closes a connection. */
\r
3000 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
\r
3001 ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
\r
3003 prvTCPSendReset( pxNetworkBuffer );
\r
3006 /* The packet can't be handled. */
\r
3011 pxSocket->u.xTCP.ucRepCount = 0u;
\r
3013 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
\r
3015 /* The matching socket is in a listening state. Test if the peer
\r
3016 has set the SYN flag. */
\r
3017 if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
\r
3019 /* What happens: maybe after a reboot, a client doesn't know the
\r
3020 connection had gone. Send a RST in order to get a new connect
\r
3022 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
3024 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
\r
3025 prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
\r
3027 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
3029 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
\r
3031 prvTCPSendReset( pxNetworkBuffer );
\r
3037 /* prvHandleListen() will either return a newly created socket
\r
3038 (if bReuseSocket is false), otherwise it returns the current
\r
3039 socket which will later get connected. */
\r
3040 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
\r
3042 if( pxSocket == NULL )
\r
3047 } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
\r
3050 /* This is not a socket in listening mode. Check for the RST
\r
3052 if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
\r
3054 /* The target socket is not in a listening state, any RST packet
\r
3055 will cause the socket to be closed. */
\r
3056 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
\r
3057 /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */
\r
3058 vTCPStateChange( pxSocket, eCLOSED );
\r
3060 /* The packet cannot be handled. */
\r
3063 else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
\r
3065 /* SYN flag while this socket is already connected. */
\r
3066 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
\r
3068 /* The packet cannot be handled. */
\r
3073 /* Update the copy of the TCP header only (skipping eth and IP
\r
3074 headers). It might be used later on, whenever data must be sent
\r
3076 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
\r
3077 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
\r
3082 if( xResult != pdFAIL )
\r
3084 /* Touch the alive timers because we received a message for this
\r
3086 prvTCPTouchSocket( pxSocket );
\r
3088 /* Parse the TCP option(s), if present. */
\r
3089 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
\r
3090 then we MUST assume an MSS size of 536 bytes for backward compatibility. */
\r
3092 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
3093 the number 5 (words) in the higher niblle of the TCP-offset byte. */
\r
3094 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
\r
3096 prvCheckOptions( pxSocket, pxNetworkBuffer );
\r
3100 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3102 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
\r
3103 pxSocket->u.xTCP.ulWindowSize =
\r
3104 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
3108 /* In prvTCPHandleState() the incoming messages will be handled
\r
3109 depending on the current state of the connection. */
\r
3110 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
\r
3112 /* prvTCPHandleState() has sent a message, see if there are more to
\r
3113 be transmitted. */
\r
3114 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3116 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
3118 #endif /* ipconfigUSE_TCP_WIN */
\r
3121 if( pxNetworkBuffer != NULL )
\r
3123 /* We must check if the buffer is unequal to NULL, because the
\r
3124 socket might keep a reference to it in case a delayed ACK must be
\r
3126 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
3127 pxNetworkBuffer = NULL;
\r
3130 /* And finally, calculate when this socket wants to be woken up. */
\r
3131 prvTCPNextTimeout ( pxSocket );
\r
3132 /* Return pdPASS to tell that the network buffer is 'consumed'. */
\r
3136 /* pdPASS being returned means the buffer has been consumed. */
\r
3139 /*-----------------------------------------------------------*/
\r
3141 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
3143 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
3144 FreeRTOS_Socket_t *pxReturn;
\r
3146 /* A pure SYN (without ACK) has come in, create a new socket to answer
\r
3148 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
3150 /* The flag bReuseSocket indicates that the same instance of the
\r
3151 listening socket should be used for the connection. */
\r
3152 pxReturn = pxSocket;
\r
3153 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3154 pxSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3158 /* The socket does not have the bReuseSocket flag set meaning create a
\r
3159 new socket when a connection comes in. */
\r
3162 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
\r
3164 FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
\r
3165 pxSocket->usLocalPort,
\r
3166 pxSocket->u.xTCP.usChildCount,
\r
3167 pxSocket->u.xTCP.usBacklog,
\r
3168 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
\r
3169 prvTCPSendReset( pxNetworkBuffer );
\r
3173 FreeRTOS_Socket_t *pxNewSocket = (FreeRTOS_Socket_t *)
\r
3174 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
3176 if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
\r
3178 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
\r
3179 prvTCPSendReset( pxNetworkBuffer );
\r
3181 else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
\r
3183 /* The socket will be connected immediately, no time for the
\r
3184 owner to setsockopt's, therefore copy properties of the server
\r
3185 socket to the new socket. Only the binding might fail (due to
\r
3186 lack of resources). */
\r
3187 pxReturn = pxNewSocket;
\r
3192 if( pxReturn != NULL )
\r
3194 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
3195 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
3196 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;
\r
3198 /* Here is the SYN action. */
\r
3199 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
3200 prvSocketSetMSS( pxReturn );
\r
3202 prvTCPCreateWindow( pxReturn );
\r
3204 /* It is recommended to increase the ISS for each new connection with a value of 0x102. */
\r
3205 ulNextInitialSequenceNumber += INITIAL_SEQUENCE_NUMBER_INCREMENT;
\r
3207 vTCPStateChange( pxReturn, eSYN_FIRST );
\r
3209 /* Make a copy of the header up to the TCP header. It is needed later
\r
3210 on, whenever data must be sent to the peer. */
\r
3211 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
\r
3215 /*-----------------------------------------------------------*/
\r
3218 * Duplicates a socket after a listening socket receives a connection.
\r
3220 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
\r
3222 struct freertos_sockaddr xAddress;
\r
3224 pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
\r
3225 pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
\r
3226 pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
\r
3227 pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
\r
3228 pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
\r
3229 pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
\r
3230 pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
\r
3231 pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
\r
3232 pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
\r
3234 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
\r
3236 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
\r
3238 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
\r
3240 #if( ipconfigUSE_CALLBACKS == 1 )
\r
3242 /* In case call-backs are used, copy them from parent to child. */
\r
3243 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
\r
3244 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
\r
3245 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
\r
3247 #endif /* ipconfigUSE_CALLBACKS */
\r
3249 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
3251 /* Child socket of listening sockets will inherit the Socket Set
\r
3252 Otherwise the owner has no chance of including it into the set. */
\r
3253 if( pxSocket->pxSocketSet )
\r
3255 pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
\r
3256 pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
\r
3259 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
3261 /* And bind it to the same local port as its parent. */
\r
3262 xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
\r
3263 xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3265 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
3267 /* Only when there is anti-hanging protection, a socket may become an
\r
3268 orphan temporarily. Once this socket is really connected, the owner of
\r
3269 the server socket will be notified. */
\r
3271 /* When bPassQueued is true, the socket is an orphan until it gets
\r
3273 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3274 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3278 /* A reference to the new socket may be stored and the socket is marked
\r
3281 /* When bPassAccept is true, this socket may be returned in a call to
\r
3283 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
3284 if(pxSocket->u.xTCP.pxPeerSocket == NULL )
\r
3286 pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
\r
3291 pxSocket->u.xTCP.usChildCount++;
\r
3293 FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
\r
3294 pxSocket->usLocalPort,
\r
3295 pxSocket->u.xTCP.usChildCount,
\r
3296 pxSocket->u.xTCP.usBacklog,
\r
3297 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
\r
3299 /* Now bind the child socket to the same port as the listening socket. */
\r
3300 if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
\r
3302 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
\r
3303 vSocketClose( pxNewSocket );
\r
3309 /*-----------------------------------------------------------*/
\r
3311 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
3313 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
\r
3315 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
\r
3317 ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
\r
3319 return pcStateNames[ ulState ];
\r
3322 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
\r
3323 /*-----------------------------------------------------------*/
\r
3326 * In the API accept(), the user asks is there is a new client? As API's can
\r
3327 * not walk through the xBoundTCPSocketsList the IP-task will do this.
\r
3329 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
\r
3331 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3332 ListItem_t *pxIterator;
\r
3333 FreeRTOS_Socket_t *pxFound;
\r
3334 BaseType_t xResult = pdFALSE;
\r
3336 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
\r
3337 who has access. */
\r
3338 for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
\r
3339 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
\r
3340 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
3342 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
\r
3344 pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
3345 if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
3347 pxSocket->u.xTCP.pxPeerSocket = pxFound;
\r
3348 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
\r
3356 /*-----------------------------------------------------------*/
\r
3358 #endif /* ipconfigUSE_TCP == 1 */
\r