in device_firmware/libraries/freertos_plus/standard/freertos_plus_tcp/source/FreeRTOS_TCP_IP.c [690:957]
static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
{
TCPPacket_t * pxTCPPacket;
IPHeader_t *pxIPHeader;
EthernetHeader_t *pxEthernetHeader;
uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
TCPWindow_t *pxTCPWindow;
NetworkBufferDescriptor_t xTempBuffer;
/* For sending, a pseudo network buffer will be used, as explained above. */
if( pxNetworkBuffer == NULL )
{
pxNetworkBuffer = &xTempBuffer;
#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
{
xTempBuffer.pxNextBuffer = NULL;
}
#endif
xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
xReleaseAfterSend = pdFALSE;
}
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
if( xReleaseAfterSend == pdFALSE )
{
pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
if( pxNetworkBuffer == NULL )
{
FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
}
xReleaseAfterSend = pdTRUE;
}
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
if( pxNetworkBuffer != NULL )
{
pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
pxIPHeader = &pxTCPPacket->xIPHeader;
pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
/* Fill the packet, using hton translations. */
if( pxSocket != NULL )
{
/* Calculate the space in the RX buffer in order to advertise the
size of this socket's reception window. */
pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
if( pxSocket->u.xTCP.rxStream != NULL )
{
/* An RX stream was created already, see how much space is
available. */
ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
}
else
{
/* No RX stream has been created, the full stream size is
available. */
ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
}
/* Take the minimum of the RX buffer space and the RX window size. */
ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace );
if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
{
/* The low-water mark was reached, meaning there was little
space left. The socket will wait until the application has read
or flushed the incoming data, and 'zero-window' will be
advertised. */
ulSpace = 0u;
}
/* If possible, advertise an RX window size of at least 1 MSS, otherwise
the peer might start 'zero window probing', i.e. sending small packets
(1, 2, 4, 8... bytes). */
if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
{
ulSpace = pxSocket->u.xTCP.usCurMSS;
}
/* Avoid overflow of the 16-bit win field. */
#if( ipconfigUSE_TCP_WIN != 0 )
{
ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
}
#else
{
ulWinSize = ulSpace;
}
#endif
if( ulWinSize > 0xfffcUL )
{
ulWinSize = 0xfffcUL;
}
pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
#if( ipconfigHAS_DEBUG_PRINTF != 0 )
{
if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
{
if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
{
size_t uxFrontSpace;
if(pxSocket->u.xTCP.rxStream != NULL)
{
uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
}
else
{
uxFrontSpace = 0u;
}
FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
pxSocket->u.xTCP.ulRemoteIP,
pxSocket->u.xTCP.usRemotePort,
pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
(int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
}
}
}
#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
/* The new window size has been advertised, switch off the flag. */
pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
/* Later on, when deciding to delay an ACK, a precise estimate is needed
of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
highest sequence number minus 1 that the socket will accept. */
pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
#if( ipconfigTCP_KEEP_ALIVE == 1 )
if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
{
/* Sending a keep-alive packet, send the current sequence number
minus 1, which will be recognised as a keep-alive packet an
responded to by acknowledging the last byte. */
pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
}
else
#endif
{
pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
{
/* Suppress FIN in case this packet carries earlier data to be
retransmitted. */
uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
{
pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
ulDataLen,
pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
}
}
}
/* Tell which sequence number is expected next time */
pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
}
else
{
/* Sending data without a socket, probably replying with a RST flag
Just swap the two sequence numbers. */
vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
}
pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
pxIPHeader->usLength = FreeRTOS_htons( ulLen );
if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
{
/* When pxSocket is NULL, this function is called by prvTCPSendReset()
and the IP-addresses must be swapped.
Also swap the IP-addresses in case the IP-tack doesn't have an
IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
}
else
{
ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
}
pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
pxIPHeader->ulSourceIPAddress = ulSourceAddress;
vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
/* Just an increasing number. */
pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
usPacketIdentifier++;
pxIPHeader->usFragmentOffset = 0u;
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
/* calculate the IP header checksum, in case the driver won't do that. */
pxIPHeader->usHeaderChecksum = 0x00u;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* calculate the TCP checksum for an outgoing packet. */
usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
/* A calculated checksum of 0 must be inverted as 0 means the checksum
is disabled. */
if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
{
pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
}
}
#endif
#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
pxNetworkBuffer->pxNextBuffer = NULL;
#endif
/* Important: tell NIC driver how many bytes must be sent. */
pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
/* Fill in the destination MAC addresses. */
memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
sizeof( pxEthernetHeader->xDestinationAddress ) );
/* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
BaseType_t xIndex;
for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
{
pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
}
pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
}
}
#endif
/* Send! */
xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
if( xReleaseAfterSend == pdFALSE )
{
/* Swap-back some fields, as pxBuffer probably points to a socket field
containing the packet header. */
vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
}
else
{
/* Nothing to do: the buffer has been passed to DMA and will be released after use */
}
} /* if( pxNetworkBuffer != NULL ) */
}