_static BaseType_t prvProcessDHCPReplies()

in FreeRTOS_DHCP.c [729:984]


    _static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )
    {
        uint8_t * pucUDPPayload;
        int32_t lBytes;
        const DHCPMessage_IPv4_t * pxDHCPMessage;
        const uint8_t * pucByte;
        uint8_t ucOptionCode;
        uint32_t ulProcessed, ulParameter;
        BaseType_t xReturn = pdFALSE;
        const uint32_t ulMandatoryOptions = 2U; /* DHCP server address, and the correct DHCP message type must be present in the options. */
        /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
        const void * pvCopySource;
        void * pvCopyDest;

        /* Passing the address of a pointer (pucUDPPayload) because FREERTOS_ZERO_COPY is used. */
        lBytes = FreeRTOS_recvfrom( xDHCPSocket, &pucUDPPayload, 0U, FREERTOS_ZERO_COPY, NULL, NULL );

        if( lBytes > 0 )
        {
            /* Map a DHCP structure onto the received data. */
            pxDHCPMessage = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( DHCPMessage_IPv4_t, pucUDPPayload );

            /* Sanity check. */
            if( lBytes < ( int32_t ) sizeof( DHCPMessage_IPv4_t ) )
            {
                /* Not enough bytes. */
            }
            else if( prvIsValidDHCPResponse( pxDHCPMessage ) == pdFAIL )
            {
                /* Invalid values in DHCP response. */
            }
            else if( ( pxDHCPMessage->ulTransactionID != FreeRTOS_htonl( EP_DHCPData.ulTransactionId ) ) )
            {
                /* Transaction ID does not match. */
            }
            else /* Looks like a valid DHCP response, with the same transaction ID. */
            {
                if( memcmp( pxDHCPMessage->ucClientHardwareAddress,
                            ipLOCAL_MAC_ADDRESS,
                            sizeof( MACAddress_t ) ) != 0 )
                {
                    /* Target MAC address doesn't match. */
                }
                else
                {
                    size_t uxIndex, uxPayloadDataLength, uxLength;

                    /* None of the essential options have been processed yet. */
                    ulProcessed = 0U;

                    /* Walk through the options until the dhcpOPTION_END_BYTE byte
                     * is found, taking care not to walk off the end of the options. */
                    pucByte = &( pucUDPPayload[ sizeof( DHCPMessage_IPv4_t ) ] );
                    uxIndex = 0;
                    uxPayloadDataLength = ( ( size_t ) lBytes ) - sizeof( DHCPMessage_IPv4_t );

                    while( uxIndex < uxPayloadDataLength )
                    {
                        ucOptionCode = pucByte[ uxIndex ];

                        if( ucOptionCode == ( uint8_t ) dhcpOPTION_END_BYTE )
                        {
                            /* Ready, the last byte has been seen. */
                            /* coverity[break_stmt] : Break statement terminating the loop */
                            break;
                        }

                        if( ucOptionCode == ( uint8_t ) dhcpIPv4_ZERO_PAD_OPTION_CODE )
                        {
                            /* The value zero is used as a pad byte,
                             * it is not followed by a length byte. */
                            uxIndex = uxIndex + 1U;
                            continue;
                        }

                        /* Stop if the response is malformed. */
                        if( ( uxIndex + 1U ) < uxPayloadDataLength )
                        {
                            /* Fetch the length byte. */
                            uxLength = ( size_t ) pucByte[ uxIndex + 1U ];
                            uxIndex = uxIndex + 2U;

                            if( !( ( ( uxIndex + uxLength ) - 1U ) < uxPayloadDataLength ) )
                            {
                                /* There are not as many bytes left as there should be. */
                                break;
                            }
                        }
                        else
                        {
                            /* The length byte is missing. */
                            break;
                        }

                        /* In most cases, a 4-byte network-endian parameter follows,
                         * just get it once here and use later. */
                        if( uxLength >= sizeof( ulParameter ) )
                        {
                            /*
                             * Use helper variables for memcpy() to remain
                             * compliant with MISRA Rule 21.15.  These should be
                             * optimized away.
                             */
                            pvCopySource = &pucByte[ uxIndex ];
                            pvCopyDest = &ulParameter;
                            ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulParameter ) );
                            /* 'uxIndex' will be increased at the end of this loop. */
                        }
                        else
                        {
                            ulParameter = 0;
                        }

                        /* Confirm uxIndex is still a valid index after adjustments to uxIndex above */
                        if( !( uxIndex < uxPayloadDataLength ) )
                        {
                            break;
                        }

                        /* Option-specific handling. */
                        switch( ucOptionCode )
                        {
                            case dhcpIPv4_MESSAGE_TYPE_OPTION_CODE:

                                if( pucByte[ uxIndex ] == ( uint8_t ) xExpectedMessageType )
                                {
                                    /* The message type is the message type the
                                     * state machine is expecting. */
                                    ulProcessed++;
                                }
                                else
                                {
                                    if( pucByte[ uxIndex ] == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )
                                    {
                                        if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )
                                        {
                                            /* Start again. */
                                            EP_DHCPData.eDHCPState = eInitialWait;
                                        }
                                    }

                                    /* Stop processing further options. */
                                    uxLength = 0;
                                }

                                break;

                            case dhcpIPv4_SUBNET_MASK_OPTION_CODE:

                                if( uxLength == sizeof( uint32_t ) )
                                {
                                    EP_IPv4_SETTINGS.ulNetMask = ulParameter;
                                }

                                break;

                            case dhcpIPv4_GATEWAY_OPTION_CODE:

                                /* The DHCP server may send more than 1 gateway addresses. */
                                if( uxLength >= sizeof( uint32_t ) )
                                {
                                    /* ulProcessed is not incremented in this case
                                     * because the gateway is not essential. */
                                    EP_IPv4_SETTINGS.ulGatewayAddress = ulParameter;
                                }

                                break;

                            case dhcpIPv4_DNS_SERVER_OPTIONS_CODE:

                                /* The DHCP server may send more than 1 DNS server addresses. */
                                if( uxLength >= sizeof( uint32_t ) )
                                {
                                    /* ulProcessed is not incremented in this case
                                     * because the DNS server is not essential.  Only the
                                     * first DNS server address is taken. */
                                    EP_IPv4_SETTINGS.ulDNSServerAddress = ulParameter;
                                }

                                break;

                            case dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE:

                                if( uxLength == sizeof( uint32_t ) )
                                {
                                    if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )
                                    {
                                        /* Offers state the replying server. */
                                        ulProcessed++;
                                        EP_DHCPData.ulDHCPServerAddress = ulParameter;
                                    }
                                    else
                                    {
                                        /* The ack must come from the expected server. */
                                        if( EP_DHCPData.ulDHCPServerAddress == ulParameter )
                                        {
                                            ulProcessed++;
                                        }
                                    }
                                }

                                break;

                            case dhcpIPv4_LEASE_TIME_OPTION_CODE:

                                if( uxLength == sizeof( EP_DHCPData.ulLeaseTime ) )
                                {
                                    /* ulProcessed is not incremented in this case
                                     * because the lease time is not essential. */

                                    /* The DHCP parameter is in seconds, convert
                                     * to host-endian format. */
                                    EP_DHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );

                                    /* Divide the lease time by two to ensure a renew
                                     * request is sent before the lease actually expires. */
                                    EP_DHCPData.ulLeaseTime >>= 1;

                                    /* Multiply with configTICK_RATE_HZ to get clock ticks. */
                                    EP_DHCPData.ulLeaseTime = ( uint32_t ) configTICK_RATE_HZ * ( uint32_t ) EP_DHCPData.ulLeaseTime;
                                }

                                break;

                            default:

                                /* Not interested in this field. */

                                break;
                        }

                        /* Jump over the data to find the next option code. */
                        if( uxLength == 0U )
                        {
                            break;
                        }

                        uxIndex = uxIndex + uxLength;
                    }

                    /* Were all the mandatory options received? */
                    if( ulProcessed >= ulMandatoryOptions )
                    {
                        /* HT:endian: used to be network order */
                        EP_DHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
                        FreeRTOS_printf( ( "vDHCPProcess: offer %xip\n", ( unsigned ) FreeRTOS_ntohl( EP_DHCPData.ulOfferedIPAddress ) ) );
                        xReturn = pdPASS;
                    }
                }
            }

            FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayload );
        } /* if( lBytes > 0 ) */

        return xReturn;
    }