Skip to content

Commit 5763c91

Browse files
tony-josi-awslightbulbkhuang
authored andcommitted
Fix DHCP race condition (FreeRTOS#1230)
* Initial * DHCP full code coverage * Fix formatting
1 parent ca583a3 commit 5763c91

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

source/FreeRTOS_DHCP.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@
257257
pxIterator = NULL;
258258
}
259259

260-
if( pxIterator != NULL )
260+
if( ( pxIterator != NULL ) && ( pxIterator->xDHCPData.eDHCPState == pxIterator->xDHCPData.eExpectedState ) )
261261
{
262262
/* The second parameter pdTRUE tells to check for a UDP message. */
263263
vDHCPProcessEndPoint( pdFALSE, pdTRUE, pxIterator );
@@ -269,15 +269,24 @@
269269
}
270270
else
271271
{
272-
/* Target not found, fetch the message and delete it. */
272+
/* Target not found or there is a state mismatch, fetch the message and delete it. */
273273
/* PAss the address of a pointer pucUDPPayload, because zero-copy is used. */
274274
lBytes = FreeRTOS_recvfrom( EP_DHCPData.xDHCPSocket, &( pucUDPPayload ), 0, FREERTOS_ZERO_COPY, NULL, NULL );
275275

276276
if( ( lBytes > 0 ) && ( pucUDPPayload != NULL ) )
277277
{
278278
/* Remove it now, destination not found. */
279279
FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayload );
280-
FreeRTOS_printf( ( "vDHCPProcess: Removed a %d-byte message: target not found\n", ( int ) lBytes ) );
280+
281+
if( pxIterator == NULL )
282+
{
283+
FreeRTOS_printf( ( "vDHCPProcess: Removed a %d-byte message: target not found\n", ( int ) lBytes ) );
284+
}
285+
else
286+
{
287+
FreeRTOS_printf( ( "vDHCPProcess: Wrong state: expected: %d got: %d : ignore\n",
288+
pxIterator->xDHCPData.eExpectedState, pxIterator->xDHCPData.eDHCPState ) );
289+
}
281290
}
282291
}
283292
}
@@ -489,6 +498,11 @@
489498
{
490499
/* Give up, start again. */
491500
EP_DHCPData.eDHCPState = eInitialWait;
501+
502+
/* Reset expected state so that DHCP packets from
503+
* different DHCP servers if available already in the DHCP socket can
504+
* be processed */
505+
EP_DHCPData.eExpectedState = eInitialWait;
492506
}
493507
}
494508
}
@@ -992,6 +1006,11 @@
9921006
{
9931007
/* Start again. */
9941008
EP_DHCPData.eDHCPState = eInitialWait;
1009+
1010+
/* Reset expected state so that DHCP packets from
1011+
* different DHCP servers if available already in the DHCP socket can
1012+
* be processed */
1013+
EP_DHCPData.eExpectedState = eInitialWait;
9951014
}
9961015
}
9971016

test/unit-test/FreeRTOS_DHCP/FreeRTOS_DHCP_stubs.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,4 +715,38 @@ static int32_t FreeRTOS_recvfrom_eWaitingOfferRecvfromSuccess_LocalMACAddrNotMat
715715

716716
return xSizeofUDPBuffer;
717717
}
718+
719+
static int32_t FreeRTOS_recvfrom_LoopedCall( const ConstSocket_t xSocket,
720+
void * pvBuffer,
721+
size_t uxBufferLength,
722+
BaseType_t xFlags,
723+
struct freertos_sockaddr * pxSourceAddress,
724+
socklen_t * pxSourceAddressLength,
725+
int callbacks )
726+
{
727+
NetworkEndPoint_t * pxIterator = pxNetworkEndPoints;
728+
size_t xSizeRetBufferSize = xSizeofUDPBuffer;
729+
730+
if( callbacks == 2 )
731+
{
732+
pxNetworkEndPoints->xDHCPData.eDHCPState = eInitialWait;
733+
}
734+
else if( callbacks == 4 )
735+
{
736+
xSizeRetBufferSize = 200;
737+
}
738+
739+
if( ( xFlags & FREERTOS_ZERO_COPY ) != 0 )
740+
{
741+
*( ( uint8_t ** ) pvBuffer ) = pucUDPBuffer;
742+
}
743+
744+
memset( pucUDPBuffer, 0, xSizeofUDPBuffer );
745+
/* Put in correct DHCP cookie. */
746+
( ( struct xDHCPMessage_IPv4 * ) pucUDPBuffer )->ulDHCPCookie = dhcpCOOKIE;
747+
( ( struct xDHCPMessage_IPv4 * ) pucUDPBuffer )->ucOpcode = dhcpREPLY_OPCODE;
748+
( ( struct xDHCPMessage_IPv4 * ) pucUDPBuffer )->ulTransactionID = FreeRTOS_htonl( 0x01ABCDEF );
749+
750+
return xSizeRetBufferSize;
751+
}
718752
/*-----------------------------------------------------------*/

test/unit-test/FreeRTOS_DHCP/FreeRTOS_DHCP_utest.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,49 @@ void test_vDHCPProcess_eLeasedAddress_CorrectState_ValidBytesInMessage( void )
12351235
TEST_ASSERT_EQUAL( eLeasedAddress, pxEndPoint->xDHCPData.eDHCPState );
12361236
}
12371237

1238+
/**
1239+
*@brief This test function ensures that when the DHCP states are mismatching after
1240+
* initial parsing of response from DHCP server, if a new response from a different DHCP
1241+
* server will cause a infinite loop inside the vDHCPProcess.
1242+
*/
1243+
void test_vDHCPProcess_eLeasedAddress_InCorrectState_Loop( void )
1244+
{
1245+
struct xSOCKET xTestSocket;
1246+
NetworkEndPoint_t xEndPoint = { 0 }, * pxEndPoint = &xEndPoint;
1247+
uint8_t * pucUDPPayload;
1248+
1249+
/* This should remain unchanged. */
1250+
xDHCPv4Socket = &xTestSocket;
1251+
xDHCPSocketUserCount = 1;
1252+
pxEndPoint->xDHCPData.xDHCPSocket = &xTestSocket;
1253+
/* Put the required state. */
1254+
pxEndPoint->xDHCPData.eDHCPState = eLeasedAddress;
1255+
pxEndPoint->xDHCPData.eExpectedState = eLeasedAddress;
1256+
pxEndPoint->xDHCPData.ulTransactionId = 0x01ABCDEF;
1257+
1258+
/* Make sure that the local IP address is uninitialised. */
1259+
pxEndPoint->ipv4_settings.ulIPAddress = 0;
1260+
/* Put a verifiable value. */
1261+
memset( &pxEndPoint->ipv4_settings, 0xAA, sizeof( IPV4Parameters_t ) );
1262+
/* Put a verifiable value. */
1263+
memset( &pxEndPoint->ipv4_defaults, 0xBB, sizeof( IPV4Parameters_t ) );
1264+
1265+
pxNetworkEndPoints = pxEndPoint;
1266+
1267+
/* Expect these arguments. */
1268+
FreeRTOS_recvfrom_Stub( FreeRTOS_recvfrom_LoopedCall );
1269+
1270+
FreeRTOS_ReleaseUDPPayloadBuffer_Expect( pucUDPBuffer );
1271+
1272+
FreeRTOS_IsEndPointUp_IgnoreAndReturn( pdFALSE );
1273+
1274+
FreeRTOS_ReleaseUDPPayloadBuffer_Ignore();
1275+
1276+
vDHCPProcess( pdFALSE, pxEndPoint );
1277+
1278+
TEST_ASSERT_EQUAL( eInitialWait, pxEndPoint->xDHCPData.eDHCPState );
1279+
}
1280+
12381281
void test_vDHCPProcess_eLeasedAddress_CorrectState_ValidBytesInMessage_TransactionIDMismatch( void )
12391282
{
12401283
struct xSOCKET xTestSocket;

0 commit comments

Comments
 (0)