in FreeRTOS_DHCP.c [201:601]
void vDHCPProcess( BaseType_t xReset,
eDHCPState_t eExpectedState )
{
BaseType_t xGivingUp = pdFALSE;
#if ( ipconfigUSE_DHCP_HOOK != 0 )
eDHCPCallbackAnswer_t eAnswer;
#endif /* ipconfigUSE_DHCP_HOOK */
/* Is DHCP starting over? */
if( xReset != pdFALSE )
{
EP_DHCPData.eDHCPState = eInitialWait;
}
if( ( EP_DHCPData.eDHCPState != eExpectedState ) && ( xReset == pdFALSE ) )
{
/* When the DHCP event was generated, the DHCP client was
* in a different state. Therefore, ignore this event. */
FreeRTOS_debug_printf( ( "DHCP wrong state: expect: %d got: %d : ignore\n",
eExpectedState, EP_DHCPData.eDHCPState ) );
}
else
{
switch( EP_DHCPData.eDHCPState )
{
case eInitialWait:
/* Initial state. Create the DHCP socket, timer, etc. if they
* have not already been created. */
prvInitialiseDHCP();
EP_DHCPData.eDHCPState = eWaitingSendFirstDiscover;
break;
case eWaitingSendFirstDiscover:
/* Ask the user if a DHCP discovery is required. */
#if ( ipconfigUSE_DHCP_HOOK != 0 )
eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress );
if( eAnswer == eDHCPContinue )
#endif /* ipconfigUSE_DHCP_HOOK */
{
/* See if prvInitialiseDHCP() has creates a socket. */
if( xDHCPSocket == NULL )
{
xGivingUp = pdTRUE;
}
else
{
*ipLOCAL_IP_ADDRESS_POINTER = 0U;
/* Send the first discover request. */
EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
if( prvSendDHCPDiscover() == pdPASS )
{
EP_DHCPData.eDHCPState = eWaitingOffer;
}
else
{
/* Either the creation of a message buffer failed, or sendto().
* Try again in the next cycle. */
FreeRTOS_debug_printf( ( "Send failed during eWaitingSendFirstDiscover\n" ) );
}
}
}
#if ( ipconfigUSE_DHCP_HOOK != 0 )
else
{
if( eAnswer == eDHCPUseDefaults )
{
( void ) memcpy( &( xNetworkAddressing ), &( xDefaultAddressing ), sizeof( xNetworkAddressing ) );
}
/* The user indicates that the DHCP process does not continue. */
xGivingUp = pdTRUE;
}
#endif /* ipconfigUSE_DHCP_HOOK */
break;
case eSendDHCPRequest:
if( prvSendDHCPRequest() == pdPASS )
{
/* Send succeeded, go to state 'eWaitingAcknowledge'. */
EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
EP_DHCPData.eDHCPState = eWaitingAcknowledge;
}
else
{
/* Either the creation of a message buffer failed, or sendto().
* Try again in the next cycle. */
FreeRTOS_debug_printf( ( "Send failed during eSendDHCPRequest.\n" ) );
}
break;
case eWaitingOffer:
xGivingUp = pdFALSE;
/* Look for offers coming in. */
if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS )
{
#if ( ipconfigUSE_DHCP_HOOK != 0 )
/* Ask the user if a DHCP request is required. */
eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, EP_DHCPData.ulOfferedIPAddress );
if( eAnswer == eDHCPContinue )
#endif /* ipconfigUSE_DHCP_HOOK */
{
/* An offer has been made, the user wants to continue,
* generate the request. */
if( prvSendDHCPRequest() == pdPASS )
{
EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
EP_DHCPData.eDHCPState = eWaitingAcknowledge;
}
else
{
/* Either the creation of a message buffer failed, or sendto().
* Try again in the next cycle. */
FreeRTOS_debug_printf( ( "Send failed during eWaitingOffer/1.\n" ) );
EP_DHCPData.eDHCPState = eSendDHCPRequest;
}
break;
}
#if ( ipconfigUSE_DHCP_HOOK != 0 )
if( eAnswer == eDHCPUseDefaults )
{
( void ) memcpy( &( xNetworkAddressing ), &( xDefaultAddressing ), sizeof( xNetworkAddressing ) );
}
/* The user indicates that the DHCP process does not continue. */
xGivingUp = pdTRUE;
#endif /* ipconfigUSE_DHCP_HOOK */
}
/* Is it time to send another Discover? */
else if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
{
/* It is time to send another Discover. Increase the time
* period, and if it has not got to the point of giving up - send
* another discovery. */
EP_DHCPData.xDHCPTxPeriod <<= 1;
if( EP_DHCPData.xDHCPTxPeriod <= ( TickType_t ) ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
{
if( xApplicationGetRandomNumber( &( EP_DHCPData.ulTransactionId ) ) != pdFALSE )
{
EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
if( EP_DHCPData.xUseBroadcast != pdFALSE )
{
EP_DHCPData.xUseBroadcast = pdFALSE;
}
else
{
EP_DHCPData.xUseBroadcast = pdTRUE;
}
if( prvSendDHCPDiscover() == pdPASS )
{
FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", EP_DHCPData.xDHCPTxPeriod ) );
}
else
{
/* Either the creation of a message buffer failed, or sendto().
* Try again in the next cycle. */
FreeRTOS_debug_printf( ( "Send failed during eWaitingOffer/2.\n" ) );
EP_DHCPData.eDHCPState = eInitialWait;
}
}
else
{
FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) );
}
}
else
{
FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", EP_DHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );
#if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
{
/* Only use a fake Ack if the default IP address == 0x00
* and the link local addressing is used. Start searching
* a free LinkLayer IP-address. Next state will be
* 'eGetLinkLayerAddress'. */
prvPrepareLinkLayerIPLookUp();
/* Setting an IP address manually so set to not using
* leased address mode. */
EP_DHCPData.eDHCPState = eGetLinkLayerAddress;
}
#else
{
xGivingUp = pdTRUE;
}
#endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
}
}
else
{
/* There was no DHCP reply, there was no time-out, just keep on waiting. */
}
break;
case eWaitingAcknowledge:
/* Look for acks coming in. */
if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS )
{
FreeRTOS_debug_printf( ( "vDHCPProcess: acked %xip\n", ( unsigned ) FreeRTOS_ntohl( EP_DHCPData.ulOfferedIPAddress ) ) );
/* DHCP completed. The IP address can now be used, and the
* timer set to the lease timeout time. */
*ipLOCAL_IP_ADDRESS_POINTER = EP_DHCPData.ulOfferedIPAddress;
/* Setting the 'local' broadcast address, something like
* '192.168.1.255'. */
EP_IPv4_SETTINGS.ulBroadcastAddress = ( EP_DHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
EP_DHCPData.eDHCPState = eLeasedAddress;
iptraceDHCP_SUCCEDEED( EP_DHCPData.ulOfferedIPAddress );
/* DHCP failed, the default configured IP-address will be used
* Now call vIPNetworkUpCalls() to send the network-up event and
* start the ARP timer. */
vIPNetworkUpCalls();
/* Close socket to ensure packets don't queue on it. */
prvCloseDHCPSocket();
if( EP_DHCPData.ulLeaseTime == 0U )
{
EP_DHCPData.ulLeaseTime = ( uint32_t ) dhcpDEFAULT_LEASE_TIME;
}
else if( EP_DHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME )
{
EP_DHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME;
}
else
{
/* The lease time is already valid. */
}
/* Check for clashes. */
vARPSendGratuitous();
vIPReloadDHCPTimer( EP_DHCPData.ulLeaseTime );
}
else
{
/* Is it time to send another Discover? */
if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
{
/* Increase the time period, and if it has not got to the
* point of giving up - send another request. */
EP_DHCPData.xDHCPTxPeriod <<= 1;
if( EP_DHCPData.xDHCPTxPeriod <= ( TickType_t ) ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
{
EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
if( prvSendDHCPRequest() == pdPASS )
{
/* The message is sent. Stay in state 'eWaitingAcknowledge'. */
}
else
{
/* Either the creation of a message buffer failed, or sendto().
* Try again in the next cycle. */
FreeRTOS_debug_printf( ( "Send failed during eWaitingAcknowledge.\n" ) );
EP_DHCPData.eDHCPState = eSendDHCPRequest;
}
}
else
{
/* Give up, start again. */
EP_DHCPData.eDHCPState = eInitialWait;
}
}
}
break;
#if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
case eGetLinkLayerAddress:
if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
{
if( xARPHadIPClash == pdFALSE )
{
/* ARP OK. proceed. */
iptraceDHCP_SUCCEDEED( EP_DHCPData.ulOfferedIPAddress );
/* Auto-IP succeeded, the default configured IP-address will
* be used. Now call vIPNetworkUpCalls() to send the
* network-up event and start the ARP timer. */
vIPNetworkUpCalls();
EP_DHCPData.eDHCPState = eNotUsingLeasedAddress;
}
else
{
/* ARP clashed - try another IP address. */
prvPrepareLinkLayerIPLookUp();
/* Setting an IP address manually so set to not using leased
* address mode. */
EP_DHCPData.eDHCPState = eGetLinkLayerAddress;
}
}
break;
#endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
case eLeasedAddress:
if( FreeRTOS_IsNetworkUp() != 0 )
{
/* Resend the request at the appropriate time to renew the lease. */
prvCreateDHCPSocket();
if( xDHCPSocket != NULL )
{
uint32_t ulID = 0U;
if( xApplicationGetRandomNumber( &( ulID ) ) != pdFALSE )
{
EP_DHCPData.ulTransactionId = ulID;
}
EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
if( prvSendDHCPRequest() == pdPASS )
{
/* The packet was sent successfully, wait for an acknowledgement. */
EP_DHCPData.eDHCPState = eWaitingAcknowledge;
}
else
{
/* The packet was not sent, try sending it later. */
EP_DHCPData.eDHCPState = eSendDHCPRequest;
FreeRTOS_debug_printf( ( "Send failed eLeasedAddress.\n" ) );
}
/* From now on, we should be called more often */
vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
}
}
else
{
/* See PR #53 on github/freertos/freertos */
FreeRTOS_printf( ( "DHCP: lease time finished but network is down\n" ) );
vIPReloadDHCPTimer( pdMS_TO_TICKS( 5000U ) );
}
break;
case eNotUsingLeasedAddress:
vIPSetDHCPTimerEnableState( pdFALSE );
break;
default:
/* Lint: all options are included. */
break;
}
if( xGivingUp != pdFALSE )
{
/* xGivingUp became true either because of a time-out, or because
* xApplicationDHCPHook() returned another value than 'eDHCPContinue',
* meaning that the conversion is cancelled from here. */
/* Revert to static IP address. */
taskENTER_CRITICAL();
{
*ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress );
}
taskEXIT_CRITICAL();
EP_DHCPData.eDHCPState = eNotUsingLeasedAddress;
vIPSetDHCPTimerEnableState( pdFALSE );
/* DHCP failed, the default configured IP-address will be used. Now
* call vIPNetworkUpCalls() to send the network-up event and start the ARP
* timer. */
vIPNetworkUpCalls();
/* Close socket to ensure packets don't queue on it. */
prvCloseDHCPSocket();
}
}
}