Skip to content

Commit 0ed2fbb

Browse files
author
Emil Popov
committed
Adds support for receiving Multicast Group addresses + IGMP ( IPv4 only )
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
1 parent 222a36d commit 0ed2fbb

14 files changed

+1300
-32
lines changed

source/FreeRTOS_DNS_Networking.c

+5
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@
8484
* going to be '0' i.e. success. Thus, return value is discarded */
8585
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &( uxWriteTimeOut_ticks ), sizeof( TickType_t ) );
8686
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &( uxReadTimeOut_ticks ), sizeof( TickType_t ) );
87+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
88+
/* Since this socket may be used for LLMNR or mDNS, set the multicast TTL to 1. */
89+
uint8_t ucMulticastTTL = 1;
90+
( void ) FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_IP_MULTICAST_TTL, &( ucMulticastTTL ), sizeof( uint8_t ) );
91+
#endif
8792
}
8893

8994
return xSocket;

source/FreeRTOS_IGMP.c

+810
Large diffs are not rendered by default.

source/FreeRTOS_IP.c

+35
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
#include "FreeRTOS_DNS.h"
6060
#include "FreeRTOS_Routing.h"
6161
#include "FreeRTOS_ND.h"
62+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
63+
#include "FreeRTOS_IGMP.h"
64+
#endif
6265

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

473+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
474+
case eSocketOptAddMembership:
475+
{
476+
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) xReceivedEvent.pvData;
477+
( void ) vModifyMulticastMembership( pxMCG, eSocketOptAddMembership );
478+
break;
479+
}
480+
481+
case eSocketOptDropMembership:
482+
{
483+
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) xReceivedEvent.pvData;
484+
( void ) vModifyMulticastMembership( pxMCG, eSocketOptDropMembership );
485+
break;
486+
}
487+
488+
case eIGMPEvent:
489+
( void ) vHandleIGMP_Event();
490+
break;
491+
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0) */
492+
470493
default:
471494
/* Should not get here. */
472495
break;
@@ -526,6 +549,11 @@ static void prvIPTask_Initialise( void )
526549
}
527550
#endif /* ( ( ipconfigUSE_DNS_CACHE != 0 ) && ( ipconfigUSE_DNS != 0 ) ) */
528551

552+
/* Init the list that will hold scheduled IGMP reports. */
553+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
554+
( void ) vIGMP_Init();
555+
#endif
556+
529557
/* Initialisation is complete and events can now be processed. */
530558
xIPTaskInitialised = pdTRUE;
531559
}
@@ -1980,6 +2008,13 @@ static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacke
19802008
break;
19812009
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
19822010

2011+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
2012+
case ipPROTOCOL_IGMP:
2013+
/* The IP packet contained an IGMP frame. */
2014+
eReturn = eProcessIGMPPacket( pxNetworkBuffer );
2015+
break;
2016+
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
2017+
19832018
case ipPROTOCOL_UDP:
19842019
/* The IP packet contained a UDP frame. */
19852020

source/FreeRTOS_IP_Timers.c

+41
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
#include "NetworkBufferManagement.h"
5656
#include "FreeRTOS_Routing.h"
5757
#include "FreeRTOS_DNS.h"
58+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
59+
#include "FreeRTOS_IGMP.h"
60+
#endif
5861
/*-----------------------------------------------------------*/
5962

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

116+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
117+
/** @brief IGMP timer. Used for sending scheduled IGMP Reports */
118+
static IPTimer_t xIGMPTimer;
119+
#endif
120+
113121
/** @brief As long as not all networks are up, repeat initialisation by calling the
114122
* xNetworkInterfaceInitialise() function of the interfaces that are not ready. */
115123

@@ -176,6 +184,15 @@ TickType_t xCalculateSleepTime( void )
176184
}
177185
#endif
178186

187+
#if ( ipconfigSUPPORT_IP_MULTICAST == 1 )
188+
{
189+
if( xIGMPTimer.ulRemainingTime < uxMaximumSleepTime )
190+
{
191+
uxMaximumSleepTime = xIGMPTimer.ulRemainingTime;
192+
}
193+
}
194+
#endif /* ipconfigSUPPORT_IP_MULTICAST */
195+
179196
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
180197
{
181198
if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
@@ -312,6 +329,16 @@ void vCheckNetworkTimers( void )
312329
vSocketListenNextTime( NULL );
313330
#endif /* ipconfigUSE_TCP == 1 */
314331

332+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
333+
{
334+
/* Is it time to send any IGMP reports? */
335+
if( prvIPTimerCheck( &xIGMPTimer ) != pdFALSE )
336+
{
337+
( void ) xSendIGMPEvent();
338+
}
339+
}
340+
#endif /* ipconfigSUPPORT_IP_MULTICAST != 0 */
341+
315342
/* Is it time to trigger the repeated NetworkDown events? */
316343
if( xAllNetworksUp == pdFALSE )
317344
{
@@ -412,6 +439,20 @@ void vARPTimerReload( TickType_t xTime )
412439

413440
/*-----------------------------------------------------------*/
414441

442+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
443+
444+
/**
445+
* @brief Reload the IGMP timer.
446+
*
447+
* @param[in] xIgmpTickTime: The reload value.
448+
*/
449+
void vIGMPTimerReload( TickType_t xIgmpTickTime )
450+
{
451+
prvIPTimerReload( &xIGMPTimer, pdMS_TO_TICKS( ipIGMP_TIMER_PERIOD_MS ) );
452+
}
453+
#endif /* ipconfigSUPPORT_IP_MULTICAST */
454+
/*-----------------------------------------------------------*/
455+
415456
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
416457

417458
/**

source/FreeRTOS_Sockets.c

+45-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
#include "FreeRTOS_DNS.h"
5353
#include "NetworkBufferManagement.h"
5454
#include "FreeRTOS_Routing.h"
55-
55+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
56+
#include "FreeRTOS_IGMP.h"
57+
#endif
5658
#if ( ipconfigUSE_TCP_MEM_STATS != 0 )
5759
#include "tcp_mem_stats.h"
5860
#endif
@@ -738,6 +740,11 @@ Socket_t FreeRTOS_socket( BaseType_t xDomain,
738740
pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
739741
}
740742
#endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */
743+
744+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
745+
pxSocket->u.xUDP.ucMulticastTTL = ipconfigMULTICAST_DEFAULT_TTL;
746+
vListInitialise( &pxSocket->u.xUDP.xMulticastGroupsList );
747+
#endif
741748
}
742749

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

1442+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
1443+
if( xIsIPv4Multicast( pxDestinationAddress->sin_address.ulIP_IPv4 ) )
1444+
{
1445+
pxNetworkBuffer->ucSendTTL = pxSocket->u.xUDP.ucMulticastTTL;
1446+
}
1447+
else
1448+
{
1449+
pxNetworkBuffer->ucSendTTL = ipconfigUDP_TIME_TO_LIVE;
1450+
}
1451+
#endif
1452+
14351453
/* The socket options are passed to the IP layer in the
14361454
* space that will eventually get used by the Ethernet header. */
14371455
pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
@@ -2132,6 +2150,18 @@ void * vSocketClose( FreeRTOS_Socket_t * pxSocket )
21322150
#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
21332151
}
21342152

2153+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
2154+
if( pxSocket->ucProtocol == ipPROTOCOL_UDP )
2155+
{
2156+
/* Un-register all multicast groups that might have been added. */
2157+
while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xMulticastGroupsList ) ) > 0U )
2158+
{
2159+
MCastGroupDesc_t * pMCD = ( MCastGroupDesc_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xMulticastGroupsList ) );
2160+
( void ) vModifyMulticastMembership( pMCD, eSocketOptDropMembership );
2161+
}
2162+
}
2163+
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
2164+
21352165
/* Now the socket is not bound the list of waiting packets can be
21362166
* drained. */
21372167
if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
@@ -2929,6 +2959,20 @@ BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
29292959
break;
29302960
#endif /* ipconfigUSE_TCP == 1 */
29312961

2962+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
2963+
case FREERTOS_SO_IP_MULTICAST_TTL:
2964+
case FREERTOS_SO_IP_ADD_MEMBERSHIP:
2965+
case FREERTOS_SO_IP_DROP_MEMBERSHIP:
2966+
/* Use extern here, because we don't want to expose xSetMulticastSocketOption through .h files */
2967+
extern BaseType_t xSetMulticastSocketOption( Socket_t xSocket,
2968+
int32_t lLevel,
2969+
int32_t lOptionName,
2970+
const void * pvOptionValue,
2971+
size_t uxOptionLength );
2972+
xReturn = xSetMulticastSocketOption( xSocket, lLevel, lOptionName, pvOptionValue, uxOptionLength );
2973+
break;
2974+
#endif /* (ipconfigSUPPORT_IP_MULTICAST != 0) */
2975+
29322976
default:
29332977
/* No other options are handled. */
29342978
xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;

source/FreeRTOS_UDP_IPv4.c

+44
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@
6363
/* *INDENT-OFF* */
6464
#if( ipconfigUSE_IPv4 != 0 )
6565
/* *INDENT-ON* */
66+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
67+
#include "FreeRTOS_IGMP.h"
68+
#endif
6669

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

235+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
236+
if( ( pxNetworkBuffer->xIPAddress.ulIP_IPv4 != ipLLMNR_IP_ADDR ) && ( pxNetworkBuffer->xIPAddress.ulIP_IPv4 == ipMDNS_IP_ADDRESS ) )
237+
{
238+
pxIPHeader->ucTimeToLive = pxNetworkBuffer->ucSendTTL;
239+
}
240+
#endif
241+
232242
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
233243
{
234244
pxIPHeader->usHeaderChecksum = 0U;
@@ -364,6 +374,40 @@ BaseType_t xProcessReceivedUDPPacket_IPv4( NetworkBufferDescriptor_t * pxNetwork
364374

365375
*pxIsWaitingForARPResolution = pdFALSE;
366376

377+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
378+
379+
/* If this incoming packet is a multicast, we may have a socket for the port, but we still need
380+
* to ensure the socket is subscribed to that particular multicast group. Note: Since this stack
381+
* does not support port reusing, we don't have to worry about two UDP sockets bound to the exact same
382+
* local port, but subscribed to different multicast groups. If this was allowed, this check
383+
* would have to be moved to the pxUDPSocketLookup() function itself. */
384+
if( ( pxSocket != NULL ) && ( xIsIPv4Multicast( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) ) )
385+
{
386+
/* Note: There is no need for vTaskSuspendAll/xTaskResumeAll here because only the IP Task
387+
* touches the socket's multicast groups list directly. */
388+
const ListItem_t * pxIterator;
389+
const ListItem_t * xEnd = listGET_END_MARKER( &( pxSocket->u.xUDP.xMulticastGroupsList ) );
390+
391+
for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
392+
pxIterator != ( const ListItem_t * ) xEnd;
393+
pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
394+
{
395+
MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
396+
397+
if( pxMCG->mreq.imr_multiaddr.sin_address.ulIP_IPv4 == pxUDPPacket->xIPHeader.ulDestinationIPAddress )
398+
{
399+
break;
400+
}
401+
}
402+
403+
if( pxIterator == ( const ListItem_t * ) xEnd )
404+
{
405+
/* This socket is not subscribed to this multicast group. Nullify the result from pxUDPSocketLookup() */
406+
pxSocket = NULL;
407+
}
408+
}
409+
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
410+
367411
do
368412
{
369413
if( pxSocket != NULL )

source/include/FreeRTOSIPConfigDefaults.h

+24
Original file line numberDiff line numberDiff line change
@@ -1160,4 +1160,28 @@
11601160
#define ipconfigPORT_SUPPRESS_WARNING ( 0 )
11611161
#endif
11621162

1163+
/* Setting to 1 will enable the reception of IPv4 multicast groups
1164+
* and the associated socket options that need to be set before
1165+
* a socket would properly receive multicast packets. */
1166+
#ifndef ipconfigSUPPORT_IP_MULTICAST
1167+
#define ipconfigSUPPORT_IP_MULTICAST ( 0 )
1168+
#endif
1169+
1170+
/* Specifies the TTL value that will be used for multicast
1171+
* UDP packets by default. Can be overridden per socket by
1172+
* setting the FREERTOS_SO_IP_MULTICAST_TTL socket option. */
1173+
#ifndef ipconfigMULTICAST_DEFAULT_TTL
1174+
#define ipconfigMULTICAST_DEFAULT_TTL ( 1 )
1175+
#endif
1176+
1177+
/* Set to 1 if you plan on implementing IGMP snooping.
1178+
* When set to 1, the user must implement the following hooks:
1179+
* eFrameProcessingResult_t eApplicationIgmpFrameReceivedHook( NetworkBufferDescriptor_t * pxNetworkBuffer )
1180+
* void vApplicationIgmpSendLocalMessageHook( NetworkBufferDescriptor_t * pxNetworkBuffer, uint8_t ucIgmpMsgType, uint32_t uiMulticastGroup )
1181+
* void vApplicationIgmpEventHook( void )
1182+
*/
1183+
#ifndef ipconfigIGMP_SNOOPING
1184+
#define ipconfigIGMP_SNOOPING ( 0 )
1185+
#endif
1186+
11631187
#endif /* FREERTOS_DEFAULT_IP_CONFIG_H */

0 commit comments

Comments
 (0)