mirror of
https://github.com/FreeRTOS/FreeRTOS-Plus-TCP
synced 2025-10-22 07:51:40 +08:00

* updating doxygen config * fixing doxygen comments * adding IPv6 files and fixing comments * fix doxygen cfg and file names in comments * wip doxygen v6 docs * adding doxygen comments * include RA src file to doxgendocs generation * fix spell check issues * Uncrustify: triggered by comment. * fix minor build issue * fix spell check issues * Uncrustify: triggered by comment * fix trailing white space * Dev integration hein.v8 (#738) * Updating tcp utilities * Some more change in dev_integration_hein.v8 * In FreeRTOS_DNS_Parser.c : use 'ipUDP_PAYLOAD_OFFSET_IPv4' in stead of 'ipIP_PAYLOAD_OFFSET' * And a few more corrections * Changes to WinPCap network interface, removed debugging code * After applying uncrustify * Oops, I forgot the push changes in include files. * Now removing it, hopefully --------- Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com> Co-authored-by: Monika Singh <108652024+moninom1@users.noreply.github.com> * Fix CBMC proofs for DNS (#718) * Use CBMC XML output to enable VSCode debugger (#673) Prior to this commit, CBMC would emit logging information in plain text format, which does not contain information required for the CBMC VSCode debugger. This commit makes CBMC use XML instead of plain text. Co-authored-by: Mark Tuttle <tuttle@acm.org> * wip * wip DNSgetHostByName * wip DNSgetHostByName * fixed cbmc proof for DNS_ReadNameField * wip DNSgetHostByName_a_harness * Fix CBMC prooff for DNSgetHostByName * wip fix DNSgetHostByName_a CBMC proof * fixed cbmc target func not called issue in DNSclear * fixed cbmc target func not called issue in DNSlookup * fix DNSgetHostByName_a CBMC proof * update comments * more asserts * fixing formatting * updating as per review comments * fix dns after review comments * adding more asserts * adds more asserts * minor fix * fixing comments * fixing comments * fixing minor issue * fixing DNS_ReadReply() signature * making code more consistant * adding more asserts * making code more consistent --------- Co-authored-by: Kareem Khazem <karkhaz@amazon.com> Co-authored-by: Mark Tuttle <tuttle@acm.org> * Uncrustify: triggered by comment * fixing formatting --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Hein Tibosch <hein_tibosch@yahoo.es> Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com> Co-authored-by: Monika Singh <108652024+moninom1@users.noreply.github.com> Co-authored-by: Kareem Khazem <karkhaz@amazon.com> Co-authored-by: Mark Tuttle <tuttle@acm.org>
1332 lines
59 KiB
C
1332 lines
59 KiB
C
/*
|
|
* FreeRTOS+TCP <DEVELOPMENT BRANCH>
|
|
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* http://aws.amazon.com/freertos
|
|
* http://www.FreeRTOS.org
|
|
*/
|
|
|
|
/**
|
|
* @file FreeRTOS_TCP_Transmission.c
|
|
* @brief Module which prepares the packet to be sent through
|
|
* a socket for FreeRTOS+TCP.
|
|
* It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
|
|
* schemes.
|
|
*
|
|
* Endianness: in this module all ports and IP addresses are stored in
|
|
* host byte-order, except fields in the IP-packets
|
|
*/
|
|
|
|
/* Standard includes. */
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "semphr.h"
|
|
|
|
/* FreeRTOS+TCP includes. */
|
|
#include "FreeRTOS_IP.h"
|
|
#include "FreeRTOS_Sockets.h"
|
|
#include "FreeRTOS_IP_Private.h"
|
|
#include "NetworkInterface.h"
|
|
#include "NetworkBufferManagement.h"
|
|
#include "FreeRTOS_ARP.h"
|
|
#include "FreeRTOSIPConfigDefaults.h"
|
|
|
|
#include "FreeRTOS_TCP_IP.h"
|
|
#include "FreeRTOS_TCP_Reception.h"
|
|
#include "FreeRTOS_TCP_Transmission.h"
|
|
#include "FreeRTOS_TCP_State_Handling.h"
|
|
#include "FreeRTOS_TCP_Utils.h"
|
|
|
|
/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
|
|
#if ipconfigUSE_TCP == 1
|
|
|
|
/*
|
|
* Let ARP look-up the MAC-address of the peer and initialise the first SYN
|
|
* packet.
|
|
*/
|
|
static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t * pxSocket );
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Check if the outgoing connection is already prepared, if not
|
|
* call prvTCPPrepareConnect() to continue the preparation.
|
|
* @param[in] pxSocket: The socket that wants to connect.
|
|
* @return Returns pdTRUE if the connection is prepared, i.e. the MAC-
|
|
* address of the peer is already known. */
|
|
static BaseType_t prvTCPMakeSurePrepared( FreeRTOS_Socket_t * pxSocket )
|
|
{
|
|
BaseType_t xReturn = pdTRUE;
|
|
|
|
if( pxSocket->u.xTCP.bits.bConnPrepared == pdFALSE_UNSIGNED )
|
|
{
|
|
if( prvTCPPrepareConnect( pxSocket ) != pdTRUE )
|
|
{
|
|
/* The preparation of a connection ( ARP resolution ) is not yet ready. */
|
|
xReturn = pdFALSE;
|
|
}
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief prvTCPSendPacket() will be called when the socket time-out has been reached.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the connection.
|
|
*
|
|
* @return Number of bytes to be sent.
|
|
*
|
|
* @note It is only called by xTCPSocketCheck().
|
|
*/
|
|
int32_t prvTCPSendPacket( FreeRTOS_Socket_t * pxSocket )
|
|
{
|
|
int32_t lResult = 0;
|
|
UBaseType_t uxOptionsLength, uxIntermediateResult = 0;
|
|
NetworkBufferDescriptor_t * pxNetworkBuffer;
|
|
|
|
if( pxSocket->u.xTCP.eTCPState != eCONNECT_SYN )
|
|
{
|
|
/* The connection is in a state other than SYN. */
|
|
pxNetworkBuffer = NULL;
|
|
|
|
/* prvTCPSendRepeated() will only create a network buffer if necessary,
|
|
* i.e. when data must be sent to the peer. */
|
|
lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
|
|
|
|
if( pxNetworkBuffer != NULL )
|
|
{
|
|
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pxSocket->u.xTCP.ucRepCount >= 3U )
|
|
{
|
|
/* The connection is in the SYN status. The packet will be repeated
|
|
* to most 3 times. When there is no response, the socket get the
|
|
* status 'eCLOSE_WAIT'. */
|
|
FreeRTOS_debug_printf( ( "Connect: giving up %xip:%u\n",
|
|
( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, /* IP address of remote machine. */
|
|
pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
|
|
vTCPStateChange( pxSocket, eCLOSE_WAIT );
|
|
}
|
|
else if( prvTCPMakeSurePrepared( pxSocket ) == pdTRUE )
|
|
{
|
|
ProtocolHeaders_t * pxProtocolHeaders;
|
|
|
|
/* Or else, if the connection has been prepared, or can be prepared
|
|
* now, proceed to send the packet with the SYN flag.
|
|
* prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
|
|
* the Ethernet address of the peer or the gateway is found. */
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
|
|
|
|
/* About to send a SYN packet. Call prvSetSynAckOptions() to set
|
|
* the proper options: The size of MSS and whether SACK's are
|
|
* allowed. */
|
|
uxOptionsLength = prvSetSynAckOptions( pxSocket, &( pxProtocolHeaders->xTCPHeader ) );
|
|
|
|
/* Return the number of bytes to be sent. */
|
|
uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
|
|
lResult = ( int32_t ) uxIntermediateResult;
|
|
|
|
/* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
|
|
* uxOptionsLength is always a multiple of 4. The complete expression
|
|
* would be:
|
|
* ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
|
|
pxProtocolHeaders->xTCPHeader.ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
|
|
|
|
/* Repeat Count is used for a connecting socket, to limit the number
|
|
* of tries. */
|
|
pxSocket->u.xTCP.ucRepCount++;
|
|
|
|
/* Send the SYN message to make a connection. The messages is
|
|
* stored in the socket field 'xPacket'. It will be wrapped in a
|
|
* pseudo network buffer descriptor before it will be sent. */
|
|
prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
|
|
}
|
|
else
|
|
{
|
|
/* Nothing to do. */
|
|
}
|
|
}
|
|
|
|
/* Return the total number of bytes sent. */
|
|
return lResult;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief prvTCPSendRepeated will try to send a series of messages, as
|
|
* long as there is data to be sent and as long as the transmit
|
|
* window isn't full.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the connection.
|
|
* @param[in,out] ppxNetworkBuffer: Pointer to pointer to the network buffer.
|
|
*
|
|
* @return Total number of bytes sent.
|
|
*/
|
|
int32_t prvTCPSendRepeated( FreeRTOS_Socket_t * pxSocket,
|
|
NetworkBufferDescriptor_t ** ppxNetworkBuffer )
|
|
{
|
|
UBaseType_t uxIndex;
|
|
int32_t lResult = 0;
|
|
UBaseType_t uxOptionsLength = 0U;
|
|
int32_t xSendLength;
|
|
|
|
for( uxIndex = 0U; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
|
|
{
|
|
/* prvTCPPrepareSend() might allocate a network buffer if there is data
|
|
* to be sent. */
|
|
xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
|
|
|
|
if( xSendLength <= 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* And return the packet to the peer. */
|
|
prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
|
|
|
|
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
|
{
|
|
*ppxNetworkBuffer = NULL;
|
|
}
|
|
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
|
|
|
lResult += xSendLength;
|
|
}
|
|
|
|
/* Return the total number of bytes sent. */
|
|
return lResult;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Return (or send) a packet to the peer. The data is stored in pxBuffer,
|
|
* which may either point to a real network buffer or to a TCP socket field
|
|
* called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
|
|
* the data to the NIC.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the connection.
|
|
* @param[in] pxDescriptor: The network buffer descriptor carrying the packet.
|
|
* @param[in] ulLen: Length of the packet being sent.
|
|
* @param[in] xReleaseAfterSend: pdTRUE if the ownership of the descriptor is
|
|
* transferred to the network interface.
|
|
*/
|
|
void prvTCPReturnPacket( FreeRTOS_Socket_t * pxSocket,
|
|
NetworkBufferDescriptor_t * pxDescriptor,
|
|
uint32_t ulLen,
|
|
BaseType_t xReleaseAfterSend )
|
|
{
|
|
const NetworkBufferDescriptor_t * pxNetworkBuffer = pxDescriptor;
|
|
BaseType_t xIsIPv6 = pdFALSE;
|
|
|
|
if( pxNetworkBuffer != NULL )
|
|
{
|
|
if( uxIPHeaderSizePacket( pxNetworkBuffer ) == ipSIZE_OF_IPv6_HEADER )
|
|
{
|
|
xIsIPv6 = pdTRUE;
|
|
}
|
|
}
|
|
else if( pxSocket != NULL )
|
|
{
|
|
if( uxIPHeaderSizeSocket( pxSocket ) == ipSIZE_OF_IPv6_HEADER )
|
|
{
|
|
xIsIPv6 = pdTRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* prvTCPReturnPacket_IPVx() needs either a network buffer, or a socket. */
|
|
configASSERT( pdFALSE );
|
|
}
|
|
|
|
if( xIsIPv6 == pdTRUE )
|
|
{
|
|
prvTCPReturnPacket_IPV6( pxSocket, pxDescriptor, ulLen, xReleaseAfterSend );
|
|
}
|
|
else
|
|
{
|
|
prvTCPReturnPacket_IPV4( pxSocket, pxDescriptor, ulLen, xReleaseAfterSend );
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Called by prvTCPReturnPacket(), this function will set the the window
|
|
* size on this side: 'xTCPHeader.usWindow'.
|
|
* @param[in] pxSocket: The socket on which the packet is being sent.
|
|
* @param[in] pxNetworkBuffer: The network buffer carrying the outgoing message.
|
|
* @param[in] uxIPHeaderSize: The size of the IP-header, which depends on the IP-type.
|
|
*/
|
|
void prvTCPReturn_CheckTCPWindow( FreeRTOS_Socket_t * pxSocket,
|
|
const NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
size_t uxIPHeaderSize )
|
|
{
|
|
/* Calculate the space in the RX buffer in order to advertise the
|
|
* size of this socket's reception window. */
|
|
const TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
|
|
uint32_t ulFrontSpace, ulSpace, ulWinSize;
|
|
ProtocolHeaders_t * pxProtocolHeaders;
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxProtocolHeaders = ( ( ProtocolHeaders_t * )
|
|
&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSize ] ) );
|
|
|
|
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.usMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usMSS ) )
|
|
{
|
|
ulSpace = pxSocket->u.xTCP.usMSS;
|
|
}
|
|
|
|
/* 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 > 0xfffcU )
|
|
{
|
|
ulWinSize = 0xfffcU;
|
|
}
|
|
|
|
pxProtocolHeaders->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
|
|
|
|
/* 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;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Called by prvTCPReturnPacket(), this function sets the sequence and ack numbers
|
|
* in the TCP-header.
|
|
* @param[in] pxSocket: The socket on which the packet is being sent.
|
|
* @param[in] pxNetworkBuffer: The network buffer carrying the outgoing message.
|
|
* @param[in] uxIPHeaderSize: The size of the IP-header, which depends on the IP-type.
|
|
* @param[in] ulLen: The size of the packet minus the size of the Ethernet header.
|
|
*
|
|
*/
|
|
void prvTCPReturn_SetSequenceNumber( FreeRTOS_Socket_t * pxSocket,
|
|
const NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
size_t uxIPHeaderSize,
|
|
uint32_t ulLen )
|
|
{
|
|
ProtocolHeaders_t * pxProtocolHeaders;
|
|
const TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxProtocolHeaders = ( ( ProtocolHeaders_t * )
|
|
&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSize ] ) );
|
|
#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 and
|
|
* responded to by acknowledging the last byte. */
|
|
pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
|
|
pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
|
|
|
|
pxProtocolHeaders->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1U;
|
|
pxProtocolHeaders->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxProtocolHeaders->xTCPHeader.ulSequenceNumber );
|
|
}
|
|
else
|
|
#endif /* if ( ipconfigTCP_KEEP_ALIVE == 1 ) */
|
|
{
|
|
pxProtocolHeaders->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
|
|
|
|
if( ( pxProtocolHeaders->xTCPHeader.ucTCPFlags & ( uint8_t ) tcpTCP_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 + uxIPHeaderSizeSocket( pxSocket ) ) );
|
|
|
|
if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
|
|
{
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~tcpTCP_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 */
|
|
pxProtocolHeaders->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Create the TCP window for the given socket.
|
|
*
|
|
* @param[in] pxSocket: The socket for which the window is being created.
|
|
*
|
|
* @note The SYN event is very important: the sequence numbers, which have a kind of
|
|
* random starting value, are being synchronized. The sliding window manager
|
|
* (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
|
|
* Size (MSS).
|
|
*/
|
|
void prvTCPCreateWindow( FreeRTOS_Socket_t * pxSocket )
|
|
{
|
|
uint32_t ulRxWindowSize = ( uint32_t ) pxSocket->u.xTCP.uxRxWinSize;
|
|
uint32_t ulTxWindowSize = ( uint32_t ) pxSocket->u.xTCP.uxTxWinSize;
|
|
|
|
if( xTCPWindowLoggingLevel != 0 )
|
|
{
|
|
FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %u Water %u <= %u <= %u\n",
|
|
( unsigned ) ( pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS ),
|
|
( unsigned ) pxSocket->u.xTCP.uxLittleSpace,
|
|
( unsigned ) pxSocket->u.xTCP.uxEnoughSpace,
|
|
( unsigned ) pxSocket->u.xTCP.uxRxStreamSize ) );
|
|
}
|
|
|
|
vTCPWindowCreate(
|
|
&pxSocket->u.xTCP.xTCPWindow,
|
|
ulRxWindowSize * ipconfigTCP_MSS,
|
|
ulTxWindowSize * ipconfigTCP_MSS,
|
|
pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
|
|
pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
|
|
( uint32_t ) pxSocket->u.xTCP.usMSS );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Let ARP look-up the MAC-address of the peer and initialise the first SYN
|
|
* packet.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the TCP connection. The first packet shall
|
|
* be created in this socket.
|
|
*
|
|
* @return pdTRUE: if the packet was successfully created and the first SYN can be sent.
|
|
* Else pdFALSE.
|
|
*
|
|
* @note Connecting sockets have a special state: eCONNECT_SYN. In this phase,
|
|
* the Ethernet address of the target will be found using ARP. In case the
|
|
* target IP address is not within the netmask, the hardware address of the
|
|
* gateway will be used.
|
|
*/
|
|
static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t * pxSocket )
|
|
{
|
|
BaseType_t xReturn = pdTRUE;
|
|
|
|
if( pxSocket->bits.bIsIPv6 != pdFALSE_UNSIGNED )
|
|
{
|
|
xReturn = prvTCPPrepareConnect_IPV6( pxSocket );
|
|
}
|
|
else
|
|
{
|
|
xReturn = prvTCPPrepareConnect_IPV4( pxSocket );
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#if ( ipconfigUSE_TCP_WIN != 0 )
|
|
|
|
/**
|
|
* @brief Get the window scaling factor for the TCP connection.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the TCP connection.
|
|
*
|
|
* @return The scaling factor.
|
|
*/
|
|
static uint8_t prvWinScaleFactor( const FreeRTOS_Socket_t * pxSocket )
|
|
{
|
|
size_t uxWinSize;
|
|
uint8_t ucFactor;
|
|
|
|
|
|
/* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
|
|
uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usMSS;
|
|
ucFactor = 0U;
|
|
|
|
while( uxWinSize > 0xffffU )
|
|
{
|
|
/* Divide by two and increase the binary factor by 1. */
|
|
uxWinSize >>= 1;
|
|
ucFactor++;
|
|
}
|
|
|
|
FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %u MSS %u Factor %u\n",
|
|
( unsigned ) pxSocket->u.xTCP.uxRxWinSize,
|
|
pxSocket->u.xTCP.usMSS,
|
|
ucFactor ) );
|
|
|
|
return ucFactor;
|
|
}
|
|
|
|
#endif /* if ( ipconfigUSE_TCP_WIN != 0 ) */
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief When opening a TCP connection, while SYN's are being sent, the parties may
|
|
* communicate what MSS (Maximum Segment Size) they intend to use, whether Selective
|
|
* ACK's ( SACK ) are supported, and the size of the reception window ( WSOPT ).
|
|
*
|
|
* @param[in] pxSocket: The socket being used for communication. It is used to set
|
|
* the MSS.
|
|
* @param[in,out] pxTCPHeader: The TCP packet header being used in the SYN transmission.
|
|
* The MSS and corresponding options shall be set in this
|
|
* header itself.
|
|
*
|
|
* @return The option length after the TCP header was updated.
|
|
*
|
|
* @note MSS is the net size of the payload, an is always smaller than MTU.
|
|
*/
|
|
UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t * pxSocket,
|
|
TCPHeader_t * pxTCPHeader )
|
|
{
|
|
uint16_t usMSS = pxSocket->u.xTCP.usMSS;
|
|
UBaseType_t uxOptionsLength;
|
|
|
|
/* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
|
|
|
|
pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) tcpTCP_OPT_MSS;
|
|
pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) tcpTCP_OPT_MSS_LEN;
|
|
pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
|
|
pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffU );
|
|
|
|
#if ( ipconfigUSE_TCP_WIN != 0 )
|
|
{
|
|
pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
|
|
|
|
pxTCPHeader->ucOptdata[ 4 ] = tcpTCP_OPT_NOOP;
|
|
pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( tcpTCP_OPT_WSOPT );
|
|
pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( tcpTCP_OPT_WSOPT_LEN );
|
|
pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
|
|
uxOptionsLength = 8U;
|
|
}
|
|
#else
|
|
{
|
|
uxOptionsLength = 4U;
|
|
}
|
|
#endif /* if ( ipconfigUSE_TCP_WIN != 0 ) */
|
|
|
|
#if ( ipconfigUSE_TCP_WIN != 0 )
|
|
{
|
|
pxTCPHeader->ucOptdata[ uxOptionsLength ] = tcpTCP_OPT_NOOP;
|
|
pxTCPHeader->ucOptdata[ uxOptionsLength + 1U ] = tcpTCP_OPT_NOOP;
|
|
pxTCPHeader->ucOptdata[ uxOptionsLength + 2U ] = tcpTCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
|
|
pxTCPHeader->ucOptdata[ uxOptionsLength + 3U ] = 2U; /* 2: length of this option. */
|
|
uxOptionsLength += 4U;
|
|
}
|
|
#endif /* ipconfigUSE_TCP_WIN == 0 */
|
|
return uxOptionsLength; /* bytes, not words. */
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the size of a network buffer is big enough to hold the outgoing message.
|
|
* Allocate a new bigger network buffer when necessary.
|
|
*
|
|
* @param[in] pxSocket: Socket whose buffer is being resized.
|
|
* @param[in] pxNetworkBuffer: The network buffer whose size is being increased.
|
|
* @param[in] lDataLen: Length of the data to be put in the buffer.
|
|
* @param[in] uxOptionsLength: Length of options.
|
|
*
|
|
* @return If the resizing is successful: The new buffer with the size being asked for
|
|
* with old data copied in it.
|
|
* Else, NULL.
|
|
*
|
|
* @note The old network buffer will be released if the resizing is successful and
|
|
* cannot be used any longer.
|
|
*/
|
|
NetworkBufferDescriptor_t * prvTCPBufferResize( const FreeRTOS_Socket_t * pxSocket,
|
|
NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
int32_t lDataLen,
|
|
UBaseType_t uxOptionsLength )
|
|
{
|
|
NetworkBufferDescriptor_t * pxReturn;
|
|
size_t uxNeeded;
|
|
BaseType_t xResize;
|
|
|
|
if( xBufferAllocFixedSize != pdFALSE )
|
|
{
|
|
/* Network buffers are created with a fixed size and can hold the largest
|
|
* MTU. */
|
|
uxNeeded = ( size_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
|
|
|
|
/* and therefore, the buffer won't be too small.
|
|
* Only ask for a new network buffer in case none was supplied. */
|
|
if( pxNetworkBuffer == NULL )
|
|
{
|
|
xResize = pdTRUE;
|
|
}
|
|
else
|
|
{
|
|
xResize = pdFALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Network buffers are created with a variable size. See if it must
|
|
* grow. */
|
|
uxNeeded = ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
|
|
uxNeeded += ( size_t ) lDataLen;
|
|
|
|
if( uxNeeded < sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) )
|
|
{
|
|
uxNeeded = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
|
|
}
|
|
|
|
/* In case we were called from a TCP timer event, a buffer must be
|
|
* created. Otherwise, test 'xDataLength' of the provided buffer. */
|
|
if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < uxNeeded ) )
|
|
{
|
|
xResize = pdTRUE;
|
|
}
|
|
else
|
|
{
|
|
xResize = pdFALSE;
|
|
}
|
|
}
|
|
|
|
if( xResize != pdFALSE )
|
|
{
|
|
/* The caller didn't provide a network buffer or the provided buffer is
|
|
* too small. As we must send-out a data packet, a buffer will be created
|
|
* here. */
|
|
pxReturn = pxGetNetworkBufferWithDescriptor( uxNeeded, 0U );
|
|
|
|
if( pxReturn != NULL )
|
|
{
|
|
/* Set the actual packet size, in case the returned buffer is larger. */
|
|
pxReturn->xDataLength = uxNeeded;
|
|
|
|
/* Copy the existing data to the new created buffer. */
|
|
if( pxNetworkBuffer != NULL )
|
|
{
|
|
/* Either from the previous buffer... */
|
|
( void ) memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
|
|
|
|
/* ...and release it. */
|
|
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
|
}
|
|
else
|
|
{
|
|
/* Or from the socket field 'xTCP.xPacket'. */
|
|
( void ) memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* xResize is false, the network buffer provided was big enough. */
|
|
configASSERT( pxNetworkBuffer != NULL ); /* LCOV_EXCL_BR_LINE this branch will not be covered, since it would never be NULL. to tell lint: when xResize is false, pxNetworkBuffer is not NULL. */
|
|
pxReturn = pxNetworkBuffer;
|
|
|
|
pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
|
|
}
|
|
|
|
return pxReturn;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Called by prvTCPReturnPacket(), this function makes sure that the network buffer
|
|
* has 'pxEndPoint' set properly.
|
|
* @param[in] pxSocket: The socket on which the packet is being sent.
|
|
* @param[in] pxNetworkBuffer: The network buffer carrying the outgoing message.
|
|
* @param[in] uxIPHeaderSize: The size of the IP-header, which depends on the IP-type.
|
|
*/
|
|
void prvTCPReturn_SetEndPoint( const FreeRTOS_Socket_t * pxSocket,
|
|
NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
size_t uxIPHeaderSize )
|
|
{
|
|
const IPHeader_t * pxIPHeader = NULL;
|
|
|
|
#if ( ipconfigUSE_IPv6 != 0 )
|
|
const IPHeader_IPv6_t * pxIPHeader_IPv6 = NULL;
|
|
#endif
|
|
|
|
if( ( pxSocket != NULL ) && ( pxSocket->pxEndPoint != NULL ) )
|
|
{
|
|
pxNetworkBuffer->pxEndPoint = pxSocket->pxEndPoint;
|
|
}
|
|
else
|
|
{
|
|
FreeRTOS_printf( ( "prvTCPReturnPacket: No pxEndPoint yet?\n" ) );
|
|
|
|
if( uxIPHeaderSize == ipSIZE_OF_IPv6_HEADER )
|
|
{
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxIPHeader_IPv6 = ( ( IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
|
|
pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv6( &( pxIPHeader_IPv6->xDestinationAddress ) );
|
|
|
|
if( pxNetworkBuffer->pxEndPoint == NULL )
|
|
{
|
|
FreeRTOS_printf( ( "prvTCPReturnPacket: no such end-point %pip => %pip\n",
|
|
pxIPHeader_IPv6->xSourceAddress.ucBytes,
|
|
pxIPHeader_IPv6->xDestinationAddress.ucBytes ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*_RB_ Was FreeRTOS_FindEndPointOnIP_IPv4() but changed to FreeRTOS_FindEndPointOnNetMask()
|
|
* as it is using the destination address. I'm confused here as sometimes the addresses are swapped. */
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxIPHeader = ( ( IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
|
|
pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnNetMask( pxIPHeader->ulDestinationIPAddress, 8 );
|
|
|
|
if( pxNetworkBuffer->pxEndPoint == NULL )
|
|
{
|
|
FreeRTOS_printf( ( "prvTCPReturnPacket: no such end-point %lxip => %lxip\n",
|
|
FreeRTOS_ntohl( pxIPHeader->ulSourceIPAddress ),
|
|
FreeRTOS_ntohl( pxIPHeader->ulDestinationIPAddress ) ) );
|
|
}
|
|
}
|
|
|
|
if( pxNetworkBuffer->pxEndPoint != NULL )
|
|
{
|
|
FreeRTOS_printf( ( "prvTCPReturnPacket: packet's end-point %02x-%02x\n",
|
|
pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes[ 4 ],
|
|
pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes[ 5 ] ) );
|
|
}
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Prepare an outgoing message, in case anything has to be sent.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the connection.
|
|
* @param[in,out] ppxNetworkBuffer: Pointer to the pointer to the network buffer.
|
|
* @param[in] uxOptionsLength: The length of the TCP options.
|
|
*
|
|
* @return Length of the data to be sent if everything is correct. Else, -1
|
|
* is returned in case of any error.
|
|
*/
|
|
int32_t prvTCPPrepareSend( FreeRTOS_Socket_t * pxSocket,
|
|
NetworkBufferDescriptor_t ** ppxNetworkBuffer,
|
|
UBaseType_t uxOptionsLength )
|
|
{
|
|
int32_t lDataLen;
|
|
uint8_t * pucEthernetBuffer, * pucSendData;
|
|
ProtocolHeaders_t * pxProtocolHeaders;
|
|
size_t uxOffset;
|
|
uint32_t ulDataGot, ulDistance;
|
|
TCPWindow_t * pxTCPWindow;
|
|
NetworkBufferDescriptor_t * pxNewBuffer;
|
|
int32_t lStreamPos;
|
|
UBaseType_t uxIntermediateResult = 0;
|
|
|
|
if( ( *ppxNetworkBuffer ) != NULL )
|
|
{
|
|
/* A network buffer descriptor was already supplied */
|
|
pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
|
|
}
|
|
else
|
|
{
|
|
/* For now let it point to the last packet header */
|
|
pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
|
|
}
|
|
|
|
/* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
|
|
pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
|
|
lDataLen = 0;
|
|
lStreamPos = 0;
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_ACK;
|
|
|
|
if( pxSocket->u.xTCP.txStream != NULL )
|
|
{
|
|
/* ulTCPWindowTxGet will return the amount of data which may be sent
|
|
* along with the position in the txStream.
|
|
* Why check for MSS > 1 ?
|
|
* Because some TCP-stacks (like uIP) use it for flow-control. */
|
|
if( pxSocket->u.xTCP.usMSS > 1U )
|
|
{
|
|
lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
|
|
}
|
|
|
|
if( lDataLen > 0 )
|
|
{
|
|
/* Check if the current network buffer is big enough, if not,
|
|
* resize it. */
|
|
pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
|
|
|
|
if( pxNewBuffer != NULL )
|
|
{
|
|
*ppxNetworkBuffer = pxNewBuffer;
|
|
pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
|
|
|
|
/* Map the byte stream onto ProtocolHeaders_t struct for easy
|
|
* access to the fields. */
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
|
|
|
|
pucSendData = &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength ] );
|
|
|
|
/* Translate the position in txStream to an offset from the tail
|
|
* marker. */
|
|
uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
|
|
|
|
/* Here data is copied from the txStream in 'peek' mode. Only
|
|
* when the packets are acked, the tail marker will be updated. */
|
|
ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
|
|
|
|
#if ( ipconfigHAS_DEBUG_PRINTF != 0 )
|
|
{
|
|
if( ulDataGot != ( uint32_t ) lDataLen )
|
|
{
|
|
FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %d offs %u only %u != %d\n",
|
|
( int ) lStreamPos, ( unsigned ) uxOffset, ( unsigned ) ulDataGot, ( int ) lDataLen ) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* If the owner of the socket requests a closure, add the FIN
|
|
* flag to the last packet. */
|
|
if( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED )
|
|
{
|
|
ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
|
|
|
|
if( ulDistance == ulDataGot )
|
|
{
|
|
#if ( ipconfigHAS_DEBUG_PRINTF == 1 )
|
|
{
|
|
/* the order of volatile accesses is undefined
|
|
* so such workaround */
|
|
size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
|
|
size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
|
|
size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
|
|
|
|
FreeRTOS_debug_printf( ( "CheckClose %u <= %u (%u <= %u <= %u)\n",
|
|
( unsigned ) ulDataGot, ( unsigned ) ulDistance,
|
|
( unsigned ) uxTail, ( unsigned ) uxMid, ( unsigned ) uxHead ) );
|
|
}
|
|
#endif /* if ( ipconfigHAS_DEBUG_PRINTF == 1 ) */
|
|
|
|
/* Although the socket sends a FIN, it will stay in
|
|
* ESTABLISHED until all current data has been received or
|
|
* delivered. */
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_FIN;
|
|
pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
|
|
pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lDataLen = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.eTCPState == eESTABLISHED ) )
|
|
{
|
|
/* See if the socket owner wants to shutdown this connection. */
|
|
if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
|
|
( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
|
|
{
|
|
pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_FIN;
|
|
pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
|
|
pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
|
|
pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
|
|
vTCPStateChange( pxSocket, eFIN_WAIT_1 );
|
|
}
|
|
|
|
#if ( ipconfigTCP_KEEP_ALIVE != 0 )
|
|
{
|
|
if( pxSocket->u.xTCP.ucKeepRepCount > 3U ) /*_RB_ Magic number. */
|
|
{
|
|
FreeRTOS_debug_printf( ( "keep-alive: giving up %xip:%u\n",
|
|
( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, /* IP address of remote machine. */
|
|
pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
|
|
vTCPStateChange( pxSocket, eCLOSE_WAIT );
|
|
lDataLen = -1;
|
|
}
|
|
|
|
if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
|
|
{
|
|
/* If there is no data to be sent, and no window-update message,
|
|
* we might want to send a keep-alive message. */
|
|
TickType_t xAge = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
|
|
TickType_t xMax;
|
|
xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * ( TickType_t ) configTICK_RATE_HZ );
|
|
|
|
if( pxSocket->u.xTCP.ucKeepRepCount != 0U )
|
|
{
|
|
xMax = 3U * configTICK_RATE_HZ;
|
|
}
|
|
|
|
if( xAge > xMax )
|
|
{
|
|
pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
|
|
|
|
if( xTCPWindowLoggingLevel != 0 )
|
|
{
|
|
FreeRTOS_debug_printf( ( "keep-alive: %xip:%u count %u\n",
|
|
( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
|
|
pxSocket->u.xTCP.usRemotePort,
|
|
pxSocket->u.xTCP.ucKeepRepCount ) );
|
|
}
|
|
|
|
pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
|
|
pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500U ) );
|
|
pxSocket->u.xTCP.ucKeepRepCount++;
|
|
}
|
|
}
|
|
}
|
|
#endif /* ipconfigTCP_KEEP_ALIVE */
|
|
}
|
|
|
|
if( lDataLen >= 0 )
|
|
{
|
|
/* Anything to send, a change of the advertised window size, or maybe send a
|
|
* keep-alive message? */
|
|
if( ( lDataLen > 0 ) ||
|
|
( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
|
|
( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
|
|
{
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~tcpTCP_FLAG_PSH );
|
|
pxProtocolHeaders->xTCPHeader.ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); /*_RB_ "2" needs comment. */
|
|
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_ACK;
|
|
|
|
if( lDataLen != 0L )
|
|
{
|
|
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_PSH;
|
|
}
|
|
|
|
uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
|
|
lDataLen += ( int32_t ) uxIntermediateResult;
|
|
}
|
|
}
|
|
|
|
return lDataLen;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
* @brief The API FreeRTOS_send() adds data to the TX stream. Add
|
|
* this data to the windowing system to it can be transmitted.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the connection.
|
|
*/
|
|
void prvTCPAddTxData( FreeRTOS_Socket_t * pxSocket )
|
|
{
|
|
int32_t lCount, lLength;
|
|
|
|
/* A txStream has been created already, see if the socket has new data for
|
|
* the sliding window.
|
|
*
|
|
* uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It
|
|
* contains new Tx data which has not been passed to the sliding window yet.
|
|
* The oldest data not-yet-confirmed can be found at rxTail. */
|
|
lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
|
|
|
|
if( lLength > 0 )
|
|
{
|
|
/* All data between txMid and rxHead will now be passed to the sliding
|
|
* window manager, so it can start transmitting them.
|
|
*
|
|
* Hand over the new data to the sliding window handler. It will be
|
|
* split-up in chunks of 1460 bytes each (or less, depending on
|
|
* ipconfigTCP_MSS). */
|
|
lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
|
|
( uint32_t ) lLength,
|
|
( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
|
|
( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
|
|
|
|
/* Move the rxMid pointer forward up to rxHead. */
|
|
if( lCount > 0 )
|
|
{
|
|
vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
|
|
}
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
* @brief Set the TCP options (if any) for the outgoing packet.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the connection.
|
|
* @param[in] pxNetworkBuffer: The network buffer holding the packet.
|
|
*
|
|
* @return Length of the TCP options after they are set.
|
|
*/
|
|
UBaseType_t prvSetOptions( FreeRTOS_Socket_t * pxSocket,
|
|
const NetworkBufferDescriptor_t * pxNetworkBuffer )
|
|
{
|
|
/* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
|
|
&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( pxNetworkBuffer ) ] ) );
|
|
TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
|
|
const TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
|
|
UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
|
|
|
|
#if ( ipconfigUSE_TCP_WIN == 1 )
|
|
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
|
|
const void * pvCopySource;
|
|
void * pvCopyDest;
|
|
|
|
if( uxOptionsLength != 0U )
|
|
{
|
|
/* TCP options must be sent because a packet which is out-of-order
|
|
* was received. */
|
|
if( xTCPWindowLoggingLevel >= 0 )
|
|
{
|
|
FreeRTOS_debug_printf( ( "SACK[%u,%u]: optlen %u sending %u - %u\n",
|
|
pxSocket->usLocalPort,
|
|
pxSocket->u.xTCP.usRemotePort,
|
|
( unsigned ) uxOptionsLength,
|
|
( unsigned ) ( FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ),
|
|
( unsigned ) ( FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) ) );
|
|
}
|
|
|
|
/*
|
|
* Use helper variables for memcpy() source & dest to remain
|
|
* compliant with MISRA Rule 21.15. These should be
|
|
* optimized away.
|
|
*/
|
|
pvCopySource = pxTCPWindow->ulOptionsData;
|
|
pvCopyDest = pxTCPHeader->ucOptdata;
|
|
( void ) memcpy( pvCopyDest, pvCopySource, ( size_t ) uxOptionsLength );
|
|
|
|
/* The header length divided by 4, goes into the higher nibble,
|
|
* effectively a shift-left 2. */
|
|
pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
|
|
}
|
|
else
|
|
#endif /* ipconfigUSE_TCP_WIN */
|
|
|
|
if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
|
|
{
|
|
/* TCP options must be sent because the MSS has changed. */
|
|
pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
|
|
|
|
if( xTCPWindowLoggingLevel >= 0 )
|
|
{
|
|
FreeRTOS_debug_printf( ( "MSS: sending %u\n", pxSocket->u.xTCP.usMSS ) );
|
|
}
|
|
|
|
pxTCPHeader->ucOptdata[ 0 ] = tcpTCP_OPT_MSS;
|
|
pxTCPHeader->ucOptdata[ 1 ] = tcpTCP_OPT_MSS_LEN;
|
|
pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usMSS ) >> 8 );
|
|
pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usMSS ) & 0xffU );
|
|
uxOptionsLength = 4U;
|
|
pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
|
|
}
|
|
else
|
|
{
|
|
/* Nothing. */
|
|
}
|
|
|
|
return uxOptionsLength;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
* @brief Called from prvTCPHandleState(). There is data to be sent. If
|
|
* ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
|
|
* checked if it would better be postponed for efficiency.
|
|
*
|
|
* @param[in] pxSocket: The socket owning the TCP connection.
|
|
* @param[in] ppxNetworkBuffer: Pointer to pointer to the network buffer.
|
|
* @param[in] ulReceiveLength: The length of the received buffer.
|
|
* @param[in] xByteCount: Length of the data to be sent.
|
|
*
|
|
* @return The number of bytes actually sent.
|
|
*/
|
|
BaseType_t prvSendData( FreeRTOS_Socket_t * pxSocket,
|
|
NetworkBufferDescriptor_t ** ppxNetworkBuffer,
|
|
uint32_t ulReceiveLength,
|
|
BaseType_t xByteCount )
|
|
{
|
|
/* Map the buffer onto the ProtocolHeader_t struct for easy access to the fields. */
|
|
|
|
/* MISRA Ref 11.3.1 [Misaligned access] */
|
|
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
|
|
/* coverity[misra_c_2012_rule_11_3_violation] */
|
|
const ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
|
|
&( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( *ppxNetworkBuffer ) ] ) );
|
|
const TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
|
|
const TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
|
|
/* Find out what window size we may advertised. */
|
|
int32_t lRxSpace;
|
|
BaseType_t xSendLength = xByteCount;
|
|
uint32_t ulRxBufferSpace;
|
|
/* Two steps to please MISRA. */
|
|
size_t uxSize = uxIPHeaderSizePacket( *ppxNetworkBuffer ) + ipSIZE_OF_TCP_HEADER;
|
|
BaseType_t xSizeWithoutData = ( BaseType_t ) uxSize;
|
|
|
|
#if ( ipconfigUSE_TCP_WIN == 1 )
|
|
int32_t lMinLength;
|
|
#endif
|
|
|
|
/* Set the time-out field, so that we'll be called by the IP-task in case no
|
|
* next message will be received. */
|
|
ulRxBufferSpace = pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber;
|
|
lRxSpace = ( int32_t ) ulRxBufferSpace;
|
|
|
|
#if ipconfigUSE_TCP_WIN == 1
|
|
{
|
|
/* An ACK may be delayed if the peer has space for at least 2 x MSS. */
|
|
lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usMSS );
|
|
|
|
/* In case we're receiving data continuously, we might postpone sending
|
|
* an ACK to gain performance. */
|
|
/* lint e9007 is OK because 'uxIPHeaderSizeSocket()' has no side-effects. */
|
|
if( ( ulReceiveLength > 0U ) && /* Data was sent to this socket. */
|
|
( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
|
|
( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
|
|
( xSendLength == xSizeWithoutData ) && /* No Tx data or options to be sent. */
|
|
( pxSocket->u.xTCP.eTCPState == eESTABLISHED ) && /* Connection established. */
|
|
( pxTCPHeader->ucTCPFlags == tcpTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
|
|
{
|
|
uint32_t ulCurMSS = ( uint32_t ) pxSocket->u.xTCP.usMSS;
|
|
|
|
if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
|
|
{
|
|
/* There was still a delayed in queue, delete it. */
|
|
if( pxSocket->u.xTCP.pxAckMessage != NULL )
|
|
{
|
|
vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
|
|
}
|
|
|
|
pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
|
|
}
|
|
|
|
if( ulReceiveLength < ulCurMSS ) /* Received a small message. */
|
|
{
|
|
pxSocket->u.xTCP.usTimeout = ( uint16_t ) tcpDELAYED_ACK_SHORT_DELAY_MS;
|
|
}
|
|
else
|
|
{
|
|
/* Normally a delayed ACK should wait 200 ms for a next incoming
|
|
* packet. Only wait 20 ms here to gain performance. A slow ACK
|
|
* for full-size message. */
|
|
pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_TICKS( tcpDELAYED_ACK_LONGER_DELAY_MS );
|
|
|
|
if( pxSocket->u.xTCP.usTimeout < 1U ) /* LCOV_EXCL_BR_LINE, the second branch will never be hit */
|
|
{
|
|
pxSocket->u.xTCP.usTimeout = 1U; /* LCOV_EXCL_LINE, this line will not be reached */
|
|
}
|
|
}
|
|
|
|
if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) )
|
|
{
|
|
FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %u SEQ %u (len %u) tmout %u d %d\n",
|
|
pxSocket->usLocalPort,
|
|
pxSocket->u.xTCP.usRemotePort,
|
|
( unsigned ) ( pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ),
|
|
( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ),
|
|
( unsigned ) xSendLength,
|
|
pxSocket->u.xTCP.usTimeout,
|
|
( int ) lRxSpace ) );
|
|
}
|
|
|
|
*ppxNetworkBuffer = NULL;
|
|
xSendLength = 0;
|
|
}
|
|
else if( pxSocket->u.xTCP.pxAckMessage != NULL )
|
|
{
|
|
/* As an ACK is not being delayed, remove any earlier delayed ACK
|
|
* message. */
|
|
if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
|
|
{
|
|
vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
|
|
}
|
|
|
|
pxSocket->u.xTCP.pxAckMessage = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* The ack will not be postponed, and there was no stored ack ( in 'pxAckMessage' ). */
|
|
}
|
|
}
|
|
#else /* if ipconfigUSE_TCP_WIN == 1 */
|
|
{
|
|
/* Remove compiler warnings. */
|
|
( void ) ulReceiveLength;
|
|
( void ) pxTCPHeader;
|
|
( void ) lRxSpace;
|
|
}
|
|
#endif /* ipconfigUSE_TCP_WIN */
|
|
|
|
if( xSendLength != 0 )
|
|
{
|
|
if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) )
|
|
{
|
|
FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %u SEQ %u (len %u)\n",
|
|
pxSocket->usLocalPort,
|
|
pxSocket->u.xTCP.usRemotePort,
|
|
( unsigned ) ( pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ),
|
|
( unsigned ) ( pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ),
|
|
( unsigned ) xSendLength ) );
|
|
}
|
|
|
|
/* Set the parameter 'xReleaseAfterSend' to the value of
|
|
* ipconfigZERO_COPY_TX_DRIVER. */
|
|
prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
|
|
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
|
{
|
|
/* The driver has taken ownership of the Network Buffer. */
|
|
*ppxNetworkBuffer = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return xSendLength;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Common code for sending a TCP protocol control packet (i.e. no options, no
|
|
* payload, just flags).
|
|
*
|
|
* @param[in] pxNetworkBuffer: The network buffer received from the peer.
|
|
* @param[in] ucTCPFlags: The flags to determine what kind of packet this is.
|
|
*
|
|
* @return pdFAIL always indicating that the packet was not consumed.
|
|
*/
|
|
BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t * pxNetworkBuffer,
|
|
uint8_t ucTCPFlags )
|
|
{
|
|
BaseType_t xReturn = pdTRUE;
|
|
|
|
#if ( ipconfigIGNORE_UNKNOWN_PACKETS == 1 )
|
|
/* Configured to ignore unknown packets just suppress a compiler warning. */
|
|
( void ) pxNetworkBuffer;
|
|
( void ) ucTCPFlags;
|
|
#else
|
|
{
|
|
if( uxIPHeaderSizePacket( pxNetworkBuffer ) == ipSIZE_OF_IPv6_HEADER )
|
|
{
|
|
xReturn = prvTCPSendSpecialPktHelper_IPV6( pxNetworkBuffer, ucTCPFlags );
|
|
}
|
|
else
|
|
{
|
|
xReturn = prvTCPSendSpecialPktHelper_IPV4( pxNetworkBuffer, ucTCPFlags );
|
|
}
|
|
}
|
|
#endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
|
|
|
|
/* The packet was not consumed. */
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2,
|
|
* case #3. In summary, an RST was received with a sequence number that is
|
|
* unexpected but still within the window.
|
|
*
|
|
* @param[in] pxNetworkBuffer: The network buffer descriptor with the packet.
|
|
*
|
|
* @return Returns the value back from #prvTCPSendSpecialPacketHelper.
|
|
*/
|
|
BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t * pxNetworkBuffer )
|
|
{
|
|
return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, tcpTCP_FLAG_ACK );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Send a RST (Reset) to peer in case the packet cannot be handled.
|
|
*
|
|
* @param[in] pxNetworkBuffer: The network buffer descriptor with the packet.
|
|
*
|
|
* @return Returns the value back from #prvTCPSendSpecialPacketHelper.
|
|
*/
|
|
BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t * pxNetworkBuffer )
|
|
{
|
|
return prvTCPSendSpecialPacketHelper( pxNetworkBuffer,
|
|
( uint8_t ) tcpTCP_FLAG_ACK | ( uint8_t ) tcpTCP_FLAG_RST );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#endif /* ipconfigUSE_TCP == 1 */
|