Skip to content

Commit

Permalink
merge prvTCPPrepareConnect
Browse files Browse the repository at this point in the history
  • Loading branch information
HTRamsey committed Feb 4, 2024
1 parent 1b9694a commit e96bc74
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 439 deletions.
2 changes: 2 additions & 0 deletions source/FreeRTOS_ARP.c
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,8 @@ void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
if( ( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) &&
( pxEndPoint->ipv4_settings.ulIPAddress != 0U ) )
{
FreeRTOS_debug_printf( ( "ARP for %xip (using %xip)", ulIPAddress, pxEndPoint->ipv4_settings.ulIPAddress) );

/* This is called from the context of the IP event task, so a block time
* must not be used. */
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0U );
Expand Down
2 changes: 2 additions & 0 deletions source/FreeRTOS_ND.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@
NetworkBufferDescriptor_t * pxNewDescriptor = NULL;
BaseType_t xReleased = pdFALSE;

FreeRTOS_debug_printf( ( "Looking up %pip with%s end-point\n", ( void * ) pxIPAddress->ucBytes, ( pxEndPoint != NULL ) ? "" : "out" ) );

if( ( pxEndPoint != NULL ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) )
{
uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPHeader_IPv6_t );
Expand Down
177 changes: 163 additions & 14 deletions source/FreeRTOS_TCP_Transmission.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,24 +730,173 @@
static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t * pxSocket )
{
BaseType_t xReturn = pdTRUE;
eARPLookupResult_t eReturned = eARPCacheMiss;
IPv46_Address_t xRemoteIP;
MACAddress_t xEthAddress = { 0 };
uint32_t ulInitialSequenceNumber = 0;
NetworkEndPoint_t * pxEndPoint;

switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE */
configASSERT( pxSocket != NULL );

pxEndPoint = pxSocket->pxEndPoint;

/* Determine the ARP cache status for the requested IP address. */
if( pxSocket->bits.bIsIPv6 == pdTRUE )
{
#if ( ipconfigUSE_IPv4 != 0 )
case pdFALSE_UNSIGNED:
xReturn = prvTCPPrepareConnect_IPV4( pxSocket );
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
( void ) memset( xRemoteIP.xIPAddress.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS );
( void ) memcpy( xRemoteIP.xIPAddress.xIP_IPv6.ucBytes, pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
eReturned = eNDGetCacheEntry( &( xRemoteIP.xIPAddress.xIP_IPv6 ), &( xEthAddress ), &( pxEndPoint ) );
FreeRTOS_debug_printf( ( "eNDGetCacheEntry: %d with end-point %p\n", eReturned, ( void * ) pxEndPoint ) );
#endif
}
else
{
xRemoteIP.xIPAddress.ulIP_IPv4 = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
#if ipconfigIS_ENABLED( ipconfigUSE_IPv4 )
eReturned = eARPGetCacheEntry( &( xRemoteIP.xIPAddress.ulIP_IPv4 ), &( xEthAddress ), &( pxEndPoint ) );
#endif
}
xRemoteIP.xIs_IPv6 = pxSocket->bits.bIsIPv6;

#if ( ipconfigUSE_IPv6 != 0 )
case pdTRUE_UNSIGNED:
xReturn = prvTCPPrepareConnect_IPV6( pxSocket );
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
switch( eReturned )
{
case eARPCacheHit: /* An ARP table lookup found a valid entry. */
break; /* We can now prepare the SYN packet. */

case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
default:
/* Count the number of times it could not find the ARP address. */
pxSocket->u.xTCP.ucRepCount++;
/* And issue a (new) ARP request */
if( pxSocket->bits.bIsIPv6 == pdTRUE )
{
if( pxEndPoint != NULL )
{
const size_t uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPHeader_IPv6_t );
NetworkBufferDescriptor_t * const pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxNeededSize, 0U );
if( pxNetworkBuffer != NULL )
{
pxNetworkBuffer->pxEndPoint = pxEndPoint;
vNDSendNeighbourSolicitation( pxNetworkBuffer, &( xRemoteIP.xIPAddress.xIP_IPv6 ) );
}
}
}
else
{
FreeRTOS_OutputARPRequest( xRemoteIP.xIPAddress.ulIP_IPv4 );
}

xReturn = pdFALSE;
break;
}

if( xReturn != pdFALSE )
{
/* Get a difficult-to-predict initial sequence number. */
if( pxSocket->bits.bIsIPv6 == pdTRUE )
{
if( ( pxEndPoint == NULL ) || xApplicationGetRandomNumber( &ulInitialSequenceNumber ) != pdPASS )
{
xReturn = pdFALSE;
}
}
else
{
ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( pxSocket->xLocalAddress.ulIP_IPv4,
pxSocket->usLocalPort,
pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
pxSocket->u.xTCP.usRemotePort );

/* Check for a random number generation error. */
if( ulInitialSequenceNumber == 0U )
{
xReturn = pdFALSE;
}
}
}

if( xReturn != pdFALSE )
{
/* 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] */
ProtocolPacket_t * const pxProtPacket = ( ( ProtocolPacket_t * ) pxSocket->u.xTCP.xPacket.u.ucLastPacket );
TCPHeader_t * pxTCPHeader;

/* The MAC-address of the peer (or gateway) has been found,
* now prepare the initial TCP packet and some fields in the socket. Map
* the buffer onto the TCPPacket_t struct to easily access it's field. */

/* reset the retry counter to zero. */
pxSocket->u.xTCP.ucRepCount = 0U;

/* And remember that the connect/SYN data are prepared. */
pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;

/* Now that the Ethernet address is known, the initial packet can be prepared. */
( void ) memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, 0, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );

/* Write the Ethernet address in Source, because it will be swapped by prvTCPReturnPacket(). */
( void ) memcpy( ( void * ) ( ( EthernetHeader_t * ) pxSocket->u.xTCP.xPacket.u.ucLastPacket ), ( const void * ) ( &xEthAddress ), sizeof( xEthAddress ) );

if( pxSocket->bits.bIsIPv6 != pdFALSE_UNSIGNED )
{
TCPPacket_IPv6_t * const pxTCPPacket = &pxProtPacket->xTCPPacketIPv6;
pxTCPPacket->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE;
IPHeader_IPv6_t * const pxIPHeader = &pxTCPPacket->xIPHeader;
pxIPHeader->ucVersionTrafficClass = ( uint8_t ) 0x60U;
pxIPHeader->ucTrafficClassFlow = ( uint8_t ) 0x00;
pxIPHeader->usFlowLabel = ( uint16_t ) 0x0000U;
pxIPHeader->usPayloadLength = FreeRTOS_htons( sizeof( TCPHeader_t ) );
pxIPHeader->ucNextHeader = ( uint8_t ) ipPROTOCOL_TCP;
pxIPHeader->ucHopLimit = 128;
/* The Source and Destination addresses will be swapped later. */
( void ) memcpy( pxIPHeader->xSourceAddress.ucBytes, pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, sizeof( pxIPHeader->xSourceAddress.ucBytes ) );
( void ) memcpy( pxIPHeader->xDestinationAddress.ucBytes, pxSocket->xLocalAddress.xIP_IPv6.ucBytes, sizeof( pxIPHeader->xDestinationAddress.ucBytes ) );
pxTCPHeader = &pxTCPPacket->xTCPHeader;
}
else
{
TCPPacket_t * const pxTCPPacket = &pxProtPacket->xTCPPacket;
/* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
IPHeader_t * const pxIPHeader = &pxTCPPacket->xIPHeader;
pxIPHeader->ucVersionHeaderLength = 0x45U;
pxIPHeader->usLength = FreeRTOS_htons( sizeof( pxTCPPacket ) - sizeof( pxTCPPacket->xEthernetHeader ) );
pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
/* Addresses and ports will be stored swapped because prvTCPReturnPacket
* will swap them back while replying. */
pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
pxTCPHeader = &pxTCPPacket->xTCPHeader;
}

pxTCPHeader->usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
pxTCPHeader->usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );

/* We are actively connecting, so the peer's Initial Sequence Number (ISN)
* isn't known yet. */
pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0U;

/* Start with ISN (Initial Sequence Number). */
pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;

/* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
* the high nibble of the TCP offset field. */
pxTCPHeader->ucTCPOffset = 0x50U;

/* Only set the SYN flag. */
pxTCPHeader->ucTCPFlags = tcpTCP_FLAG_SYN;

/* Set the value of usMSS for this socket. */
prvSocketSetMSS( pxSocket );

default: /* LCOV_EXCL_LINE */
/* MISRA 16.4 Compliance */
break; /* LCOV_EXCL_LINE */
/* The initial sequence numbers at our side are known. Later
* vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
* first wait for a SYN+ACK reply. */
prvTCPCreateWindow( pxSocket );
}

return xReturn;
Expand Down
153 changes: 0 additions & 153 deletions source/FreeRTOS_TCP_Transmission_IPv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,159 +66,6 @@
#if( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_TCP == 1 )
/* *INDENT-ON* */

/*------------------------------------------------------------------------*/

/**
* @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.
*/
BaseType_t prvTCPPrepareConnect_IPV4( FreeRTOS_Socket_t * pxSocket )
{
TCPPacket_t * pxTCPPacket;
IPHeader_t * pxIPHeader;
eARPLookupResult_t eReturned;
uint32_t ulRemoteIP;
MACAddress_t xEthAddress;
BaseType_t xReturn = pdTRUE;
uint32_t ulInitialSequenceNumber = 0;

#if ( ipconfigHAS_PRINTF != 0 )
{
/* Only necessary for nicer logging. */
( void ) memset( xEthAddress.ucBytes, 0, sizeof( xEthAddress.ucBytes ) );
}
#endif /* ipconfigHAS_PRINTF != 0 */

ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
/* Determine the ARP cache status for the requested IP address. */
eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ), &( pxSocket->pxEndPoint ) );

switch( eReturned )
{
case eARPCacheHit: /* An ARP table lookup found a valid entry. */
break; /* We can now prepare the SYN packet. */

case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
default:
/* Count the number of times it could not find the ARP address. */
pxSocket->u.xTCP.ucRepCount++;

FreeRTOS_debug_printf( ( "ARP for %xip (using %xip): rc=%d %02x-%02x-%02x-%02x-%02x-%02x\n",
( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
( unsigned ) FreeRTOS_htonl( ulRemoteIP ),
eReturned,
xEthAddress.ucBytes[ 0 ],
xEthAddress.ucBytes[ 1 ],
xEthAddress.ucBytes[ 2 ],
xEthAddress.ucBytes[ 3 ],
xEthAddress.ucBytes[ 4 ],
xEthAddress.ucBytes[ 5 ] ) );

/* And issue a (new) ARP request */
FreeRTOS_OutputARPRequest( ulRemoteIP );
xReturn = pdFALSE;
break;
}

if( xReturn != pdFALSE )
{
/* Get a difficult-to-predict initial sequence number for this 4-tuple. */
ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( pxSocket->xLocalAddress.ulIP_IPv4,
pxSocket->usLocalPort,
pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
pxSocket->u.xTCP.usRemotePort );

/* Check for a random number generation error. */
if( ulInitialSequenceNumber == 0U )
{
xReturn = pdFALSE;
}
}

if( xReturn != pdFALSE )
{
uint16_t usLength;

/* The MAC-address of the peer (or gateway) has been found,
* now prepare the initial TCP packet and some fields in the socket. Map
* the buffer onto the TCPPacket_t struct to easily access it's field. */

/* 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] */
pxTCPPacket = ( ( TCPPacket_t * ) pxSocket->u.xTCP.xPacket.u.ucLastPacket );
pxIPHeader = &pxTCPPacket->xIPHeader;

/* reset the retry counter to zero. */
pxSocket->u.xTCP.ucRepCount = 0U;

/* And remember that the connect/SYN data are prepared. */
pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;

/* Now that the Ethernet address is known, the initial packet can be
* prepared. */
( void ) memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, 0, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );

/* Write the Ethernet address in Source, because it will be swapped by
* prvTCPReturnPacket(). */
( void ) memcpy( ( void * ) ( &pxTCPPacket->xEthernetHeader.xSourceAddress ), ( const void * ) ( &xEthAddress ), sizeof( xEthAddress ) );

/* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;

pxIPHeader->ucVersionHeaderLength = 0x45U;
usLength = ( uint16_t ) ( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
pxIPHeader->usLength = FreeRTOS_htons( usLength );
pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;

pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;

/* Addresses and ports will be stored swapped because prvTCPReturnPacket
* will swap them back while replying. */
pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );

pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );

/* We are actively connecting, so the peer's Initial Sequence Number (ISN)
* isn't known yet. */
pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0U;

/* Start with ISN (Initial Sequence Number). */
pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;

/* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
* the high nibble of the TCP offset field. */
pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50U;

/* Only set the SYN flag. */
pxTCPPacket->xTCPHeader.ucTCPFlags = tcpTCP_FLAG_SYN;

/* Set the value of usMSS for this socket. */
prvSocketSetMSS( pxSocket );

/* The initial sequence numbers at our side are known. Later
* vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
* first wait for a SYN+ACK reply. */
prvTCPCreateWindow( pxSocket );
}

return xReturn;
}
/*-----------------------------------------------------------*/

/* *INDENT-OFF* */
#endif /* ( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_TCP == 1 ) */
/* *INDENT-ON* */
Loading

0 comments on commit e96bc74

Please sign in to comment.