in FreeRTOS_TCP_IP.c [3266:3453]
static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer )
{
/* Map the buffer onto the ProtocolHeader_t struct for easy access to the fields. */
ProtocolHeaders_t * pxProtocolHeaders = ipCAST_PTR_TO_TYPE_PTR( ProtocolHeaders_t,
&( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( *ppxNetworkBuffer ) ] ) );
TCPHeader_t * pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
BaseType_t xSendLength = 0;
uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
uint8_t * pucRecvData;
uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
/* uxOptionsLength: the size of the options to be sent (always a multiple of
* 4 bytes)
* 1. in the SYN phase, we shall communicate the MSS
* 2. in case of a SACK, Selective ACK, ack a segment which comes in
* out-of-order. */
UBaseType_t uxOptionsLength = 0U;
uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
UBaseType_t uxIntermediateResult = 0;
uint32_t ulSum;
/* First get the length and the position of the received data, if any.
* pucRecvData will point to the first byte of the TCP payload. */
ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
if( pxSocket->u.xTCP.ucTCPState >= ( uint8_t ) eESTABLISHED )
{
if( pxTCPWindow->rx.ulCurrentSequenceNumber == ( ulSequenceNumber + 1U ) )
{
/* This is most probably a keep-alive message from peer. Setting
* 'bWinChange' doesn't cause a window-size-change, the flag is used
* here to force sending an immediate ACK. */
pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
}
}
/* Keep track of the highest sequence number that might be expected within
* this connection. */
ulSum = ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber;
if( ( ( int32_t ) ulSum ) > 0 )
{
pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
}
/* Storing data may result in a fatal error if malloc() fails. */
if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
{
xSendLength = -1;
}
else
{
eIPTCPState_t eState;
uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
if( ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eSYN_RECEIVED ) && ( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_CTRL ) == ( uint8_t ) tcpTCP_FLAG_SYN ) )
{
FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
/* In eSYN_RECEIVED a simple ACK is expected, but apparently the
* 'SYN+ACK' didn't arrive. Step back to the previous state in which
* a first incoming SYN is handled. The SYN was counted already so
* decrease it first. */
vTCPStateChange( pxSocket, eSYN_FIRST );
}
if( ( ( ucTCPFlags & tcpTCP_FLAG_FIN ) != 0U ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
{
/* It's the first time a FIN has been received, remember its
* sequence number. */
pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
/* Was peer the first one to send a FIN? */
if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
{
/* If so, don't send the-last-ACK. */
pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
}
}
eState = pxSocket->u.xTCP.ucTCPState;
switch( eState )
{
case eCLOSED: /* (server + client) no connection state at all. */
/* Nothing to do for a closed socket, except waiting for the
* owner. */
break;
case eTCP_LISTEN: /* (server) waiting for a connection request from
* any remote TCP and port. */
/* The listen state was handled in xProcessReceivedTCPPacket().
* Should not come here. */
break;
case eSYN_FIRST: /* (server) Just received a SYN request for a server
* socket. */
/* A new socket has been created, reply with a SYN+ACK.
* Acknowledge with seq+1 because the SYN is seen as pseudo data
* with len = 1. */
uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPHeader );
pxTCPHeader->ucTCPFlags = ( uint8_t ) tcpTCP_FLAG_SYN | ( uint8_t ) tcpTCP_FLAG_ACK;
uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
xSendLength = ( BaseType_t ) uxIntermediateResult;
/* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
* uxOptionsLength is a multiple of 4. The complete expression is:
* ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
vTCPStateChange( pxSocket, eSYN_RECEIVED );
pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1U;
pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber + 1U;
pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1U;
pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1U; /* because we send a TCP_SYN. */
break;
case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
* SYN, expect a SYN+ACK and send a ACK now. */
/* Fall through */
case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
* expect a ACK and do nothing. */
xSendLength = prvHandleSynReceived( pxSocket, *( ppxNetworkBuffer ), ulReceiveLength, uxOptionsLength );
break;
case eESTABLISHED: /* (server + client) an open connection, data
* received can be delivered to the user. The normal
* state for the data transfer phase of the connection
* The closing states are also handled here with the
* use of some flags. */
xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
break;
case eLAST_ACK: /* (server + client) waiting for an acknowledgement
* of the connection termination request previously
* sent to the remote TCP (which includes an
* acknowledgement of its connection termination
* request). */
/* Fall through */
case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
* or an acknowledgement of the connection termination request previously sent. */
/* Fall through */
case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
break;
case eCLOSE_WAIT: /* (server + client) waiting for a connection
* termination request from the local user. Nothing to
* do, connection is closed, wait for owner to close
* this socket. */
break;
case eCLOSING: /* (server + client) waiting for a connection
* termination request acknowledgement from the remote
* TCP. */
break;
case eTIME_WAIT: /* (either server or client) waiting for enough time
* to pass to be sure the remote TCP received the
* acknowledgement of its connection termination
* request. [According to RFC 793 a connection can stay
* in TIME-WAIT for a maximum of four minutes known as
* a MSL (maximum segment lifetime).] These states are
* implemented implicitly by settings flags like
* 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
break;
default:
/* No more known states. */
break;
}
}
if( xSendLength > 0 )
{
xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
}
return xSendLength;
}