Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 46 additions & 42 deletions source/FreeRTOS_ARP.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@
* entry is still valid and can therefore be refreshed. */
#define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3U )

/** @brief The time between gratuitous ARPs. */
#ifndef arpGRATUITOUS_ARP_PERIOD
#define arpGRATUITOUS_ARP_PERIOD ( pdMS_TO_TICKS( 20000U ) )
#endif

/** @brief When there is another device which has the same IP address as the IP address
* of this device, a defensive ARP request should be sent out. However, according to
* RFC 5227 section 1.1, there must be a minimum interval of 10 seconds between
Expand Down Expand Up @@ -127,10 +122,6 @@

/*-----------------------------------------------------------*/

/** @brief The time at which the last gratuitous ARP was sent. Gratuitous ARPs are used
* to ensure ARP tables are up to date and to detect IP address conflicts. */
static TickType_t xLastGratuitousARPTime = 0U;

/**
* @brief Process the ARP packets.
*
Expand Down Expand Up @@ -226,8 +217,8 @@
FreeRTOS_OutputARPRequest_Multi( pxTargetEndPoint, pxTargetEndPoint->ipv4_settings.ulIPAddress );

/* Since an ARP Request for this IP was just sent, do not send a gratuitous
* ARP for arpGRATUITOUS_ARP_PERIOD. */
xLastGratuitousARPTime = xTaskGetTickCount();
* ARP for arpGRATUITOUS_ARP_PERIOD_MS, normally 300 seconds. */
vGARP_TimerReload( arpGRATUITOUS_ARP_PERIOD_MS );

/* Note the time at which this request was sent. */
vTaskSetTimeOutState( &xARPClashTimeOut );
Expand Down Expand Up @@ -943,6 +934,18 @@
eReturn = eARPGetCacheEntryGateWay( pulIPAddress, pxMACAddress, ppxEndPoint );
}

if( *ppxEndPoint != NULL )
{
struct xNetworkEndPoint * pxEndPoint = *ppxEndPoint;

if( ( pxEndPoint->bits.bEndPointUp == pdFALSE ) || ( pxEndPoint->pxNetworkInterface->bits.bInterfaceUp == pdFALSE ) )
{
/* _HT_ this printf is only used while testing. */
FreeRTOS_printf( ( "eARPGetCacheEntry: endpoint that serves %xip is not up.\n", ( unsigned ) ( *pulIPAddress ) ) );
eReturn = eResolutionFailed;
}
}

return eReturn;
}
/*-----------------------------------------------------------*/
Expand Down Expand Up @@ -1110,9 +1113,16 @@
* When the age reaches zero it is no longer considered valid. */
( xARPCache[ x ].ucAge )--;

if( xARPCache[ x ].ucAge == 0U )
{
/* The entry is no longer valid. Wipe it out. */
iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
xARPCache[ x ].ulIPAddress = 0U;
}

/* If the entry is not yet valid, then it is waiting an ARP
* reply, and the ARP request should be retransmitted. */
if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
else if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
{
FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
}
Expand All @@ -1127,21 +1137,21 @@
{
/* The age has just ticked down, with nothing to do. */
}

if( xARPCache[ x ].ucAge == 0U )
{
/* The entry is no longer valid. Wipe it out. */
iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
xARPCache[ x ].ulIPAddress = 0U;
}
}
}
}
/*-----------------------------------------------------------*/

xTimeNow = xTaskGetTickCount();

if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
/**
* @brief Send a Gratuitous ARP packet to allow this node to announce the IP-MAC
* mapping to the entire network.
*/
void vARPSendGratuitous( void )
{
/* The IP-task is calling, allow it to actually send the packet. */
if( xIsCallingFromIPTask() )
{
NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );

while( pxEndPoint != NULL )
{
Expand All @@ -1153,26 +1163,16 @@
}
}

pxEndPoint = pxEndPoint->pxNext;
pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint );
}

xLastGratuitousARPTime = xTimeNow;
}
}
/*-----------------------------------------------------------*/

/**
* @brief Send a Gratuitous ARP packet to allow this node to announce the IP-MAC
* mapping to the entire network.
*/
void vARPSendGratuitous( void )
{
/* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
* time vARPAgeCache() is called. */
xLastGratuitousARPTime = ( TickType_t ) 0;
else
{
/* Let the IP-task call vARPAgeCache(). */
( void ) xSendEventToIPTask( eARPGratuitousEvent );
}

/* Let the IP-task call vARPAgeCache(). */
( void ) xSendEventToIPTask( eARPTimerEvent );
vGARP_TimerReload( arpGRATUITOUS_ARP_PERIOD_MS );
}

/*-----------------------------------------------------------*/
Expand All @@ -1189,7 +1189,11 @@
{
NetworkBufferDescriptor_t * pxNetworkBuffer;

if( ( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) &&
NetworkInterface_t * pxInterface = pxEndPoint->pxNetworkInterface;

/* If the interface is up, and it is an IPv4 end-point, and it has an IP address. */
if( ( pxInterface->bits.bInterfaceUp == pdTRUE ) &&
( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) &&
( pxEndPoint->ipv4_settings.ulIPAddress != 0U ) )
{
/* This is called from the context of the IP event task, so a block time
Expand Down Expand Up @@ -1300,7 +1304,7 @@

if( xLookupResult == eResolutionCacheMiss )
{
const TickType_t uxSleepTime = pdMS_TO_TICKS( 250U );
const TickType_t uxSleepTime = pdMS_TO_TICKS( 20U );

/* We might use ipconfigMAX_ARP_RETRANSMISSIONS here. */
vTaskSetTimeOutState( &xTimeOut );
Expand Down
18 changes: 18 additions & 0 deletions source/FreeRTOS_IP.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,27 @@ static void prvProcessIPEventsAndTimers( void )
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
break;

case eARPGratuitousEvent:
/* Send a Gratuitous ARP request. */
#if ipconfigIS_ENABLED( ipconfigUSE_IPv4 )
vARPSendGratuitous();
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
break;

case eNDTimerEvent:
/* The ND Resolution timer has expired, process the cache. */
#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
vNDAgeCache();
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
break;

case eNDSendUNAEvent:
/* The ARP Resolution timer has expired, process the cache. */
#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
vSendUnsolicitedNeighborAdvertisement();
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
break;

case eSocketBindEvent:

/* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
Expand Down Expand Up @@ -521,11 +535,15 @@ static void prvIPTask_Initialise( void )
#if ipconfigIS_ENABLED( ipconfigUSE_IPv4 )
/* Mark the ARP timer as inactive since we are not waiting on any resolution as of now. */
vIPSetARPResolutionTimerEnableState( pdFALSE );
/* Make sure the GARP timer is started. */
vGARP_TimerReload( arpGRATUITOUS_ARP_PERIOD_MS );
#endif

#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
/* Mark the ND timer as inactive since we are not waiting on any resolution as of now. */
vIPSetNDResolutionTimerEnableState( pdFALSE );
/* Make sure the UNA timer is started. */
vND_UNA_TimerReload( ndGRATUITOUS_UNA_PERIOD_MS );
#endif

#if ( ( ipconfigDNS_USE_CALLBACKS != 0 ) && ( ipconfigUSE_DNS != 0 ) )
Expand Down
103 changes: 101 additions & 2 deletions source/FreeRTOS_IP_Timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ static void prvIPTimerReload( IPTimer_t * pxTimer,

/** @brief ARP timer, to check its table entries. */
static IPTimer_t xARPTimer;

/** @brief Gratuitous timer, to send our IP-address unsolicited. */
static IPTimer_t xGratuitousTimer;
#endif
#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )

Expand All @@ -111,6 +114,9 @@ static void prvIPTimerReload( IPTimer_t * pxTimer,

/** @brief ND timer, to check its table entries. */
static IPTimer_t xNDTimer;

/** @brief Timer to send Unsolicited Neighbor Advertisements (UNA). */
static IPTimer_t xUnaTimer;
#endif
#if ( ipconfigUSE_TCP != 0 )
/** @brief TCP timer, to check for timeouts, resends. */
Expand Down Expand Up @@ -156,7 +162,15 @@ TickType_t xCalculateSleepTime( void )
uxMaximumSleepTime = xARPTimer.ulRemainingTime;
}
}
#endif

if( xGratuitousTimer.bActive != pdFALSE_UNSIGNED )
{
if( xGratuitousTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xGratuitousTimer.ulRemainingTime;
}
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */

#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
if( xNDTimer.bActive != pdFALSE_UNSIGNED )
Expand All @@ -166,7 +180,15 @@ TickType_t xCalculateSleepTime( void )
uxMaximumSleepTime = xNDTimer.ulRemainingTime;
}
}
#endif

if( xUnaTimer.bActive != pdFALSE_UNSIGNED )
{
if( xUnaTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xUnaTimer.ulRemainingTime;
}
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) */

#if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 )
{
Expand Down Expand Up @@ -254,6 +276,13 @@ void vCheckNetworkTimers( void )
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */

#if ipconfigIS_ENABLED( ipconfigUSE_IPv4 )
if( prvIPTimerCheck( &xGratuitousTimer ) != pdFALSE )
{
( void ) xSendEventToIPTask( eARPGratuitousEvent );
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */

#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
/* Is it time for ND processing? */
if( prvIPTimerCheck( &xNDTimer ) != pdFALSE )
Expand All @@ -279,6 +308,11 @@ void vCheckNetworkTimers( void )
iptraceDELAYED_ND_TIMER_EXPIRED();
}
}

if( prvIPTimerCheck( &xUnaTimer ) != pdFALSE )
{
( void ) xSendEventToIPTask( eNDSendUNAEvent );
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) */

#if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 )
Expand Down Expand Up @@ -482,6 +516,71 @@ static void prvIPTimerReload( IPTimer_t * pxTimer,
#endif
/*-----------------------------------------------------------*/

#if ipconfigIS_ENABLED( ipconfigUSE_IPv4 )

/**
* @brief Sets the reload time of the ARP gratuitous timer and restarts it.
*
* @param[in] xTime Time to be reloaded into the ARP timer.
*/
void vGARP_TimerReload( const TickType_t uxTimeMs )
{
/* ulRandMs gives a random variation expressed in ms. */
/* E.g. every 300 seconds +/- 10% (randomized per endpoint). */
uint32_t ulRandMs = uxTimeMs;
TickType_t uxPeriod;
const TickType_t ulMaxMs = uxTimeMs / 10u;

xApplicationGetRandomNumber( &ulRandMs );

if( ulRandMs > ulMaxMs )
{
ulRandMs %= ulMaxMs;
}

uxPeriod = pdMS_TO_TICKS( uxTimeMs ) + pdMS_TO_TICKS( ulRandMs );
prvIPTimerReload( &xGratuitousTimer, uxPeriod );
FreeRTOS_printf( ( "vGARP_TimerReload: %u + %u = %u ms\n",
( unsigned ) uxTimeMs,
( unsigned ) ulRandMs,
( unsigned ) uxPeriod ) );
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */
/*-----------------------------------------------------------*/

#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )

/**
* @brief Sets the reload time of a UNA:
* Unsolicited Neighbor Advertisements.
*
* @param[in] uxTimeMs Time (ms) to be reloaded into the timer.
*/
void vND_UNA_TimerReload( const TickType_t uxTimeMs )
{
/* ulRandMs gives a random variation expressed in ms. */
/* E.g. every 300 seconds +/- 10% (randomized per endpoint). */
uint32_t ulRandMs = uxTimeMs;
TickType_t uxPeriod;
const TickType_t ulMaxMs = uxTimeMs / 10u;

xApplicationGetRandomNumber( &ulRandMs );

if( ulRandMs > ulMaxMs )
{
ulRandMs %= ulMaxMs;
}

uxPeriod = pdMS_TO_TICKS( uxTimeMs ) + pdMS_TO_TICKS( ulRandMs );
prvIPTimerReload( &xUnaTimer, uxPeriod );
FreeRTOS_printf( ( "vSUNA_TimerReload: %u + %u = %u ms\n",
( unsigned ) uxTimeMs,
( unsigned ) ulRandMs,
( unsigned ) uxPeriod ) );
}
#endif /* if ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) */
/*-----------------------------------------------------------*/

#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )

/**
Expand Down
10 changes: 3 additions & 7 deletions source/FreeRTOS_IP_Utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,13 +822,9 @@ void prvProcessNetworkDownEvent( struct xNetworkInterface * pxInterface )

configASSERT( pxInterface != NULL );
configASSERT( pxInterface->pfInitialise != NULL );
/* Stop the Address Resolution timer while there is no network. */
#if ipconfigIS_ENABLED( ipconfigUSE_IPv4 )
vIPSetARPTimerEnableState( pdFALSE );
#endif
#if ipconfigIS_ENABLED( ipconfigUSE_IPv6 )
vIPSetNDTimerEnableState( pdFALSE );
#endif

/* Let the ARP and ND-timers vIPSetARPTimerEnableState()
* and vIPSetNDTimerEnableState() running. */

/* The first network down event is generated by the IP stack itself to
* initialise the network hardware, so do not call the network down event
Expand Down
Loading