in amazon-freertos/lib/FreeRTOS-Plus-TCP/source/FreeRTOS_DHCP.c [615:823]
static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )
{
uint8_t *pucUDPPayload, *pucLastByte;
struct freertos_sockaddr xClient;
uint32_t xClientLength = sizeof( xClient );
int32_t lBytes;
DHCPMessage_t *pxDHCPMessage;
uint8_t *pucByte, ucOptionCode, ucLength;
uint32_t ulProcessed, ulParameter;
BaseType_t xReturn = pdFALSE;
const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct DHCP message type must be present in the options. */
lBytes = FreeRTOS_recvfrom( xDHCPData.xDHCPSocket, ( void * ) &pucUDPPayload, 0ul, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
if( lBytes > 0 )
{
/* Map a DHCP structure onto the received data. */
pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload );
/* Sanity check. */
if( ( lBytes >= sizeof( DHCPMessage_t ) ) &&
( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) &&
( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) &&
( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) )
{
if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ),
( void * ) ipLOCAL_MAC_ADDRESS,
sizeof( MACAddress_t ) ) == 0 )
{
/* None of the essential options have been processed yet. */
ulProcessed = 0ul;
/* Walk through the options until the dhcpOPTION_END_BYTE byte
is found, taking care not to walk off the end of the options. */
pucByte = &( pxDHCPMessage->ucFirstOptionByte );
pucLastByte = &( pucUDPPayload[ lBytes - dhcpMAX_OPTION_LENGTH_OF_INTEREST ] );
while( pucByte < pucLastByte )
{
ucOptionCode = pucByte[ 0 ];
if( ucOptionCode == dhcpOPTION_END_BYTE )
{
/* Ready, the last byte has been seen. */
break;
}
if( ucOptionCode == dhcpZERO_PAD_OPTION_CODE )
{
/* The value zero is used as a pad byte,
it is not followed by a length byte. */
pucByte += 1;
continue;
}
/* Stop if the response is malformed. */
if( pucByte < pucLastByte - 1 )
{
ucLength = pucByte[ 1 ];
pucByte += 2;
if( pucByte >= pucLastByte - ucLength )
{
break;
}
}
else
{
break;
}
/* In most cases, a 4-byte network-endian parameter follows,
just get it once here and use later. */
if( ucLength >= sizeof( ulParameter ) )
{
memcpy( ( void * ) &( ulParameter ),
( void * ) pucByte,
( size_t ) sizeof( ulParameter ) );
}
else
{
ulParameter = 0;
}
/* Option-specific handling. */
switch( ucOptionCode )
{
case dhcpMESSAGE_TYPE_OPTION_CODE :
if( *pucByte == ( uint8_t ) xExpectedMessageType )
{
/* The message type is the message type the
state machine is expecting. */
ulProcessed++;
}
else if( *pucByte == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )
{
if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )
{
/* Start again. */
xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
}
}
else
{
/* Don't process other message types. */
}
break;
case dhcpSUBNET_MASK_OPTION_CODE :
if( ucLength == sizeof( uint32_t ) )
{
xNetworkAddressing.ulNetMask = ulParameter;
}
break;
case dhcpGATEWAY_OPTION_CODE :
if( ucLength == sizeof( uint32_t ) )
{
/* ulProcessed is not incremented in this case
because the gateway is not essential. */
xNetworkAddressing.ulGatewayAddress = ulParameter;
}
break;
case dhcpDNS_SERVER_OPTIONS_CODE :
/* ulProcessed is not incremented in this case
because the DNS server is not essential. Only the
first DNS server address is taken. */
xNetworkAddressing.ulDNSServerAddress = ulParameter;
break;
case dhcpSERVER_IP_ADDRESS_OPTION_CODE :
if( ucLength == sizeof( uint32_t ) )
{
if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )
{
/* Offers state the replying server. */
ulProcessed++;
xDHCPData.ulDHCPServerAddress = ulParameter;
}
else
{
/* The ack must come from the expected server. */
if( xDHCPData.ulDHCPServerAddress == ulParameter )
{
ulProcessed++;
}
}
}
break;
case dhcpLEASE_TIME_OPTION_CODE :
if( ucLength == sizeof( xDHCPData.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. */
xDHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );
/* Divide the lease time by two to ensure a
renew request is sent before the lease actually
expires. */
xDHCPData.ulLeaseTime >>= 1UL;
/* Multiply with configTICK_RATE_HZ to get clock
ticks. */
xDHCPData.ulLeaseTime = configTICK_RATE_HZ * xDHCPData.ulLeaseTime;
}
break;
default :
/* Not interested in this field. */
break;
}
/* Jump over the data to find the next option code. */
if( ucLength == 0u )
{
break;
}
else
{
pucByte += ucLength;
}
}
/* Were all the mandatory options received? */
if( ulProcessed >= ulMandatoryOptions )
{
/* HT:endian: used to be network order */
xDHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
xReturn = pdPASS;
}
}
}
FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload );
}
return xReturn;
}