Skip to content

Commit

Permalink
Adds support for receiving Multicast Group addresses + IGMP ( IPv4 on…
Browse files Browse the repository at this point in the history
…ly )

Adds 2 function pointers to the network interface struct that handle adding and removing  multicast MAC addresses.
Updates IGMP to use function pointers through the network interface.
Makes the Add/Remove Multicast functions private to NetworkInterface.c They are now used through pointers in the NetworkInterface_t struct.
Improves the SAME70 driver to handle adding/removing muticast MAC addresses
  • Loading branch information
Emil Popov committed Sep 19, 2023
1 parent 222a36d commit 0ed2fbb
Show file tree
Hide file tree
Showing 14 changed files with 1,300 additions and 32 deletions.
5 changes: 5 additions & 0 deletions source/FreeRTOS_DNS_Networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
* going to be '0' i.e. success. Thus, return value is discarded */
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &( uxWriteTimeOut_ticks ), sizeof( TickType_t ) );
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &( uxReadTimeOut_ticks ), sizeof( TickType_t ) );
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
/* Since this socket may be used for LLMNR or mDNS, set the multicast TTL to 1. */
uint8_t ucMulticastTTL = 1;
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_IP_MULTICAST_TTL, &( ucMulticastTTL ), sizeof( uint8_t ) );
#endif
}

return xSocket;
Expand Down
810 changes: 810 additions & 0 deletions source/FreeRTOS_IGMP.c

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions source/FreeRTOS_IP.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_Routing.h"
#include "FreeRTOS_ND.h"
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
#include "FreeRTOS_IGMP.h"
#endif

/** @brief Time delay between repeated attempts to initialise the network hardware. */
#ifndef ipINITIALISATION_RETRY_DELAY
Expand Down Expand Up @@ -467,6 +470,26 @@ static void prvProcessIPEventsAndTimers( void )
/* xQueueReceive() returned because of a normal time-out. */
break;

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
case eSocketOptAddMembership:
{
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) xReceivedEvent.pvData;
( void ) vModifyMulticastMembership( pxMCG, eSocketOptAddMembership );
break;
}

case eSocketOptDropMembership:
{
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) xReceivedEvent.pvData;
( void ) vModifyMulticastMembership( pxMCG, eSocketOptDropMembership );
break;
}

case eIGMPEvent:
( void ) vHandleIGMP_Event();
break;
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0) */

default:
/* Should not get here. */
break;
Expand Down Expand Up @@ -526,6 +549,11 @@ static void prvIPTask_Initialise( void )
}
#endif /* ( ( ipconfigUSE_DNS_CACHE != 0 ) && ( ipconfigUSE_DNS != 0 ) ) */

/* Init the list that will hold scheduled IGMP reports. */
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
( void ) vIGMP_Init();
#endif

/* Initialisation is complete and events can now be processed. */
xIPTaskInitialised = pdTRUE;
}
Expand Down Expand Up @@ -1980,6 +2008,13 @@ static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacke
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
case ipPROTOCOL_IGMP:
/* The IP packet contained an IGMP frame. */
eReturn = eProcessIGMPPacket( pxNetworkBuffer );
break;
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */

case ipPROTOCOL_UDP:
/* The IP packet contained a UDP frame. */

Expand Down
41 changes: 41 additions & 0 deletions source/FreeRTOS_IP_Timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
#include "NetworkBufferManagement.h"
#include "FreeRTOS_Routing.h"
#include "FreeRTOS_DNS.h"
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
#include "FreeRTOS_IGMP.h"
#endif
/*-----------------------------------------------------------*/

/** @brief 'xAllNetworksUp' becomes pdTRUE as soon as all network interfaces have
Expand Down Expand Up @@ -110,6 +113,11 @@ static IPTimer_t xARPTimer;
static IPTimer_t xDNSTimer;
#endif

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
/** @brief IGMP timer. Used for sending scheduled IGMP Reports */
static IPTimer_t xIGMPTimer;
#endif

/** @brief As long as not all networks are up, repeat initialisation by calling the
* xNetworkInterfaceInitialise() function of the interfaces that are not ready. */

Expand Down Expand Up @@ -176,6 +184,15 @@ TickType_t xCalculateSleepTime( void )
}
#endif

#if ( ipconfigSUPPORT_IP_MULTICAST == 1 )
{
if( xIGMPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xIGMPTimer.ulRemainingTime;
}
}
#endif /* ipconfigSUPPORT_IP_MULTICAST */

#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
Expand Down Expand Up @@ -312,6 +329,16 @@ void vCheckNetworkTimers( void )
vSocketListenNextTime( NULL );
#endif /* ipconfigUSE_TCP == 1 */

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
{
/* Is it time to send any IGMP reports? */
if( prvIPTimerCheck( &xIGMPTimer ) != pdFALSE )
{
( void ) xSendIGMPEvent();
}
}
#endif /* ipconfigSUPPORT_IP_MULTICAST != 0 */

/* Is it time to trigger the repeated NetworkDown events? */
if( xAllNetworksUp == pdFALSE )
{
Expand Down Expand Up @@ -412,6 +439,20 @@ void vARPTimerReload( TickType_t xTime )

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

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )

/**
* @brief Reload the IGMP timer.
*
* @param[in] xIgmpTickTime: The reload value.
*/
void vIGMPTimerReload( TickType_t xIgmpTickTime )
{
prvIPTimerReload( &xIGMPTimer, pdMS_TO_TICKS( ipIGMP_TIMER_PERIOD_MS ) );
}
#endif /* ipconfigSUPPORT_IP_MULTICAST */
/*-----------------------------------------------------------*/

#if ( ipconfigDNS_USE_CALLBACKS != 0 )

/**
Expand Down
46 changes: 45 additions & 1 deletion source/FreeRTOS_Sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
#include "FreeRTOS_DNS.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_Routing.h"

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
#include "FreeRTOS_IGMP.h"
#endif
#if ( ipconfigUSE_TCP_MEM_STATS != 0 )
#include "tcp_mem_stats.h"
#endif
Expand Down Expand Up @@ -738,6 +740,11 @@ Socket_t FreeRTOS_socket( BaseType_t xDomain,
pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
}
#endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
pxSocket->u.xUDP.ucMulticastTTL = ipconfigMULTICAST_DEFAULT_TTL;
vListInitialise( &pxSocket->u.xUDP.xMulticastGroupsList );
#endif
}

#if ( ipconfigUSE_TCP == 1 )
Expand Down Expand Up @@ -1432,6 +1439,17 @@ static int32_t prvSendUDPPacket( const FreeRTOS_Socket_t * pxSocket,
pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket );

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
if( xIsIPv4Multicast( pxDestinationAddress->sin_address.ulIP_IPv4 ) )
{
pxNetworkBuffer->ucSendTTL = pxSocket->u.xUDP.ucMulticastTTL;
}
else
{
pxNetworkBuffer->ucSendTTL = ipconfigUDP_TIME_TO_LIVE;
}
#endif

/* The socket options are passed to the IP layer in the
* space that will eventually get used by the Ethernet header. */
pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
Expand Down Expand Up @@ -2132,6 +2150,18 @@ void * vSocketClose( FreeRTOS_Socket_t * pxSocket )
#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
}

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
if( pxSocket->ucProtocol == ipPROTOCOL_UDP )
{
/* Un-register all multicast groups that might have been added. */
while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xMulticastGroupsList ) ) > 0U )
{
MCastGroupDesc_t * pMCD = ( MCastGroupDesc_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xMulticastGroupsList ) );
( void ) vModifyMulticastMembership( pMCD, eSocketOptDropMembership );
}
}
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */

/* Now the socket is not bound the list of waiting packets can be
* drained. */
if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
Expand Down Expand Up @@ -2929,6 +2959,20 @@ BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
break;
#endif /* ipconfigUSE_TCP == 1 */

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
case FREERTOS_SO_IP_MULTICAST_TTL:
case FREERTOS_SO_IP_ADD_MEMBERSHIP:
case FREERTOS_SO_IP_DROP_MEMBERSHIP:
/* Use extern here, because we don't want to expose xSetMulticastSocketOption through .h files */
extern BaseType_t xSetMulticastSocketOption( Socket_t xSocket,
int32_t lLevel,
int32_t lOptionName,
const void * pvOptionValue,
size_t uxOptionLength );
xReturn = xSetMulticastSocketOption( xSocket, lLevel, lOptionName, pvOptionValue, uxOptionLength );
break;
#endif /* (ipconfigSUPPORT_IP_MULTICAST != 0) */

default:
/* No other options are handled. */
xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
Expand Down
44 changes: 44 additions & 0 deletions source/FreeRTOS_UDP_IPv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
/* *INDENT-OFF* */
#if( ipconfigUSE_IPv4 != 0 )
/* *INDENT-ON* */
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
#include "FreeRTOS_IGMP.h"
#endif

/** @brief The expected IP version and header length coded into the IP header itself. */
#define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
Expand Down Expand Up @@ -229,6 +232,13 @@ void vProcessGeneratedUDPPacket_IPv4( NetworkBufferDescriptor_t * const pxNetwor
}
#endif

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
if( ( pxNetworkBuffer->xIPAddress.ulIP_IPv4 != ipLLMNR_IP_ADDR ) && ( pxNetworkBuffer->xIPAddress.ulIP_IPv4 == ipMDNS_IP_ADDRESS ) )
{
pxIPHeader->ucTimeToLive = pxNetworkBuffer->ucSendTTL;
}
#endif

#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
pxIPHeader->usHeaderChecksum = 0U;
Expand Down Expand Up @@ -364,6 +374,40 @@ BaseType_t xProcessReceivedUDPPacket_IPv4( NetworkBufferDescriptor_t * pxNetwork

*pxIsWaitingForARPResolution = pdFALSE;

#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )

/* If this incoming packet is a multicast, we may have a socket for the port, but we still need
* to ensure the socket is subscribed to that particular multicast group. Note: Since this stack
* does not support port reusing, we don't have to worry about two UDP sockets bound to the exact same
* local port, but subscribed to different multicast groups. If this was allowed, this check
* would have to be moved to the pxUDPSocketLookup() function itself. */
if( ( pxSocket != NULL ) && ( xIsIPv4Multicast( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) ) )
{
/* Note: There is no need for vTaskSuspendAll/xTaskResumeAll here because only the IP Task
* touches the socket's multicast groups list directly. */
const ListItem_t * pxIterator;
const ListItem_t * xEnd = listGET_END_MARKER( &( pxSocket->u.xUDP.xMulticastGroupsList ) );

for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
pxIterator != ( const ListItem_t * ) xEnd;
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
{
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );

if( pxMCG->mreq.imr_multiaddr.sin_address.ulIP_IPv4 == pxUDPPacket->xIPHeader.ulDestinationIPAddress )
{
break;
}
}

if( pxIterator == ( const ListItem_t * ) xEnd )
{
/* This socket is not subscribed to this multicast group. Nullify the result from pxUDPSocketLookup() */
pxSocket = NULL;
}
}
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */

do
{
if( pxSocket != NULL )
Expand Down
24 changes: 24 additions & 0 deletions source/include/FreeRTOSIPConfigDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -1160,4 +1160,28 @@
#define ipconfigPORT_SUPPRESS_WARNING ( 0 )
#endif

/* Setting to 1 will enable the reception of IPv4 multicast groups
* and the associated socket options that need to be set before
* a socket would properly receive multicast packets. */
#ifndef ipconfigSUPPORT_IP_MULTICAST
#define ipconfigSUPPORT_IP_MULTICAST ( 0 )
#endif

/* Specifies the TTL value that will be used for multicast
* UDP packets by default. Can be overridden per socket by
* setting the FREERTOS_SO_IP_MULTICAST_TTL socket option. */
#ifndef ipconfigMULTICAST_DEFAULT_TTL
#define ipconfigMULTICAST_DEFAULT_TTL ( 1 )
#endif

/* Set to 1 if you plan on implementing IGMP snooping.
* When set to 1, the user must implement the following hooks:
* eFrameProcessingResult_t eApplicationIgmpFrameReceivedHook( NetworkBufferDescriptor_t * pxNetworkBuffer )
* void vApplicationIgmpSendLocalMessageHook( NetworkBufferDescriptor_t * pxNetworkBuffer, uint8_t ucIgmpMsgType, uint32_t uiMulticastGroup )
* void vApplicationIgmpEventHook( void )
*/
#ifndef ipconfigIGMP_SNOOPING
#define ipconfigIGMP_SNOOPING ( 0 )
#endif

#endif /* FREERTOS_DEFAULT_IP_CONFIG_H */
Loading

0 comments on commit 0ed2fbb

Please sign in to comment.