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