Skip to content

Commit

Permalink
changes the mreq structures definition to be more inline with the res…
Browse files Browse the repository at this point in the history
…t of the world.

a bunch of refactoring
  • Loading branch information
Emil Popov committed Oct 13, 2023
1 parent 156d924 commit 293f543
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 87 deletions.
118 changes: 79 additions & 39 deletions source/FreeRTOS_IGMP.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,16 @@
pxInterface->pfAddMulticastMAC( IGMP_MacAddress.ucBytes );
}

IGMPReportDesc_t * pxIRD;
MCastReportData_t * pxIRD;
#if ( ipconfigUSE_LLMNR != 0 )
if( NULL != ( pxIRD = ( IGMPReportDesc_t * ) pvPortMalloc( sizeof( IGMPReportDesc_t ) ) ) )
if( NULL != ( pxIRD = ( MCastReportData_t * ) pvPortMalloc( sizeof( MCastReportData_t ) ) ) )
{
listSET_LIST_ITEM_OWNER( &( pxIRD->xListItem ), ( void * ) pxIRD );
/* Quick and dirty assignment of end-point. This will probably have to be re-designed and re-done. */
pxIRD->pxEndPoint = FreeRTOS_FirstEndPoint( FreeRTOS_FirstNetworkInterface() );
pxIRD->mreq.imr_interface.sin_family = FREERTOS_AF_INET;
pxIRD->mreq.imr_interface.sin_len = sizeof( struct freertos_sockaddr );
pxIRD->mreq.imr_interface.sin_address.ulIP_IPv4 = FreeRTOS_htonl( 0x00000000U );
pxIRD->mreq.imr_multiaddr.sin_family = FREERTOS_AF_INET;
pxIRD->mreq.imr_multiaddr.sin_len = sizeof( struct freertos_sockaddr );
pxIRD->mreq.imr_multiaddr.sin_address.ulIP_IPv4 = ipLLMNR_IP_ADDR;
/* ToDo: make sure we also join the IPv6 multicast group */
pxIRD->pxEndPoint = NULL;
pxIRD->xMCastGroupAddress.xIs_IPv6 = pdFALSE_UNSIGNED;
pxIRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 = ipLLMNR_IP_ADDR;
BaseType_t bReportItemConsumed = xAddIGMPReportToList( pxIRD );

if( pdTRUE != bReportItemConsumed )
Expand Down Expand Up @@ -198,33 +195,33 @@

/* and schedule the reports. Note, the IGMP event is set at 100ms
* which corresponds to the increment used in ucMaxRespTime.
* pxIRD->ucCountDown holds a count in increments of the IGMP event time, so 12 = 1200ms = 1.2s */
* pxMRD->ucCountDown holds a count in increments of the IGMP event time, so 12 = 1200ms = 1.2s */
const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &xIGMP_ScheduleList );
IGMPReportDesc_t * pxIRD;
MCastReportData_t * pxMRD;

for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
pxIterator != ( const ListItem_t * ) xEnd;
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
pxIRD = ( IGMPReportDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
pxMRD = ( MCastReportData_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

/* Continue parsing if we are dealing with a general query, or if we are servicing a group-specific
* query and this report matches the group-specific query's destination address*/
if( ( uiGroupAddress == 0U ) || ( uiGroupAddress == pxIRD->mreq.imr_multiaddr.sin_address.ulIP_IPv4 ) )
if( ( uiGroupAddress == 0U ) || ( uiGroupAddress == pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 ) )
{
/* This report needs to be scheduled for sending. Remember that it may already be scheduled.
* pxIRD->ucCountDown of zero means the report is not scheduled to be sent. If a report is scheduled, and it's
* pxMRD->ucCountDown of zero means the report is not scheduled to be sent. If a report is scheduled, and it's
* scheduled time is before ucMaxRespTime, there is nothing to be done. If a
* report is scheduled past ucMaxRespTime, or not scheduled at all, we need
* to schedule it for a random time between 0 and ucMaxRespTime. */
if( ( pxIRD->ucCountDown == 0 ) || ( pxIRD->ucCountDown >= ucMaxRespTime ) )
if( ( pxMRD->ucCountDown == 0 ) || ( pxMRD->ucCountDown >= ucMaxRespTime ) )
{
uint32_t uiRandom;

if( xApplicationGetRandomNumber( &( uiRandom ) ) == pdFALSE )
{
pxIRD->ucCountDown = uiNonRandomCounter++;
pxMRD->ucCountDown = uiNonRandomCounter++;

if( uiNonRandomCounter > ucMaxRespTime )
{
Expand All @@ -245,7 +242,7 @@
uiRandom -= ucMaxRespTime;
}

pxIRD->ucCountDown = ( uint8_t ) uiRandom;
pxMRD->ucCountDown = ( uint8_t ) uiRandom;
}
}
}
Expand All @@ -261,30 +258,67 @@
/* Go through the list of IGMP reports and send anything that needs to be sent. */
const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &xIGMP_ScheduleList );
IGMPReportDesc_t * pxIRD;
MCastReportData_t * pxMRD;
NetworkInterface_t * pxInterface;
NetworkEndPoint_t * pxEndPoint;

for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd ); pxIterator != ( const ListItem_t * ) xEnd; pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
pxIRD = ( IGMPReportDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
pxMRD = ( MCastReportData_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

/* Only decrement down to one. Decrementing to zero is handled later. */
if( pxIRD->ucCountDown > 1 )
if( pxMRD->ucCountDown > 1 )
{
pxIRD->ucCountDown--;
pxMRD->ucCountDown--;
}

if( pxIRD->pxEndPoint->bits.bIPv6 )
if( pxMRD->xMCastGroupAddress.xIs_IPv6 == pdTRUE_UNSIGNED )
{
/* ToDo: handle IPv6 multicast groups through ICMPv6 messages */
continue;
}

/* Hold off on sending reports until our IP is non-zero. This allows a bit of a wait during power up
* when the IP can be zero and also allows us to add reports to the list with a countdown of 1 for fast initial delay. */
if( ( pxIRD->ucCountDown == 1 ) && ( pxIRD->pxEndPoint->ipv4_settings.ulIPAddress != 0 ) )
if( pxMRD->ucCountDown == 1 )
{
pxIRD->ucCountDown = 0;
xSendIGMP( 0, ipIGMP_MEMBERSHIP_REPORT_V2, 0, pxIRD->mreq.imr_multiaddr.sin_address.ulIP_IPv4, pxIRD->pxEndPoint );
pxEndPoint = pxMRD->pxEndPoint;
/* If the end-point is null, the report is for all interfaces. */
if ( pxEndPoint == NULL)
{
for( pxInterface = FreeRTOS_FirstNetworkInterface();
pxInterface != NULL;
pxInterface = FreeRTOS_NextNetworkInterface( pxInterface ) )
{
for( pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
pxEndPoint != NULL;
pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ) )
{
if ( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED )
{
/* ToDo: handle ICMPv6 reports*/
continue;
}

/* Make sure the end-point has an IP address */
if ( pxEndPoint->ipv4_settings.ulIPAddress != 0 )
{
pxMRD->ucCountDown = 0;
xSendIGMP( 0, ipIGMP_MEMBERSHIP_REPORT_V2, 0, pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4, pxEndPoint );
}
else
{
}
}
}
}
else
{
/* Make sure the end-point has an IP address */
if ( pxEndPoint->ipv4_settings.ulIPAddress != 0 )
{
pxMRD->ucCountDown = 0;
xSendIGMP( 0, ipIGMP_MEMBERSHIP_REPORT_V2, 0, pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4, pxEndPoint );
}
}
}
}

Expand Down Expand Up @@ -324,15 +358,21 @@

const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &xIGMP_ScheduleList );
IGMPReportDesc_t * pxIRD;
MCastReportData_t * pxIRD;

for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
pxIterator != ( const ListItem_t * ) xEnd;
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
pxIRD = ( IGMPReportDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

if( pxIRD->mreq.imr_multiaddr.sin_address.ulIP_IPv4 == pMCastGroup->imr_multiaddr.sin_address.ulIP_IPv4 )
pxIRD = ( MCastReportData_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

if ( pxIRD->xMCastGroupAddress.xIs_IPv6 == pdTRUE_UNSIGNED )
{
/* ToDo: handle IPv6 */
continue;
}

if( pxIRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 == pMCastGroup->imr_multiaddr.s_addr )
{
/* Found a match. */
if( pxIRD->xNumSockets > 0 )
Expand All @@ -356,21 +396,21 @@
*
* @param[in] pNewEntry: The multicast group descriptor to search for.
*/
BaseType_t xAddIGMPReportToList( IGMPReportDesc_t * pNewEntry )
BaseType_t xAddIGMPReportToList( MCastReportData_t * pNewEntry )
{
configASSERT( pNewEntry != NULL );

const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &xIGMP_ScheduleList );
IGMPReportDesc_t * pxIRD;
MCastReportData_t * pxIRD;

for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
pxIterator != ( const ListItem_t * ) xEnd;
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
pxIRD = ( IGMPReportDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
pxIRD = ( MCastReportData_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

if( pxIRD->mreq.imr_multiaddr.sin_address.ulIP_IPv4 == pNewEntry->mreq.imr_multiaddr.sin_address.ulIP_IPv4 )
if( pxIRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 == pNewEntry->xMCastGroupAddress.xIPAddress.ulIP_IPv4 )
{
/* Found a duplicate. All IGMP snooping switches already know that we are interested.
* Just keep track of how many sockets are interested in this multicast group. */
Expand Down Expand Up @@ -431,7 +471,7 @@
{
pxMCG = ( MCastGroupDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

if( pxMCG->mreq.imr_multiaddr.sin_address.ulIP_IPv4 == pxMulticastGroup->mreq.imr_multiaddr.sin_address.ulIP_IPv4 )
if( pxMCG->mreq.imr_multiaddr.s_addr == pxMulticastGroup->mreq.imr_multiaddr.s_addr )
{
/* Found a match. If we need to remove this address, go ahead.
* If we need to add it, it's already there, so just free the the descriptor to prevent memory leaks. */
Expand Down Expand Up @@ -462,7 +502,7 @@
vListInsertEnd( &( pxSocket->u.xUDP.xMulticastGroupsList ), &( pxMulticastGroup->xListItem ) );
/* Inform the network driver */
uint8_t MCastDestMacBytes[ 6 ];
vSetMultiCastIPv4MacAddress( pxMulticastGroup->mreq.imr_multiaddr.sin_address.ulIP_IPv4, MCastDestMacBytes );
vSetMultiCastIPv4MacAddress( pxMulticastGroup->mreq.imr_multiaddr.s_addr, MCastDestMacBytes );

if( pxNetIf )
{
Expand Down Expand Up @@ -493,7 +533,7 @@
else
{
/* Adding, but found duplicate. No need to inform the network driver. Simply free
* the IGMPReportDesc_t */
* the MCastReportData_t */
if( pxMulticastGroup->pxIGMPReportDesc )
{
vPortFree( pxMulticastGroup->pxIGMPReportDesc );
Expand All @@ -512,7 +552,7 @@
/* Removing and found a match. */
/* Inform the network driver */
uint8_t MCastDestMacBytes[ 6 ];
vSetMultiCastIPv4MacAddress( pxMulticastGroup->mreq.imr_multiaddr.sin_address.ulIP_IPv4, MCastDestMacBytes );
vSetMultiCastIPv4MacAddress( pxMulticastGroup->mreq.imr_multiaddr.s_addr, MCastDestMacBytes );

if( pxNetIf )
{
Expand Down
24 changes: 13 additions & 11 deletions source/FreeRTOS_Sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -6427,22 +6427,22 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )

struct freertos_ip_mreq * pMReq = ( struct freertos_ip_mreq * ) pvOptionValue;

if( pdFALSE == xIsIPv4Multicast( pMReq->imr_multiaddr.sin_address.ulIP_IPv4 ) )
if( pdFALSE == xIsIPv4Multicast( pMReq->imr_multiaddr.s_addr ) )
{
break; /* will return -pdFREERTOS_ERRNO_EINVAL */
}

/* Allocate some RAM to remember the multicast group that is being registered */
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) pvPortMalloc( sizeof( MCastGroupDesc_t ) );
IGMPReportDesc_t * pxIRD = ( IGMPReportDesc_t * ) pvPortMalloc( sizeof( IGMPReportDesc_t ) );
MCastReportData_t * pxMRD = ( MCastReportData_t * ) pvPortMalloc( sizeof( MCastReportData_t ) );

if( NULL == pxMCG )
{
xReturn = -pdFREERTOS_ERRNO_ENOMEM;
break;
}

if( NULL == pxIRD )
if( NULL == pxMRD )
{
xReturn = -pdFREERTOS_ERRNO_ENOMEM;
vPortFree( pxMCG );
Expand All @@ -6460,24 +6460,26 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )

/* Init the IGMP report description. It needs to hold the same membership information
* and it will eventually be added to the IGMP list. */
( void ) memcpy( ( void * ) &pxIRD->mreq, pvOptionValue, uxOptionLength );
listSET_LIST_ITEM_OWNER( &( pxIRD->xListItem ), ( void * ) pxIRD );
pxIRD->xNumSockets = 0;
pxIRD->ucCountDown = 0;
pxMRD->xMCastGroupAddress.xIs_IPv6 = pdFALSE_UNSIGNED;
pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 = pMReq->imr_multiaddr.s_addr;
pxMRD->pxEndPoint = NULL;
listSET_LIST_ITEM_OWNER( &( pxMRD->xListItem ), ( void * ) pxMRD );
pxMRD->xNumSockets = 0;
pxMRD->ucCountDown = 0;
/* Quick and dirty assignment of end-point. This will probably have to be re-designed and re-done. */
pxIRD->pxEndPoint = ( pxSocket->bits.bIsIPv6 ) ? FreeRTOS_FirstEndPoint_IPv6( FreeRTOS_FirstNetworkInterface() ) : FreeRTOS_FirstEndPoint( FreeRTOS_FirstNetworkInterface() );
pxMRD->pxEndPoint = ( pxSocket->bits.bIsIPv6 ) ? FreeRTOS_FirstEndPoint_IPv6( FreeRTOS_FirstNetworkInterface() ) : FreeRTOS_FirstEndPoint( FreeRTOS_FirstNetworkInterface() );


/* Pass the IGMP report descriptor inside the multicast group descriptor,
* so we can easily pass it to the IP task in one message. */
pxMCG->pxIGMPReportDesc = pxIRD;
pxMCG->pxIGMPReportDesc = pxMRD;

IPStackEvent_t xSockOptsEvent = { eSocketOptAddMembership, ( void * ) pxMCG };

if( xSendEventStructToIPTask( &( xSockOptsEvent ), portMAX_DELAY ) != pdPASS )
{
vPortFree( pxMCG );
vPortFree( pxIRD );
vPortFree( pxMRD );
xReturn = -1;
}
else
Expand All @@ -6496,7 +6498,7 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )

struct freertos_ip_mreq * pMReq = ( struct freertos_ip_mreq * ) pvOptionValue;

if( pdFALSE == xIsIPv4Multicast( pMReq->imr_multiaddr.sin_address.ulIP_IPv4 ) )
if( pdFALSE == xIsIPv4Multicast( pMReq->imr_multiaddr.s_addr ) )
{
break; /* will return -pdFREERTOS_ERRNO_EINVAL */
}
Expand Down
2 changes: 1 addition & 1 deletion source/FreeRTOS_UDP_IPv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ BaseType_t xProcessReceivedUDPPacket_IPv4( NetworkBufferDescriptor_t * pxNetwork
{
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

if( pxMCG->mreq.imr_multiaddr.sin_address.ulIP_IPv4 == pxUDPPacket->xIPHeader.ulDestinationIPAddress )
if( pxMCG->mreq.imr_multiaddr.s_addr == pxUDPPacket->xIPHeader.ulDestinationIPAddress )
{
break;
}
Expand Down
28 changes: 1 addition & 27 deletions source/include/FreeRTOS_IGMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,6 @@
#define ipIGMP_IP_ADDR 0x010000E0UL
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */

struct freertos_ip_mreq
{
/* _EVP_ This can be simplified a bit on a single IF, IPv4 only system
* but keeping it more generic allows for future use in multi-IF dual-stack implementations. */
struct freertos_sockaddr imr_multiaddr; /* IP multicast address of a group */
struct freertos_sockaddr imr_interface; /* local IP address of the interface to be used */
};

/** @brief The structure information about the IGMP reports that will get sent when the stack receives an IGMP general query. */
typedef struct xIGMPReportDesc
{
struct freertos_ip_mreq mreq; /**< Struct for storing the original mreq structure that was sent to setsockopts() */
struct xLIST_ITEM xListItem; /**< List struct. */
NetworkEndPoint_t * pxEndPoint;
BaseType_t xNumSockets;
uint8_t ucCountDown;
} IGMPReportDesc_t;

/** @brief The structure to hold a "descriptor" for a multicast group that a socket has registered to. */
typedef struct xMCastGroupDesc
{
struct freertos_ip_mreq mreq; /**< Struct for storing the original mreq structure that was sent to setsockopts() */
struct xLIST_ITEM xListItem; /**< List struct. */
FreeRTOS_Socket_t * pxSocket;
IGMPReportDesc_t * pxIGMPReportDesc; /** Optional. used to hold the allocated IGMP report descriptor while passing from user code to the IP Task. */
} MCastGroupDesc_t;

#include "pack_struct_start.h"
struct xIGMP_HEADER
Expand Down Expand Up @@ -116,7 +90,7 @@
BaseType_t xSendIGMPEvent( void );
void vHandleIGMP_Event( void );
void vRemoveIGMPReportFromList( struct freertos_ip_mreq * pMCastGroup );
BaseType_t xAddIGMPReportToList( IGMPReportDesc_t * pNewEntry );
BaseType_t xAddIGMPReportToList( MCastReportData_t * pNewEntry );
eFrameProcessingResult_t eProcessIGMPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );


Expand Down
24 changes: 24 additions & 0 deletions source/include/FreeRTOS_IP_Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ typedef struct xxIPv46_Address
BaseType_t xIs_IPv6; /**< pdTRUE if IPv6 address. */
} IPv46_Address_t;

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
/** @brief The structure represents an IPv4 address. */
typedef struct freertos_in_addr {
uint32_t s_addr; /**< IPv4 address in network byte order */
} In_Addr_t;

/** @brief The structure is used to join/leave an IPv4 multicast group. */
typedef struct freertos_ip_mreq {
In_Addr_t imr_multiaddr; /**< The address of the multicast group */
In_Addr_t imr_interface; /**< The address of the network interface on which the multicast group is to be joined or left */
} IP_MReq_t;

/** @brief The structure represents an IPv6 address. */
typedef struct freertos_in6_addr {
IPv6_Address_t s6_addr; /**< IPv6 address */
}In6_Addr_t;

/** @brief The structure is used to join/leave an IPv6 multicast group. */
typedef struct freertos_ipv6_mreq {
In6_Addr_t ipv6mr_multiaddr; /**< The address of the multicast group */
uint32_t ipv6mr_interface; /**< The network interface index on which the multicast group is to be joined or left. 0 means use the default multicast interface. */
} IP6_MReq_t;
#endif

struct xNetworkEndPoint;
struct xNetworkInterface;

Expand Down
Loading

0 comments on commit 293f543

Please sign in to comment.