in FreeRTOS_IP.c [2151:2346]
static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * pxIPPacket,
NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
eFrameProcessingResult_t eReturn;
IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
size_t uxLength = ( size_t ) pxIPHeader->ucVersionHeaderLength;
UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( uxLength & 0x0FU ) << 2 );
uint8_t ucProtocol;
/* Bound the calculated header length: take away the Ethernet header size,
* then check if the IP header is claiming to be longer than the remaining
* total packet size. Also check for minimal header field length. */
if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
{
eReturn = eReleaseBuffer;
}
else
{
ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
/* Check if the IP headers are acceptable and if it has our destination. */
eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
if( eReturn == eProcessBuffer )
{
/* Are there IP-options. */
if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )
{
/* The size of the IP-header is larger than 20 bytes.
* The extra space is used for IP-options. */
#if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 )
{
/* All structs of headers expect a IP header size of 20 bytes
* IP header options were included, we'll ignore them and cut them out. */
const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;
/* From: the previous start of UDP/ICMP/TCP data. */
const uint8_t * pucSource = ( const uint8_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( EthernetHeader_t ) + uxHeaderLength ] );
/* To: the usual start of UDP/ICMP/TCP data at offset 20 (decimal ) from IP header. */
uint8_t * pucTarget = ( uint8_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER ] );
/* How many: total length minus the options and the lower headers. */
const size_t xMoveLen = pxNetworkBuffer->xDataLength - ( optlen + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_ETH_HEADER );
( void ) memmove( pucTarget, pucSource, xMoveLen );
pxNetworkBuffer->xDataLength -= optlen;
pxIPHeader->usLength = FreeRTOS_htons( FreeRTOS_ntohs( pxIPHeader->usLength ) - optlen );
/* Rewrite the Version/IHL byte to indicate that this packet has no IP options. */
pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0U ) | /* High nibble is the version. */
( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0FU );
}
#else /* if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 ) */
{
/* 'ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS' is not set, so packets carrying
* IP-options will be dropped. */
eReturn = eReleaseBuffer;
}
#endif /* if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 ) */
}
if( eReturn != eReleaseBuffer )
{
/* Add the IP and MAC addresses to the ARP table if they are not
* already there - otherwise refresh the age of the existing
* entry. */
if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )
{
if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )
{
eReturn = eWaitingARPResolution;
}
else
{
/* Refresh the age of this cache entry since a packet was received. */
vARPRefreshCacheEntryAge( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
}
}
if( eReturn != eWaitingARPResolution )
{
switch( ucProtocol )
{
case ipPROTOCOL_ICMP:
/* The IP packet contained an ICMP frame. Don't bother checking
* the ICMP checksum, as if it is wrong then the wrong data will
* also be returned, and the source of the ping will know something
* went wrong because it will not be able to validate what it
* receives. */
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
{
if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
{
eReturn = prvProcessICMPPacket( pxNetworkBuffer );
}
}
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
break;
case ipPROTOCOL_UDP:
{
/* The IP packet contained a UDP frame. */
/* Map the buffer onto a UDP-Packet struct to easily access the
* fields of UDP packet. */
const UDPPacket_t * pxUDPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( UDPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
uint16_t usLength;
BaseType_t xIsWaitingARPResolution = pdFALSE;
/* Note the header values required prior to the checksum
* generation as the checksum pseudo header may clobber some of
* these values. */
usLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength );
if( ( pxNetworkBuffer->xDataLength < sizeof( UDPPacket_t ) ) ||
( ( ( size_t ) usLength ) < sizeof( UDPHeader_t ) ) )
{
eReturn = eReleaseBuffer;
}
else if( usLength > ( FreeRTOS_ntohs( pxIPHeader->usLength ) - ipSIZE_OF_IPv4_HEADER ) )
{
/* The UDP packet is bigger than the IP-payload. Something is wrong, drop the packet. */
eReturn = eReleaseBuffer;
}
else
{
size_t uxPayloadSize_1, uxPayloadSize_2;
/* Ensure that downstream UDP packet handling has the lesser
* of: the actual network buffer Ethernet frame length, or
* the sender's UDP packet header payload length, minus the
* size of the UDP header.
*
* The size of the UDP packet structure in this implementation
* includes the size of the Ethernet header, the size of
* the IP header, and the size of the UDP header. */
uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
uxPayloadSize_2 = ( ( size_t ) usLength ) - sizeof( UDPHeader_t );
if( uxPayloadSize_1 > uxPayloadSize_2 )
{
pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t );
}
/* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */
pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
/* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:
* In some cases, the upper-layer checksum has been calculated
* by the NIC driver. */
/* Pass the packet payload to the UDP sockets
* implementation. */
if( xProcessReceivedUDPPacket( pxNetworkBuffer,
pxUDPPacket->xUDPHeader.usDestinationPort,
&( xIsWaitingARPResolution ) ) == pdPASS )
{
eReturn = eFrameConsumed;
}
else
{
/* Is this packet to be set aside for ARP resolution. */
if( xIsWaitingARPResolution == pdTRUE )
{
eReturn = eWaitingARPResolution;
}
}
}
}
break;
#if ipconfigUSE_TCP == 1
case ipPROTOCOL_TCP:
if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )
{
eReturn = eFrameConsumed;
}
/* Setting this variable will cause xTCPTimerCheck()
* to be called just before the IP-task blocks. */
xProcessedTCPMessage++;
break;
#endif /* if ipconfigUSE_TCP == 1 */
default:
/* Not a supported frame type. */
eReturn = eReleaseBuffer;
break;
}
}
}
}
}
return eReturn;
}