2 * FreeRTOS+TCP V2.0.7
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
28 * Module which handles the TCP connections for FreeRTOS+TCP.
\r
29 * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
\r
32 * Endianness: in this module all ports and IP addresses are stored in
\r
33 * host byte-order, except fields in the IP-packets
\r
36 /* Standard includes. */
\r
40 /* FreeRTOS includes. */
\r
41 #include "FreeRTOS.h"
\r
46 /* FreeRTOS+TCP includes. */
\r
47 #include "FreeRTOS_IP.h"
\r
48 #include "FreeRTOS_Sockets.h"
\r
49 #include "FreeRTOS_IP_Private.h"
\r
50 #include "FreeRTOS_UDP_IP.h"
\r
51 #include "FreeRTOS_TCP_IP.h"
\r
52 #include "FreeRTOS_DHCP.h"
\r
53 #include "NetworkInterface.h"
\r
54 #include "NetworkBufferManagement.h"
\r
55 #include "FreeRTOS_ARP.h"
\r
56 #include "FreeRTOS_TCP_WIN.h"
\r
59 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
\r
60 #if ipconfigUSE_TCP == 1
\r
62 /* This compile-time test was moved to here because some macro's
\r
63 were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether
\r
64 the defined MTU size can contain at least a complete TCP packet. */
\r
66 #if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )
\r
67 #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.
\r
71 * The meaning of the TCP flags:
\r
73 #define ipTCP_FLAG_FIN 0x0001u /* No more data from sender */
\r
74 #define ipTCP_FLAG_SYN 0x0002u /* Synchronize sequence numbers */
\r
75 #define ipTCP_FLAG_RST 0x0004u /* Reset the connection */
\r
76 #define ipTCP_FLAG_PSH 0x0008u /* Push function: please push buffered data to the recv application */
\r
77 #define ipTCP_FLAG_ACK 0x0010u /* Acknowledgment field is significant */
\r
78 #define ipTCP_FLAG_URG 0x0020u /* Urgent pointer field is significant */
\r
79 #define ipTCP_FLAG_ECN 0x0040u /* ECN-Echo */
\r
80 #define ipTCP_FLAG_CWR 0x0080u /* Congestion Window Reduced */
\r
81 #define ipTCP_FLAG_NS 0x0100u /* ECN-nonce concealment protection */
\r
82 #define ipTCP_FLAG_RSV 0x0E00u /* Reserved, keep 0 */
\r
84 /* A mask to filter all protocol flags. */
\r
85 #define ipTCP_FLAG_CTRL 0x001Fu
\r
88 * A few values of the TCP options:
\r
90 #define TCP_OPT_END 0u /* End of TCP options list */
\r
91 #define TCP_OPT_NOOP 1u /* "No-operation" TCP option */
\r
92 #define TCP_OPT_MSS 2u /* Maximum segment size TCP option */
\r
93 #define TCP_OPT_WSOPT 3u /* TCP Window Scale Option (3-byte long) */
\r
94 #define TCP_OPT_SACK_P 4u /* Advertize that SACK is permitted */
\r
95 #define TCP_OPT_SACK_A 5u /* SACK option with first/last */
\r
96 #define TCP_OPT_TIMESTAMP 8u /* Time-stamp option */
\r
98 #define TCP_OPT_MSS_LEN 4u /* Length of TCP MSS option. */
\r
99 #define TCP_OPT_WSOPT_LEN 3u /* Length of TCP WSOPT option. */
\r
101 #define TCP_OPT_TIMESTAMP_LEN 10 /* fixed length of the time-stamp option */
\r
103 #ifndef ipconfigTCP_ACK_EARLIER_PACKET
\r
104 #define ipconfigTCP_ACK_EARLIER_PACKET 1
\r
108 * The macro NOW_CONNECTED() is use to determine if the connection makes a
\r
109 * transition from connected to non-connected and vice versa.
\r
110 * NOW_CONNECTED() returns true when the status has one of these values:
\r
111 * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
\r
112 * Technically the connection status is closed earlier, but the library wants
\r
113 * to prevent that the socket will be deleted before the last ACK has been
\r
114 * and thus causing a 'RST' packet on either side.
\r
116 #define NOW_CONNECTED( status )\
\r
117 ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )
\r
120 * The highest 4 bits in the TCP offset byte indicate the total length of the
\r
121 * TCP header, divided by 4.
\r
123 #define VALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0u )
\r
126 * Acknowledgements to TCP data packets may be delayed as long as more is being expected.
\r
127 * A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to
\r
128 * gain performance.
\r
130 #define DELAYED_ACK_SHORT_DELAY_MS ( 2 )
\r
131 #define DELAYED_ACK_LONGER_DELAY_MS ( 20 )
\r
134 * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
\r
135 * an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced
\r
138 #define REDUCED_MSS_THROUGH_INTERNET ( 1400 )
\r
141 * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
142 * the number 5 (words) in the higher niblle of the TCP-offset byte.
\r
144 #define TCP_OFFSET_LENGTH_BITS ( 0xf0u )
\r
145 #define TCP_OFFSET_STANDARD_LENGTH ( 0x50u )
\r
148 * Each TCP socket is checked regularly to see if it can send data packets.
\r
149 * By default, the maximum number of packets sent during one check is limited to 8.
\r
150 * This amount may be further limited by setting the socket's TX window size.
\r
152 #if( !defined( SEND_REPEATED_COUNT ) )
\r
153 #define SEND_REPEATED_COUNT ( 8 )
\r
154 #endif /* !defined( SEND_REPEATED_COUNT ) */
\r
157 * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.
\r
158 * When a TCP timer expires, retries and keep-alive messages will be checked.
\r
160 #ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS
\r
161 #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000u
\r
165 * The names of the different TCP states may be useful in logging.
\r
167 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
168 static const char *pcStateNames[] = {
\r
183 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */
\r
186 * Returns true if the socket must be checked. Non-active sockets are waiting
\r
187 * for user action, either connect() or close().
\r
189 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );
\r
192 * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
\r
194 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );
\r
197 * Try to send a series of messages.
\r
199 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
\r
202 * Return or send a packet to the other party.
\r
204 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
205 uint32_t ulLen, BaseType_t xReleaseAfterSend );
\r
208 * Initialise the data structures which keep track of the TCP windowing system.
\r
210 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );
\r
213 * Let ARP look-up the MAC-address of the peer and initialise the first SYN
\r
216 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );
\r
218 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
220 * For logging and debugging: make a string showing the TCP flags.
\r
222 static const char *prvTCPFlagMeaning( UBaseType_t xFlags);
\r
223 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
226 * Parse the TCP option(s) received, if present.
\r
228 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
231 * Set the initial properties in the options fields, like the preferred
\r
232 * value of MSS and whether SACK allowed. Will be transmitted in the state
\r
235 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );
\r
238 * For anti-hang protection and TCP keep-alive messages. Called in two places:
\r
239 * after receiving a packet and after a state change. The socket's alive timer
\r
242 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );
\r
245 * Prepare an outgoing message, if anything has to be sent.
\r
247 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );
\r
250 * Calculate when this socket needs to be checked to do (re-)transmissions.
\r
252 static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );
\r
255 * The API FreeRTOS_send() adds data to the TX stream. Add
\r
256 * this data to the windowing system to it can be transmitted.
\r
258 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );
\r
261 * Called to handle the closure of a TCP connection.
\r
263 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
266 * Called from prvTCPHandleState(). Find the TCP payload data and check and
\r
267 * return its length.
\r
269 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );
\r
272 * Called from prvTCPHandleState(). Check if the payload data may be accepted.
\r
273 * If so, it will be added to the socket's reception queue.
\r
275 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
276 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );
\r
279 * Set the TCP options (if any) for the outgoing packet.
\r
281 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
284 * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
\r
287 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
288 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
\r
291 * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
\r
293 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
294 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
\r
297 * Called from prvTCPHandleState(). There is data to be sent.
\r
298 * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
\r
299 * be checked if it would better be postponed for efficiency.
\r
301 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
302 uint32_t ulReceiveLength, BaseType_t xSendLength );
\r
305 * The heart of all: check incoming packet for valid data and acks and do what
\r
306 * is necessary in each state.
\r
308 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
\r
311 * Reply to a peer with the RST flag on, in case a packet can not be handled.
\r
313 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
316 * Set the initial value for MSS (Maximum Segment Size) to be used.
\r
318 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
\r
321 * Return either a newly created socket, or the current socket in a connected
\r
322 * state (depends on the 'bReuseSocket' flag).
\r
324 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
327 * After a listening socket receives a new connection, it may duplicate itself.
\r
328 * The copying takes place in prvTCPSocketCopy.
\r
330 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
\r
333 * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
\r
334 * state for too long. If so, the socket will be closed, and -1 will be
\r
337 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
338 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
\r
341 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
342 int32_t lDataLen, UBaseType_t uxOptionsLength );
\r
344 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
345 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
\r
348 #if( ipconfigUSE_TCP_WIN != 0 )
\r
349 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
\r
353 * Generate a randomized TCP Initial Sequence Number per RFC.
\r
355 extern uint32_t ulApplicationGetNextSequenceNumber(
\r
356 uint32_t ulSourceAddress,
\r
357 uint16_t usSourcePort,
\r
358 uint32_t ulDestinationAddress,
\r
359 uint16_t usDestinationPort );
\r
361 /*-----------------------------------------------------------*/
\r
363 /* prvTCPSocketIsActive() returns true if the socket must be checked.
\r
364 * Non-active sockets are waiting for user action, either connect()
\r
366 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
\r
380 /*-----------------------------------------------------------*/
\r
382 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
384 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
\r
386 BaseType_t xResult;
\r
387 switch( pxSocket->u.xTCP.ucTCPState )
\r
390 /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
\r
391 state ESTABLISHED can be protected using keep-alive messages. */
\r
397 /* These 3 states may last for ever, up to the owner. */
\r
401 /* All other (non-connected) states will get anti-hanging
\r
406 if( xResult != pdFALSE )
\r
408 /* How much time has past since the last active moment which is
\r
409 defined as A) a state change or B) a packet has arrived. */
\r
410 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
\r
412 /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
\r
413 if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
\r
415 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
417 FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
\r
418 pxSocket->usLocalPort,
\r
419 pxSocket->u.xTCP.ulRemoteIP,
\r
420 pxSocket->u.xTCP.usRemotePort,
\r
421 FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
\r
423 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
425 /* Move to eCLOSE_WAIT, user may close the socket. */
\r
426 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
428 /* When 'bPassQueued' true, this socket is an orphan until it
\r
430 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
432 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
434 /* As it did not get connected, and the user can never
\r
435 accept() it anymore, it will be deleted now. Called from
\r
436 the IP-task, so it's safe to call the internal Close
\r
437 function: vSocketClose(). */
\r
438 vSocketClose( pxSocket );
\r
440 /* Return a negative value to tell to inform the caller
\r
442 that the socket got closed and may not be accessed anymore. */
\r
449 /*-----------------------------------------------------------*/
\r
454 * As soon as a TCP socket timer expires, this function xTCPSocketCheck
\r
455 * will be called (from xTCPTimerCheck)
\r
456 * It can send a delayed ACK or new data
\r
457 * Sequence of calling (normally) :
\r
459 * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
\r
460 * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
\r
461 * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
\r
462 * prvTCPSendRepeated() // Send at most 8 messages on a row
\r
463 * prvTCPReturnPacket() // Prepare for returning
\r
464 * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
\r
466 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
\r
468 BaseType_t xResult = 0;
\r
469 BaseType_t xReady = pdFALSE;
\r
471 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
\r
473 /* The API FreeRTOS_send() might have added data to the TX stream. Add
\r
474 this data to the windowing system to it can be transmitted. */
\r
475 prvTCPAddTxData( pxSocket );
\r
478 #if ipconfigUSE_TCP_WIN == 1
\r
480 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
482 /* The first task of this regular socket check is to send-out delayed
\r
484 if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
\r
486 /* Earlier data was received but not yet acknowledged. This
\r
487 function is called when the TCP timer for the socket expires, the
\r
488 ACK may be sent now. */
\r
489 if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
\r
491 if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
\r
493 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
\r
494 pxSocket->usLocalPort,
\r
495 pxSocket->u.xTCP.usRemotePort,
\r
496 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
497 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
\r
498 ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
\r
501 prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
\r
503 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
505 /* The ownership has been passed to the SEND routine,
\r
506 clear the pointer to it. */
\r
507 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
509 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
511 if( prvTCPNextTimeout( pxSocket ) > 1 )
\r
513 /* Tell the code below that this function is ready. */
\r
519 /* The user wants to perform an active shutdown(), skip sending
\r
520 the delayed ACK. The function prvTCPSendPacket() will send the
\r
521 FIN along with the ACK's. */
\r
524 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
526 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
527 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
531 #endif /* ipconfigUSE_TCP_WIN */
\r
533 if( xReady == pdFALSE )
\r
535 /* The second task of this regular socket check is sending out data. */
\r
536 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
\r
537 ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
\r
539 prvTCPSendPacket( pxSocket );
\r
542 /* Set the time-out for the next wakeup for this socket. */
\r
543 prvTCPNextTimeout( pxSocket );
\r
545 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
547 /* In all (non-connected) states in which keep-alive messages can not be sent
\r
548 the anti-hang protocol will close sockets that are 'hanging'. */
\r
549 xResult = prvTCPStatusAgeCheck( pxSocket );
\r
556 /*-----------------------------------------------------------*/
\r
559 * prvTCPSendPacket() will be called when the socket time-out has been reached.
\r
560 * It is only called by xTCPSocketCheck().
\r
562 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
\r
564 int32_t lResult = 0;
\r
565 UBaseType_t uxOptionsLength;
\r
566 TCPPacket_t *pxTCPPacket;
\r
567 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
569 if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
\r
571 /* The connection is in s state other than SYN. */
\r
572 pxNetworkBuffer = NULL;
\r
574 /* prvTCPSendRepeated() will only create a network buffer if necessary,
\r
575 i.e. when data must be sent to the peer. */
\r
576 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
578 if( pxNetworkBuffer != NULL )
\r
580 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
585 if( pxSocket->u.xTCP.ucRepCount >= 3u )
\r
587 /* The connection is in the SYN status. The packet will be repeated
\r
588 to most 3 times. When there is no response, the socket get the
\r
589 status 'eCLOSE_WAIT'. */
\r
590 FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
\r
591 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
592 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
593 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
595 else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
\r
597 /* Or else, if the connection has been prepared, or can be prepared
\r
598 now, proceed to send the packet with the SYN flag.
\r
599 prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
\r
600 the Ethernet address of the peer or the gateway is found. */
\r
601 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
603 /* About to send a SYN packet. Call prvSetSynAckOptions() to set
\r
604 the proper options: The size of MSS and whether SACK's are
\r
606 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
608 /* Return the number of bytes to be sent. */
\r
609 lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
611 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
612 uxOptionsLength is always a multiple of 4. The complete expression
\r
614 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
615 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
617 /* Repeat Count is used for a connecting socket, to limit the number
\r
619 pxSocket->u.xTCP.ucRepCount++;
\r
621 /* Send the SYN message to make a connection. The messages is
\r
622 stored in the socket field 'xPacket'. It will be wrapped in a
\r
623 pseudo network buffer descriptor before it will be sent. */
\r
624 prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
\r
628 /* Return the total number of bytes sent. */
\r
631 /*-----------------------------------------------------------*/
\r
634 * prvTCPSendRepeated will try to send a series of messages, as long as there is
\r
635 * data to be sent and as long as the transmit window isn't full.
\r
637 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
639 UBaseType_t uxIndex;
\r
640 int32_t lResult = 0;
\r
641 UBaseType_t uxOptionsLength = 0u;
\r
642 int32_t xSendLength;
\r
644 for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
\r
646 /* prvTCPPrepareSend() might allocate a network buffer if there is data
\r
648 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
649 if( xSendLength <= 0 )
\r
654 /* And return the packet to the peer. */
\r
655 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
657 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
659 *ppxNetworkBuffer = NULL;
\r
661 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
663 lResult += xSendLength;
\r
666 /* Return the total number of bytes sent. */
\r
669 /*-----------------------------------------------------------*/
\r
672 * Return (or send) a packet the the peer. The data is stored in pxBuffer,
\r
673 * which may either point to a real network buffer or to a TCP socket field
\r
674 * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
\r
675 * the data to the NIC.
\r
677 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
\r
679 TCPPacket_t * pxTCPPacket;
\r
680 IPHeader_t *pxIPHeader;
\r
681 EthernetHeader_t *pxEthernetHeader;
\r
682 uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
\r
683 TCPWindow_t *pxTCPWindow;
\r
684 NetworkBufferDescriptor_t xTempBuffer;
\r
685 /* For sending, a pseudo network buffer will be used, as explained above. */
\r
687 if( pxNetworkBuffer == NULL )
\r
689 pxNetworkBuffer = &xTempBuffer;
\r
691 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
693 xTempBuffer.pxNextBuffer = NULL;
\r
696 xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
697 xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
698 xReleaseAfterSend = pdFALSE;
\r
701 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
703 if( xReleaseAfterSend == pdFALSE )
\r
705 pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
\r
706 if( pxNetworkBuffer == NULL )
\r
708 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
\r
710 xReleaseAfterSend = pdTRUE;
\r
713 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
715 if( pxNetworkBuffer != NULL )
\r
717 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
718 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
719 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
\r
721 /* Fill the packet, using hton translations. */
\r
722 if( pxSocket != NULL )
\r
724 /* Calculate the space in the RX buffer in order to advertise the
\r
725 size of this socket's reception window. */
\r
726 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
728 if( pxSocket->u.xTCP.rxStream != NULL )
\r
730 /* An RX stream was created already, see how much space is
\r
732 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
736 /* No RX stream has been created, the full stream size is
\r
738 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
741 /* Take the minimum of the RX buffer space and the RX window size. */
\r
742 ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );
\r
744 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
\r
746 /* The low-water mark was reached, meaning there was little
\r
747 space left. The socket will wait until the application has read
\r
748 or flushed the incoming data, and 'zero-window' will be
\r
753 /* If possible, advertise an RX window size of at least 1 MSS, otherwise
\r
754 the peer might start 'zero window probing', i.e. sending small packets
\r
755 (1, 2, 4, 8... bytes). */
\r
756 if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
\r
758 ulSpace = pxSocket->u.xTCP.usCurMSS;
\r
761 /* Avoid overflow of the 16-bit win field. */
\r
762 #if( ipconfigUSE_TCP_WIN != 0 )
\r
764 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
\r
768 ulWinSize = ulSpace;
\r
771 if( ulWinSize > 0xfffcUL )
\r
773 ulWinSize = 0xfffcUL;
\r
776 pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
\r
778 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
780 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
\r
782 if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
\r
784 size_t uxFrontSpace;
\r
786 if(pxSocket->u.xTCP.rxStream != NULL)
\r
788 uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
\r
795 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
\r
796 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
\r
797 pxSocket->u.xTCP.ulRemoteIP,
\r
798 pxSocket->u.xTCP.usRemotePort,
\r
799 pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
\r
800 (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
\r
804 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
806 /* The new window size has been advertised, switch off the flag. */
\r
807 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
\r
809 /* Later on, when deciding to delay an ACK, a precise estimate is needed
\r
810 of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
\r
811 highest sequence number minus 1 that the socket will accept. */
\r
812 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
\r
814 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
815 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
\r
817 /* Sending a keep-alive packet, send the current sequence number
\r
818 minus 1, which will be recognised as a keep-alive packet an
\r
819 responded to by acknowledging the last byte. */
\r
820 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
821 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
\r
823 pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
\r
824 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
829 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
\r
831 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
\r
833 /* Suppress FIN in case this packet carries earlier data to be
\r
835 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
\r
836 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
\r
838 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
\r
839 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
\r
840 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
842 pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
\r
847 /* Tell which sequence number is expected next time */
\r
848 pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
852 /* Sending data without a socket, probably replying with a RST flag
\r
853 Just swap the two sequence numbers. */
\r
854 vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
\r
857 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
858 pxIPHeader->usLength = FreeRTOS_htons( ulLen );
\r
859 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
\r
861 /* When pxSocket is NULL, this function is called by prvTCPSendReset()
\r
862 and the IP-addresses must be swapped.
\r
863 Also swap the IP-addresses in case the IP-tack doesn't have an
\r
864 IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
\r
865 ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
\r
869 ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
871 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
872 pxIPHeader->ulSourceIPAddress = ulSourceAddress;
\r
873 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
\r
875 /* Just an increasing number. */
\r
876 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
877 usPacketIdentifier++;
\r
878 pxIPHeader->usFragmentOffset = 0u;
\r
880 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
882 /* calculate the IP header checksum, in case the driver won't do that. */
\r
883 pxIPHeader->usHeaderChecksum = 0x00u;
\r
884 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
885 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
887 /* calculate the TCP checksum for an outgoing packet. */
\r
888 usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
\r
890 /* A calculated checksum of 0 must be inverted as 0 means the checksum
\r
892 if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
\r
894 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
\r
899 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
900 pxNetworkBuffer->pxNextBuffer = NULL;
\r
903 /* Important: tell NIC driver how many bytes must be sent. */
\r
904 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
\r
906 /* Fill in the destination MAC addresses. */
\r
907 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
\r
908 sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
910 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
\r
911 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
913 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
915 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
919 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
921 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
923 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
929 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
\r
931 if( xReleaseAfterSend == pdFALSE )
\r
933 /* Swap-back some fields, as pxBuffer probably points to a socket field
\r
934 containing the packet header. */
\r
935 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
\r
936 pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
\r
937 memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
941 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
\r
943 } /* if( pxNetworkBuffer != NULL ) */
\r
945 /*-----------------------------------------------------------*/
\r
948 * The SYN event is very important: the sequence numbers, which have a kind of
\r
949 * random starting value, are being synchronised. The sliding window manager
\r
950 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
\r
951 * Size (MSS) in use.
\r
953 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
\r
955 if( xTCPWindowLoggingLevel )
\r
956 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
\r
957 pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
\r
958 pxSocket->u.xTCP.uxLittleSpace ,
\r
959 pxSocket->u.xTCP.uxEnoughSpace,
\r
960 pxSocket->u.xTCP.uxRxStreamSize ) );
\r
962 &pxSocket->u.xTCP.xTCPWindow,
\r
963 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
\r
964 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
\r
965 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
\r
966 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
\r
967 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
\r
969 /*-----------------------------------------------------------*/
\r
972 * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
\r
973 * the Ethernet address of the target will be found using ARP. In case the
\r
974 * target IP address is not within the netmask, the hardware address of the
\r
975 * gateway will be used.
\r
977 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
\r
979 TCPPacket_t *pxTCPPacket;
\r
980 IPHeader_t *pxIPHeader;
\r
981 eARPLookupResult_t eReturned;
\r
982 uint32_t ulRemoteIP;
\r
983 MACAddress_t xEthAddress;
\r
984 BaseType_t xReturn = pdTRUE;
\r
985 uint32_t ulInitialSequenceNumber = 0;
\r
987 #if( ipconfigHAS_PRINTF != 0 )
\r
989 /* Only necessary for nicer logging. */
\r
990 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
\r
992 #endif /* ipconfigHAS_PRINTF != 0 */
\r
994 ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
996 /* Determine the ARP cache status for the requested IP address. */
\r
997 eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
\r
999 switch( eReturned )
\r
1001 case eARPCacheHit: /* An ARP table lookup found a valid entry. */
\r
1002 break; /* We can now prepare the SYN packet. */
\r
1003 case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
\r
1004 case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
\r
1006 /* Count the number of times it couldn't find the ARP address. */
\r
1007 pxSocket->u.xTCP.ucRepCount++;
\r
1009 FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
\r
1010 pxSocket->u.xTCP.ulRemoteIP,
\r
1011 FreeRTOS_htonl( ulRemoteIP ),
\r
1013 xEthAddress.ucBytes[ 0 ],
\r
1014 xEthAddress.ucBytes[ 1 ],
\r
1015 xEthAddress.ucBytes[ 2 ],
\r
1016 xEthAddress.ucBytes[ 3 ],
\r
1017 xEthAddress.ucBytes[ 4 ],
\r
1018 xEthAddress.ucBytes[ 5 ] ) );
\r
1020 /* And issue a (new) ARP request */
\r
1021 FreeRTOS_OutputARPRequest( ulRemoteIP );
\r
1023 xReturn = pdFALSE;
\r
1026 if( xReturn != pdFALSE )
\r
1028 /* Get a difficult-to-predict initial sequence number for this 4-tuple. */
\r
1029 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber(
\r
1030 *ipLOCAL_IP_ADDRESS_POINTER,
\r
1031 pxSocket->usLocalPort,
\r
1032 pxSocket->u.xTCP.ulRemoteIP,
\r
1033 pxSocket->u.xTCP.usRemotePort );
\r
1035 /* Check for a random number generation error. */
\r
1036 if( 0 == ulInitialSequenceNumber )
\r
1038 xReturn = pdFALSE;
\r
1042 if( xReturn != pdFALSE )
\r
1044 /* The MAC-address of the peer (or gateway) has been found,
\r
1045 now prepare the initial TCP packet and some fields in the socket. */
\r
1046 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1047 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
1049 /* reset the retry counter to zero. */
\r
1050 pxSocket->u.xTCP.ucRepCount = 0u;
\r
1052 /* And remember that the connect/SYN data are prepared. */
\r
1053 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
\r
1055 /* Now that the Ethernet address is known, the initial packet can be
\r
1057 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1059 /* Write the Ethernet address in Source, because it will be swapped by
\r
1060 prvTCPReturnPacket(). */
\r
1061 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
\r
1063 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
\r
1064 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
\r
1066 pxIPHeader->ucVersionHeaderLength = 0x45u;
\r
1067 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
\r
1068 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
1070 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
\r
1072 /* Addresses and ports will be stored swapped because prvTCPReturnPacket
\r
1073 will swap them back while replying. */
\r
1074 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1075 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1077 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
\r
1078 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
1080 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
\r
1081 isn't known yet. */
\r
1082 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
\r
1084 /* Start with ISN (Initial Sequence Number). */
\r
1085 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
\r
1087 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
\r
1088 the high nibble of the TCP offset field. */
\r
1089 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
\r
1091 /* Only set the SYN flag. */
\r
1092 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
\r
1094 /* Set the values of usInitMSS / usCurMSS for this socket. */
\r
1095 prvSocketSetMSS( pxSocket );
\r
1097 /* For now this is also the advertised window size. */
\r
1098 pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;
\r
1100 /* The initial sequence numbers at our side are known. Later
\r
1101 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
\r
1102 first wait for a SYN+ACK reply. */
\r
1103 prvTCPCreateWindow( pxSocket );
\r
1108 /*-----------------------------------------------------------*/
\r
1110 /* For logging and debugging: make a string showing the TCP flags
\r
1112 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1114 static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
\r
1116 static char retString[10];
\r
1117 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
\r
1118 ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
\r
1119 ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
\r
1120 ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
\r
1121 ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
\r
1122 ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
\r
1123 ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
\r
1124 ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
\r
1125 ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
\r
1126 ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
\r
1129 /*-----------------------------------------------------------*/
\r
1131 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1134 * Parse the TCP option(s) received, if present. It has already been verified
\r
1135 * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
\r
1136 * is longer than the usual 20 (5 x 4) bytes.
\r
1138 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1140 TCPPacket_t * pxTCPPacket;
\r
1141 TCPHeader_t * pxTCPHeader;
\r
1142 const unsigned char *pucPtr;
\r
1143 const unsigned char *pucLast;
\r
1144 TCPWindow_t *pxTCPWindow;
\r
1145 UBaseType_t uxNewMSS;
\r
1147 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1148 pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1150 /* A character pointer to iterate through the option data */
\r
1151 pucPtr = pxTCPHeader->ucOptdata;
\r
1152 pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
\r
1153 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1155 /* Validate options size calculation. */
\r
1156 if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) )
\r
1161 /* The comparison with pucLast is only necessary in case the option data are
\r
1162 corrupted, we don't like to run into invalid memory and crash. */
\r
1163 while( pucPtr < pucLast )
\r
1165 UBaseType_t xRemainingOptionsBytes = pucLast - pucPtr;
\r
1167 if( pucPtr[ 0 ] == TCP_OPT_END )
\r
1169 /* End of options. */
\r
1172 if( pucPtr[ 0 ] == TCP_OPT_NOOP)
\r
1174 /* NOP option, inserted to make the length a multiple of 4. */
\r
1179 /* Any other well-formed option must be at least two bytes: the option
\r
1180 type byte followed by a length byte. */
\r
1181 if( xRemainingOptionsBytes < 2 )
\r
1185 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1186 else if( pucPtr[ 0 ] == TCP_OPT_WSOPT )
\r
1188 /* Confirm that the option fits in the remaining buffer space. */
\r
1189 if( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ||
\r
1190 pucPtr[ 1 ] != TCP_OPT_WSOPT_LEN )
\r
1195 pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
\r
1196 pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
\r
1197 pucPtr += TCP_OPT_WSOPT_LEN;
\r
1199 #endif /* ipconfigUSE_TCP_WIN */
\r
1200 else if( pucPtr[ 0 ] == TCP_OPT_MSS )
\r
1202 /* Confirm that the option fits in the remaining buffer space. */
\r
1203 if( xRemainingOptionsBytes < TCP_OPT_MSS_LEN ||
\r
1204 pucPtr[ 1 ] != TCP_OPT_MSS_LEN )
\r
1209 /* An MSS option with the correct option length. FreeRTOS_htons()
\r
1210 is not needed here because usChar2u16() already returns a host
\r
1212 uxNewMSS = usChar2u16( pucPtr + 2 );
\r
1214 if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
\r
1216 /* Perform a basic check on the the new MSS. */
\r
1217 if( uxNewMSS == 0 )
\r
1222 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
\r
1225 if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
\r
1227 /* our MSS was bigger than the MSS of the other party: adapt it. */
\r
1228 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
\r
1229 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )
\r
1231 /* The peer advertises a smaller MSS than this socket was
\r
1232 using. Use that as well. */
\r
1233 FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
\r
1234 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1236 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
\r
1237 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
\r
1238 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
\r
1239 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
\r
1240 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1243 #if( ipconfigUSE_TCP_WIN != 1 )
\r
1244 /* Without scaled windows, MSS is the only interesting option. */
\r
1247 /* Or else we continue to check another option: selective ACK. */
\r
1248 pucPtr += TCP_OPT_MSS_LEN;
\r
1249 #endif /* ipconfigUSE_TCP_WIN != 1 */
\r
1253 /* All other options have a length field, so that we easily
\r
1254 can skip past them. */
\r
1255 unsigned char len = pucPtr[ 1 ];
\r
1256 if( len < 2 || len > xRemainingOptionsBytes )
\r
1258 /* If the length field is too small or too big, the options are malformed.
\r
1259 Don't process them further. */
\r
1263 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1265 /* Selective ACK: the peer has received a packet but it is missing earlier
\r
1266 packets. At least this packet does not need retransmission anymore
\r
1267 ulTCPWindowTxSack( ) takes care of this administration. */
\r
1268 if( pucPtr[0] == TCP_OPT_SACK_A )
\r
1275 uint32_t ulFirst = ulChar2u32( pucPtr );
\r
1276 uint32_t ulLast = ulChar2u32( pucPtr + 4 );
\r
1277 uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );
\r
1278 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
\r
1279 starting from the head position.
\r
1280 Advance the tail pointer in txStream. */
\r
1281 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
\r
1283 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
\r
1284 uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
\r
1285 pxSocket->xEventBits |= eSOCKET_SEND;
\r
1287 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
1289 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1291 /* The field 'xEventBits' is used to store regular socket events (at most 8),
\r
1292 as well as 'select events', which will be left-shifted */
\r
1293 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1298 /* In case the socket owner has installed an OnSent handler,
\r
1300 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1302 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
1304 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
1307 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
1312 /* len should be 0 by now. */
\r
1315 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1321 /*-----------------------------------------------------------*/
\r
1323 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1325 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
\r
1330 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
\r
1331 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
\r
1333 while( uxWinSize > 0xfffful )
\r
1335 /* Divide by two and increase the binary factor by 1. */
\r
1340 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
\r
1341 pxSocket->u.xTCP.uxRxWinSize,
\r
1342 pxSocket->u.xTCP.usInitMSS,
\r
1349 /*-----------------------------------------------------------*/
\r
1352 * When opening a TCP connection, while SYN's are being sent, the parties may
\r
1353 * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
\r
1354 * nett size of the payload, always smaller than MTU.
\r
1356 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
\r
1358 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1359 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
\r
1360 UBaseType_t uxOptionsLength;
\r
1362 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
\r
1364 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
\r
1365 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
\r
1366 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
\r
1367 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
\r
1369 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1371 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
\r
1373 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
\r
1374 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
\r
1375 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
\r
1376 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
\r
1377 uxOptionsLength = 8u;
\r
1381 uxOptionsLength = 4u;
\r
1385 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1387 return uxOptionsLength;
\r
1391 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
\r
1392 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
\r
1393 pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1394 pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
\r
1395 uxOptionsLength += 4u;
\r
1397 return uxOptionsLength; /* bytes, not words. */
\r
1399 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1403 * For anti-hanging protection and TCP keep-alive messages. Called in two
\r
1404 * places: after receiving a packet and after a state change. The socket's
\r
1405 * alive timer may be reset.
\r
1407 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
\r
1409 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
1411 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
\r
1415 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
1417 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
\r
1418 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
1419 pxSocket->u.xTCP.ucKeepRepCount = 0u;
\r
1420 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
\r
1424 ( void ) pxSocket;
\r
1426 /*-----------------------------------------------------------*/
\r
1429 * Changing to a new state. Centralised here to do specific actions such as
\r
1430 * resetting the alive timer, calling the user's OnConnect handler to notify
\r
1431 * that a socket has got (dis)connected, and setting bit to unblock a call to
\r
1432 * FreeRTOS_select()
\r
1434 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
\r
1436 FreeRTOS_Socket_t *xParent = NULL;
\r
1437 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
\r
1438 BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
\r
1439 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1440 BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
\r
1442 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1443 FreeRTOS_Socket_t *xConnected = NULL;
\r
1446 /* Has the connected status changed? */
\r
1447 if( bBefore != bAfter )
\r
1449 /* Is the socket connected now ? */
\r
1450 if( bAfter != pdFALSE )
\r
1452 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
\r
1453 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
1455 /* Now that it is connected, find it's parent. */
\r
1456 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
1458 xParent = pxSocket;
\r
1462 xParent = pxSocket->u.xTCP.pxPeerSocket;
\r
1463 configASSERT( xParent != NULL );
\r
1465 if( xParent != NULL )
\r
1467 if( xParent->u.xTCP.pxPeerSocket == NULL )
\r
1469 xParent->u.xTCP.pxPeerSocket = pxSocket;
\r
1472 xParent->xEventBits |= eSOCKET_ACCEPT;
\r
1474 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1476 /* Library support FreeRTOS_select(). Receiving a new
\r
1477 connection is being translated as a READ event. */
\r
1478 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
\r
1480 xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
\r
1485 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1487 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
\r
1488 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
\r
1490 /* The listening socket does not become connected itself, in stead
\r
1491 a child socket is created.
\r
1492 Postpone a call the OnConnect event until the end of this function. */
\r
1493 xConnected = xParent;
\r
1499 /* Don't need to access the parent socket anymore, so the
\r
1500 reference 'pxPeerSocket' may be cleared. */
\r
1501 pxSocket->u.xTCP.pxPeerSocket = NULL;
\r
1502 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
\r
1504 /* When true, this socket may be returned in a call to accept(). */
\r
1505 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
1509 pxSocket->xEventBits |= eSOCKET_CONNECT;
\r
1511 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1513 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1515 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1521 else /* bAfter == pdFALSE, connection is closed. */
\r
1523 /* Notify/wake-up the socket-owner by setting a semaphore. */
\r
1524 pxSocket->xEventBits |= eSOCKET_CLOSED;
\r
1526 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1528 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
\r
1530 pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
\r
1535 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1537 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
\r
1539 /* The 'connected' state has changed, call the user handler. */
\r
1540 xConnected = pxSocket;
\r
1543 #endif /* ipconfigUSE_CALLBACKS */
\r
1545 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
\r
1547 /* Now the socket isn't in an active state anymore so it
\r
1548 won't need further attention of the IP-task.
\r
1549 Setting time-out to zero means that the socket won't get checked during
\r
1551 pxSocket->u.xTCP.usTimeout = 0u;
\r
1556 if( eTCPState == eCLOSED )
\r
1558 /* Socket goes to status eCLOSED because of a RST.
\r
1559 When nobody owns the socket yet, delete it. */
\r
1560 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
\r
1561 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
1563 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
\r
1564 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
1566 FreeRTOS_closesocket( pxSocket );
\r
1572 /* Fill in the new state. */
\r
1573 pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
\r
1575 /* touch the alive timers because moving to another state. */
\r
1576 prvTCPTouchSocket( pxSocket );
\r
1578 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
1580 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
1581 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
\r
1582 pxSocket->usLocalPort,
\r
1583 pxSocket->u.xTCP.ulRemoteIP,
\r
1584 pxSocket->u.xTCP.usRemotePort,
\r
1585 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
\r
1586 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
\r
1588 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1590 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1592 if( xConnected != NULL )
\r
1594 /* The 'connected' state has changed, call the OnConnect handler of the parent. */
\r
1595 xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );
\r
1599 if( xParent != NULL )
\r
1601 vSocketWakeUpUser( xParent );
\r
1604 /*-----------------------------------------------------------*/
\r
1606 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
1607 int32_t lDataLen, UBaseType_t uxOptionsLength )
\r
1609 NetworkBufferDescriptor_t *pxReturn;
\r
1611 BaseType_t xResize;
\r
1613 if( xBufferAllocFixedSize != pdFALSE )
\r
1615 /* Network buffers are created with a fixed size and can hold the largest
\r
1617 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
\r
1618 /* and therefore, the buffer won't be too small.
\r
1619 Only ask for a new network buffer in case none was supplied. */
\r
1620 xResize = ( pxNetworkBuffer == NULL );
\r
1624 /* Network buffers are created with a variable size. See if it must
\r
1626 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
\r
1627 ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
\r
1628 /* In case we were called from a TCP timer event, a buffer must be
\r
1629 created. Otherwise, test 'xDataLength' of the provided buffer. */
\r
1630 xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded );
\r
1633 if( xResize != pdFALSE )
\r
1635 /* The caller didn't provide a network buffer or the provided buffer is
\r
1636 too small. As we must send-out a data packet, a buffer will be created
\r
1638 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
\r
1640 if( pxReturn != NULL )
\r
1642 /* Set the actual packet size, in case the returned buffer is larger. */
\r
1643 pxReturn->xDataLength = lNeeded;
\r
1645 /* Copy the existing data to the new created buffer. */
\r
1646 if( pxNetworkBuffer )
\r
1648 /* Either from the previous buffer... */
\r
1649 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
1651 /* ...and release it. */
\r
1652 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1656 /* Or from the socket field 'xTCP.xPacket'. */
\r
1657 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1663 /* xResize is false, the network buffer provided was big enough. */
\r
1664 pxReturn = pxNetworkBuffer;
\r
1666 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
\r
1667 xDataLength member must get the correct length too! */
\r
1668 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
\r
1673 /*-----------------------------------------------------------*/
\r
1676 * Prepare an outgoing message, in case anything has to be sent.
\r
1678 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
\r
1681 uint8_t *pucEthernetBuffer, *pucSendData;
\r
1682 TCPPacket_t *pxTCPPacket;
\r
1684 uint32_t ulDataGot, ulDistance;
\r
1685 TCPWindow_t *pxTCPWindow;
\r
1686 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1687 int32_t lStreamPos;
\r
1689 if( ( *ppxNetworkBuffer ) != NULL )
\r
1691 /* A network buffer descriptor was already supplied */
\r
1692 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
\r
1696 /* For now let it point to the last packet header */
\r
1697 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1700 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1701 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1704 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
\r
1706 if( pxSocket->u.xTCP.txStream != NULL )
\r
1708 /* ulTCPWindowTxGet will return the amount of data which may be sent
\r
1709 along with the position in the txStream.
\r
1710 Why check for MSS > 1 ?
\r
1711 Because some TCP-stacks (like uIP) use it for flow-control. */
\r
1712 if( pxSocket->u.xTCP.usCurMSS > 1u )
\r
1714 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
\r
1717 if( lDataLen > 0 )
\r
1719 /* Check if the current network buffer is big enough, if not,
\r
1721 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
\r
1723 if( pxNewBuffer != NULL )
\r
1725 *ppxNetworkBuffer = pxNewBuffer;
\r
1726 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
\r
1727 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1729 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
\r
1731 /* Translate the position in txStream to an offset from the tail
\r
1733 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
\r
1735 /* Here data is copied from the txStream in 'peek' mode. Only
\r
1736 when the packets are acked, the tail marker will be updated. */
\r
1737 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
\r
1739 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1741 if( ulDataGot != ( uint32_t ) lDataLen )
\r
1743 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
\r
1744 lStreamPos, uxOffset, ulDataGot, lDataLen ) );
\r
1749 /* If the owner of the socket requests a closure, add the FIN
\r
1750 flag to the last packet. */
\r
1751 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
\r
1753 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
\r
1755 if( ulDistance == ulDataGot )
\r
1757 #if (ipconfigHAS_DEBUG_PRINTF == 1)
\r
1759 /* the order of volatile accesses is undefined
\r
1760 so such workaround */
\r
1761 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
\r
1762 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
\r
1763 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
\r
1765 FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
\r
1766 uxTail, uxMid, uxHead ) );
\r
1769 /* Although the socket sends a FIN, it will stay in
\r
1770 ESTABLISHED until all current data has been received or
\r
1772 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1773 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
\r
1774 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1785 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
\r
1787 /* See if the socket owner wants to shutdown this connection. */
\r
1788 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
\r
1789 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
\r
1791 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
\r
1792 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1793 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1794 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
1795 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1796 vTCPStateChange( pxSocket, eFIN_WAIT_1 );
\r
1799 #if( ipconfigTCP_KEEP_ALIVE != 0 )
\r
1801 if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
\r
1803 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
\r
1804 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
1805 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
1806 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
1809 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
\r
1811 /* If there is no data to be sent, and no window-update message,
\r
1812 we might want to send a keep-alive message. */
\r
1813 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
\r
1815 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
\r
1816 if( pxSocket->u.xTCP.ucKeepRepCount )
\r
1818 xMax = ( 3u * configTICK_RATE_HZ );
\r
1822 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
\r
1823 if( xTCPWindowLoggingLevel )
\r
1824 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
\r
1825 pxSocket->u.xTCP.ulRemoteIP,
\r
1826 pxSocket->u.xTCP.usRemotePort,
\r
1827 pxSocket->u.xTCP.ucKeepRepCount ) );
\r
1828 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
\r
1829 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
\r
1830 pxSocket->u.xTCP.ucKeepRepCount++;
\r
1834 #endif /* ipconfigTCP_KEEP_ALIVE */
\r
1837 /* Anything to send, a change of the advertised window size, or maybe send a
\r
1838 keep-alive message? */
\r
1839 if( ( lDataLen > 0 ) ||
\r
1840 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
\r
1841 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
\r
1843 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
\r
1844 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
1846 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
\r
1848 if( lDataLen != 0l )
\r
1850 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
\r
1853 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
1858 /*-----------------------------------------------------------*/
\r
1861 * Calculate after how much time this socket needs to be checked again.
\r
1863 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
\r
1865 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1867 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
1869 /* The socket is actively connecting to a peer. */
\r
1870 if( pxSocket->u.xTCP.bits.bConnPrepared )
\r
1872 /* Ethernet address has been found, use progressive timeout for
\r
1873 active connect(). */
\r
1874 if( pxSocket->u.xTCP.ucRepCount < 3u )
\r
1876 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
\r
1880 ulDelayMs = 11000UL;
\r
1885 /* Still in the ARP phase: check every half second. */
\r
1886 ulDelayMs = 500UL;
\r
1889 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
\r
1890 pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
\r
1891 pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
\r
1892 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1894 else if( pxSocket->u.xTCP.usTimeout == 0u )
\r
1896 /* Let the sliding window mechanism decide what time-out is appropriate. */
\r
1897 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
\r
1898 if( ulDelayMs == 0u )
\r
1900 if( xResult != ( BaseType_t )0 )
\r
1906 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1911 /* ulDelayMs contains the time to wait before a re-transmission. */
\r
1913 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1917 /* field '.usTimeout' has already been set (by the
\r
1918 keep-alive/delayed-ACK mechanism). */
\r
1921 /* Return the number of clock ticks before the timer expires. */
\r
1922 return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
\r
1924 /*-----------------------------------------------------------*/
\r
1926 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
\r
1928 int32_t lCount, lLength;
\r
1930 /* A txStream has been created already, see if the socket has new data for
\r
1931 the sliding window.
\r
1933 uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It contains new
\r
1934 Tx data which has not been passed to the sliding window yet. The oldest
\r
1935 data not-yet-confirmed can be found at rxTail. */
\r
1936 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
\r
1940 /* All data between txMid and rxHead will now be passed to the sliding
\r
1941 window manager, so it can start transmitting them.
\r
1943 Hand over the new data to the sliding window handler. It will be
\r
1944 split-up in chunks of 1460 bytes each (or less, depending on
\r
1945 ipconfigTCP_MSS). */
\r
1946 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
\r
1947 ( uint32_t ) lLength,
\r
1948 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
\r
1949 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
\r
1951 /* Move the rxMid pointer forward up to rxHead. */
\r
1954 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
\r
1958 /*-----------------------------------------------------------*/
\r
1961 * prvTCPHandleFin() will be called to handle socket closure
\r
1962 * The Closure starts when either a FIN has been received and accepted,
\r
1963 * Or when the socket has sent a FIN flag to the peer
\r
1964 * Before being called, it has been checked that both reception and transmission
\r
1967 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1969 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1970 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1971 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
1972 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1973 BaseType_t xSendLength = 0;
\r
1974 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
\r
1976 if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
\r
1978 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
\r
1980 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
1982 /* We haven't yet replied with a FIN, do so now. */
\r
1983 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1984 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1988 /* We did send a FIN already, see if it's ACK'd. */
\r
1989 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
\r
1991 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
\r
1995 if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
\r
1997 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
1998 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
\r
2000 /* And wait for the final ACK. */
\r
2001 vTCPStateChange( pxSocket, eLAST_ACK );
\r
2005 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
\r
2006 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
\r
2007 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
\r
2009 /* We have sent out a FIN but the peer hasn't replied with a FIN
\r
2010 yet. Do nothing for the moment. */
\r
2011 pxTCPHeader->ucTCPFlags = 0u;
\r
2015 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
\r
2017 /* This is the third of the three-way hand shake: the last
\r
2019 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2023 /* The other party started the closure, so we just wait for the
\r
2025 pxTCPHeader->ucTCPFlags = 0u;
\r
2028 /* And wait for the user to close this socket. */
\r
2029 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2033 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2035 if( pxTCPHeader->ucTCPFlags != 0u )
\r
2037 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
\r
2040 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
\r
2042 if( xTCPWindowLoggingLevel != 0 )
\r
2044 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
\r
2045 ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2046 pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2047 pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2048 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2049 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2052 return xSendLength;
\r
2054 /*-----------------------------------------------------------*/
\r
2057 * prvCheckRxData(): called from prvTCPHandleState()
\r
2059 * The first thing that will be done is find the TCP payload data
\r
2060 * and check the length of this data.
\r
2062 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
\r
2064 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2065 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2066 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
\r
2068 /* Determine the length and the offset of the user-data sent to this
\r
2071 The size of the TCP header is given in a multiple of 4-byte words (single
\r
2072 byte, needs no ntoh() translation). A shift-right 2: is the same as
\r
2073 (offset >> 4) * 4. */
\r
2074 lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
\r
2076 /* Let pucRecvData point to the first byte received. */
\r
2077 *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
\r
2079 /* Calculate lReceiveLength - the length of the TCP data received. This is
\r
2080 equal to the total packet length minus:
\r
2081 ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
\r
2082 lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
\r
2083 lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
\r
2085 if( lReceiveLength > lLength )
\r
2087 /* More bytes were received than the reported length, often because of
\r
2088 padding bytes at the end. */
\r
2089 lReceiveLength = lLength;
\r
2092 /* Subtract the size of the TCP and IP headers and the actual data size is
\r
2094 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
\r
2096 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
\r
2100 lReceiveLength = 0;
\r
2103 /* Urgent Pointer:
\r
2104 This field communicates the current value of the urgent pointer as a
\r
2105 positive offset from the sequence number in this segment. The urgent
\r
2106 pointer points to the sequence number of the octet following the urgent
\r
2107 data. This field is only be interpreted in segments with the URG control
\r
2109 if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
\r
2111 /* Although we ignore the urgent data, we have to skip it. */
\r
2112 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
\r
2113 *ppucRecvData += lUrgentLength;
\r
2114 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
\r
2117 return ( BaseType_t ) lReceiveLength;
\r
2119 /*-----------------------------------------------------------*/
\r
2122 * prvStoreRxData(): called from prvTCPHandleState()
\r
2124 * The second thing is to do is check if the payload data may be accepted
\r
2125 * If so, they will be added to the reception queue.
\r
2127 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
2128 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
\r
2130 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2131 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2132 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2133 uint32_t ulSequenceNumber, ulSpace;
\r
2134 int32_t lOffset, lStored;
\r
2135 BaseType_t xResult = 0;
\r
2137 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2139 if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
\r
2141 /* See if way may accept the data contents and forward it to the socket
\r
2144 If it can't be "accept"ed it may have to be stored and send a selective
\r
2145 ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
\r
2146 called later to store an out-of-order packet (in case lOffset is
\r
2148 if ( pxSocket->u.xTCP.rxStream )
\r
2150 ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
\r
2154 ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
\r
2157 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
\r
2159 if( lOffset >= 0 )
\r
2161 /* New data has arrived and may be made available to the user. See
\r
2162 if the head marker in rxStream may be advanced, only if lOffset == 0.
\r
2163 In case the low-water mark is reached, bLowWater will be set
\r
2164 "low-water" here stands for "little space". */
\r
2165 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
\r
2167 if( lStored != ( int32_t ) ulReceiveLength )
\r
2169 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
\r
2171 /* Received data could not be stored. The socket's flag
\r
2172 bMallocError has been set. The socket now has the status
\r
2173 eCLOSE_WAIT and a RST packet will be sent back. */
\r
2174 prvTCPSendReset( pxNetworkBuffer );
\r
2179 /* After a missing packet has come in, higher packets may be passed to
\r
2181 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2183 /* Now lTCPAddRxdata() will move the rxHead pointer forward
\r
2184 so data becomes available to the user immediately
\r
2185 In case the low-water mark is reached, bLowWater will be set. */
\r
2186 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
\r
2188 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
\r
2189 pxTCPWindow->ulUserDataLength = 0;
\r
2192 #endif /* ipconfigUSE_TCP_WIN */
\r
2196 pxTCPWindow->ucOptionLength = 0u;
\r
2201 /*-----------------------------------------------------------*/
\r
2203 /* Set the TCP options (if any) for the outgoing packet. */
\r
2204 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2206 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2207 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2208 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2209 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
\r
2211 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2212 if( uxOptionsLength != 0u )
\r
2214 /* TCP options must be sent because a packet which is out-of-order
\r
2216 if( xTCPWindowLoggingLevel >= 0 )
\r
2217 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
\r
2218 pxSocket->usLocalPort,
\r
2219 pxSocket->u.xTCP.usRemotePort,
\r
2221 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
2222 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
\r
2223 memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
\r
2225 /* The header length divided by 4, goes into the higher nibble,
\r
2226 effectively a shift-left 2. */
\r
2227 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2230 #endif /* ipconfigUSE_TCP_WIN */
\r
2231 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
\r
2233 /* TCP options must be sent because the MSS has changed. */
\r
2234 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
\r
2235 if( xTCPWindowLoggingLevel >= 0 )
\r
2237 FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
\r
2240 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
\r
2241 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
\r
2242 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
\r
2243 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
\r
2244 uxOptionsLength = 4u;
\r
2245 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2248 return uxOptionsLength;
\r
2250 /*-----------------------------------------------------------*/
\r
2253 * prvHandleSynReceived(): called from prvTCPHandleState()
\r
2255 * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
\r
2256 * If the flags received are correct, the socket will move to eESTABLISHED.
\r
2258 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2259 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2261 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2262 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2263 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2264 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2265 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2266 BaseType_t xSendLength = 0;
\r
2268 /* Either expect a ACK or a SYN+ACK. */
\r
2269 uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
\r
2270 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2272 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
\r
2275 if( ( ucTCPFlags & 0x17u ) != usExpect )
\r
2277 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
\r
2278 /* eSYN_RECEIVED: flags ACK expected, not SYN. */
\r
2279 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
\r
2280 pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
\r
2281 usExpect, ucTCPFlags ) );
\r
2282 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2283 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
\r
2284 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2285 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2289 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
\r
2290 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
\r
2292 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2294 TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
2296 /* Clear the SYN flag in lastPacket. */
\r
2297 pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
\r
2299 /* This socket was the one connecting actively so now perofmr the
\r
2300 synchronisation. */
\r
2301 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
\r
2302 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2303 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2304 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
\r
2305 pxTCPWindow->ulNextTxSequenceNumber++;
\r
2307 else if( ulReceiveLength == 0u )
\r
2309 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
2312 /* The SYN+ACK has been confirmed, increase the next sequence number by
\r
2314 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
\r
2316 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2318 FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
\r
2319 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
\r
2320 pxSocket->usLocalPort,
\r
2321 pxSocket->u.xTCP.ulRemoteIP,
\r
2322 pxSocket->u.xTCP.usRemotePort,
\r
2323 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
\r
2325 #endif /* ipconfigUSE_TCP_WIN */
\r
2327 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
\r
2329 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2330 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2331 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2333 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2335 if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
\r
2337 /* The other party did not send a scaling factor.
\r
2338 A shifting factor in this side must be canceled. */
\r
2339 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
\r
2340 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
\r
2343 #endif /* ipconfigUSE_TCP_WIN */
\r
2344 /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
\r
2345 connection is established. */
\r
2346 vTCPStateChange( pxSocket, eESTABLISHED );
\r
2349 return xSendLength;
\r
2351 /*-----------------------------------------------------------*/
\r
2354 * prvHandleEstablished(): called from prvTCPHandleState()
\r
2356 * Called if the status is eESTABLISHED. Data reception has been handled
\r
2357 * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
\r
2358 * the code will check if it may be accepted, i.e. if all expected data has been
\r
2359 * completely received.
\r
2361 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2362 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2364 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2365 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2366 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2367 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2368 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
\r
2369 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
\r
2370 int32_t lDistance, lSendResult;
\r
2372 /* Remember the window size the peer is advertising. */
\r
2373 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
\r
2374 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2376 pxSocket->u.xTCP.ulWindowSize =
\r
2377 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
2381 if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
\r
2383 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
\r
2385 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
\r
2386 starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
\r
2388 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
\r
2390 /* Just advancing the tail index, 'ulCount' bytes have been
\r
2391 confirmed, and because there is new space in the txStream, the
\r
2392 user/owner should be woken up. */
\r
2393 /* _HT_ : only in case the socket's waiting? */
\r
2394 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
\r
2396 pxSocket->xEventBits |= eSOCKET_SEND;
\r
2398 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
2400 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
\r
2402 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
2406 /* In case the socket owner has installed an OnSent handler,
\r
2408 #if( ipconfigUSE_CALLBACKS == 1 )
\r
2410 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
2412 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
2415 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
2420 /* If this socket has a stream for transmission, add the data to the
\r
2421 outgoing segment(s). */
\r
2422 if( pxSocket->u.xTCP.txStream != NULL )
\r
2424 prvTCPAddTxData( pxSocket );
\r
2427 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2429 if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
\r
2431 /* Peer is requesting to stop, see if we're really finished. */
\r
2432 xMayClose = pdTRUE;
\r
2434 /* Checks are only necessary if we haven't sent a FIN yet. */
\r
2435 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2437 /* xTCPWindowTxDone returns true when all Tx queues are empty. */
\r
2438 bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
\r
2439 bTxDone = xTCPWindowTxDone( pxTCPWindow );
\r
2441 if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
\r
2443 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
\r
2444 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
\r
2445 pxSocket->usLocalPort,
\r
2446 pxSocket->u.xTCP.usRemotePort,
\r
2447 bRxComplete, bTxDone ) );
\r
2448 xMayClose = pdFALSE;
\r
2452 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2454 if( lDistance > 1 )
\r
2456 FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
\r
2457 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2458 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2460 xMayClose = pdFALSE;
\r
2465 if( xTCPWindowLoggingLevel > 0 )
\r
2467 FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
\r
2468 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
\r
2469 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
\r
2472 if( xMayClose != pdFALSE )
\r
2474 pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
\r
2475 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2479 if( xMayClose == pdFALSE )
\r
2481 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2483 if( ulReceiveLength != 0u )
\r
2485 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2486 /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
\r
2487 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2489 if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
\r
2491 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2495 /* Now get data to be transmitted. */
\r
2496 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
\r
2497 can not send-out both TCP options and also a full packet. Sending
\r
2498 options (SACK) is always more urgent than sending data, which can be
\r
2500 if( uxOptionsLength == 0u )
\r
2502 /* prvTCPPrepareSend might allocate a bigger network buffer, if
\r
2504 lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
2505 if( lSendResult > 0 )
\r
2507 xSendLength = ( BaseType_t ) lSendResult;
\r
2512 return xSendLength;
\r
2514 /*-----------------------------------------------------------*/
\r
2517 * Called from prvTCPHandleState(). There is data to be sent. If
\r
2518 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
\r
2519 * checked if it would better be postponed for efficiency.
\r
2521 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2522 uint32_t ulReceiveLength, BaseType_t xSendLength )
\r
2524 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2525 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2526 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2527 /* Find out what window size we may advertised. */
\r
2528 uint32_t ulFrontSpace;
\r
2530 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2531 #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
\r
2532 const int32_t lMinLength = 0;
\r
2534 int32_t lMinLength;
\r
2537 pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -
\r
2538 ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2540 /* Free space in rxStream. */
\r
2541 if( pxSocket->u.xTCP.rxStream != NULL )
\r
2543 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
2547 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
2550 pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );
\r
2552 /* Set the time-out field, so that we'll be called by the IP-task in case no
\r
2553 next message will be received. */
\r
2554 lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2555 #if ipconfigUSE_TCP_WIN == 1
\r
2558 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
\r
2560 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2562 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
\r
2564 /* In case we're receiving data continuously, we might postpone sending
\r
2565 an ACK to gain performance. */
\r
2566 if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
\r
2567 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
\r
2568 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
\r
2569 ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
\r
2570 ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
\r
2571 ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
\r
2573 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2575 /* There was still a delayed in queue, delete it. */
\r
2576 if( pxSocket->u.xTCP.pxAckMessage != 0 )
\r
2578 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2581 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
\r
2583 if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
\r
2584 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
\r
2586 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
\r
2590 /* Normally a delayed ACK should wait 200 ms for a next incoming
\r
2591 packet. Only wait 20 ms here to gain performance. A slow ACK
\r
2592 for full-size message. */
\r
2593 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
\r
2596 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2598 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
\r
2599 pxSocket->usLocalPort,
\r
2600 pxSocket->u.xTCP.usRemotePort,
\r
2601 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2602 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2604 pxSocket->u.xTCP.usTimeout, lRxSpace ) );
\r
2607 *ppxNetworkBuffer = NULL;
\r
2610 else if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
2612 /* As an ACK is not being delayed, remove any earlier delayed ACK
\r
2614 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2616 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2619 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
2624 /* Remove compiler warnings. */
\r
2625 ( void ) ulReceiveLength;
\r
2626 ( void ) pxTCPHeader;
\r
2627 ( void ) lRxSpace;
\r
2629 #endif /* ipconfigUSE_TCP_WIN */
\r
2631 if( xSendLength != 0 )
\r
2633 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2635 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
\r
2636 pxSocket->usLocalPort,
\r
2637 pxSocket->u.xTCP.usRemotePort,
\r
2638 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2639 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2643 /* Set the parameter 'xReleaseAfterSend' to the value of
\r
2644 ipconfigZERO_COPY_TX_DRIVER. */
\r
2645 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
2646 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
2648 /* The driver has taken ownership of the Network Buffer. */
\r
2649 *ppxNetworkBuffer = NULL;
\r
2654 return xSendLength;
\r
2656 /*-----------------------------------------------------------*/
\r
2659 * prvTCPHandleState()
\r
2660 * is the most important function of this TCP stack
\r
2661 * We've tried to keep it (relatively short) by putting a lot of code in
\r
2662 * the static functions above:
\r
2664 * prvCheckRxData()
\r
2665 * prvStoreRxData()
\r
2667 * prvHandleSynReceived()
\r
2668 * prvHandleEstablished()
\r
2671 * As these functions are declared static, and they're called from one location
\r
2672 * only, most compilers will inline them, thus avoiding a call and return.
\r
2674 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
2676 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2677 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2678 BaseType_t xSendLength = 0;
\r
2679 uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
\r
2680 uint8_t *pucRecvData;
\r
2681 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
\r
2683 /* uxOptionsLength: the size of the options to be sent (always a multiple of
\r
2685 1. in the SYN phase, we shall communicate the MSS
\r
2686 2. in case of a SACK, Selective ACK, ack a segment which comes in
\r
2688 UBaseType_t uxOptionsLength = 0u;
\r
2689 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2690 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
2692 /* First get the length and the position of the received data, if any.
\r
2693 pucRecvData will point to the first byte of the TCP payload. */
\r
2694 ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
\r
2696 if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
\r
2698 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
\r
2700 /* This is most probably a keep-alive message from peer. Setting
\r
2701 'bWinChange' doesn't cause a window-size-change, the flag is used
\r
2702 here to force sending an immediate ACK. */
\r
2703 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
2707 /* Keep track of the highest sequence number that might be expected within
\r
2708 this connection. */
\r
2709 if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
\r
2711 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2714 /* Storing data may result in a fatal error if malloc() fails. */
\r
2715 if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
\r
2721 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
\r
2723 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
\r
2725 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
\r
2727 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
\r
2728 'SYN+ACK' didn't arrive. Step back to the previous state in which
\r
2729 a first incoming SYN is handled. The SYN was counted already so
\r
2730 decrease it first. */
\r
2731 vTCPStateChange( pxSocket, eSYN_FIRST );
\r
2734 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
\r
2736 /* It's the first time a FIN has been received, remember its
\r
2737 sequence number. */
\r
2738 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2739 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
\r
2741 /* Was peer the first one to send a FIN? */
\r
2742 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2744 /* If so, don't send the-last-ACK. */
\r
2745 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
\r
2749 switch (pxSocket->u.xTCP.ucTCPState)
\r
2751 case eCLOSED: /* (server + client) no connection state at all. */
\r
2752 /* Nothing to do for a closed socket, except waiting for the
\r
2756 case eTCP_LISTEN: /* (server) waiting for a connection request from
\r
2757 any remote TCP and port. */
\r
2758 /* The listen state was handled in xProcessReceivedTCPPacket().
\r
2759 Should not come here. */
\r
2762 case eSYN_FIRST: /* (server) Just received a SYN request for a server
\r
2765 /* A new socket has been created, reply with a SYN+ACK.
\r
2766 Acknowledge with seq+1 because the SYN is seen as pseudo data
\r
2768 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
2769 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
\r
2771 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2773 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
2774 uxOptionsLength is a multiple of 4. The complete expression is:
\r
2775 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
2776 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2777 vTCPStateChange( pxSocket, eSYN_RECEIVED );
\r
2779 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2780 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
\r
2784 case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
\r
2785 SYN, expect a SYN+ACK and send a ACK now. */
\r
2786 /* Fall through */
\r
2787 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
\r
2788 expect a ACK and do nothing. */
\r
2789 xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2792 case eESTABLISHED: /* (server + client) an open connection, data
\r
2793 received can be delivered to the user. The normal
\r
2794 state for the data transfer phase of the connection
\r
2795 The closing states are also handled here with the
\r
2796 use of some flags. */
\r
2797 xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2800 case eLAST_ACK: /* (server + client) waiting for an acknowledgement
\r
2801 of the connection termination request previously
\r
2802 sent to the remote TCP (which includes an
\r
2803 acknowledgement of its connection termination
\r
2805 /* Fall through */
\r
2806 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
\r
2807 * or an acknowledgement of the connection termination request previously sent. */
\r
2808 /* Fall through */
\r
2809 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
\r
2810 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2813 case eCLOSE_WAIT: /* (server + client) waiting for a connection
\r
2814 termination request from the local user. Nothing to
\r
2815 do, connection is closed, wait for owner to close
\r
2819 case eCLOSING: /* (server + client) waiting for a connection
\r
2820 termination request acknowledgement from the remote
\r
2824 case eTIME_WAIT: /* (either server or client) waiting for enough time
\r
2825 to pass to be sure the remote TCP received the
\r
2826 acknowledgement of its connection termination
\r
2827 request. [According to RFC 793 a connection can stay
\r
2828 in TIME-WAIT for a maximum of four minutes known as
\r
2829 a MSL (maximum segment lifetime).] These states are
\r
2830 implemented implicitly by settings flags like
\r
2831 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
\r
2838 if( xSendLength > 0 )
\r
2840 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
\r
2843 return xSendLength;
\r
2845 /*-----------------------------------------------------------*/
\r
2847 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2849 #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
\r
2851 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2852 const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
\r
2854 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;
\r
2855 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
\r
2857 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );
\r
2859 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
\r
2861 /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
\r
2862 ( void ) pxNetworkBuffer;
\r
2864 /* The packet was not consumed. */
\r
2867 /*-----------------------------------------------------------*/
\r
2869 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
\r
2871 uint32_t ulMSS = ipconfigTCP_MSS;
\r
2873 if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
\r
2875 /* Data for this peer will pass through a router, and maybe through
\r
2876 the internet. Limit the MSS to 1400 bytes or less. */
\r
2877 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
\r
2880 FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
\r
2882 pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
\r
2884 /*-----------------------------------------------------------*/
\r
2887 * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
\r
2888 * xProcessReceivedTCPPacket()
\r
2889 * prvTCPHandleState()
\r
2890 * prvTCPPrepareSend()
\r
2891 * prvTCPReturnPacket()
\r
2892 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2893 * prvTCPSendRepeated()
\r
2894 * prvTCPReturnPacket() // Prepare for returning
\r
2895 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2897 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2899 FreeRTOS_Socket_t *pxSocket;
\r
2900 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2901 uint16_t ucTCPFlags;
\r
2902 uint32_t ulLocalIP;
\r
2903 uint16_t xLocalPort;
\r
2904 uint32_t ulRemoteIP;
\r
2905 uint16_t xRemotePort;
\r
2906 BaseType_t xResult = pdPASS;
\r
2908 /* Check for a minimum packet size. */
\r
2909 if( pxNetworkBuffer->xDataLength >=
\r
2910 ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER )
\r
2912 ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
\r
2913 ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
\r
2914 xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
\r
2915 ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
2916 xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
2918 /* Find the destination socket, and if not found: return a socket listing to
\r
2919 the destination PORT. */
\r
2920 pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
\r
2927 if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
\r
2929 /* A TCP messages is received but either there is no socket with the
\r
2930 given port number or the there is a socket, but it is in one of these
\r
2931 non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
\r
2934 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
\r
2936 /* Send a RST to all packets that can not be handled. As a result
\r
2937 the other party will get a ECONN error. There are two exceptions:
\r
2938 1) A packet that already has the RST flag set.
\r
2939 2) A packet that only has the ACK flag set.
\r
2940 A packet with only the ACK flag set might be the last ACK in
\r
2941 a three-way hand-shake that closes a connection. */
\r
2942 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
\r
2943 ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
\r
2945 prvTCPSendReset( pxNetworkBuffer );
\r
2948 /* The packet can't be handled. */
\r
2953 pxSocket->u.xTCP.ucRepCount = 0u;
\r
2955 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
\r
2957 /* The matching socket is in a listening state. Test if the peer
\r
2958 has set the SYN flag. */
\r
2959 if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
\r
2961 /* What happens: maybe after a reboot, a client doesn't know the
\r
2962 connection had gone. Send a RST in order to get a new connect
\r
2964 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
2966 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
\r
2967 prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
\r
2969 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
2971 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
\r
2973 prvTCPSendReset( pxNetworkBuffer );
\r
2979 /* prvHandleListen() will either return a newly created socket
\r
2980 (if bReuseSocket is false), otherwise it returns the current
\r
2981 socket which will later get connected. */
\r
2982 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
\r
2984 if( pxSocket == NULL )
\r
2989 } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
\r
2992 /* This is not a socket in listening mode. Check for the RST
\r
2994 if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
\r
2996 /* The target socket is not in a listening state, any RST packet
\r
2997 will cause the socket to be closed. */
\r
2998 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
\r
2999 /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */
\r
3000 vTCPStateChange( pxSocket, eCLOSED );
\r
3002 /* The packet cannot be handled. */
\r
3005 else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
\r
3007 /* SYN flag while this socket is already connected. */
\r
3008 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
\r
3010 /* The packet cannot be handled. */
\r
3015 /* Update the copy of the TCP header only (skipping eth and IP
\r
3016 headers). It might be used later on, whenever data must be sent
\r
3018 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
\r
3019 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
\r
3024 if( xResult != pdFAIL )
\r
3026 /* Touch the alive timers because we received a message for this
\r
3028 prvTCPTouchSocket( pxSocket );
\r
3030 /* Parse the TCP option(s), if present. */
\r
3031 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
\r
3032 then we MUST assume an MSS size of 536 bytes for backward compatibility. */
\r
3034 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
3035 the number 5 (words) in the higher niblle of the TCP-offset byte. */
\r
3036 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
\r
3038 prvCheckOptions( pxSocket, pxNetworkBuffer );
\r
3042 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3044 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
\r
3045 pxSocket->u.xTCP.ulWindowSize =
\r
3046 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
3050 /* In prvTCPHandleState() the incoming messages will be handled
\r
3051 depending on the current state of the connection. */
\r
3052 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
\r
3054 /* prvTCPHandleState() has sent a message, see if there are more to
\r
3055 be transmitted. */
\r
3056 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3058 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
3060 #endif /* ipconfigUSE_TCP_WIN */
\r
3063 if( pxNetworkBuffer != NULL )
\r
3065 /* We must check if the buffer is unequal to NULL, because the
\r
3066 socket might keep a reference to it in case a delayed ACK must be
\r
3068 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
3069 pxNetworkBuffer = NULL;
\r
3072 /* And finally, calculate when this socket wants to be woken up. */
\r
3073 prvTCPNextTimeout ( pxSocket );
\r
3074 /* Return pdPASS to tell that the network buffer is 'consumed'. */
\r
3078 /* pdPASS being returned means the buffer has been consumed. */
\r
3081 /*-----------------------------------------------------------*/
\r
3083 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
3085 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
3086 FreeRTOS_Socket_t *pxReturn = NULL;
\r
3087 uint32_t ulInitialSequenceNumber;
\r
3089 /* Assume that a new Initial Sequence Number will be required. Request
\r
3090 it now in order to fail out if necessary. */
\r
3091 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber(
\r
3092 *ipLOCAL_IP_ADDRESS_POINTER,
\r
3093 pxSocket->usLocalPort,
\r
3094 pxTCPPacket->xIPHeader.ulSourceIPAddress,
\r
3095 pxTCPPacket->xTCPHeader.usSourcePort );
\r
3097 /* A pure SYN (without ACK) has come in, create a new socket to answer
\r
3099 if( 0 != ulInitialSequenceNumber )
\r
3101 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
3103 /* The flag bReuseSocket indicates that the same instance of the
\r
3104 listening socket should be used for the connection. */
\r
3105 pxReturn = pxSocket;
\r
3106 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3107 pxSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3111 /* The socket does not have the bReuseSocket flag set meaning create a
\r
3112 new socket when a connection comes in. */
\r
3115 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
\r
3117 FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
\r
3118 pxSocket->usLocalPort,
\r
3119 pxSocket->u.xTCP.usChildCount,
\r
3120 pxSocket->u.xTCP.usBacklog,
\r
3121 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
\r
3122 prvTCPSendReset( pxNetworkBuffer );
\r
3126 FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * )
\r
3127 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
3129 if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
\r
3131 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
\r
3132 prvTCPSendReset( pxNetworkBuffer );
\r
3134 else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
\r
3136 /* The socket will be connected immediately, no time for the
\r
3137 owner to setsockopt's, therefore copy properties of the server
\r
3138 socket to the new socket. Only the binding might fail (due to
\r
3139 lack of resources). */
\r
3140 pxReturn = pxNewSocket;
\r
3146 if( 0 != ulInitialSequenceNumber && pxReturn != NULL )
\r
3148 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
3149 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
3150 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
\r
3152 /* Here is the SYN action. */
\r
3153 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
3154 prvSocketSetMSS( pxReturn );
\r
3156 prvTCPCreateWindow( pxReturn );
\r
3158 vTCPStateChange( pxReturn, eSYN_FIRST );
\r
3160 /* Make a copy of the header up to the TCP header. It is needed later
\r
3161 on, whenever data must be sent to the peer. */
\r
3162 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
\r
3166 /*-----------------------------------------------------------*/
\r
3169 * Duplicates a socket after a listening socket receives a connection.
\r
3171 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
\r
3173 struct freertos_sockaddr xAddress;
\r
3175 pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
\r
3176 pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
\r
3177 pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
\r
3178 pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
\r
3179 pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
\r
3180 pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
\r
3181 pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
\r
3182 pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
\r
3183 pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
\r
3185 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
\r
3187 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
\r
3189 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
\r
3191 #if( ipconfigUSE_CALLBACKS == 1 )
\r
3193 /* In case call-backs are used, copy them from parent to child. */
\r
3194 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
\r
3195 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
\r
3196 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
\r
3198 #endif /* ipconfigUSE_CALLBACKS */
\r
3200 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
3202 /* Child socket of listening sockets will inherit the Socket Set
\r
3203 Otherwise the owner has no chance of including it into the set. */
\r
3204 if( pxSocket->pxSocketSet )
\r
3206 pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
\r
3207 pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
\r
3210 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
3212 /* And bind it to the same local port as its parent. */
\r
3213 xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
\r
3214 xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3216 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
3218 /* Only when there is anti-hanging protection, a socket may become an
\r
3219 orphan temporarily. Once this socket is really connected, the owner of
\r
3220 the server socket will be notified. */
\r
3222 /* When bPassQueued is true, the socket is an orphan until it gets
\r
3224 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3225 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3229 /* A reference to the new socket may be stored and the socket is marked
\r
3232 /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to
\r
3234 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
3235 if(pxSocket->u.xTCP.pxPeerSocket == NULL )
\r
3237 pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
\r
3242 pxSocket->u.xTCP.usChildCount++;
\r
3244 FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
\r
3245 pxSocket->usLocalPort,
\r
3246 pxSocket->u.xTCP.usChildCount,
\r
3247 pxSocket->u.xTCP.usBacklog,
\r
3248 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
\r
3250 /* Now bind the child socket to the same port as the listening socket. */
\r
3251 if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
\r
3253 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
\r
3254 vSocketClose( pxNewSocket );
\r
3260 /*-----------------------------------------------------------*/
\r
3262 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
3264 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
\r
3266 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
\r
3268 ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
\r
3270 return pcStateNames[ ulState ];
\r
3273 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
\r
3274 /*-----------------------------------------------------------*/
\r
3277 * In the API accept(), the user asks is there is a new client? As API's can
\r
3278 * not walk through the xBoundTCPSocketsList the IP-task will do this.
\r
3280 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
\r
3282 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3283 ListItem_t *pxIterator;
\r
3284 FreeRTOS_Socket_t *pxFound;
\r
3285 BaseType_t xResult = pdFALSE;
\r
3287 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
\r
3288 who has access. */
\r
3289 for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
\r
3290 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
\r
3291 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
3293 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
\r
3295 pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
3296 if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
3298 pxSocket->u.xTCP.pxPeerSocket = pxFound;
\r
3299 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
\r
3307 /*-----------------------------------------------------------*/
\r
3309 #endif /* ipconfigUSE_TCP == 1 */
\r
3311 /* Provide access to private members for testing. */
\r
3312 #ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS
\r
3313 #include "aws_freertos_tcp_test_access_tcp_define.h"
\r