static eFrameProcessingResult_t prvProcessIPPacket()

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;
}