2 * FreeRTOS+TCP V2.0.11
\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 * Common code for sending a TCP protocol control packet (i.e. no options, no
\r
312 * payload, just flags).
\r
314 static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
315 uint8_t ucTCPFlags );
\r
318 * A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2,
\r
319 * case #3. In summary, an RST was received with a sequence number that is
\r
320 * unexpected but still within the window.
\r
322 static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
325 * Reply to a peer with the RST flag on, in case a packet can not be handled.
\r
327 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
330 * Set the initial value for MSS (Maximum Segment Size) to be used.
\r
332 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
\r
335 * Return either a newly created socket, or the current socket in a connected
\r
336 * state (depends on the 'bReuseSocket' flag).
\r
338 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
341 * After a listening socket receives a new connection, it may duplicate itself.
\r
342 * The copying takes place in prvTCPSocketCopy.
\r
344 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
\r
347 * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
\r
348 * state for too long. If so, the socket will be closed, and -1 will be
\r
351 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
352 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
\r
355 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
356 int32_t lDataLen, UBaseType_t uxOptionsLength );
\r
358 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
359 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
\r
362 #if( ipconfigUSE_TCP_WIN != 0 )
\r
363 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
\r
367 * Generate a randomized TCP Initial Sequence Number per RFC.
\r
369 extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
\r
370 uint16_t usSourcePort,
\r
371 uint32_t ulDestinationAddress,
\r
372 uint16_t usDestinationPort );
\r
374 /*-----------------------------------------------------------*/
\r
376 /* prvTCPSocketIsActive() returns true if the socket must be checked.
\r
377 * Non-active sockets are waiting for user action, either connect()
\r
379 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
\r
393 /*-----------------------------------------------------------*/
\r
395 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
397 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
\r
399 BaseType_t xResult;
\r
400 switch( pxSocket->u.xTCP.ucTCPState )
\r
403 /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
\r
404 state ESTABLISHED can be protected using keep-alive messages. */
\r
410 /* These 3 states may last for ever, up to the owner. */
\r
414 /* All other (non-connected) states will get anti-hanging
\r
419 if( xResult != pdFALSE )
\r
421 /* How much time has past since the last active moment which is
\r
422 defined as A) a state change or B) a packet has arrived. */
\r
423 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
\r
425 /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
\r
426 if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
\r
428 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
430 FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
\r
431 pxSocket->usLocalPort,
\r
432 pxSocket->u.xTCP.ulRemoteIP,
\r
433 pxSocket->u.xTCP.usRemotePort,
\r
434 FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
\r
436 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
438 /* Move to eCLOSE_WAIT, user may close the socket. */
\r
439 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
441 /* When 'bPassQueued' true, this socket is an orphan until it
\r
443 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
445 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
447 /* As it did not get connected, and the user can never
\r
448 accept() it anymore, it will be deleted now. Called from
\r
449 the IP-task, so it's safe to call the internal Close
\r
450 function: vSocketClose(). */
\r
451 vSocketClose( pxSocket );
\r
453 /* Return a negative value to tell to inform the caller
\r
455 that the socket got closed and may not be accessed anymore. */
\r
462 /*-----------------------------------------------------------*/
\r
467 * As soon as a TCP socket timer expires, this function xTCPSocketCheck
\r
468 * will be called (from xTCPTimerCheck)
\r
469 * It can send a delayed ACK or new data
\r
470 * Sequence of calling (normally) :
\r
472 * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
\r
473 * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
\r
474 * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
\r
475 * prvTCPSendRepeated() // Send at most 8 messages on a row
\r
476 * prvTCPReturnPacket() // Prepare for returning
\r
477 * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
\r
479 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
\r
481 BaseType_t xResult = 0;
\r
482 BaseType_t xReady = pdFALSE;
\r
484 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
\r
486 /* The API FreeRTOS_send() might have added data to the TX stream. Add
\r
487 this data to the windowing system to it can be transmitted. */
\r
488 prvTCPAddTxData( pxSocket );
\r
491 #if ipconfigUSE_TCP_WIN == 1
\r
493 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
495 /* The first task of this regular socket check is to send-out delayed
\r
497 if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
\r
499 /* Earlier data was received but not yet acknowledged. This
\r
500 function is called when the TCP timer for the socket expires, the
\r
501 ACK may be sent now. */
\r
502 if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
\r
504 if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
\r
506 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
\r
507 pxSocket->usLocalPort,
\r
508 pxSocket->u.xTCP.usRemotePort,
\r
509 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
510 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
\r
511 ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
\r
514 prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
\r
516 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
518 /* The ownership has been passed to the SEND routine,
\r
519 clear the pointer to it. */
\r
520 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
522 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
524 if( prvTCPNextTimeout( pxSocket ) > 1 )
\r
526 /* Tell the code below that this function is ready. */
\r
532 /* The user wants to perform an active shutdown(), skip sending
\r
533 the delayed ACK. The function prvTCPSendPacket() will send the
\r
534 FIN along with the ACK's. */
\r
537 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
539 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
540 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
544 #endif /* ipconfigUSE_TCP_WIN */
\r
546 if( xReady == pdFALSE )
\r
548 /* The second task of this regular socket check is sending out data. */
\r
549 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
\r
550 ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
\r
552 prvTCPSendPacket( pxSocket );
\r
555 /* Set the time-out for the next wakeup for this socket. */
\r
556 prvTCPNextTimeout( pxSocket );
\r
558 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
560 /* In all (non-connected) states in which keep-alive messages can not be sent
\r
561 the anti-hang protocol will close sockets that are 'hanging'. */
\r
562 xResult = prvTCPStatusAgeCheck( pxSocket );
\r
569 /*-----------------------------------------------------------*/
\r
572 * prvTCPSendPacket() will be called when the socket time-out has been reached.
\r
573 * It is only called by xTCPSocketCheck().
\r
575 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
\r
577 int32_t lResult = 0;
\r
578 UBaseType_t uxOptionsLength;
\r
579 TCPPacket_t *pxTCPPacket;
\r
580 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
582 if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
\r
584 /* The connection is in s state other than SYN. */
\r
585 pxNetworkBuffer = NULL;
\r
587 /* prvTCPSendRepeated() will only create a network buffer if necessary,
\r
588 i.e. when data must be sent to the peer. */
\r
589 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
591 if( pxNetworkBuffer != NULL )
\r
593 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
598 if( pxSocket->u.xTCP.ucRepCount >= 3u )
\r
600 /* The connection is in the SYN status. The packet will be repeated
\r
601 to most 3 times. When there is no response, the socket get the
\r
602 status 'eCLOSE_WAIT'. */
\r
603 FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
\r
604 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
605 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
606 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
608 else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
\r
610 /* Or else, if the connection has been prepared, or can be prepared
\r
611 now, proceed to send the packet with the SYN flag.
\r
612 prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
\r
613 the Ethernet address of the peer or the gateway is found. */
\r
614 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
616 /* About to send a SYN packet. Call prvSetSynAckOptions() to set
\r
617 the proper options: The size of MSS and whether SACK's are
\r
619 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
621 /* Return the number of bytes to be sent. */
\r
622 lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
624 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
625 uxOptionsLength is always a multiple of 4. The complete expression
\r
627 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
628 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
630 /* Repeat Count is used for a connecting socket, to limit the number
\r
632 pxSocket->u.xTCP.ucRepCount++;
\r
634 /* Send the SYN message to make a connection. The messages is
\r
635 stored in the socket field 'xPacket'. It will be wrapped in a
\r
636 pseudo network buffer descriptor before it will be sent. */
\r
637 prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
\r
641 /* Return the total number of bytes sent. */
\r
644 /*-----------------------------------------------------------*/
\r
647 * prvTCPSendRepeated will try to send a series of messages, as long as there is
\r
648 * data to be sent and as long as the transmit window isn't full.
\r
650 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
652 UBaseType_t uxIndex;
\r
653 int32_t lResult = 0;
\r
654 UBaseType_t uxOptionsLength = 0u;
\r
655 int32_t xSendLength;
\r
657 for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
\r
659 /* prvTCPPrepareSend() might allocate a network buffer if there is data
\r
661 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
662 if( xSendLength <= 0 )
\r
667 /* And return the packet to the peer. */
\r
668 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
670 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
672 *ppxNetworkBuffer = NULL;
\r
674 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
676 lResult += xSendLength;
\r
679 /* Return the total number of bytes sent. */
\r
682 /*-----------------------------------------------------------*/
\r
685 * Return (or send) a packet the the peer. The data is stored in pxBuffer,
\r
686 * which may either point to a real network buffer or to a TCP socket field
\r
687 * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
\r
688 * the data to the NIC.
\r
690 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
\r
692 TCPPacket_t * pxTCPPacket;
\r
693 IPHeader_t *pxIPHeader;
\r
694 EthernetHeader_t *pxEthernetHeader;
\r
695 uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
\r
696 TCPWindow_t *pxTCPWindow;
\r
697 NetworkBufferDescriptor_t xTempBuffer;
\r
698 /* For sending, a pseudo network buffer will be used, as explained above. */
\r
700 if( pxNetworkBuffer == NULL )
\r
702 pxNetworkBuffer = &xTempBuffer;
\r
704 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
706 xTempBuffer.pxNextBuffer = NULL;
\r
709 xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
710 xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
711 xReleaseAfterSend = pdFALSE;
\r
714 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
716 if( xReleaseAfterSend == pdFALSE )
\r
718 pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
\r
719 if( pxNetworkBuffer == NULL )
\r
721 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
\r
723 xReleaseAfterSend = pdTRUE;
\r
726 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
728 if( pxNetworkBuffer != NULL )
\r
730 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
731 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
732 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
\r
734 /* Fill the packet, using hton translations. */
\r
735 if( pxSocket != NULL )
\r
737 /* Calculate the space in the RX buffer in order to advertise the
\r
738 size of this socket's reception window. */
\r
739 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
741 if( pxSocket->u.xTCP.rxStream != NULL )
\r
743 /* An RX stream was created already, see how much space is
\r
745 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
749 /* No RX stream has been created, the full stream size is
\r
751 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
754 /* Take the minimum of the RX buffer space and the RX window size. */
\r
755 ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace );
\r
757 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
\r
759 /* The low-water mark was reached, meaning there was little
\r
760 space left. The socket will wait until the application has read
\r
761 or flushed the incoming data, and 'zero-window' will be
\r
766 /* If possible, advertise an RX window size of at least 1 MSS, otherwise
\r
767 the peer might start 'zero window probing', i.e. sending small packets
\r
768 (1, 2, 4, 8... bytes). */
\r
769 if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
\r
771 ulSpace = pxSocket->u.xTCP.usCurMSS;
\r
774 /* Avoid overflow of the 16-bit win field. */
\r
775 #if( ipconfigUSE_TCP_WIN != 0 )
\r
777 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
\r
781 ulWinSize = ulSpace;
\r
784 if( ulWinSize > 0xfffcUL )
\r
786 ulWinSize = 0xfffcUL;
\r
789 pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
\r
791 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
793 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
\r
795 if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
\r
797 size_t uxFrontSpace;
\r
799 if(pxSocket->u.xTCP.rxStream != NULL)
\r
801 uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
\r
808 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
\r
809 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
\r
810 pxSocket->u.xTCP.ulRemoteIP,
\r
811 pxSocket->u.xTCP.usRemotePort,
\r
812 pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
\r
813 (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
\r
817 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
819 /* The new window size has been advertised, switch off the flag. */
\r
820 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
\r
822 /* Later on, when deciding to delay an ACK, a precise estimate is needed
\r
823 of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
\r
824 highest sequence number minus 1 that the socket will accept. */
\r
825 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
\r
827 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
828 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
\r
830 /* Sending a keep-alive packet, send the current sequence number
\r
831 minus 1, which will be recognised as a keep-alive packet an
\r
832 responded to by acknowledging the last byte. */
\r
833 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
834 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
\r
836 pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
\r
837 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
842 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
\r
844 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
\r
846 /* Suppress FIN in case this packet carries earlier data to be
\r
848 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
\r
849 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
\r
851 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
\r
852 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
\r
853 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
855 pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
\r
860 /* Tell which sequence number is expected next time */
\r
861 pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
865 /* Sending data without a socket, probably replying with a RST flag
\r
866 Just swap the two sequence numbers. */
\r
867 vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
\r
870 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
871 pxIPHeader->usLength = FreeRTOS_htons( ulLen );
\r
872 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
\r
874 /* When pxSocket is NULL, this function is called by prvTCPSendReset()
\r
875 and the IP-addresses must be swapped.
\r
876 Also swap the IP-addresses in case the IP-tack doesn't have an
\r
877 IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
\r
878 ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
\r
882 ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
884 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
885 pxIPHeader->ulSourceIPAddress = ulSourceAddress;
\r
886 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
\r
888 /* Just an increasing number. */
\r
889 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
890 usPacketIdentifier++;
\r
891 pxIPHeader->usFragmentOffset = 0u;
\r
893 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
895 /* calculate the IP header checksum, in case the driver won't do that. */
\r
896 pxIPHeader->usHeaderChecksum = 0x00u;
\r
897 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
898 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
900 /* calculate the TCP checksum for an outgoing packet. */
\r
901 usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
\r
903 /* A calculated checksum of 0 must be inverted as 0 means the checksum
\r
905 if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
\r
907 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
\r
912 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
913 pxNetworkBuffer->pxNextBuffer = NULL;
\r
916 /* Important: tell NIC driver how many bytes must be sent. */
\r
917 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
\r
919 /* Fill in the destination MAC addresses. */
\r
920 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
\r
921 sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
923 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
\r
924 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
926 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
928 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
932 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
934 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
936 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
942 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
\r
944 if( xReleaseAfterSend == pdFALSE )
\r
946 /* Swap-back some fields, as pxBuffer probably points to a socket field
\r
947 containing the packet header. */
\r
948 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
\r
949 pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
\r
950 memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
954 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
\r
956 } /* if( pxNetworkBuffer != NULL ) */
\r
958 /*-----------------------------------------------------------*/
\r
961 * The SYN event is very important: the sequence numbers, which have a kind of
\r
962 * random starting value, are being synchronised. The sliding window manager
\r
963 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
\r
964 * Size (MSS) in use.
\r
966 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
\r
968 if( xTCPWindowLoggingLevel )
\r
969 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
\r
970 pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
\r
971 pxSocket->u.xTCP.uxLittleSpace ,
\r
972 pxSocket->u.xTCP.uxEnoughSpace,
\r
973 pxSocket->u.xTCP.uxRxStreamSize ) );
\r
975 &pxSocket->u.xTCP.xTCPWindow,
\r
976 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
\r
977 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
\r
978 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
\r
979 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
\r
980 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
\r
982 /*-----------------------------------------------------------*/
\r
985 * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
\r
986 * the Ethernet address of the target will be found using ARP. In case the
\r
987 * target IP address is not within the netmask, the hardware address of the
\r
988 * gateway will be used.
\r
990 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
\r
992 TCPPacket_t *pxTCPPacket;
\r
993 IPHeader_t *pxIPHeader;
\r
994 eARPLookupResult_t eReturned;
\r
995 uint32_t ulRemoteIP;
\r
996 MACAddress_t xEthAddress;
\r
997 BaseType_t xReturn = pdTRUE;
\r
998 uint32_t ulInitialSequenceNumber = 0;
\r
1000 #if( ipconfigHAS_PRINTF != 0 )
\r
1002 /* Only necessary for nicer logging. */
\r
1003 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
\r
1005 #endif /* ipconfigHAS_PRINTF != 0 */
\r
1007 ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1009 /* Determine the ARP cache status for the requested IP address. */
\r
1010 eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
\r
1012 switch( eReturned )
\r
1014 case eARPCacheHit: /* An ARP table lookup found a valid entry. */
\r
1015 break; /* We can now prepare the SYN packet. */
\r
1016 case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
\r
1017 case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
\r
1019 /* Count the number of times it couldn't find the ARP address. */
\r
1020 pxSocket->u.xTCP.ucRepCount++;
\r
1022 FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
\r
1023 pxSocket->u.xTCP.ulRemoteIP,
\r
1024 FreeRTOS_htonl( ulRemoteIP ),
\r
1026 xEthAddress.ucBytes[ 0 ],
\r
1027 xEthAddress.ucBytes[ 1 ],
\r
1028 xEthAddress.ucBytes[ 2 ],
\r
1029 xEthAddress.ucBytes[ 3 ],
\r
1030 xEthAddress.ucBytes[ 4 ],
\r
1031 xEthAddress.ucBytes[ 5 ] ) );
\r
1033 /* And issue a (new) ARP request */
\r
1034 FreeRTOS_OutputARPRequest( ulRemoteIP );
\r
1036 xReturn = pdFALSE;
\r
1039 if( xReturn != pdFALSE )
\r
1041 /* Get a difficult-to-predict initial sequence number for this 4-tuple. */
\r
1042 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
\r
1043 pxSocket->usLocalPort,
\r
1044 pxSocket->u.xTCP.ulRemoteIP,
\r
1045 pxSocket->u.xTCP.usRemotePort );
\r
1047 /* Check for a random number generation error. */
\r
1048 if( 0 == ulInitialSequenceNumber )
\r
1050 xReturn = pdFALSE;
\r
1054 if( xReturn != pdFALSE )
\r
1056 /* The MAC-address of the peer (or gateway) has been found,
\r
1057 now prepare the initial TCP packet and some fields in the socket. */
\r
1058 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1059 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
1061 /* reset the retry counter to zero. */
\r
1062 pxSocket->u.xTCP.ucRepCount = 0u;
\r
1064 /* And remember that the connect/SYN data are prepared. */
\r
1065 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
\r
1067 /* Now that the Ethernet address is known, the initial packet can be
\r
1069 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1071 /* Write the Ethernet address in Source, because it will be swapped by
\r
1072 prvTCPReturnPacket(). */
\r
1073 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
\r
1075 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
\r
1076 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
\r
1078 pxIPHeader->ucVersionHeaderLength = 0x45u;
\r
1079 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
\r
1080 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
1082 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
\r
1084 /* Addresses and ports will be stored swapped because prvTCPReturnPacket
\r
1085 will swap them back while replying. */
\r
1086 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1087 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1089 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
\r
1090 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
1092 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
\r
1093 isn't known yet. */
\r
1094 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
\r
1096 /* Start with ISN (Initial Sequence Number). */
\r
1097 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
\r
1099 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
\r
1100 the high nibble of the TCP offset field. */
\r
1101 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
\r
1103 /* Only set the SYN flag. */
\r
1104 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
\r
1106 /* Set the values of usInitMSS / usCurMSS for this socket. */
\r
1107 prvSocketSetMSS( pxSocket );
\r
1109 /* The initial sequence numbers at our side are known. Later
\r
1110 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
\r
1111 first wait for a SYN+ACK reply. */
\r
1112 prvTCPCreateWindow( pxSocket );
\r
1117 /*-----------------------------------------------------------*/
\r
1119 /* For logging and debugging: make a string showing the TCP flags
\r
1121 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1123 static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
\r
1125 static char retString[10];
\r
1126 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
\r
1127 ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
\r
1128 ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
\r
1129 ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
\r
1130 ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
\r
1131 ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
\r
1132 ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
\r
1133 ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
\r
1134 ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
\r
1135 ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
\r
1138 /*-----------------------------------------------------------*/
\r
1140 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1143 * Parse the TCP option(s) received, if present. It has already been verified
\r
1144 * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
\r
1145 * is longer than the usual 20 (5 x 4) bytes.
\r
1147 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1149 TCPPacket_t * pxTCPPacket;
\r
1150 TCPHeader_t * pxTCPHeader;
\r
1151 const unsigned char *pucPtr;
\r
1152 const unsigned char *pucLast;
\r
1153 TCPWindow_t *pxTCPWindow;
\r
1154 UBaseType_t uxNewMSS;
\r
1156 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1157 pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1159 /* A character pointer to iterate through the option data */
\r
1160 pucPtr = pxTCPHeader->ucOptdata;
\r
1161 pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
\r
1162 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1164 /* Validate options size calculation. */
\r
1165 if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) )
\r
1170 /* The comparison with pucLast is only necessary in case the option data are
\r
1171 corrupted, we don't like to run into invalid memory and crash. */
\r
1172 while( pucPtr < pucLast )
\r
1174 UBaseType_t xRemainingOptionsBytes = pucLast - pucPtr;
\r
1176 if( pucPtr[ 0 ] == TCP_OPT_END )
\r
1178 /* End of options. */
\r
1181 if( pucPtr[ 0 ] == TCP_OPT_NOOP)
\r
1183 /* NOP option, inserted to make the length a multiple of 4. */
\r
1188 /* Any other well-formed option must be at least two bytes: the option
\r
1189 type byte followed by a length byte. */
\r
1190 if( xRemainingOptionsBytes < 2 )
\r
1194 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1195 else if( pucPtr[ 0 ] == TCP_OPT_WSOPT )
\r
1197 /* Confirm that the option fits in the remaining buffer space. */
\r
1198 if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != TCP_OPT_WSOPT_LEN ) )
\r
1203 pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
\r
1204 pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
\r
1205 pucPtr += TCP_OPT_WSOPT_LEN;
\r
1207 #endif /* ipconfigUSE_TCP_WIN */
\r
1208 else if( pucPtr[ 0 ] == TCP_OPT_MSS )
\r
1210 /* Confirm that the option fits in the remaining buffer space. */
\r
1211 if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( pucPtr[ 1 ] != TCP_OPT_MSS_LEN ) )
\r
1216 /* An MSS option with the correct option length. FreeRTOS_htons()
\r
1217 is not needed here because usChar2u16() already returns a host
\r
1219 uxNewMSS = usChar2u16( pucPtr + 2 );
\r
1221 if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
\r
1223 /* Perform a basic check on the the new MSS. */
\r
1224 if( uxNewMSS == 0 )
\r
1229 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
\r
1232 if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
\r
1234 /* our MSS was bigger than the MSS of the other party: adapt it. */
\r
1235 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
\r
1236 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )
\r
1238 /* The peer advertises a smaller MSS than this socket was
\r
1239 using. Use that as well. */
\r
1240 FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
\r
1241 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1243 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
\r
1244 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
\r
1245 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
\r
1246 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
\r
1247 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1250 #if( ipconfigUSE_TCP_WIN != 1 )
\r
1251 /* Without scaled windows, MSS is the only interesting option. */
\r
1254 /* Or else we continue to check another option: selective ACK. */
\r
1255 pucPtr += TCP_OPT_MSS_LEN;
\r
1256 #endif /* ipconfigUSE_TCP_WIN != 1 */
\r
1260 /* All other options have a length field, so that we easily
\r
1261 can skip past them. */
\r
1262 unsigned char len = pucPtr[ 1 ];
\r
1263 if( ( len < 2 ) || ( len > xRemainingOptionsBytes ) )
\r
1265 /* If the length field is too small or too big, the options are malformed.
\r
1266 Don't process them further. */
\r
1270 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1272 /* Selective ACK: the peer has received a packet but it is missing earlier
\r
1273 packets. At least this packet does not need retransmission anymore
\r
1274 ulTCPWindowTxSack( ) takes care of this administration. */
\r
1275 if( pucPtr[0] == TCP_OPT_SACK_A )
\r
1282 uint32_t ulFirst = ulChar2u32( pucPtr );
\r
1283 uint32_t ulLast = ulChar2u32( pucPtr + 4 );
\r
1284 uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );
\r
1285 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
\r
1286 starting from the head position.
\r
1287 Advance the tail pointer in txStream. */
\r
1288 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
\r
1290 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
\r
1291 uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
\r
1292 pxSocket->xEventBits |= eSOCKET_SEND;
\r
1294 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
1296 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1298 /* The field 'xEventBits' is used to store regular socket events (at most 8),
\r
1299 as well as 'select events', which will be left-shifted */
\r
1300 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1305 /* In case the socket owner has installed an OnSent handler,
\r
1307 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1309 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
1311 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
1314 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
1319 /* len should be 0 by now. */
\r
1322 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1328 /*-----------------------------------------------------------*/
\r
1330 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1332 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
\r
1337 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
\r
1338 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
\r
1340 while( uxWinSize > 0xfffful )
\r
1342 /* Divide by two and increase the binary factor by 1. */
\r
1347 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
\r
1348 pxSocket->u.xTCP.uxRxWinSize,
\r
1349 pxSocket->u.xTCP.usInitMSS,
\r
1356 /*-----------------------------------------------------------*/
\r
1359 * When opening a TCP connection, while SYN's are being sent, the parties may
\r
1360 * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
\r
1361 * nett size of the payload, always smaller than MTU.
\r
1363 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
\r
1365 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1366 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
\r
1367 UBaseType_t uxOptionsLength;
\r
1369 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
\r
1371 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
\r
1372 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
\r
1373 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
\r
1374 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
\r
1376 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1378 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
\r
1380 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
\r
1381 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
\r
1382 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
\r
1383 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
\r
1384 uxOptionsLength = 8u;
\r
1388 uxOptionsLength = 4u;
\r
1392 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1394 return uxOptionsLength;
\r
1398 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
\r
1399 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
\r
1400 pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1401 pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
\r
1402 uxOptionsLength += 4u;
\r
1404 return uxOptionsLength; /* bytes, not words. */
\r
1406 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1410 * For anti-hanging protection and TCP keep-alive messages. Called in two
\r
1411 * places: after receiving a packet and after a state change. The socket's
\r
1412 * alive timer may be reset.
\r
1414 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
\r
1416 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
1418 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
\r
1422 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
1424 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
\r
1425 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
1426 pxSocket->u.xTCP.ucKeepRepCount = 0u;
\r
1427 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
\r
1431 ( void ) pxSocket;
\r
1433 /*-----------------------------------------------------------*/
\r
1436 * Changing to a new state. Centralised here to do specific actions such as
\r
1437 * resetting the alive timer, calling the user's OnConnect handler to notify
\r
1438 * that a socket has got (dis)connected, and setting bit to unblock a call to
\r
1439 * FreeRTOS_select()
\r
1441 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
\r
1443 FreeRTOS_Socket_t *xParent = NULL;
\r
1444 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
\r
1445 BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
\r
1446 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1447 BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
\r
1449 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1450 FreeRTOS_Socket_t *xConnected = NULL;
\r
1453 /* Has the connected status changed? */
\r
1454 if( bBefore != bAfter )
\r
1456 /* Is the socket connected now ? */
\r
1457 if( bAfter != pdFALSE )
\r
1459 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
\r
1460 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
1462 /* Now that it is connected, find it's parent. */
\r
1463 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
1465 xParent = pxSocket;
\r
1469 xParent = pxSocket->u.xTCP.pxPeerSocket;
\r
1470 configASSERT( xParent != NULL );
\r
1472 if( xParent != NULL )
\r
1474 if( xParent->u.xTCP.pxPeerSocket == NULL )
\r
1476 xParent->u.xTCP.pxPeerSocket = pxSocket;
\r
1479 xParent->xEventBits |= eSOCKET_ACCEPT;
\r
1481 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1483 /* Library support FreeRTOS_select(). Receiving a new
\r
1484 connection is being translated as a READ event. */
\r
1485 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
\r
1487 xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
\r
1492 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1494 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
\r
1495 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
\r
1497 /* The listening socket does not become connected itself, in stead
\r
1498 a child socket is created.
\r
1499 Postpone a call the OnConnect event until the end of this function. */
\r
1500 xConnected = xParent;
\r
1506 /* Don't need to access the parent socket anymore, so the
\r
1507 reference 'pxPeerSocket' may be cleared. */
\r
1508 pxSocket->u.xTCP.pxPeerSocket = NULL;
\r
1509 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
\r
1511 /* When true, this socket may be returned in a call to accept(). */
\r
1512 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
1516 pxSocket->xEventBits |= eSOCKET_CONNECT;
\r
1518 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1520 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1522 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1528 else /* bAfter == pdFALSE, connection is closed. */
\r
1530 /* Notify/wake-up the socket-owner by setting a semaphore. */
\r
1531 pxSocket->xEventBits |= eSOCKET_CLOSED;
\r
1533 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1535 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
\r
1537 pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
\r
1542 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1544 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
\r
1546 /* The 'connected' state has changed, call the user handler. */
\r
1547 xConnected = pxSocket;
\r
1550 #endif /* ipconfigUSE_CALLBACKS */
\r
1552 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
\r
1554 /* Now the socket isn't in an active state anymore so it
\r
1555 won't need further attention of the IP-task.
\r
1556 Setting time-out to zero means that the socket won't get checked during
\r
1558 pxSocket->u.xTCP.usTimeout = 0u;
\r
1563 if( eTCPState == eCLOSED )
\r
1565 /* Socket goes to status eCLOSED because of a RST.
\r
1566 When nobody owns the socket yet, delete it. */
\r
1567 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
\r
1568 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
1570 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
\r
1571 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
1573 FreeRTOS_closesocket( pxSocket );
\r
1579 /* Fill in the new state. */
\r
1580 pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
\r
1582 /* touch the alive timers because moving to another state. */
\r
1583 prvTCPTouchSocket( pxSocket );
\r
1585 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
1587 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
1588 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
\r
1589 pxSocket->usLocalPort,
\r
1590 pxSocket->u.xTCP.ulRemoteIP,
\r
1591 pxSocket->u.xTCP.usRemotePort,
\r
1592 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
\r
1593 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
\r
1595 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1597 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1599 if( xConnected != NULL )
\r
1601 /* The 'connected' state has changed, call the OnConnect handler of the parent. */
\r
1602 xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );
\r
1606 if( xParent != NULL )
\r
1608 vSocketWakeUpUser( xParent );
\r
1611 /*-----------------------------------------------------------*/
\r
1613 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
1614 int32_t lDataLen, UBaseType_t uxOptionsLength )
\r
1616 NetworkBufferDescriptor_t *pxReturn;
\r
1618 BaseType_t xResize;
\r
1620 if( xBufferAllocFixedSize != pdFALSE )
\r
1622 /* Network buffers are created with a fixed size and can hold the largest
\r
1624 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
\r
1625 /* and therefore, the buffer won't be too small.
\r
1626 Only ask for a new network buffer in case none was supplied. */
\r
1627 xResize = ( pxNetworkBuffer == NULL );
\r
1631 /* Network buffers are created with a variable size. See if it must
\r
1633 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
\r
1634 ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
\r
1635 /* In case we were called from a TCP timer event, a buffer must be
\r
1636 created. Otherwise, test 'xDataLength' of the provided buffer. */
\r
1637 xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded );
\r
1640 if( xResize != pdFALSE )
\r
1642 /* The caller didn't provide a network buffer or the provided buffer is
\r
1643 too small. As we must send-out a data packet, a buffer will be created
\r
1645 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
\r
1647 if( pxReturn != NULL )
\r
1649 /* Set the actual packet size, in case the returned buffer is larger. */
\r
1650 pxReturn->xDataLength = lNeeded;
\r
1652 /* Copy the existing data to the new created buffer. */
\r
1653 if( pxNetworkBuffer )
\r
1655 /* Either from the previous buffer... */
\r
1656 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
1658 /* ...and release it. */
\r
1659 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1663 /* Or from the socket field 'xTCP.xPacket'. */
\r
1664 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1670 /* xResize is false, the network buffer provided was big enough. */
\r
1671 pxReturn = pxNetworkBuffer;
\r
1673 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
\r
1674 xDataLength member must get the correct length too! */
\r
1675 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
\r
1680 /*-----------------------------------------------------------*/
\r
1683 * Prepare an outgoing message, in case anything has to be sent.
\r
1685 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
\r
1688 uint8_t *pucEthernetBuffer, *pucSendData;
\r
1689 TCPPacket_t *pxTCPPacket;
\r
1691 uint32_t ulDataGot, ulDistance;
\r
1692 TCPWindow_t *pxTCPWindow;
\r
1693 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1694 int32_t lStreamPos;
\r
1696 if( ( *ppxNetworkBuffer ) != NULL )
\r
1698 /* A network buffer descriptor was already supplied */
\r
1699 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
\r
1703 /* For now let it point to the last packet header */
\r
1704 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1707 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1708 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1711 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
\r
1713 if( pxSocket->u.xTCP.txStream != NULL )
\r
1715 /* ulTCPWindowTxGet will return the amount of data which may be sent
\r
1716 along with the position in the txStream.
\r
1717 Why check for MSS > 1 ?
\r
1718 Because some TCP-stacks (like uIP) use it for flow-control. */
\r
1719 if( pxSocket->u.xTCP.usCurMSS > 1u )
\r
1721 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
\r
1724 if( lDataLen > 0 )
\r
1726 /* Check if the current network buffer is big enough, if not,
\r
1728 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
\r
1730 if( pxNewBuffer != NULL )
\r
1732 *ppxNetworkBuffer = pxNewBuffer;
\r
1733 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
\r
1734 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1736 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
\r
1738 /* Translate the position in txStream to an offset from the tail
\r
1740 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
\r
1742 /* Here data is copied from the txStream in 'peek' mode. Only
\r
1743 when the packets are acked, the tail marker will be updated. */
\r
1744 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
\r
1746 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1748 if( ulDataGot != ( uint32_t ) lDataLen )
\r
1750 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
\r
1751 lStreamPos, uxOffset, ulDataGot, lDataLen ) );
\r
1756 /* If the owner of the socket requests a closure, add the FIN
\r
1757 flag to the last packet. */
\r
1758 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
\r
1760 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
\r
1762 if( ulDistance == ulDataGot )
\r
1764 #if (ipconfigHAS_DEBUG_PRINTF == 1)
\r
1766 /* the order of volatile accesses is undefined
\r
1767 so such workaround */
\r
1768 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
\r
1769 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
\r
1770 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
\r
1772 FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
\r
1773 uxTail, uxMid, uxHead ) );
\r
1776 /* Although the socket sends a FIN, it will stay in
\r
1777 ESTABLISHED until all current data has been received or
\r
1779 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1780 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
\r
1781 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1792 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
\r
1794 /* See if the socket owner wants to shutdown this connection. */
\r
1795 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
\r
1796 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
\r
1798 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
\r
1799 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1800 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1801 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
1802 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1803 vTCPStateChange( pxSocket, eFIN_WAIT_1 );
\r
1806 #if( ipconfigTCP_KEEP_ALIVE != 0 )
\r
1808 if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
\r
1810 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
\r
1811 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
1812 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
1813 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
1816 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
\r
1818 /* If there is no data to be sent, and no window-update message,
\r
1819 we might want to send a keep-alive message. */
\r
1820 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
\r
1822 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
\r
1823 if( pxSocket->u.xTCP.ucKeepRepCount )
\r
1825 xMax = ( 3u * configTICK_RATE_HZ );
\r
1829 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
\r
1830 if( xTCPWindowLoggingLevel )
\r
1831 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
\r
1832 pxSocket->u.xTCP.ulRemoteIP,
\r
1833 pxSocket->u.xTCP.usRemotePort,
\r
1834 pxSocket->u.xTCP.ucKeepRepCount ) );
\r
1835 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
\r
1836 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
\r
1837 pxSocket->u.xTCP.ucKeepRepCount++;
\r
1841 #endif /* ipconfigTCP_KEEP_ALIVE */
\r
1844 /* Anything to send, a change of the advertised window size, or maybe send a
\r
1845 keep-alive message? */
\r
1846 if( ( lDataLen > 0 ) ||
\r
1847 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
\r
1848 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
\r
1850 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
\r
1851 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
1853 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
\r
1855 if( lDataLen != 0l )
\r
1857 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
\r
1860 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
1865 /*-----------------------------------------------------------*/
\r
1868 * Calculate after how much time this socket needs to be checked again.
\r
1870 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
\r
1872 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1874 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
1876 /* The socket is actively connecting to a peer. */
\r
1877 if( pxSocket->u.xTCP.bits.bConnPrepared )
\r
1879 /* Ethernet address has been found, use progressive timeout for
\r
1880 active connect(). */
\r
1881 if( pxSocket->u.xTCP.ucRepCount < 3u )
\r
1883 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
\r
1887 ulDelayMs = 11000UL;
\r
1892 /* Still in the ARP phase: check every half second. */
\r
1893 ulDelayMs = 500UL;
\r
1896 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
\r
1897 pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
\r
1898 pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
\r
1899 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1901 else if( pxSocket->u.xTCP.usTimeout == 0u )
\r
1903 /* Let the sliding window mechanism decide what time-out is appropriate. */
\r
1904 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
\r
1905 if( ulDelayMs == 0u )
\r
1907 if( xResult != ( BaseType_t )0 )
\r
1913 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1918 /* ulDelayMs contains the time to wait before a re-transmission. */
\r
1920 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1924 /* field '.usTimeout' has already been set (by the
\r
1925 keep-alive/delayed-ACK mechanism). */
\r
1928 /* Return the number of clock ticks before the timer expires. */
\r
1929 return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
\r
1931 /*-----------------------------------------------------------*/
\r
1933 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
\r
1935 int32_t lCount, lLength;
\r
1937 /* A txStream has been created already, see if the socket has new data for
\r
1938 the sliding window.
\r
1940 uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It contains new
\r
1941 Tx data which has not been passed to the sliding window yet. The oldest
\r
1942 data not-yet-confirmed can be found at rxTail. */
\r
1943 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
\r
1947 /* All data between txMid and rxHead will now be passed to the sliding
\r
1948 window manager, so it can start transmitting them.
\r
1950 Hand over the new data to the sliding window handler. It will be
\r
1951 split-up in chunks of 1460 bytes each (or less, depending on
\r
1952 ipconfigTCP_MSS). */
\r
1953 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
\r
1954 ( uint32_t ) lLength,
\r
1955 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
\r
1956 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
\r
1958 /* Move the rxMid pointer forward up to rxHead. */
\r
1961 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
\r
1965 /*-----------------------------------------------------------*/
\r
1968 * prvTCPHandleFin() will be called to handle socket closure
\r
1969 * The Closure starts when either a FIN has been received and accepted,
\r
1970 * Or when the socket has sent a FIN flag to the peer
\r
1971 * Before being called, it has been checked that both reception and transmission
\r
1974 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1976 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1977 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1978 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
1979 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1980 BaseType_t xSendLength = 0;
\r
1981 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
\r
1983 if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
\r
1985 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
\r
1987 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
1989 /* We haven't yet replied with a FIN, do so now. */
\r
1990 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1991 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1995 /* We did send a FIN already, see if it's ACK'd. */
\r
1996 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
\r
1998 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
\r
2002 if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
\r
2004 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2005 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
\r
2007 /* And wait for the final ACK. */
\r
2008 vTCPStateChange( pxSocket, eLAST_ACK );
\r
2012 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
\r
2013 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
\r
2014 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
\r
2016 /* We have sent out a FIN but the peer hasn't replied with a FIN
\r
2017 yet. Do nothing for the moment. */
\r
2018 pxTCPHeader->ucTCPFlags = 0u;
\r
2022 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
\r
2024 /* This is the third of the three-way hand shake: the last
\r
2026 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2030 /* The other party started the closure, so we just wait for the
\r
2032 pxTCPHeader->ucTCPFlags = 0u;
\r
2035 /* And wait for the user to close this socket. */
\r
2036 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2040 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2042 if( pxTCPHeader->ucTCPFlags != 0u )
\r
2044 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
\r
2047 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
\r
2049 if( xTCPWindowLoggingLevel != 0 )
\r
2051 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
\r
2052 ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2053 pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2054 pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2055 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2056 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2059 return xSendLength;
\r
2061 /*-----------------------------------------------------------*/
\r
2064 * prvCheckRxData(): called from prvTCPHandleState()
\r
2066 * The first thing that will be done is find the TCP payload data
\r
2067 * and check the length of this data.
\r
2069 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
\r
2071 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2072 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2073 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
\r
2075 /* Determine the length and the offset of the user-data sent to this
\r
2078 The size of the TCP header is given in a multiple of 4-byte words (single
\r
2079 byte, needs no ntoh() translation). A shift-right 2: is the same as
\r
2080 (offset >> 4) * 4. */
\r
2081 lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
\r
2083 /* Let pucRecvData point to the first byte received. */
\r
2084 *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
\r
2086 /* Calculate lReceiveLength - the length of the TCP data received. This is
\r
2087 equal to the total packet length minus:
\r
2088 ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
\r
2089 lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
\r
2090 lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
\r
2092 if( lReceiveLength > lLength )
\r
2094 /* More bytes were received than the reported length, often because of
\r
2095 padding bytes at the end. */
\r
2096 lReceiveLength = lLength;
\r
2099 /* Subtract the size of the TCP and IP headers and the actual data size is
\r
2101 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
\r
2103 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
\r
2107 lReceiveLength = 0;
\r
2110 /* Urgent Pointer:
\r
2111 This field communicates the current value of the urgent pointer as a
\r
2112 positive offset from the sequence number in this segment. The urgent
\r
2113 pointer points to the sequence number of the octet following the urgent
\r
2114 data. This field is only be interpreted in segments with the URG control
\r
2116 if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
\r
2118 /* Although we ignore the urgent data, we have to skip it. */
\r
2119 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
\r
2120 *ppucRecvData += lUrgentLength;
\r
2121 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
\r
2124 return ( BaseType_t ) lReceiveLength;
\r
2126 /*-----------------------------------------------------------*/
\r
2129 * prvStoreRxData(): called from prvTCPHandleState()
\r
2131 * The second thing is to do is check if the payload data may be accepted
\r
2132 * If so, they will be added to the reception queue.
\r
2134 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
2135 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
\r
2137 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2138 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2139 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2140 uint32_t ulSequenceNumber, ulSpace;
\r
2141 int32_t lOffset, lStored;
\r
2142 BaseType_t xResult = 0;
\r
2144 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2146 if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
\r
2148 /* See if way may accept the data contents and forward it to the socket
\r
2151 If it can't be "accept"ed it may have to be stored and send a selective
\r
2152 ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
\r
2153 called later to store an out-of-order packet (in case lOffset is
\r
2155 if ( pxSocket->u.xTCP.rxStream )
\r
2157 ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
\r
2161 ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
\r
2164 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
\r
2166 if( lOffset >= 0 )
\r
2168 /* New data has arrived and may be made available to the user. See
\r
2169 if the head marker in rxStream may be advanced, only if lOffset == 0.
\r
2170 In case the low-water mark is reached, bLowWater will be set
\r
2171 "low-water" here stands for "little space". */
\r
2172 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
\r
2174 if( lStored != ( int32_t ) ulReceiveLength )
\r
2176 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
\r
2178 /* Received data could not be stored. The socket's flag
\r
2179 bMallocError has been set. The socket now has the status
\r
2180 eCLOSE_WAIT and a RST packet will be sent back. */
\r
2181 prvTCPSendReset( pxNetworkBuffer );
\r
2186 /* After a missing packet has come in, higher packets may be passed to
\r
2188 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2190 /* Now lTCPAddRxdata() will move the rxHead pointer forward
\r
2191 so data becomes available to the user immediately
\r
2192 In case the low-water mark is reached, bLowWater will be set. */
\r
2193 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
\r
2195 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
\r
2196 pxTCPWindow->ulUserDataLength = 0;
\r
2199 #endif /* ipconfigUSE_TCP_WIN */
\r
2203 pxTCPWindow->ucOptionLength = 0u;
\r
2208 /*-----------------------------------------------------------*/
\r
2210 /* Set the TCP options (if any) for the outgoing packet. */
\r
2211 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2213 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2214 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2215 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2216 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
\r
2218 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2219 if( uxOptionsLength != 0u )
\r
2221 /* TCP options must be sent because a packet which is out-of-order
\r
2223 if( xTCPWindowLoggingLevel >= 0 )
\r
2224 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
\r
2225 pxSocket->usLocalPort,
\r
2226 pxSocket->u.xTCP.usRemotePort,
\r
2228 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
2229 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
\r
2230 memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
\r
2232 /* The header length divided by 4, goes into the higher nibble,
\r
2233 effectively a shift-left 2. */
\r
2234 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2237 #endif /* ipconfigUSE_TCP_WIN */
\r
2238 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
\r
2240 /* TCP options must be sent because the MSS has changed. */
\r
2241 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
\r
2242 if( xTCPWindowLoggingLevel >= 0 )
\r
2244 FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
\r
2247 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
\r
2248 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
\r
2249 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
\r
2250 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
\r
2251 uxOptionsLength = 4u;
\r
2252 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2255 return uxOptionsLength;
\r
2257 /*-----------------------------------------------------------*/
\r
2260 * prvHandleSynReceived(): called from prvTCPHandleState()
\r
2262 * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
\r
2263 * If the flags received are correct, the socket will move to eESTABLISHED.
\r
2265 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2266 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2268 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2269 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2270 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2271 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2272 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2273 BaseType_t xSendLength = 0;
\r
2275 /* Either expect a ACK or a SYN+ACK. */
\r
2276 uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
\r
2277 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2279 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
\r
2282 if( ( ucTCPFlags & 0x17u ) != usExpect )
\r
2284 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
\r
2285 /* eSYN_RECEIVED: flags ACK expected, not SYN. */
\r
2286 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
\r
2287 pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
\r
2288 usExpect, ucTCPFlags ) );
\r
2289 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2290 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
\r
2291 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2292 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2296 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
\r
2297 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
\r
2299 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2301 TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
2303 /* Clear the SYN flag in lastPacket. */
\r
2304 pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
\r
2306 /* This socket was the one connecting actively so now perofmr the
\r
2307 synchronisation. */
\r
2308 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
\r
2309 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2310 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2311 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
\r
2312 pxTCPWindow->ulNextTxSequenceNumber++;
\r
2314 else if( ulReceiveLength == 0u )
\r
2316 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
2319 /* The SYN+ACK has been confirmed, increase the next sequence number by
\r
2321 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
\r
2323 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2325 FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
\r
2326 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
\r
2327 pxSocket->usLocalPort,
\r
2328 pxSocket->u.xTCP.ulRemoteIP,
\r
2329 pxSocket->u.xTCP.usRemotePort,
\r
2330 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
\r
2332 #endif /* ipconfigUSE_TCP_WIN */
\r
2334 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
\r
2336 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2337 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2338 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2340 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2342 if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
\r
2344 /* The other party did not send a scaling factor.
\r
2345 A shifting factor in this side must be canceled. */
\r
2346 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
\r
2347 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
\r
2350 #endif /* ipconfigUSE_TCP_WIN */
\r
2351 /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
\r
2352 connection is established. */
\r
2353 vTCPStateChange( pxSocket, eESTABLISHED );
\r
2356 return xSendLength;
\r
2358 /*-----------------------------------------------------------*/
\r
2361 * prvHandleEstablished(): called from prvTCPHandleState()
\r
2363 * Called if the status is eESTABLISHED. Data reception has been handled
\r
2364 * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
\r
2365 * the code will check if it may be accepted, i.e. if all expected data has been
\r
2366 * completely received.
\r
2368 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2369 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2371 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2372 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2373 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2374 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2375 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
\r
2376 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
\r
2377 int32_t lDistance, lSendResult;
\r
2379 /* Remember the window size the peer is advertising. */
\r
2380 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
\r
2381 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2383 pxSocket->u.xTCP.ulWindowSize =
\r
2384 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
2388 if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
\r
2390 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
\r
2392 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
\r
2393 starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
\r
2395 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
\r
2397 /* Just advancing the tail index, 'ulCount' bytes have been
\r
2398 confirmed, and because there is new space in the txStream, the
\r
2399 user/owner should be woken up. */
\r
2400 /* _HT_ : only in case the socket's waiting? */
\r
2401 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
\r
2403 pxSocket->xEventBits |= eSOCKET_SEND;
\r
2405 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
2407 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
\r
2409 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
2413 /* In case the socket owner has installed an OnSent handler,
\r
2415 #if( ipconfigUSE_CALLBACKS == 1 )
\r
2417 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
2419 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
2422 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
2427 /* If this socket has a stream for transmission, add the data to the
\r
2428 outgoing segment(s). */
\r
2429 if( pxSocket->u.xTCP.txStream != NULL )
\r
2431 prvTCPAddTxData( pxSocket );
\r
2434 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2436 if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
\r
2438 /* Peer is requesting to stop, see if we're really finished. */
\r
2439 xMayClose = pdTRUE;
\r
2441 /* Checks are only necessary if we haven't sent a FIN yet. */
\r
2442 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2444 /* xTCPWindowTxDone returns true when all Tx queues are empty. */
\r
2445 bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
\r
2446 bTxDone = xTCPWindowTxDone( pxTCPWindow );
\r
2448 if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
\r
2450 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
\r
2451 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
\r
2452 pxSocket->usLocalPort,
\r
2453 pxSocket->u.xTCP.usRemotePort,
\r
2454 bRxComplete, bTxDone ) );
\r
2455 xMayClose = pdFALSE;
\r
2459 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2461 if( lDistance > 1 )
\r
2463 FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
\r
2464 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2465 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2467 xMayClose = pdFALSE;
\r
2472 if( xTCPWindowLoggingLevel > 0 )
\r
2474 FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
\r
2475 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
\r
2476 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
\r
2479 if( xMayClose != pdFALSE )
\r
2481 pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
\r
2482 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2486 if( xMayClose == pdFALSE )
\r
2488 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2490 if( ulReceiveLength != 0u )
\r
2492 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2493 /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
\r
2494 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2496 if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
\r
2498 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2502 /* Now get data to be transmitted. */
\r
2503 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
\r
2504 can not send-out both TCP options and also a full packet. Sending
\r
2505 options (SACK) is always more urgent than sending data, which can be
\r
2507 if( uxOptionsLength == 0u )
\r
2509 /* prvTCPPrepareSend might allocate a bigger network buffer, if
\r
2511 lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
2512 if( lSendResult > 0 )
\r
2514 xSendLength = ( BaseType_t ) lSendResult;
\r
2519 return xSendLength;
\r
2521 /*-----------------------------------------------------------*/
\r
2524 * Called from prvTCPHandleState(). There is data to be sent. If
\r
2525 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
\r
2526 * checked if it would better be postponed for efficiency.
\r
2528 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2529 uint32_t ulReceiveLength, BaseType_t xSendLength )
\r
2531 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2532 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2533 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2534 /* Find out what window size we may advertised. */
\r
2536 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2537 #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
\r
2538 const int32_t lMinLength = 0;
\r
2540 int32_t lMinLength;
\r
2544 /* Set the time-out field, so that we'll be called by the IP-task in case no
\r
2545 next message will be received. */
\r
2546 lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2547 #if ipconfigUSE_TCP_WIN == 1
\r
2550 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
\r
2552 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2554 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
\r
2556 /* In case we're receiving data continuously, we might postpone sending
\r
2557 an ACK to gain performance. */
\r
2558 if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
\r
2559 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
\r
2560 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
\r
2561 ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
\r
2562 ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
\r
2563 ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
\r
2565 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2567 /* There was still a delayed in queue, delete it. */
\r
2568 if( pxSocket->u.xTCP.pxAckMessage != 0 )
\r
2570 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2573 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
\r
2575 if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
\r
2576 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
\r
2578 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
\r
2582 /* Normally a delayed ACK should wait 200 ms for a next incoming
\r
2583 packet. Only wait 20 ms here to gain performance. A slow ACK
\r
2584 for full-size message. */
\r
2585 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
\r
2588 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2590 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
\r
2591 pxSocket->usLocalPort,
\r
2592 pxSocket->u.xTCP.usRemotePort,
\r
2593 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2594 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2596 pxSocket->u.xTCP.usTimeout, lRxSpace ) );
\r
2599 *ppxNetworkBuffer = NULL;
\r
2602 else if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
2604 /* As an ACK is not being delayed, remove any earlier delayed ACK
\r
2606 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2608 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2611 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
2616 /* Remove compiler warnings. */
\r
2617 ( void ) ulReceiveLength;
\r
2618 ( void ) pxTCPHeader;
\r
2619 ( void ) lRxSpace;
\r
2621 #endif /* ipconfigUSE_TCP_WIN */
\r
2623 if( xSendLength != 0 )
\r
2625 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2627 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
\r
2628 pxSocket->usLocalPort,
\r
2629 pxSocket->u.xTCP.usRemotePort,
\r
2630 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2631 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2635 /* Set the parameter 'xReleaseAfterSend' to the value of
\r
2636 ipconfigZERO_COPY_TX_DRIVER. */
\r
2637 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
2638 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
2640 /* The driver has taken ownership of the Network Buffer. */
\r
2641 *ppxNetworkBuffer = NULL;
\r
2646 return xSendLength;
\r
2648 /*-----------------------------------------------------------*/
\r
2651 * prvTCPHandleState()
\r
2652 * is the most important function of this TCP stack
\r
2653 * We've tried to keep it (relatively short) by putting a lot of code in
\r
2654 * the static functions above:
\r
2656 * prvCheckRxData()
\r
2657 * prvStoreRxData()
\r
2659 * prvHandleSynReceived()
\r
2660 * prvHandleEstablished()
\r
2663 * As these functions are declared static, and they're called from one location
\r
2664 * only, most compilers will inline them, thus avoiding a call and return.
\r
2666 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
2668 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2669 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2670 BaseType_t xSendLength = 0;
\r
2671 uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
\r
2672 uint8_t *pucRecvData;
\r
2673 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
\r
2675 /* uxOptionsLength: the size of the options to be sent (always a multiple of
\r
2677 1. in the SYN phase, we shall communicate the MSS
\r
2678 2. in case of a SACK, Selective ACK, ack a segment which comes in
\r
2680 UBaseType_t uxOptionsLength = 0u;
\r
2681 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2682 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
2684 /* First get the length and the position of the received data, if any.
\r
2685 pucRecvData will point to the first byte of the TCP payload. */
\r
2686 ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
\r
2688 if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
\r
2690 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
\r
2692 /* This is most probably a keep-alive message from peer. Setting
\r
2693 'bWinChange' doesn't cause a window-size-change, the flag is used
\r
2694 here to force sending an immediate ACK. */
\r
2695 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
2699 /* Keep track of the highest sequence number that might be expected within
\r
2700 this connection. */
\r
2701 if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
\r
2703 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2706 /* Storing data may result in a fatal error if malloc() fails. */
\r
2707 if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
\r
2713 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
\r
2715 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
\r
2717 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
\r
2719 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
\r
2720 'SYN+ACK' didn't arrive. Step back to the previous state in which
\r
2721 a first incoming SYN is handled. The SYN was counted already so
\r
2722 decrease it first. */
\r
2723 vTCPStateChange( pxSocket, eSYN_FIRST );
\r
2726 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
\r
2728 /* It's the first time a FIN has been received, remember its
\r
2729 sequence number. */
\r
2730 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2731 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
\r
2733 /* Was peer the first one to send a FIN? */
\r
2734 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2736 /* If so, don't send the-last-ACK. */
\r
2737 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
\r
2741 switch (pxSocket->u.xTCP.ucTCPState)
\r
2743 case eCLOSED: /* (server + client) no connection state at all. */
\r
2744 /* Nothing to do for a closed socket, except waiting for the
\r
2748 case eTCP_LISTEN: /* (server) waiting for a connection request from
\r
2749 any remote TCP and port. */
\r
2750 /* The listen state was handled in xProcessReceivedTCPPacket().
\r
2751 Should not come here. */
\r
2754 case eSYN_FIRST: /* (server) Just received a SYN request for a server
\r
2757 /* A new socket has been created, reply with a SYN+ACK.
\r
2758 Acknowledge with seq+1 because the SYN is seen as pseudo data
\r
2760 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
2761 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
\r
2763 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2765 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
2766 uxOptionsLength is a multiple of 4. The complete expression is:
\r
2767 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
2768 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2769 vTCPStateChange( pxSocket, eSYN_RECEIVED );
\r
2771 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2772 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
\r
2776 case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
\r
2777 SYN, expect a SYN+ACK and send a ACK now. */
\r
2778 /* Fall through */
\r
2779 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
\r
2780 expect a ACK and do nothing. */
\r
2781 xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2784 case eESTABLISHED: /* (server + client) an open connection, data
\r
2785 received can be delivered to the user. The normal
\r
2786 state for the data transfer phase of the connection
\r
2787 The closing states are also handled here with the
\r
2788 use of some flags. */
\r
2789 xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2792 case eLAST_ACK: /* (server + client) waiting for an acknowledgement
\r
2793 of the connection termination request previously
\r
2794 sent to the remote TCP (which includes an
\r
2795 acknowledgement of its connection termination
\r
2797 /* Fall through */
\r
2798 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
\r
2799 * or an acknowledgement of the connection termination request previously sent. */
\r
2800 /* Fall through */
\r
2801 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
\r
2802 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2805 case eCLOSE_WAIT: /* (server + client) waiting for a connection
\r
2806 termination request from the local user. Nothing to
\r
2807 do, connection is closed, wait for owner to close
\r
2811 case eCLOSING: /* (server + client) waiting for a connection
\r
2812 termination request acknowledgement from the remote
\r
2816 case eTIME_WAIT: /* (either server or client) waiting for enough time
\r
2817 to pass to be sure the remote TCP received the
\r
2818 acknowledgement of its connection termination
\r
2819 request. [According to RFC 793 a connection can stay
\r
2820 in TIME-WAIT for a maximum of four minutes known as
\r
2821 a MSL (maximum segment lifetime).] These states are
\r
2822 implemented implicitly by settings flags like
\r
2823 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
\r
2830 if( xSendLength > 0 )
\r
2832 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
\r
2835 return xSendLength;
\r
2837 /*-----------------------------------------------------------*/
\r
2839 static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
2840 uint8_t ucTCPFlags )
\r
2842 #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
\r
2844 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );
\r
2845 const BaseType_t xSendLength = ( BaseType_t )
\r
2846 ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
\r
2848 pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags;
\r
2849 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
\r
2851 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE );
\r
2853 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
\r
2855 /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
\r
2856 ( void )pxNetworkBuffer;
\r
2857 ( void )ucTCPFlags;
\r
2859 /* The packet was not consumed. */
\r
2862 /*-----------------------------------------------------------*/
\r
2864 static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2866 return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK );
\r
2868 /*-----------------------------------------------------------*/
\r
2870 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2872 return prvTCPSendSpecialPacketHelper( pxNetworkBuffer,
\r
2873 ipTCP_FLAG_ACK | ipTCP_FLAG_RST );
\r
2875 /*-----------------------------------------------------------*/
\r
2877 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
\r
2879 uint32_t ulMSS = ipconfigTCP_MSS;
\r
2881 if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
\r
2883 /* Data for this peer will pass through a router, and maybe through
\r
2884 the internet. Limit the MSS to 1400 bytes or less. */
\r
2885 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
\r
2888 FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
\r
2890 pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
\r
2892 /*-----------------------------------------------------------*/
\r
2895 * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
\r
2896 * xProcessReceivedTCPPacket()
\r
2897 * prvTCPHandleState()
\r
2898 * prvTCPPrepareSend()
\r
2899 * prvTCPReturnPacket()
\r
2900 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2901 * prvTCPSendRepeated()
\r
2902 * prvTCPReturnPacket() // Prepare for returning
\r
2903 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2905 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2907 FreeRTOS_Socket_t *pxSocket;
\r
2908 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2909 uint16_t ucTCPFlags;
\r
2910 uint32_t ulLocalIP;
\r
2911 uint16_t xLocalPort;
\r
2912 uint32_t ulRemoteIP;
\r
2913 uint16_t xRemotePort;
\r
2914 uint32_t ulSequenceNumber;
\r
2915 uint32_t ulAckNumber;
\r
2916 BaseType_t xResult = pdPASS;
\r
2918 configASSERT( pxNetworkBuffer );
\r
2919 configASSERT( pxNetworkBuffer->pucEthernetBuffer );
\r
2921 /* Check for a minimum packet size. */
\r
2922 if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) )
\r
2924 ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
\r
2925 ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
\r
2926 xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
\r
2927 ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
2928 xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
2929 ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
2930 ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr );
\r
2932 /* Find the destination socket, and if not found: return a socket listing to
\r
2933 the destination PORT. */
\r
2934 pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
\r
2941 if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
\r
2943 /* A TCP messages is received but either there is no socket with the
\r
2944 given port number or the there is a socket, but it is in one of these
\r
2945 non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
\r
2948 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
\r
2950 /* Send a RST to all packets that can not be handled. As a result
\r
2951 the other party will get a ECONN error. There are two exceptions:
\r
2952 1) A packet that already has the RST flag set.
\r
2953 2) A packet that only has the ACK flag set.
\r
2954 A packet with only the ACK flag set might be the last ACK in
\r
2955 a three-way hand-shake that closes a connection. */
\r
2956 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
\r
2957 ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
\r
2959 prvTCPSendReset( pxNetworkBuffer );
\r
2962 /* The packet can't be handled. */
\r
2967 pxSocket->u.xTCP.ucRepCount = 0u;
\r
2969 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
\r
2971 /* The matching socket is in a listening state. Test if the peer
\r
2972 has set the SYN flag. */
\r
2973 if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
\r
2975 /* What happens: maybe after a reboot, a client doesn't know the
\r
2976 connection had gone. Send a RST in order to get a new connect
\r
2978 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
2980 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
\r
2981 prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
\r
2983 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
2985 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
\r
2987 prvTCPSendReset( pxNetworkBuffer );
\r
2993 /* prvHandleListen() will either return a newly created socket
\r
2994 (if bReuseSocket is false), otherwise it returns the current
\r
2995 socket which will later get connected. */
\r
2996 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
\r
2998 if( pxSocket == NULL )
\r
3003 } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
\r
3006 /* This is not a socket in listening mode. Check for the RST
\r
3008 if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
\r
3010 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
\r
3012 /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */
\r
3013 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
3015 /* Per the above RFC, "In the SYN-SENT state ... the RST is
\r
3016 acceptable if the ACK field acknowledges the SYN." */
\r
3017 if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 )
\r
3019 vTCPStateChange( pxSocket, eCLOSED );
\r
3024 /* Check whether the packet matches the next expected sequence number. */
\r
3025 if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber )
\r
3027 vTCPStateChange( pxSocket, eCLOSED );
\r
3029 /* Otherwise, check whether the packet is within the receive window. */
\r
3030 else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber &&
\r
3031 ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber +
\r
3032 pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) )
\r
3034 /* Send a challenge ACK. */
\r
3035 prvTCPSendChallengeAck( pxNetworkBuffer );
\r
3039 /* Otherwise, do nothing. In any case, the packet cannot be handled. */
\r
3042 else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
\r
3044 /* SYN flag while this socket is already connected. */
\r
3045 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
\r
3047 /* The packet cannot be handled. */
\r
3052 /* Update the copy of the TCP header only (skipping eth and IP
\r
3053 headers). It might be used later on, whenever data must be sent
\r
3055 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
\r
3056 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
\r
3061 if( xResult != pdFAIL )
\r
3063 /* Touch the alive timers because we received a message for this
\r
3065 prvTCPTouchSocket( pxSocket );
\r
3067 /* Parse the TCP option(s), if present. */
\r
3068 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
\r
3069 then we MUST assume an MSS size of 536 bytes for backward compatibility. */
\r
3071 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
3072 the number 5 (words) in the higher niblle of the TCP-offset byte. */
\r
3073 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
\r
3075 prvCheckOptions( pxSocket, pxNetworkBuffer );
\r
3079 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3081 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
\r
3082 pxSocket->u.xTCP.ulWindowSize =
\r
3083 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
3087 /* In prvTCPHandleState() the incoming messages will be handled
\r
3088 depending on the current state of the connection. */
\r
3089 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
\r
3091 /* prvTCPHandleState() has sent a message, see if there are more to
\r
3092 be transmitted. */
\r
3093 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3095 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
3097 #endif /* ipconfigUSE_TCP_WIN */
\r
3100 if( pxNetworkBuffer != NULL )
\r
3102 /* We must check if the buffer is unequal to NULL, because the
\r
3103 socket might keep a reference to it in case a delayed ACK must be
\r
3105 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
3106 pxNetworkBuffer = NULL;
\r
3109 /* And finally, calculate when this socket wants to be woken up. */
\r
3110 prvTCPNextTimeout ( pxSocket );
\r
3111 /* Return pdPASS to tell that the network buffer is 'consumed'. */
\r
3115 /* pdPASS being returned means the buffer has been consumed. */
\r
3118 /*-----------------------------------------------------------*/
\r
3120 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
3122 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
3123 FreeRTOS_Socket_t *pxReturn = NULL;
\r
3124 uint32_t ulInitialSequenceNumber;
\r
3126 /* Assume that a new Initial Sequence Number will be required. Request
\r
3127 it now in order to fail out if necessary. */
\r
3128 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
\r
3129 pxSocket->usLocalPort,
\r
3130 pxTCPPacket->xIPHeader.ulSourceIPAddress,
\r
3131 pxTCPPacket->xTCPHeader.usSourcePort );
\r
3133 /* A pure SYN (without ACK) has come in, create a new socket to answer
\r
3135 if( 0 != ulInitialSequenceNumber )
\r
3137 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
3139 /* The flag bReuseSocket indicates that the same instance of the
\r
3140 listening socket should be used for the connection. */
\r
3141 pxReturn = pxSocket;
\r
3142 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3143 pxSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3147 /* The socket does not have the bReuseSocket flag set meaning create a
\r
3148 new socket when a connection comes in. */
\r
3151 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
\r
3153 FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
\r
3154 pxSocket->usLocalPort,
\r
3155 pxSocket->u.xTCP.usChildCount,
\r
3156 pxSocket->u.xTCP.usBacklog,
\r
3157 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
\r
3158 prvTCPSendReset( pxNetworkBuffer );
\r
3162 FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * )
\r
3163 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
3165 if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
\r
3167 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
\r
3168 prvTCPSendReset( pxNetworkBuffer );
\r
3170 else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
\r
3172 /* The socket will be connected immediately, no time for the
\r
3173 owner to setsockopt's, therefore copy properties of the server
\r
3174 socket to the new socket. Only the binding might fail (due to
\r
3175 lack of resources). */
\r
3176 pxReturn = pxNewSocket;
\r
3182 if( ( 0 != ulInitialSequenceNumber ) && ( pxReturn != NULL ) )
\r
3184 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
3185 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
3186 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
\r
3188 /* Here is the SYN action. */
\r
3189 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
3190 prvSocketSetMSS( pxReturn );
\r
3192 prvTCPCreateWindow( pxReturn );
\r
3194 vTCPStateChange( pxReturn, eSYN_FIRST );
\r
3196 /* Make a copy of the header up to the TCP header. It is needed later
\r
3197 on, whenever data must be sent to the peer. */
\r
3198 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
\r
3202 /*-----------------------------------------------------------*/
\r
3205 * Duplicates a socket after a listening socket receives a connection.
\r
3207 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
\r
3209 struct freertos_sockaddr xAddress;
\r
3211 pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
\r
3212 pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
\r
3213 pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
\r
3214 pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
\r
3215 pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
\r
3216 pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
\r
3217 pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
\r
3218 pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
\r
3219 pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
\r
3221 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
\r
3223 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
\r
3225 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
\r
3227 #if( ipconfigUSE_CALLBACKS == 1 )
\r
3229 /* In case call-backs are used, copy them from parent to child. */
\r
3230 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
\r
3231 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
\r
3232 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
\r
3234 #endif /* ipconfigUSE_CALLBACKS */
\r
3236 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
3238 /* Child socket of listening sockets will inherit the Socket Set
\r
3239 Otherwise the owner has no chance of including it into the set. */
\r
3240 if( pxSocket->pxSocketSet )
\r
3242 pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
\r
3243 pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
\r
3246 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
3248 /* And bind it to the same local port as its parent. */
\r
3249 xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
\r
3250 xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3252 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
3254 /* Only when there is anti-hanging protection, a socket may become an
\r
3255 orphan temporarily. Once this socket is really connected, the owner of
\r
3256 the server socket will be notified. */
\r
3258 /* When bPassQueued is true, the socket is an orphan until it gets
\r
3260 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3261 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3265 /* A reference to the new socket may be stored and the socket is marked
\r
3268 /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to
\r
3270 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
3271 if(pxSocket->u.xTCP.pxPeerSocket == NULL )
\r
3273 pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
\r
3278 pxSocket->u.xTCP.usChildCount++;
\r
3280 FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
\r
3281 pxSocket->usLocalPort,
\r
3282 pxSocket->u.xTCP.usChildCount,
\r
3283 pxSocket->u.xTCP.usBacklog,
\r
3284 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
\r
3286 /* Now bind the child socket to the same port as the listening socket. */
\r
3287 if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
\r
3289 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
\r
3290 vSocketClose( pxNewSocket );
\r
3296 /*-----------------------------------------------------------*/
\r
3298 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
3300 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
\r
3302 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
\r
3304 ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
\r
3306 return pcStateNames[ ulState ];
\r
3309 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
\r
3310 /*-----------------------------------------------------------*/
\r
3313 * In the API accept(), the user asks is there is a new client? As API's can
\r
3314 * not walk through the xBoundTCPSocketsList the IP-task will do this.
\r
3316 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
\r
3318 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3319 ListItem_t *pxIterator;
\r
3320 FreeRTOS_Socket_t *pxFound;
\r
3321 BaseType_t xResult = pdFALSE;
\r
3323 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
\r
3324 who has access. */
\r
3325 for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
\r
3326 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
\r
3327 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
3329 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
\r
3331 pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
3332 if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
3334 pxSocket->u.xTCP.pxPeerSocket = pxFound;
\r
3335 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
\r
3343 /*-----------------------------------------------------------*/
\r
3345 #endif /* ipconfigUSE_TCP == 1 */
\r
3347 /* Provide access to private members for testing. */
\r
3348 #ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS
\r
3349 #include "iot_freertos_tcp_test_access_tcp_define.h"
\r
3352 /* Provide access to private members for verification. */
\r
3353 #ifdef FREERTOS_TCP_ENABLE_VERIFICATION
\r
3354 #include "aws_freertos_tcp_verification_access_tcp_define.h"
\r