2 * FreeRTOS+TCP V2.0.7
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
28 * Module which handles the TCP connections for FreeRTOS+TCP.
\r
29 * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
\r
32 * Endianness: in this module all ports and IP addresses are stored in
\r
33 * host byte-order, except fields in the IP-packets
\r
36 /* Standard includes. */
\r
40 /* FreeRTOS includes. */
\r
41 #include "FreeRTOS.h"
\r
46 /* FreeRTOS+TCP includes. */
\r
47 #include "FreeRTOS_IP.h"
\r
48 #include "FreeRTOS_Sockets.h"
\r
49 #include "FreeRTOS_IP_Private.h"
\r
50 #include "FreeRTOS_UDP_IP.h"
\r
51 #include "FreeRTOS_TCP_IP.h"
\r
52 #include "FreeRTOS_DHCP.h"
\r
53 #include "NetworkInterface.h"
\r
54 #include "NetworkBufferManagement.h"
\r
55 #include "FreeRTOS_ARP.h"
\r
56 #include "FreeRTOS_TCP_WIN.h"
\r
59 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
\r
60 #if ipconfigUSE_TCP == 1
\r
62 /* This compile-time test was moved to here because some macro's
\r
63 were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether
\r
64 the defined MTU size can contain at least a complete TCP packet. */
\r
66 #if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )
\r
67 #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.
\r
71 * The meaning of the TCP flags:
\r
73 #define ipTCP_FLAG_FIN 0x0001u /* No more data from sender */
\r
74 #define ipTCP_FLAG_SYN 0x0002u /* Synchronize sequence numbers */
\r
75 #define ipTCP_FLAG_RST 0x0004u /* Reset the connection */
\r
76 #define ipTCP_FLAG_PSH 0x0008u /* Push function: please push buffered data to the recv application */
\r
77 #define ipTCP_FLAG_ACK 0x0010u /* Acknowledgment field is significant */
\r
78 #define ipTCP_FLAG_URG 0x0020u /* Urgent pointer field is significant */
\r
79 #define ipTCP_FLAG_ECN 0x0040u /* ECN-Echo */
\r
80 #define ipTCP_FLAG_CWR 0x0080u /* Congestion Window Reduced */
\r
81 #define ipTCP_FLAG_NS 0x0100u /* ECN-nonce concealment protection */
\r
82 #define ipTCP_FLAG_RSV 0x0E00u /* Reserved, keep 0 */
\r
84 /* A mask to filter all protocol flags. */
\r
85 #define ipTCP_FLAG_CTRL 0x001Fu
\r
88 * A few values of the TCP options:
\r
90 #define TCP_OPT_END 0u /* End of TCP options list */
\r
91 #define TCP_OPT_NOOP 1u /* "No-operation" TCP option */
\r
92 #define TCP_OPT_MSS 2u /* Maximum segment size TCP option */
\r
93 #define TCP_OPT_WSOPT 3u /* TCP Window Scale Option (3-byte long) */
\r
94 #define TCP_OPT_SACK_P 4u /* Advertize that SACK is permitted */
\r
95 #define TCP_OPT_SACK_A 5u /* SACK option with first/last */
\r
96 #define TCP_OPT_TIMESTAMP 8u /* Time-stamp option */
\r
98 #define TCP_OPT_MSS_LEN 4u /* Length of TCP MSS option. */
\r
99 #define TCP_OPT_WSOPT_LEN 3u /* Length of TCP WSOPT option. */
\r
101 #define TCP_OPT_TIMESTAMP_LEN 10 /* fixed length of the time-stamp option */
\r
103 #ifndef ipconfigTCP_ACK_EARLIER_PACKET
\r
104 #define ipconfigTCP_ACK_EARLIER_PACKET 1
\r
108 * The macro NOW_CONNECTED() is use to determine if the connection makes a
\r
109 * transition from connected to non-connected and vice versa.
\r
110 * NOW_CONNECTED() returns true when the status has one of these values:
\r
111 * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
\r
112 * Technically the connection status is closed earlier, but the library wants
\r
113 * to prevent that the socket will be deleted before the last ACK has been
\r
114 * and thus causing a 'RST' packet on either side.
\r
116 #define NOW_CONNECTED( status )\
\r
117 ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )
\r
120 * The highest 4 bits in the TCP offset byte indicate the total length of the
\r
121 * TCP header, divided by 4.
\r
123 #define VALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0u )
\r
126 * Acknowledgements to TCP data packets may be delayed as long as more is being expected.
\r
127 * A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to
\r
128 * gain performance.
\r
130 #define DELAYED_ACK_SHORT_DELAY_MS ( 2 )
\r
131 #define DELAYED_ACK_LONGER_DELAY_MS ( 20 )
\r
134 * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
\r
135 * an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced
\r
138 #define REDUCED_MSS_THROUGH_INTERNET ( 1400 )
\r
141 * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
142 * the number 5 (words) in the higher niblle of the TCP-offset byte.
\r
144 #define TCP_OFFSET_LENGTH_BITS ( 0xf0u )
\r
145 #define TCP_OFFSET_STANDARD_LENGTH ( 0x50u )
\r
148 * Each TCP socket is checked regularly to see if it can send data packets.
\r
149 * By default, the maximum number of packets sent during one check is limited to 8.
\r
150 * This amount may be further limited by setting the socket's TX window size.
\r
152 #if( !defined( SEND_REPEATED_COUNT ) )
\r
153 #define SEND_REPEATED_COUNT ( 8 )
\r
154 #endif /* !defined( SEND_REPEATED_COUNT ) */
\r
157 * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.
\r
158 * When a TCP timer expires, retries and keep-alive messages will be checked.
\r
160 #ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS
\r
161 #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000u
\r
165 * The names of the different TCP states may be useful in logging.
\r
167 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
168 static const char *pcStateNames[] = {
\r
183 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */
\r
186 * Returns true if the socket must be checked. Non-active sockets are waiting
\r
187 * for user action, either connect() or close().
\r
189 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );
\r
192 * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
\r
194 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );
\r
197 * Try to send a series of messages.
\r
199 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
\r
202 * Return or send a packet to the other party.
\r
204 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
205 uint32_t ulLen, BaseType_t xReleaseAfterSend );
\r
208 * Initialise the data structures which keep track of the TCP windowing system.
\r
210 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );
\r
213 * Let ARP look-up the MAC-address of the peer and initialise the first SYN
\r
216 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );
\r
218 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
220 * For logging and debugging: make a string showing the TCP flags.
\r
222 static const char *prvTCPFlagMeaning( UBaseType_t xFlags);
\r
223 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
226 * Parse the TCP option(s) received, if present.
\r
228 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
231 * Set the initial properties in the options fields, like the preferred
\r
232 * value of MSS and whether SACK allowed. Will be transmitted in the state
\r
235 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );
\r
238 * For anti-hang protection and TCP keep-alive messages. Called in two places:
\r
239 * after receiving a packet and after a state change. The socket's alive timer
\r
242 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );
\r
245 * Prepare an outgoing message, if anything has to be sent.
\r
247 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );
\r
250 * Calculate when this socket needs to be checked to do (re-)transmissions.
\r
252 static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );
\r
255 * The API FreeRTOS_send() adds data to the TX stream. Add
\r
256 * this data to the windowing system to it can be transmitted.
\r
258 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );
\r
261 * Called to handle the closure of a TCP connection.
\r
263 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
266 * Called from prvTCPHandleState(). Find the TCP payload data and check and
\r
267 * return its length.
\r
269 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );
\r
272 * Called from prvTCPHandleState(). Check if the payload data may be accepted.
\r
273 * If so, it will be added to the socket's reception queue.
\r
275 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
276 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );
\r
279 * Set the TCP options (if any) for the outgoing packet.
\r
281 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
284 * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
\r
287 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
288 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
\r
291 * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
\r
293 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
294 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
\r
297 * Called from prvTCPHandleState(). There is data to be sent.
\r
298 * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
\r
299 * be checked if it would better be postponed for efficiency.
\r
301 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
302 uint32_t ulReceiveLength, BaseType_t xSendLength );
\r
305 * The heart of all: check incoming packet for valid data and acks and do what
\r
306 * is necessary in each state.
\r
308 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
\r
311 * Reply to a peer with the RST flag on, in case a packet can not be handled.
\r
313 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
316 * Set the initial value for MSS (Maximum Segment Size) to be used.
\r
318 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
\r
321 * Return either a newly created socket, or the current socket in a connected
\r
322 * state (depends on the 'bReuseSocket' flag).
\r
324 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
\r
327 * After a listening socket receives a new connection, it may duplicate itself.
\r
328 * The copying takes place in prvTCPSocketCopy.
\r
330 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
\r
333 * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
\r
334 * state for too long. If so, the socket will be closed, and -1 will be
\r
337 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
338 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
\r
341 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
342 int32_t lDataLen, UBaseType_t uxOptionsLength );
\r
344 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
345 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
\r
348 #if( ipconfigUSE_TCP_WIN != 0 )
\r
349 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
\r
353 * Generate a randomized TCP Initial Sequence Number per RFC.
\r
355 extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
\r
356 uint16_t usSourcePort,
\r
357 uint32_t ulDestinationAddress,
\r
358 uint16_t usDestinationPort );
\r
360 /*-----------------------------------------------------------*/
\r
362 /* prvTCPSocketIsActive() returns true if the socket must be checked.
\r
363 * Non-active sockets are waiting for user action, either connect()
\r
365 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
\r
379 /*-----------------------------------------------------------*/
\r
381 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
383 static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
\r
385 BaseType_t xResult;
\r
386 switch( pxSocket->u.xTCP.ucTCPState )
\r
389 /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
\r
390 state ESTABLISHED can be protected using keep-alive messages. */
\r
396 /* These 3 states may last for ever, up to the owner. */
\r
400 /* All other (non-connected) states will get anti-hanging
\r
405 if( xResult != pdFALSE )
\r
407 /* How much time has past since the last active moment which is
\r
408 defined as A) a state change or B) a packet has arrived. */
\r
409 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
\r
411 /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
\r
412 if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
\r
414 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
416 FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
\r
417 pxSocket->usLocalPort,
\r
418 pxSocket->u.xTCP.ulRemoteIP,
\r
419 pxSocket->u.xTCP.usRemotePort,
\r
420 FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
\r
422 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
424 /* Move to eCLOSE_WAIT, user may close the socket. */
\r
425 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
427 /* When 'bPassQueued' true, this socket is an orphan until it
\r
429 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
431 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
433 /* As it did not get connected, and the user can never
\r
434 accept() it anymore, it will be deleted now. Called from
\r
435 the IP-task, so it's safe to call the internal Close
\r
436 function: vSocketClose(). */
\r
437 vSocketClose( pxSocket );
\r
439 /* Return a negative value to tell to inform the caller
\r
441 that the socket got closed and may not be accessed anymore. */
\r
448 /*-----------------------------------------------------------*/
\r
453 * As soon as a TCP socket timer expires, this function xTCPSocketCheck
\r
454 * will be called (from xTCPTimerCheck)
\r
455 * It can send a delayed ACK or new data
\r
456 * Sequence of calling (normally) :
\r
458 * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
\r
459 * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
\r
460 * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
\r
461 * prvTCPSendRepeated() // Send at most 8 messages on a row
\r
462 * prvTCPReturnPacket() // Prepare for returning
\r
463 * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
\r
465 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
\r
467 BaseType_t xResult = 0;
\r
468 BaseType_t xReady = pdFALSE;
\r
470 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
\r
472 /* The API FreeRTOS_send() might have added data to the TX stream. Add
\r
473 this data to the windowing system to it can be transmitted. */
\r
474 prvTCPAddTxData( pxSocket );
\r
477 #if ipconfigUSE_TCP_WIN == 1
\r
479 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
481 /* The first task of this regular socket check is to send-out delayed
\r
483 if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
\r
485 /* Earlier data was received but not yet acknowledged. This
\r
486 function is called when the TCP timer for the socket expires, the
\r
487 ACK may be sent now. */
\r
488 if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
\r
490 if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
\r
492 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
\r
493 pxSocket->usLocalPort,
\r
494 pxSocket->u.xTCP.usRemotePort,
\r
495 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
496 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
\r
497 ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
\r
500 prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
\r
502 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
504 /* The ownership has been passed to the SEND routine,
\r
505 clear the pointer to it. */
\r
506 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
508 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
510 if( prvTCPNextTimeout( pxSocket ) > 1 )
\r
512 /* Tell the code below that this function is ready. */
\r
518 /* The user wants to perform an active shutdown(), skip sending
\r
519 the delayed ACK. The function prvTCPSendPacket() will send the
\r
520 FIN along with the ACK's. */
\r
523 if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
525 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
526 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
530 #endif /* ipconfigUSE_TCP_WIN */
\r
532 if( xReady == pdFALSE )
\r
534 /* The second task of this regular socket check is sending out data. */
\r
535 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
\r
536 ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
\r
538 prvTCPSendPacket( pxSocket );
\r
541 /* Set the time-out for the next wakeup for this socket. */
\r
542 prvTCPNextTimeout( pxSocket );
\r
544 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
546 /* In all (non-connected) states in which keep-alive messages can not be sent
\r
547 the anti-hang protocol will close sockets that are 'hanging'. */
\r
548 xResult = prvTCPStatusAgeCheck( pxSocket );
\r
555 /*-----------------------------------------------------------*/
\r
558 * prvTCPSendPacket() will be called when the socket time-out has been reached.
\r
559 * It is only called by xTCPSocketCheck().
\r
561 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
\r
563 int32_t lResult = 0;
\r
564 UBaseType_t uxOptionsLength;
\r
565 TCPPacket_t *pxTCPPacket;
\r
566 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
568 if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
\r
570 /* The connection is in s state other than SYN. */
\r
571 pxNetworkBuffer = NULL;
\r
573 /* prvTCPSendRepeated() will only create a network buffer if necessary,
\r
574 i.e. when data must be sent to the peer. */
\r
575 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
577 if( pxNetworkBuffer != NULL )
\r
579 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
584 if( pxSocket->u.xTCP.ucRepCount >= 3u )
\r
586 /* The connection is in the SYN status. The packet will be repeated
\r
587 to most 3 times. When there is no response, the socket get the
\r
588 status 'eCLOSE_WAIT'. */
\r
589 FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
\r
590 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
591 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
592 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
594 else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
\r
596 /* Or else, if the connection has been prepared, or can be prepared
\r
597 now, proceed to send the packet with the SYN flag.
\r
598 prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
\r
599 the Ethernet address of the peer or the gateway is found. */
\r
600 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
602 /* About to send a SYN packet. Call prvSetSynAckOptions() to set
\r
603 the proper options: The size of MSS and whether SACK's are
\r
605 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
607 /* Return the number of bytes to be sent. */
\r
608 lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
610 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
611 uxOptionsLength is always a multiple of 4. The complete expression
\r
613 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
614 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
616 /* Repeat Count is used for a connecting socket, to limit the number
\r
618 pxSocket->u.xTCP.ucRepCount++;
\r
620 /* Send the SYN message to make a connection. The messages is
\r
621 stored in the socket field 'xPacket'. It will be wrapped in a
\r
622 pseudo network buffer descriptor before it will be sent. */
\r
623 prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
\r
627 /* Return the total number of bytes sent. */
\r
630 /*-----------------------------------------------------------*/
\r
633 * prvTCPSendRepeated will try to send a series of messages, as long as there is
\r
634 * data to be sent and as long as the transmit window isn't full.
\r
636 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
638 UBaseType_t uxIndex;
\r
639 int32_t lResult = 0;
\r
640 UBaseType_t uxOptionsLength = 0u;
\r
641 int32_t xSendLength;
\r
643 for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
\r
645 /* prvTCPPrepareSend() might allocate a network buffer if there is data
\r
647 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
648 if( xSendLength <= 0 )
\r
653 /* And return the packet to the peer. */
\r
654 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
656 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
658 *ppxNetworkBuffer = NULL;
\r
660 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
662 lResult += xSendLength;
\r
665 /* Return the total number of bytes sent. */
\r
668 /*-----------------------------------------------------------*/
\r
671 * Return (or send) a packet the the peer. The data is stored in pxBuffer,
\r
672 * which may either point to a real network buffer or to a TCP socket field
\r
673 * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
\r
674 * the data to the NIC.
\r
676 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
\r
678 TCPPacket_t * pxTCPPacket;
\r
679 IPHeader_t *pxIPHeader;
\r
680 EthernetHeader_t *pxEthernetHeader;
\r
681 uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
\r
682 TCPWindow_t *pxTCPWindow;
\r
683 NetworkBufferDescriptor_t xTempBuffer;
\r
684 /* For sending, a pseudo network buffer will be used, as explained above. */
\r
686 if( pxNetworkBuffer == NULL )
\r
688 pxNetworkBuffer = &xTempBuffer;
\r
690 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
692 xTempBuffer.pxNextBuffer = NULL;
\r
695 xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
696 xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
697 xReleaseAfterSend = pdFALSE;
\r
700 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
702 if( xReleaseAfterSend == pdFALSE )
\r
704 pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
\r
705 if( pxNetworkBuffer == NULL )
\r
707 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
\r
709 xReleaseAfterSend = pdTRUE;
\r
712 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
714 if( pxNetworkBuffer != NULL )
\r
716 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
717 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
718 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
\r
720 /* Fill the packet, using hton translations. */
\r
721 if( pxSocket != NULL )
\r
723 /* Calculate the space in the RX buffer in order to advertise the
\r
724 size of this socket's reception window. */
\r
725 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
727 if( pxSocket->u.xTCP.rxStream != NULL )
\r
729 /* An RX stream was created already, see how much space is
\r
731 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
735 /* No RX stream has been created, the full stream size is
\r
737 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
740 /* Take the minimum of the RX buffer space and the RX window size. */
\r
741 ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );
\r
743 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
\r
745 /* The low-water mark was reached, meaning there was little
\r
746 space left. The socket will wait until the application has read
\r
747 or flushed the incoming data, and 'zero-window' will be
\r
752 /* If possible, advertise an RX window size of at least 1 MSS, otherwise
\r
753 the peer might start 'zero window probing', i.e. sending small packets
\r
754 (1, 2, 4, 8... bytes). */
\r
755 if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
\r
757 ulSpace = pxSocket->u.xTCP.usCurMSS;
\r
760 /* Avoid overflow of the 16-bit win field. */
\r
761 #if( ipconfigUSE_TCP_WIN != 0 )
\r
763 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
\r
767 ulWinSize = ulSpace;
\r
770 if( ulWinSize > 0xfffcUL )
\r
772 ulWinSize = 0xfffcUL;
\r
775 pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
\r
777 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
779 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
\r
781 if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
\r
783 size_t uxFrontSpace;
\r
785 if(pxSocket->u.xTCP.rxStream != NULL)
\r
787 uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
\r
794 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
\r
795 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
\r
796 pxSocket->u.xTCP.ulRemoteIP,
\r
797 pxSocket->u.xTCP.usRemotePort,
\r
798 pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
\r
799 (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
\r
803 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
\r
805 /* The new window size has been advertised, switch off the flag. */
\r
806 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
\r
808 /* Later on, when deciding to delay an ACK, a precise estimate is needed
\r
809 of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
\r
810 highest sequence number minus 1 that the socket will accept. */
\r
811 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
\r
813 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
814 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
\r
816 /* Sending a keep-alive packet, send the current sequence number
\r
817 minus 1, which will be recognised as a keep-alive packet an
\r
818 responded to by acknowledging the last byte. */
\r
819 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
820 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
\r
822 pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
\r
823 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
828 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
\r
830 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
\r
832 /* Suppress FIN in case this packet carries earlier data to be
\r
834 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
\r
835 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
\r
837 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
\r
838 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
\r
839 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
841 pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
\r
846 /* Tell which sequence number is expected next time */
\r
847 pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
851 /* Sending data without a socket, probably replying with a RST flag
\r
852 Just swap the two sequence numbers. */
\r
853 vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
\r
856 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
857 pxIPHeader->usLength = FreeRTOS_htons( ulLen );
\r
858 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
\r
860 /* When pxSocket is NULL, this function is called by prvTCPSendReset()
\r
861 and the IP-addresses must be swapped.
\r
862 Also swap the IP-addresses in case the IP-tack doesn't have an
\r
863 IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
\r
864 ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
\r
868 ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
870 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
871 pxIPHeader->ulSourceIPAddress = ulSourceAddress;
\r
872 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
\r
874 /* Just an increasing number. */
\r
875 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
876 usPacketIdentifier++;
\r
877 pxIPHeader->usFragmentOffset = 0u;
\r
879 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
881 /* calculate the IP header checksum, in case the driver won't do that. */
\r
882 pxIPHeader->usHeaderChecksum = 0x00u;
\r
883 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
884 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
886 /* calculate the TCP checksum for an outgoing packet. */
\r
887 usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
\r
889 /* A calculated checksum of 0 must be inverted as 0 means the checksum
\r
891 if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
\r
893 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
\r
898 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
\r
899 pxNetworkBuffer->pxNextBuffer = NULL;
\r
902 /* Important: tell NIC driver how many bytes must be sent. */
\r
903 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
\r
905 /* Fill in the destination MAC addresses. */
\r
906 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
\r
907 sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
909 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
\r
910 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
912 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
914 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
918 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
920 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
922 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
928 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
\r
930 if( xReleaseAfterSend == pdFALSE )
\r
932 /* Swap-back some fields, as pxBuffer probably points to a socket field
\r
933 containing the packet header. */
\r
934 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
\r
935 pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
\r
936 memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
940 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
\r
942 } /* if( pxNetworkBuffer != NULL ) */
\r
944 /*-----------------------------------------------------------*/
\r
947 * The SYN event is very important: the sequence numbers, which have a kind of
\r
948 * random starting value, are being synchronised. The sliding window manager
\r
949 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
\r
950 * Size (MSS) in use.
\r
952 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
\r
954 if( xTCPWindowLoggingLevel )
\r
955 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
\r
956 pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
\r
957 pxSocket->u.xTCP.uxLittleSpace ,
\r
958 pxSocket->u.xTCP.uxEnoughSpace,
\r
959 pxSocket->u.xTCP.uxRxStreamSize ) );
\r
961 &pxSocket->u.xTCP.xTCPWindow,
\r
962 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
\r
963 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
\r
964 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
\r
965 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
\r
966 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
\r
968 /*-----------------------------------------------------------*/
\r
971 * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
\r
972 * the Ethernet address of the target will be found using ARP. In case the
\r
973 * target IP address is not within the netmask, the hardware address of the
\r
974 * gateway will be used.
\r
976 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
\r
978 TCPPacket_t *pxTCPPacket;
\r
979 IPHeader_t *pxIPHeader;
\r
980 eARPLookupResult_t eReturned;
\r
981 uint32_t ulRemoteIP;
\r
982 MACAddress_t xEthAddress;
\r
983 BaseType_t xReturn = pdTRUE;
\r
984 uint32_t ulInitialSequenceNumber = 0;
\r
986 #if( ipconfigHAS_PRINTF != 0 )
\r
988 /* Only necessary for nicer logging. */
\r
989 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
\r
991 #endif /* ipconfigHAS_PRINTF != 0 */
\r
993 ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
995 /* Determine the ARP cache status for the requested IP address. */
\r
996 eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
\r
998 switch( eReturned )
\r
1000 case eARPCacheHit: /* An ARP table lookup found a valid entry. */
\r
1001 break; /* We can now prepare the SYN packet. */
\r
1002 case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
\r
1003 case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
\r
1005 /* Count the number of times it couldn't find the ARP address. */
\r
1006 pxSocket->u.xTCP.ucRepCount++;
\r
1008 FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
\r
1009 pxSocket->u.xTCP.ulRemoteIP,
\r
1010 FreeRTOS_htonl( ulRemoteIP ),
\r
1012 xEthAddress.ucBytes[ 0 ],
\r
1013 xEthAddress.ucBytes[ 1 ],
\r
1014 xEthAddress.ucBytes[ 2 ],
\r
1015 xEthAddress.ucBytes[ 3 ],
\r
1016 xEthAddress.ucBytes[ 4 ],
\r
1017 xEthAddress.ucBytes[ 5 ] ) );
\r
1019 /* And issue a (new) ARP request */
\r
1020 FreeRTOS_OutputARPRequest( ulRemoteIP );
\r
1022 xReturn = pdFALSE;
\r
1025 if( xReturn != pdFALSE )
\r
1027 /* Get a difficult-to-predict initial sequence number for this 4-tuple. */
\r
1028 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
\r
1029 pxSocket->usLocalPort,
\r
1030 pxSocket->u.xTCP.ulRemoteIP,
\r
1031 pxSocket->u.xTCP.usRemotePort );
\r
1033 /* Check for a random number generation error. */
\r
1034 if( 0 == ulInitialSequenceNumber )
\r
1036 xReturn = pdFALSE;
\r
1040 if( xReturn != pdFALSE )
\r
1042 /* The MAC-address of the peer (or gateway) has been found,
\r
1043 now prepare the initial TCP packet and some fields in the socket. */
\r
1044 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1045 pxIPHeader = &pxTCPPacket->xIPHeader;
\r
1047 /* reset the retry counter to zero. */
\r
1048 pxSocket->u.xTCP.ucRepCount = 0u;
\r
1050 /* And remember that the connect/SYN data are prepared. */
\r
1051 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
\r
1053 /* Now that the Ethernet address is known, the initial packet can be
\r
1055 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1057 /* Write the Ethernet address in Source, because it will be swapped by
\r
1058 prvTCPReturnPacket(). */
\r
1059 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
\r
1061 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
\r
1062 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
\r
1064 pxIPHeader->ucVersionHeaderLength = 0x45u;
\r
1065 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
\r
1066 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
\r
1068 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
\r
1070 /* Addresses and ports will be stored swapped because prvTCPReturnPacket
\r
1071 will swap them back while replying. */
\r
1072 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1073 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
\r
1075 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
\r
1076 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
1078 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
\r
1079 isn't known yet. */
\r
1080 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
\r
1082 /* Start with ISN (Initial Sequence Number). */
\r
1083 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
\r
1085 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
\r
1086 the high nibble of the TCP offset field. */
\r
1087 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
\r
1089 /* Only set the SYN flag. */
\r
1090 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
\r
1092 /* Set the values of usInitMSS / usCurMSS for this socket. */
\r
1093 prvSocketSetMSS( pxSocket );
\r
1095 /* For now this is also the advertised window size. */
\r
1096 pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;
\r
1098 /* The initial sequence numbers at our side are known. Later
\r
1099 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
\r
1100 first wait for a SYN+ACK reply. */
\r
1101 prvTCPCreateWindow( pxSocket );
\r
1106 /*-----------------------------------------------------------*/
\r
1108 /* For logging and debugging: make a string showing the TCP flags
\r
1110 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1112 static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
\r
1114 static char retString[10];
\r
1115 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
\r
1116 ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
\r
1117 ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
\r
1118 ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
\r
1119 ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
\r
1120 ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
\r
1121 ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
\r
1122 ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
\r
1123 ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
\r
1124 ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
\r
1127 /*-----------------------------------------------------------*/
\r
1129 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1132 * Parse the TCP option(s) received, if present. It has already been verified
\r
1133 * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
\r
1134 * is longer than the usual 20 (5 x 4) bytes.
\r
1136 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1138 TCPPacket_t * pxTCPPacket;
\r
1139 TCPHeader_t * pxTCPHeader;
\r
1140 const unsigned char *pucPtr;
\r
1141 const unsigned char *pucLast;
\r
1142 TCPWindow_t *pxTCPWindow;
\r
1143 UBaseType_t uxNewMSS;
\r
1145 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1146 pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1148 /* A character pointer to iterate through the option data */
\r
1149 pucPtr = pxTCPHeader->ucOptdata;
\r
1150 pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
\r
1151 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1153 /* Validate options size calculation. */
\r
1154 if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) )
\r
1159 /* The comparison with pucLast is only necessary in case the option data are
\r
1160 corrupted, we don't like to run into invalid memory and crash. */
\r
1161 while( pucPtr < pucLast )
\r
1163 UBaseType_t xRemainingOptionsBytes = pucLast - pucPtr;
\r
1165 if( pucPtr[ 0 ] == TCP_OPT_END )
\r
1167 /* End of options. */
\r
1170 if( pucPtr[ 0 ] == TCP_OPT_NOOP)
\r
1172 /* NOP option, inserted to make the length a multiple of 4. */
\r
1177 /* Any other well-formed option must be at least two bytes: the option
\r
1178 type byte followed by a length byte. */
\r
1179 if( xRemainingOptionsBytes < 2 )
\r
1183 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1184 else if( pucPtr[ 0 ] == TCP_OPT_WSOPT )
\r
1186 /* Confirm that the option fits in the remaining buffer space. */
\r
1187 if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != TCP_OPT_WSOPT_LEN ) )
\r
1192 pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
\r
1193 pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
\r
1194 pucPtr += TCP_OPT_WSOPT_LEN;
\r
1196 #endif /* ipconfigUSE_TCP_WIN */
\r
1197 else if( pucPtr[ 0 ] == TCP_OPT_MSS )
\r
1199 /* Confirm that the option fits in the remaining buffer space. */
\r
1200 if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( pucPtr[ 1 ] != TCP_OPT_MSS_LEN ) )
\r
1205 /* An MSS option with the correct option length. FreeRTOS_htons()
\r
1206 is not needed here because usChar2u16() already returns a host
\r
1208 uxNewMSS = usChar2u16( pucPtr + 2 );
\r
1210 if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
\r
1212 /* Perform a basic check on the the new MSS. */
\r
1213 if( uxNewMSS == 0 )
\r
1218 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
\r
1221 if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
\r
1223 /* our MSS was bigger than the MSS of the other party: adapt it. */
\r
1224 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
\r
1225 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )
\r
1227 /* The peer advertises a smaller MSS than this socket was
\r
1228 using. Use that as well. */
\r
1229 FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
\r
1230 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1232 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
\r
1233 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
\r
1234 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
\r
1235 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
\r
1236 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
\r
1239 #if( ipconfigUSE_TCP_WIN != 1 )
\r
1240 /* Without scaled windows, MSS is the only interesting option. */
\r
1243 /* Or else we continue to check another option: selective ACK. */
\r
1244 pucPtr += TCP_OPT_MSS_LEN;
\r
1245 #endif /* ipconfigUSE_TCP_WIN != 1 */
\r
1249 /* All other options have a length field, so that we easily
\r
1250 can skip past them. */
\r
1251 unsigned char len = pucPtr[ 1 ];
\r
1252 if( ( len < 2 ) || ( len > xRemainingOptionsBytes ) )
\r
1254 /* If the length field is too small or too big, the options are malformed.
\r
1255 Don't process them further. */
\r
1259 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1261 /* Selective ACK: the peer has received a packet but it is missing earlier
\r
1262 packets. At least this packet does not need retransmission anymore
\r
1263 ulTCPWindowTxSack( ) takes care of this administration. */
\r
1264 if( pucPtr[0] == TCP_OPT_SACK_A )
\r
1271 uint32_t ulFirst = ulChar2u32( pucPtr );
\r
1272 uint32_t ulLast = ulChar2u32( pucPtr + 4 );
\r
1273 uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );
\r
1274 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
\r
1275 starting from the head position.
\r
1276 Advance the tail pointer in txStream. */
\r
1277 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
\r
1279 /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
\r
1280 uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
\r
1281 pxSocket->xEventBits |= eSOCKET_SEND;
\r
1283 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
1285 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1287 /* The field 'xEventBits' is used to store regular socket events (at most 8),
\r
1288 as well as 'select events', which will be left-shifted */
\r
1289 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1294 /* In case the socket owner has installed an OnSent handler,
\r
1296 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1298 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
1300 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
1303 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
1308 /* len should be 0 by now. */
\r
1311 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1317 /*-----------------------------------------------------------*/
\r
1319 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1321 static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
\r
1326 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
\r
1327 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
\r
1329 while( uxWinSize > 0xfffful )
\r
1331 /* Divide by two and increase the binary factor by 1. */
\r
1336 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
\r
1337 pxSocket->u.xTCP.uxRxWinSize,
\r
1338 pxSocket->u.xTCP.usInitMSS,
\r
1345 /*-----------------------------------------------------------*/
\r
1348 * When opening a TCP connection, while SYN's are being sent, the parties may
\r
1349 * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
\r
1350 * nett size of the payload, always smaller than MTU.
\r
1352 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
\r
1354 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1355 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
\r
1356 UBaseType_t uxOptionsLength;
\r
1358 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
\r
1360 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
\r
1361 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
\r
1362 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
\r
1363 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
\r
1365 #if( ipconfigUSE_TCP_WIN != 0 )
\r
1367 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
\r
1369 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
\r
1370 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
\r
1371 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
\r
1372 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
\r
1373 uxOptionsLength = 8u;
\r
1377 uxOptionsLength = 4u;
\r
1381 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1383 return uxOptionsLength;
\r
1387 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
\r
1388 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
\r
1389 pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
\r
1390 pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
\r
1391 uxOptionsLength += 4u;
\r
1393 return uxOptionsLength; /* bytes, not words. */
\r
1395 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1399 * For anti-hanging protection and TCP keep-alive messages. Called in two
\r
1400 * places: after receiving a packet and after a state change. The socket's
\r
1401 * alive timer may be reset.
\r
1403 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
\r
1405 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
1407 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
\r
1411 #if( ipconfigTCP_KEEP_ALIVE == 1 )
\r
1413 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
\r
1414 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
\r
1415 pxSocket->u.xTCP.ucKeepRepCount = 0u;
\r
1416 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
\r
1420 ( void ) pxSocket;
\r
1422 /*-----------------------------------------------------------*/
\r
1425 * Changing to a new state. Centralised here to do specific actions such as
\r
1426 * resetting the alive timer, calling the user's OnConnect handler to notify
\r
1427 * that a socket has got (dis)connected, and setting bit to unblock a call to
\r
1428 * FreeRTOS_select()
\r
1430 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
\r
1432 FreeRTOS_Socket_t *xParent = NULL;
\r
1433 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
\r
1434 BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
\r
1435 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1436 BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
\r
1438 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1439 FreeRTOS_Socket_t *xConnected = NULL;
\r
1442 /* Has the connected status changed? */
\r
1443 if( bBefore != bAfter )
\r
1445 /* Is the socket connected now ? */
\r
1446 if( bAfter != pdFALSE )
\r
1448 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
\r
1449 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
\r
1451 /* Now that it is connected, find it's parent. */
\r
1452 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
1454 xParent = pxSocket;
\r
1458 xParent = pxSocket->u.xTCP.pxPeerSocket;
\r
1459 configASSERT( xParent != NULL );
\r
1461 if( xParent != NULL )
\r
1463 if( xParent->u.xTCP.pxPeerSocket == NULL )
\r
1465 xParent->u.xTCP.pxPeerSocket = pxSocket;
\r
1468 xParent->xEventBits |= eSOCKET_ACCEPT;
\r
1470 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1472 /* Library support FreeRTOS_select(). Receiving a new
\r
1473 connection is being translated as a READ event. */
\r
1474 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
\r
1476 xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
\r
1481 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1483 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
\r
1484 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
\r
1486 /* The listening socket does not become connected itself, in stead
\r
1487 a child socket is created.
\r
1488 Postpone a call the OnConnect event until the end of this function. */
\r
1489 xConnected = xParent;
\r
1495 /* Don't need to access the parent socket anymore, so the
\r
1496 reference 'pxPeerSocket' may be cleared. */
\r
1497 pxSocket->u.xTCP.pxPeerSocket = NULL;
\r
1498 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
\r
1500 /* When true, this socket may be returned in a call to accept(). */
\r
1501 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
1505 pxSocket->xEventBits |= eSOCKET_CONNECT;
\r
1507 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1509 if( pxSocket->xSelectBits & eSELECT_WRITE )
\r
1511 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
1517 else /* bAfter == pdFALSE, connection is closed. */
\r
1519 /* Notify/wake-up the socket-owner by setting a semaphore. */
\r
1520 pxSocket->xEventBits |= eSOCKET_CLOSED;
\r
1522 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
1524 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
\r
1526 pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
\r
1531 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1533 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
\r
1535 /* The 'connected' state has changed, call the user handler. */
\r
1536 xConnected = pxSocket;
\r
1539 #endif /* ipconfigUSE_CALLBACKS */
\r
1541 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
\r
1543 /* Now the socket isn't in an active state anymore so it
\r
1544 won't need further attention of the IP-task.
\r
1545 Setting time-out to zero means that the socket won't get checked during
\r
1547 pxSocket->u.xTCP.usTimeout = 0u;
\r
1552 if( eTCPState == eCLOSED )
\r
1554 /* Socket goes to status eCLOSED because of a RST.
\r
1555 When nobody owns the socket yet, delete it. */
\r
1556 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
\r
1557 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
1559 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
\r
1560 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
\r
1562 FreeRTOS_closesocket( pxSocket );
\r
1568 /* Fill in the new state. */
\r
1569 pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
\r
1571 /* touch the alive timers because moving to another state. */
\r
1572 prvTCPTouchSocket( pxSocket );
\r
1574 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
1576 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
1577 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
\r
1578 pxSocket->usLocalPort,
\r
1579 pxSocket->u.xTCP.ulRemoteIP,
\r
1580 pxSocket->u.xTCP.usRemotePort,
\r
1581 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
\r
1582 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
\r
1584 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1586 #if( ipconfigUSE_CALLBACKS == 1 )
\r
1588 if( xConnected != NULL )
\r
1590 /* The 'connected' state has changed, call the OnConnect handler of the parent. */
\r
1591 xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );
\r
1595 if( xParent != NULL )
\r
1597 vSocketWakeUpUser( xParent );
\r
1600 /*-----------------------------------------------------------*/
\r
1602 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
\r
1603 int32_t lDataLen, UBaseType_t uxOptionsLength )
\r
1605 NetworkBufferDescriptor_t *pxReturn;
\r
1607 BaseType_t xResize;
\r
1609 if( xBufferAllocFixedSize != pdFALSE )
\r
1611 /* Network buffers are created with a fixed size and can hold the largest
\r
1613 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
\r
1614 /* and therefore, the buffer won't be too small.
\r
1615 Only ask for a new network buffer in case none was supplied. */
\r
1616 xResize = ( pxNetworkBuffer == NULL );
\r
1620 /* Network buffers are created with a variable size. See if it must
\r
1622 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
\r
1623 ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
\r
1624 /* In case we were called from a TCP timer event, a buffer must be
\r
1625 created. Otherwise, test 'xDataLength' of the provided buffer. */
\r
1626 xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded );
\r
1629 if( xResize != pdFALSE )
\r
1631 /* The caller didn't provide a network buffer or the provided buffer is
\r
1632 too small. As we must send-out a data packet, a buffer will be created
\r
1634 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
\r
1636 if( pxReturn != NULL )
\r
1638 /* Set the actual packet size, in case the returned buffer is larger. */
\r
1639 pxReturn->xDataLength = lNeeded;
\r
1641 /* Copy the existing data to the new created buffer. */
\r
1642 if( pxNetworkBuffer )
\r
1644 /* Either from the previous buffer... */
\r
1645 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
\r
1647 /* ...and release it. */
\r
1648 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1652 /* Or from the socket field 'xTCP.xPacket'. */
\r
1653 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
\r
1659 /* xResize is false, the network buffer provided was big enough. */
\r
1660 pxReturn = pxNetworkBuffer;
\r
1662 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
\r
1663 xDataLength member must get the correct length too! */
\r
1664 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
\r
1669 /*-----------------------------------------------------------*/
\r
1672 * Prepare an outgoing message, in case anything has to be sent.
\r
1674 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
\r
1677 uint8_t *pucEthernetBuffer, *pucSendData;
\r
1678 TCPPacket_t *pxTCPPacket;
\r
1680 uint32_t ulDataGot, ulDistance;
\r
1681 TCPWindow_t *pxTCPWindow;
\r
1682 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1683 int32_t lStreamPos;
\r
1685 if( ( *ppxNetworkBuffer ) != NULL )
\r
1687 /* A network buffer descriptor was already supplied */
\r
1688 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
\r
1692 /* For now let it point to the last packet header */
\r
1693 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
\r
1696 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1697 pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1700 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
\r
1702 if( pxSocket->u.xTCP.txStream != NULL )
\r
1704 /* ulTCPWindowTxGet will return the amount of data which may be sent
\r
1705 along with the position in the txStream.
\r
1706 Why check for MSS > 1 ?
\r
1707 Because some TCP-stacks (like uIP) use it for flow-control. */
\r
1708 if( pxSocket->u.xTCP.usCurMSS > 1u )
\r
1710 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
\r
1713 if( lDataLen > 0 )
\r
1715 /* Check if the current network buffer is big enough, if not,
\r
1717 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
\r
1719 if( pxNewBuffer != NULL )
\r
1721 *ppxNetworkBuffer = pxNewBuffer;
\r
1722 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
\r
1723 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
\r
1725 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
\r
1727 /* Translate the position in txStream to an offset from the tail
\r
1729 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
\r
1731 /* Here data is copied from the txStream in 'peek' mode. Only
\r
1732 when the packets are acked, the tail marker will be updated. */
\r
1733 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
\r
1735 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1737 if( ulDataGot != ( uint32_t ) lDataLen )
\r
1739 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
\r
1740 lStreamPos, uxOffset, ulDataGot, lDataLen ) );
\r
1745 /* If the owner of the socket requests a closure, add the FIN
\r
1746 flag to the last packet. */
\r
1747 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
\r
1749 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
\r
1751 if( ulDistance == ulDataGot )
\r
1753 #if (ipconfigHAS_DEBUG_PRINTF == 1)
\r
1755 /* the order of volatile accesses is undefined
\r
1756 so such workaround */
\r
1757 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
\r
1758 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
\r
1759 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
\r
1761 FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
\r
1762 uxTail, uxMid, uxHead ) );
\r
1765 /* Although the socket sends a FIN, it will stay in
\r
1766 ESTABLISHED until all current data has been received or
\r
1768 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1769 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
\r
1770 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1781 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
\r
1783 /* See if the socket owner wants to shutdown this connection. */
\r
1784 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
\r
1785 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
\r
1787 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
\r
1788 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
\r
1789 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1790 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
1791 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1792 vTCPStateChange( pxSocket, eFIN_WAIT_1 );
\r
1795 #if( ipconfigTCP_KEEP_ALIVE != 0 )
\r
1797 if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
\r
1799 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
\r
1800 pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
\r
1801 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
\r
1802 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
1805 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
\r
1807 /* If there is no data to be sent, and no window-update message,
\r
1808 we might want to send a keep-alive message. */
\r
1809 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
\r
1811 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
\r
1812 if( pxSocket->u.xTCP.ucKeepRepCount )
\r
1814 xMax = ( 3u * configTICK_RATE_HZ );
\r
1818 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
\r
1819 if( xTCPWindowLoggingLevel )
\r
1820 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
\r
1821 pxSocket->u.xTCP.ulRemoteIP,
\r
1822 pxSocket->u.xTCP.usRemotePort,
\r
1823 pxSocket->u.xTCP.ucKeepRepCount ) );
\r
1824 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
\r
1825 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
\r
1826 pxSocket->u.xTCP.ucKeepRepCount++;
\r
1830 #endif /* ipconfigTCP_KEEP_ALIVE */
\r
1833 /* Anything to send, a change of the advertised window size, or maybe send a
\r
1834 keep-alive message? */
\r
1835 if( ( lDataLen > 0 ) ||
\r
1836 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
\r
1837 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
\r
1839 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
\r
1840 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
1842 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
\r
1844 if( lDataLen != 0l )
\r
1846 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
\r
1849 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
1854 /*-----------------------------------------------------------*/
\r
1857 * Calculate after how much time this socket needs to be checked again.
\r
1859 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
\r
1861 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1863 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
1865 /* The socket is actively connecting to a peer. */
\r
1866 if( pxSocket->u.xTCP.bits.bConnPrepared )
\r
1868 /* Ethernet address has been found, use progressive timeout for
\r
1869 active connect(). */
\r
1870 if( pxSocket->u.xTCP.ucRepCount < 3u )
\r
1872 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
\r
1876 ulDelayMs = 11000UL;
\r
1881 /* Still in the ARP phase: check every half second. */
\r
1882 ulDelayMs = 500UL;
\r
1885 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
\r
1886 pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
\r
1887 pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
\r
1888 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1890 else if( pxSocket->u.xTCP.usTimeout == 0u )
\r
1892 /* Let the sliding window mechanism decide what time-out is appropriate. */
\r
1893 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
\r
1894 if( ulDelayMs == 0u )
\r
1896 if( xResult != ( BaseType_t )0 )
\r
1902 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
\r
1907 /* ulDelayMs contains the time to wait before a re-transmission. */
\r
1909 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
\r
1913 /* field '.usTimeout' has already been set (by the
\r
1914 keep-alive/delayed-ACK mechanism). */
\r
1917 /* Return the number of clock ticks before the timer expires. */
\r
1918 return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
\r
1920 /*-----------------------------------------------------------*/
\r
1922 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
\r
1924 int32_t lCount, lLength;
\r
1926 /* A txStream has been created already, see if the socket has new data for
\r
1927 the sliding window.
\r
1929 uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It contains new
\r
1930 Tx data which has not been passed to the sliding window yet. The oldest
\r
1931 data not-yet-confirmed can be found at rxTail. */
\r
1932 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
\r
1936 /* All data between txMid and rxHead will now be passed to the sliding
\r
1937 window manager, so it can start transmitting them.
\r
1939 Hand over the new data to the sliding window handler. It will be
\r
1940 split-up in chunks of 1460 bytes each (or less, depending on
\r
1941 ipconfigTCP_MSS). */
\r
1942 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
\r
1943 ( uint32_t ) lLength,
\r
1944 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
\r
1945 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
\r
1947 /* Move the rxMid pointer forward up to rxHead. */
\r
1950 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
\r
1954 /*-----------------------------------------------------------*/
\r
1957 * prvTCPHandleFin() will be called to handle socket closure
\r
1958 * The Closure starts when either a FIN has been received and accepted,
\r
1959 * Or when the socket has sent a FIN flag to the peer
\r
1960 * Before being called, it has been checked that both reception and transmission
\r
1963 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
1965 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1966 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
1967 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
1968 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
1969 BaseType_t xSendLength = 0;
\r
1970 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
\r
1972 if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
\r
1974 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
\r
1976 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
1978 /* We haven't yet replied with a FIN, do so now. */
\r
1979 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
1980 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
\r
1984 /* We did send a FIN already, see if it's ACK'd. */
\r
1985 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
\r
1987 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
\r
1991 if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
\r
1993 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
1994 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
\r
1996 /* And wait for the final ACK. */
\r
1997 vTCPStateChange( pxSocket, eLAST_ACK );
\r
2001 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
\r
2002 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
\r
2003 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
\r
2005 /* We have sent out a FIN but the peer hasn't replied with a FIN
\r
2006 yet. Do nothing for the moment. */
\r
2007 pxTCPHeader->ucTCPFlags = 0u;
\r
2011 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
\r
2013 /* This is the third of the three-way hand shake: the last
\r
2015 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2019 /* The other party started the closure, so we just wait for the
\r
2021 pxTCPHeader->ucTCPFlags = 0u;
\r
2024 /* And wait for the user to close this socket. */
\r
2025 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2029 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2031 if( pxTCPHeader->ucTCPFlags != 0u )
\r
2033 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
\r
2036 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
\r
2038 if( xTCPWindowLoggingLevel != 0 )
\r
2040 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
\r
2041 ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2042 pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2043 pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2044 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2045 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2048 return xSendLength;
\r
2050 /*-----------------------------------------------------------*/
\r
2053 * prvCheckRxData(): called from prvTCPHandleState()
\r
2055 * The first thing that will be done is find the TCP payload data
\r
2056 * and check the length of this data.
\r
2058 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
\r
2060 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2061 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2062 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
\r
2064 /* Determine the length and the offset of the user-data sent to this
\r
2067 The size of the TCP header is given in a multiple of 4-byte words (single
\r
2068 byte, needs no ntoh() translation). A shift-right 2: is the same as
\r
2069 (offset >> 4) * 4. */
\r
2070 lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
\r
2072 /* Let pucRecvData point to the first byte received. */
\r
2073 *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
\r
2075 /* Calculate lReceiveLength - the length of the TCP data received. This is
\r
2076 equal to the total packet length minus:
\r
2077 ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
\r
2078 lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
\r
2079 lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
\r
2081 if( lReceiveLength > lLength )
\r
2083 /* More bytes were received than the reported length, often because of
\r
2084 padding bytes at the end. */
\r
2085 lReceiveLength = lLength;
\r
2088 /* Subtract the size of the TCP and IP headers and the actual data size is
\r
2090 if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
\r
2092 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
\r
2096 lReceiveLength = 0;
\r
2099 /* Urgent Pointer:
\r
2100 This field communicates the current value of the urgent pointer as a
\r
2101 positive offset from the sequence number in this segment. The urgent
\r
2102 pointer points to the sequence number of the octet following the urgent
\r
2103 data. This field is only be interpreted in segments with the URG control
\r
2105 if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
\r
2107 /* Although we ignore the urgent data, we have to skip it. */
\r
2108 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
\r
2109 *ppucRecvData += lUrgentLength;
\r
2110 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
\r
2113 return ( BaseType_t ) lReceiveLength;
\r
2115 /*-----------------------------------------------------------*/
\r
2118 * prvStoreRxData(): called from prvTCPHandleState()
\r
2120 * The second thing is to do is check if the payload data may be accepted
\r
2121 * If so, they will be added to the reception queue.
\r
2123 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
\r
2124 NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
\r
2126 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2127 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2128 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2129 uint32_t ulSequenceNumber, ulSpace;
\r
2130 int32_t lOffset, lStored;
\r
2131 BaseType_t xResult = 0;
\r
2133 ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2135 if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
\r
2137 /* See if way may accept the data contents and forward it to the socket
\r
2140 If it can't be "accept"ed it may have to be stored and send a selective
\r
2141 ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
\r
2142 called later to store an out-of-order packet (in case lOffset is
\r
2144 if ( pxSocket->u.xTCP.rxStream )
\r
2146 ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
\r
2150 ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
\r
2153 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
\r
2155 if( lOffset >= 0 )
\r
2157 /* New data has arrived and may be made available to the user. See
\r
2158 if the head marker in rxStream may be advanced, only if lOffset == 0.
\r
2159 In case the low-water mark is reached, bLowWater will be set
\r
2160 "low-water" here stands for "little space". */
\r
2161 lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
\r
2163 if( lStored != ( int32_t ) ulReceiveLength )
\r
2165 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
\r
2167 /* Received data could not be stored. The socket's flag
\r
2168 bMallocError has been set. The socket now has the status
\r
2169 eCLOSE_WAIT and a RST packet will be sent back. */
\r
2170 prvTCPSendReset( pxNetworkBuffer );
\r
2175 /* After a missing packet has come in, higher packets may be passed to
\r
2177 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2179 /* Now lTCPAddRxdata() will move the rxHead pointer forward
\r
2180 so data becomes available to the user immediately
\r
2181 In case the low-water mark is reached, bLowWater will be set. */
\r
2182 if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
\r
2184 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
\r
2185 pxTCPWindow->ulUserDataLength = 0;
\r
2188 #endif /* ipconfigUSE_TCP_WIN */
\r
2192 pxTCPWindow->ucOptionLength = 0u;
\r
2197 /*-----------------------------------------------------------*/
\r
2199 /* Set the TCP options (if any) for the outgoing packet. */
\r
2200 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2202 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2203 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2204 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2205 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
\r
2207 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2208 if( uxOptionsLength != 0u )
\r
2210 /* TCP options must be sent because a packet which is out-of-order
\r
2212 if( xTCPWindowLoggingLevel >= 0 )
\r
2213 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
\r
2214 pxSocket->usLocalPort,
\r
2215 pxSocket->u.xTCP.usRemotePort,
\r
2217 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
\r
2218 FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
\r
2219 memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
\r
2221 /* The header length divided by 4, goes into the higher nibble,
\r
2222 effectively a shift-left 2. */
\r
2223 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2226 #endif /* ipconfigUSE_TCP_WIN */
\r
2227 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
\r
2229 /* TCP options must be sent because the MSS has changed. */
\r
2230 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
\r
2231 if( xTCPWindowLoggingLevel >= 0 )
\r
2233 FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
\r
2236 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
\r
2237 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
\r
2238 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
\r
2239 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
\r
2240 uxOptionsLength = 4u;
\r
2241 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2244 return uxOptionsLength;
\r
2246 /*-----------------------------------------------------------*/
\r
2249 * prvHandleSynReceived(): called from prvTCPHandleState()
\r
2251 * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
\r
2252 * If the flags received are correct, the socket will move to eESTABLISHED.
\r
2254 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2255 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2257 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2258 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2259 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2260 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2261 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
\r
2262 BaseType_t xSendLength = 0;
\r
2264 /* Either expect a ACK or a SYN+ACK. */
\r
2265 uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
\r
2266 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2268 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
\r
2271 if( ( ucTCPFlags & 0x17u ) != usExpect )
\r
2273 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
\r
2274 /* eSYN_RECEIVED: flags ACK expected, not SYN. */
\r
2275 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
\r
2276 pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
\r
2277 usExpect, ucTCPFlags ) );
\r
2278 vTCPStateChange( pxSocket, eCLOSE_WAIT );
\r
2279 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
\r
2280 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2281 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2285 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
\r
2286 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
\r
2288 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
\r
2290 TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
\r
2292 /* Clear the SYN flag in lastPacket. */
\r
2293 pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
\r
2295 /* This socket was the one connecting actively so now perofmr the
\r
2296 synchronisation. */
\r
2297 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
\r
2298 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2299 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2300 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
\r
2301 pxTCPWindow->ulNextTxSequenceNumber++;
\r
2303 else if( ulReceiveLength == 0u )
\r
2305 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
2308 /* The SYN+ACK has been confirmed, increase the next sequence number by
\r
2310 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
\r
2312 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2314 FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
\r
2315 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
\r
2316 pxSocket->usLocalPort,
\r
2317 pxSocket->u.xTCP.ulRemoteIP,
\r
2318 pxSocket->u.xTCP.usRemotePort,
\r
2319 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
\r
2321 #endif /* ipconfigUSE_TCP_WIN */
\r
2323 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
\r
2325 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2326 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2327 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2329 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2331 if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
\r
2333 /* The other party did not send a scaling factor.
\r
2334 A shifting factor in this side must be canceled. */
\r
2335 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
\r
2336 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
\r
2339 #endif /* ipconfigUSE_TCP_WIN */
\r
2340 /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
\r
2341 connection is established. */
\r
2342 vTCPStateChange( pxSocket, eESTABLISHED );
\r
2345 return xSendLength;
\r
2347 /*-----------------------------------------------------------*/
\r
2350 * prvHandleEstablished(): called from prvTCPHandleState()
\r
2352 * Called if the status is eESTABLISHED. Data reception has been handled
\r
2353 * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
\r
2354 * the code will check if it may be accepted, i.e. if all expected data has been
\r
2355 * completely received.
\r
2357 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2358 uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
\r
2360 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2361 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2362 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2363 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2364 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
\r
2365 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
\r
2366 int32_t lDistance, lSendResult;
\r
2368 /* Remember the window size the peer is advertising. */
\r
2369 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
\r
2370 #if( ipconfigUSE_TCP_WIN != 0 )
\r
2372 pxSocket->u.xTCP.ulWindowSize =
\r
2373 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
2377 if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
\r
2379 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
\r
2381 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
\r
2382 starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
\r
2384 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
\r
2386 /* Just advancing the tail index, 'ulCount' bytes have been
\r
2387 confirmed, and because there is new space in the txStream, the
\r
2388 user/owner should be woken up. */
\r
2389 /* _HT_ : only in case the socket's waiting? */
\r
2390 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
\r
2392 pxSocket->xEventBits |= eSOCKET_SEND;
\r
2394 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
2396 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
\r
2398 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
\r
2402 /* In case the socket owner has installed an OnSent handler,
\r
2404 #if( ipconfigUSE_CALLBACKS == 1 )
\r
2406 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
\r
2408 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
\r
2411 #endif /* ipconfigUSE_CALLBACKS == 1 */
\r
2416 /* If this socket has a stream for transmission, add the data to the
\r
2417 outgoing segment(s). */
\r
2418 if( pxSocket->u.xTCP.txStream != NULL )
\r
2420 prvTCPAddTxData( pxSocket );
\r
2423 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
\r
2425 if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
\r
2427 /* Peer is requesting to stop, see if we're really finished. */
\r
2428 xMayClose = pdTRUE;
\r
2430 /* Checks are only necessary if we haven't sent a FIN yet. */
\r
2431 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2433 /* xTCPWindowTxDone returns true when all Tx queues are empty. */
\r
2434 bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
\r
2435 bTxDone = xTCPWindowTxDone( pxTCPWindow );
\r
2437 if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
\r
2439 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
\r
2440 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
\r
2441 pxSocket->usLocalPort,
\r
2442 pxSocket->u.xTCP.usRemotePort,
\r
2443 bRxComplete, bTxDone ) );
\r
2444 xMayClose = pdFALSE;
\r
2448 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2450 if( lDistance > 1 )
\r
2452 FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
\r
2453 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2454 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
\r
2456 xMayClose = pdFALSE;
\r
2461 if( xTCPWindowLoggingLevel > 0 )
\r
2463 FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
\r
2464 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
\r
2465 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
\r
2468 if( xMayClose != pdFALSE )
\r
2470 pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
\r
2471 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2475 if( xMayClose == pdFALSE )
\r
2477 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
\r
2479 if( ulReceiveLength != 0u )
\r
2481 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2482 /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
\r
2483 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2485 if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
\r
2487 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
\r
2491 /* Now get data to be transmitted. */
\r
2492 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
\r
2493 can not send-out both TCP options and also a full packet. Sending
\r
2494 options (SACK) is always more urgent than sending data, which can be
\r
2496 if( uxOptionsLength == 0u )
\r
2498 /* prvTCPPrepareSend might allocate a bigger network buffer, if
\r
2500 lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
\r
2501 if( lSendResult > 0 )
\r
2503 xSendLength = ( BaseType_t ) lSendResult;
\r
2508 return xSendLength;
\r
2510 /*-----------------------------------------------------------*/
\r
2513 * Called from prvTCPHandleState(). There is data to be sent. If
\r
2514 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
\r
2515 * checked if it would better be postponed for efficiency.
\r
2517 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
\r
2518 uint32_t ulReceiveLength, BaseType_t xSendLength )
\r
2520 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2521 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
\r
2522 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
\r
2523 /* Find out what window size we may advertised. */
\r
2524 uint32_t ulFrontSpace;
\r
2526 #if( ipconfigUSE_TCP_WIN == 1 )
\r
2527 #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
\r
2528 const int32_t lMinLength = 0;
\r
2530 int32_t lMinLength;
\r
2533 pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -
\r
2534 ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2536 /* Free space in rxStream. */
\r
2537 if( pxSocket->u.xTCP.rxStream != NULL )
\r
2539 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
\r
2543 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
\r
2546 pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );
\r
2548 /* Set the time-out field, so that we'll be called by the IP-task in case no
\r
2549 next message will be received. */
\r
2550 lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
\r
2551 #if ipconfigUSE_TCP_WIN == 1
\r
2554 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
\r
2556 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
\r
2558 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
\r
2560 /* In case we're receiving data continuously, we might postpone sending
\r
2561 an ACK to gain performance. */
\r
2562 if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
\r
2563 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
\r
2564 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
\r
2565 ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
\r
2566 ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
\r
2567 ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
\r
2569 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2571 /* There was still a delayed in queue, delete it. */
\r
2572 if( pxSocket->u.xTCP.pxAckMessage != 0 )
\r
2574 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2577 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
\r
2579 if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
\r
2580 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
\r
2582 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
\r
2586 /* Normally a delayed ACK should wait 200 ms for a next incoming
\r
2587 packet. Only wait 20 ms here to gain performance. A slow ACK
\r
2588 for full-size message. */
\r
2589 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
\r
2592 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2594 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
\r
2595 pxSocket->usLocalPort,
\r
2596 pxSocket->u.xTCP.usRemotePort,
\r
2597 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2598 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2600 pxSocket->u.xTCP.usTimeout, lRxSpace ) );
\r
2603 *ppxNetworkBuffer = NULL;
\r
2606 else if( pxSocket->u.xTCP.pxAckMessage != NULL )
\r
2608 /* As an ACK is not being delayed, remove any earlier delayed ACK
\r
2610 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
\r
2612 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
\r
2615 pxSocket->u.xTCP.pxAckMessage = NULL;
\r
2620 /* Remove compiler warnings. */
\r
2621 ( void ) ulReceiveLength;
\r
2622 ( void ) pxTCPHeader;
\r
2623 ( void ) lRxSpace;
\r
2625 #endif /* ipconfigUSE_TCP_WIN */
\r
2627 if( xSendLength != 0 )
\r
2629 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
\r
2631 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
\r
2632 pxSocket->usLocalPort,
\r
2633 pxSocket->u.xTCP.usRemotePort,
\r
2634 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
\r
2635 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
\r
2639 /* Set the parameter 'xReleaseAfterSend' to the value of
\r
2640 ipconfigZERO_COPY_TX_DRIVER. */
\r
2641 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
\r
2642 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
2644 /* The driver has taken ownership of the Network Buffer. */
\r
2645 *ppxNetworkBuffer = NULL;
\r
2650 return xSendLength;
\r
2652 /*-----------------------------------------------------------*/
\r
2655 * prvTCPHandleState()
\r
2656 * is the most important function of this TCP stack
\r
2657 * We've tried to keep it (relatively short) by putting a lot of code in
\r
2658 * the static functions above:
\r
2660 * prvCheckRxData()
\r
2661 * prvStoreRxData()
\r
2663 * prvHandleSynReceived()
\r
2664 * prvHandleEstablished()
\r
2667 * As these functions are declared static, and they're called from one location
\r
2668 * only, most compilers will inline them, thus avoiding a call and return.
\r
2670 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
\r
2672 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
\r
2673 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
\r
2674 BaseType_t xSendLength = 0;
\r
2675 uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
\r
2676 uint8_t *pucRecvData;
\r
2677 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
\r
2679 /* uxOptionsLength: the size of the options to be sent (always a multiple of
\r
2681 1. in the SYN phase, we shall communicate the MSS
\r
2682 2. in case of a SACK, Selective ACK, ack a segment which comes in
\r
2684 UBaseType_t uxOptionsLength = 0u;
\r
2685 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
\r
2686 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
\r
2688 /* First get the length and the position of the received data, if any.
\r
2689 pucRecvData will point to the first byte of the TCP payload. */
\r
2690 ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
\r
2692 if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
\r
2694 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
\r
2696 /* This is most probably a keep-alive message from peer. Setting
\r
2697 'bWinChange' doesn't cause a window-size-change, the flag is used
\r
2698 here to force sending an immediate ACK. */
\r
2699 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
\r
2703 /* Keep track of the highest sequence number that might be expected within
\r
2704 this connection. */
\r
2705 if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
\r
2707 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2710 /* Storing data may result in a fatal error if malloc() fails. */
\r
2711 if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
\r
2717 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
\r
2719 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
\r
2721 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
\r
2723 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
\r
2724 'SYN+ACK' didn't arrive. Step back to the previous state in which
\r
2725 a first incoming SYN is handled. The SYN was counted already so
\r
2726 decrease it first. */
\r
2727 vTCPStateChange( pxSocket, eSYN_FIRST );
\r
2730 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
\r
2732 /* It's the first time a FIN has been received, remember its
\r
2733 sequence number. */
\r
2734 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
\r
2735 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
\r
2737 /* Was peer the first one to send a FIN? */
\r
2738 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
\r
2740 /* If so, don't send the-last-ACK. */
\r
2741 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
\r
2745 switch (pxSocket->u.xTCP.ucTCPState)
\r
2747 case eCLOSED: /* (server + client) no connection state at all. */
\r
2748 /* Nothing to do for a closed socket, except waiting for the
\r
2752 case eTCP_LISTEN: /* (server) waiting for a connection request from
\r
2753 any remote TCP and port. */
\r
2754 /* The listen state was handled in xProcessReceivedTCPPacket().
\r
2755 Should not come here. */
\r
2758 case eSYN_FIRST: /* (server) Just received a SYN request for a server
\r
2761 /* A new socket has been created, reply with a SYN+ACK.
\r
2762 Acknowledge with seq+1 because the SYN is seen as pseudo data
\r
2764 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
\r
2765 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
\r
2767 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
\r
2769 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
\r
2770 uxOptionsLength is a multiple of 4. The complete expression is:
\r
2771 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
\r
2772 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
\r
2773 vTCPStateChange( pxSocket, eSYN_RECEIVED );
\r
2775 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
\r
2776 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
\r
2780 case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
\r
2781 SYN, expect a SYN+ACK and send a ACK now. */
\r
2782 /* Fall through */
\r
2783 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
\r
2784 expect a ACK and do nothing. */
\r
2785 xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2788 case eESTABLISHED: /* (server + client) an open connection, data
\r
2789 received can be delivered to the user. The normal
\r
2790 state for the data transfer phase of the connection
\r
2791 The closing states are also handled here with the
\r
2792 use of some flags. */
\r
2793 xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
\r
2796 case eLAST_ACK: /* (server + client) waiting for an acknowledgement
\r
2797 of the connection termination request previously
\r
2798 sent to the remote TCP (which includes an
\r
2799 acknowledgement of its connection termination
\r
2801 /* Fall through */
\r
2802 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
\r
2803 * or an acknowledgement of the connection termination request previously sent. */
\r
2804 /* Fall through */
\r
2805 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
\r
2806 xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
\r
2809 case eCLOSE_WAIT: /* (server + client) waiting for a connection
\r
2810 termination request from the local user. Nothing to
\r
2811 do, connection is closed, wait for owner to close
\r
2815 case eCLOSING: /* (server + client) waiting for a connection
\r
2816 termination request acknowledgement from the remote
\r
2820 case eTIME_WAIT: /* (either server or client) waiting for enough time
\r
2821 to pass to be sure the remote TCP received the
\r
2822 acknowledgement of its connection termination
\r
2823 request. [According to RFC 793 a connection can stay
\r
2824 in TIME-WAIT for a maximum of four minutes known as
\r
2825 a MSL (maximum segment lifetime).] These states are
\r
2826 implemented implicitly by settings flags like
\r
2827 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
\r
2834 if( xSendLength > 0 )
\r
2836 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
\r
2839 return xSendLength;
\r
2841 /*-----------------------------------------------------------*/
\r
2843 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2845 #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
\r
2847 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2848 const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
\r
2850 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;
\r
2851 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
\r
2853 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );
\r
2855 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
\r
2857 /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
\r
2858 ( void ) pxNetworkBuffer;
\r
2860 /* The packet was not consumed. */
\r
2863 /*-----------------------------------------------------------*/
\r
2865 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
\r
2867 uint32_t ulMSS = ipconfigTCP_MSS;
\r
2869 if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
\r
2871 /* Data for this peer will pass through a router, and maybe through
\r
2872 the internet. Limit the MSS to 1400 bytes or less. */
\r
2873 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
\r
2876 FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
\r
2878 pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
\r
2880 /*-----------------------------------------------------------*/
\r
2883 * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
\r
2884 * xProcessReceivedTCPPacket()
\r
2885 * prvTCPHandleState()
\r
2886 * prvTCPPrepareSend()
\r
2887 * prvTCPReturnPacket()
\r
2888 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2889 * prvTCPSendRepeated()
\r
2890 * prvTCPReturnPacket() // Prepare for returning
\r
2891 * xNetworkInterfaceOutput() // Sends data to the NIC
\r
2893 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
2895 FreeRTOS_Socket_t *pxSocket;
\r
2896 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
2897 uint16_t ucTCPFlags;
\r
2898 uint32_t ulLocalIP;
\r
2899 uint16_t xLocalPort;
\r
2900 uint32_t ulRemoteIP;
\r
2901 uint16_t xRemotePort;
\r
2902 BaseType_t xResult = pdPASS;
\r
2904 /* Check for a minimum packet size. */
\r
2905 if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) )
\r
2907 ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
\r
2908 ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
\r
2909 xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
\r
2910 ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
2911 xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
2913 /* Find the destination socket, and if not found: return a socket listing to
\r
2914 the destination PORT. */
\r
2915 pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
\r
2922 if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
\r
2924 /* A TCP messages is received but either there is no socket with the
\r
2925 given port number or the there is a socket, but it is in one of these
\r
2926 non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
\r
2929 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
\r
2931 /* Send a RST to all packets that can not be handled. As a result
\r
2932 the other party will get a ECONN error. There are two exceptions:
\r
2933 1) A packet that already has the RST flag set.
\r
2934 2) A packet that only has the ACK flag set.
\r
2935 A packet with only the ACK flag set might be the last ACK in
\r
2936 a three-way hand-shake that closes a connection. */
\r
2937 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
\r
2938 ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
\r
2940 prvTCPSendReset( pxNetworkBuffer );
\r
2943 /* The packet can't be handled. */
\r
2948 pxSocket->u.xTCP.ucRepCount = 0u;
\r
2950 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
\r
2952 /* The matching socket is in a listening state. Test if the peer
\r
2953 has set the SYN flag. */
\r
2954 if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
\r
2956 /* What happens: maybe after a reboot, a client doesn't know the
\r
2957 connection had gone. Send a RST in order to get a new connect
\r
2959 #if( ipconfigHAS_DEBUG_PRINTF == 1 )
\r
2961 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
\r
2962 prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
\r
2964 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
2966 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
\r
2968 prvTCPSendReset( pxNetworkBuffer );
\r
2974 /* prvHandleListen() will either return a newly created socket
\r
2975 (if bReuseSocket is false), otherwise it returns the current
\r
2976 socket which will later get connected. */
\r
2977 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
\r
2979 if( pxSocket == NULL )
\r
2984 } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
\r
2987 /* This is not a socket in listening mode. Check for the RST
\r
2989 if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
\r
2991 /* The target socket is not in a listening state, any RST packet
\r
2992 will cause the socket to be closed. */
\r
2993 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
\r
2994 /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */
\r
2995 vTCPStateChange( pxSocket, eCLOSED );
\r
2997 /* The packet cannot be handled. */
\r
3000 else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
\r
3002 /* SYN flag while this socket is already connected. */
\r
3003 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
\r
3005 /* The packet cannot be handled. */
\r
3010 /* Update the copy of the TCP header only (skipping eth and IP
\r
3011 headers). It might be used later on, whenever data must be sent
\r
3013 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
\r
3014 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
\r
3019 if( xResult != pdFAIL )
\r
3021 /* Touch the alive timers because we received a message for this
\r
3023 prvTCPTouchSocket( pxSocket );
\r
3025 /* Parse the TCP option(s), if present. */
\r
3026 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
\r
3027 then we MUST assume an MSS size of 536 bytes for backward compatibility. */
\r
3029 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
\r
3030 the number 5 (words) in the higher niblle of the TCP-offset byte. */
\r
3031 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
\r
3033 prvCheckOptions( pxSocket, pxNetworkBuffer );
\r
3037 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3039 pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
\r
3040 pxSocket->u.xTCP.ulWindowSize =
\r
3041 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
\r
3045 /* In prvTCPHandleState() the incoming messages will be handled
\r
3046 depending on the current state of the connection. */
\r
3047 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
\r
3049 /* prvTCPHandleState() has sent a message, see if there are more to
\r
3050 be transmitted. */
\r
3051 #if( ipconfigUSE_TCP_WIN == 1 )
\r
3053 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
\r
3055 #endif /* ipconfigUSE_TCP_WIN */
\r
3058 if( pxNetworkBuffer != NULL )
\r
3060 /* We must check if the buffer is unequal to NULL, because the
\r
3061 socket might keep a reference to it in case a delayed ACK must be
\r
3063 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
3064 pxNetworkBuffer = NULL;
\r
3067 /* And finally, calculate when this socket wants to be woken up. */
\r
3068 prvTCPNextTimeout ( pxSocket );
\r
3069 /* Return pdPASS to tell that the network buffer is 'consumed'. */
\r
3073 /* pdPASS being returned means the buffer has been consumed. */
\r
3076 /*-----------------------------------------------------------*/
\r
3078 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
3080 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
3081 FreeRTOS_Socket_t *pxReturn = NULL;
\r
3082 uint32_t ulInitialSequenceNumber;
\r
3084 /* Assume that a new Initial Sequence Number will be required. Request
\r
3085 it now in order to fail out if necessary. */
\r
3086 ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
\r
3087 pxSocket->usLocalPort,
\r
3088 pxTCPPacket->xIPHeader.ulSourceIPAddress,
\r
3089 pxTCPPacket->xTCPHeader.usSourcePort );
\r
3091 /* A pure SYN (without ACK) has come in, create a new socket to answer
\r
3093 if( 0 != ulInitialSequenceNumber )
\r
3095 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
\r
3097 /* The flag bReuseSocket indicates that the same instance of the
\r
3098 listening socket should be used for the connection. */
\r
3099 pxReturn = pxSocket;
\r
3100 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3101 pxSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3105 /* The socket does not have the bReuseSocket flag set meaning create a
\r
3106 new socket when a connection comes in. */
\r
3109 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
\r
3111 FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
\r
3112 pxSocket->usLocalPort,
\r
3113 pxSocket->u.xTCP.usChildCount,
\r
3114 pxSocket->u.xTCP.usBacklog,
\r
3115 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
\r
3116 prvTCPSendReset( pxNetworkBuffer );
\r
3120 FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * )
\r
3121 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
3123 if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
\r
3125 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
\r
3126 prvTCPSendReset( pxNetworkBuffer );
\r
3128 else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
\r
3130 /* The socket will be connected immediately, no time for the
\r
3131 owner to setsockopt's, therefore copy properties of the server
\r
3132 socket to the new socket. Only the binding might fail (due to
\r
3133 lack of resources). */
\r
3134 pxReturn = pxNewSocket;
\r
3140 if( ( 0 != ulInitialSequenceNumber ) && ( pxReturn != NULL ) )
\r
3142 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
\r
3143 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
\r
3144 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
\r
3146 /* Here is the SYN action. */
\r
3147 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
\r
3148 prvSocketSetMSS( pxReturn );
\r
3150 prvTCPCreateWindow( pxReturn );
\r
3152 vTCPStateChange( pxReturn, eSYN_FIRST );
\r
3154 /* Make a copy of the header up to the TCP header. It is needed later
\r
3155 on, whenever data must be sent to the peer. */
\r
3156 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
\r
3160 /*-----------------------------------------------------------*/
\r
3163 * Duplicates a socket after a listening socket receives a connection.
\r
3165 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
\r
3167 struct freertos_sockaddr xAddress;
\r
3169 pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
\r
3170 pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
\r
3171 pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
\r
3172 pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
\r
3173 pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
\r
3174 pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
\r
3175 pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
\r
3176 pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
\r
3177 pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
\r
3179 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
\r
3181 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
\r
3183 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
\r
3185 #if( ipconfigUSE_CALLBACKS == 1 )
\r
3187 /* In case call-backs are used, copy them from parent to child. */
\r
3188 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
\r
3189 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
\r
3190 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
\r
3192 #endif /* ipconfigUSE_CALLBACKS */
\r
3194 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
3196 /* Child socket of listening sockets will inherit the Socket Set
\r
3197 Otherwise the owner has no chance of including it into the set. */
\r
3198 if( pxSocket->pxSocketSet )
\r
3200 pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
\r
3201 pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
\r
3204 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
3206 /* And bind it to the same local port as its parent. */
\r
3207 xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
\r
3208 xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3210 #if( ipconfigTCP_HANG_PROTECTION == 1 )
\r
3212 /* Only when there is anti-hanging protection, a socket may become an
\r
3213 orphan temporarily. Once this socket is really connected, the owner of
\r
3214 the server socket will be notified. */
\r
3216 /* When bPassQueued is true, the socket is an orphan until it gets
\r
3218 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
\r
3219 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
\r
3223 /* A reference to the new socket may be stored and the socket is marked
\r
3226 /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to
\r
3228 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
\r
3229 if(pxSocket->u.xTCP.pxPeerSocket == NULL )
\r
3231 pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
\r
3236 pxSocket->u.xTCP.usChildCount++;
\r
3238 FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
\r
3239 pxSocket->usLocalPort,
\r
3240 pxSocket->u.xTCP.usChildCount,
\r
3241 pxSocket->u.xTCP.usBacklog,
\r
3242 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
\r
3244 /* Now bind the child socket to the same port as the listening socket. */
\r
3245 if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
\r
3247 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
\r
3248 vSocketClose( pxNewSocket );
\r
3254 /*-----------------------------------------------------------*/
\r
3256 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
\r
3258 const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
\r
3260 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
\r
3262 ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
\r
3264 return pcStateNames[ ulState ];
\r
3267 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
\r
3268 /*-----------------------------------------------------------*/
\r
3271 * In the API accept(), the user asks is there is a new client? As API's can
\r
3272 * not walk through the xBoundTCPSocketsList the IP-task will do this.
\r
3274 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
\r
3276 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
\r
3277 ListItem_t *pxIterator;
\r
3278 FreeRTOS_Socket_t *pxFound;
\r
3279 BaseType_t xResult = pdFALSE;
\r
3281 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
\r
3282 who has access. */
\r
3283 for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
\r
3284 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
\r
3285 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
3287 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
\r
3289 pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
3290 if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
\r
3292 pxSocket->u.xTCP.pxPeerSocket = pxFound;
\r
3293 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
\r
3301 /*-----------------------------------------------------------*/
\r
3303 #endif /* ipconfigUSE_TCP == 1 */
\r
3305 /* Provide access to private members for testing. */
\r
3306 #ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS
\r
3307 #include "aws_freertos_tcp_test_access_tcp_define.h"
\r