Skip to content

Commit 9b911f6

Browse files
author
Emil Popov
committed
Moves more functions to FreeRTOS_Sockets.c
Sends IGMPv2 Leave Group messages whenever the last socket subscribed to a group drops that membership. Adds ipconfigPERIODIC_MULTICAST_REPORT_INTERVAL for debug purposes when there is no IGMP/MLD querier
1 parent 05873a1 commit 9b911f6

7 files changed

+288
-255
lines changed

source/FreeRTOS_IGMP.c

+41-233
Large diffs are not rendered by default.

source/FreeRTOS_IP.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -475,12 +475,12 @@ static void prvProcessIPEventsAndTimers( void )
475475
case eSocketOptDropMembership:
476476
{
477477
MulticastAction_t * pxMCA = ( MulticastAction_t * ) xReceivedEvent.pvData;
478-
( void ) vModifyMulticastMembership( pxMCA, xReceivedEvent.eEventType );
478+
vModifyMulticastMembership( pxMCA, xReceivedEvent.eEventType );
479479
break;
480480
}
481481

482-
case eIGMPEvent:
483-
( void ) vHandleIGMP_Event();
482+
case eMulticastTimerEvent:
483+
vHandleIGMP_Event();
484484
break;
485485
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0) */
486486

@@ -688,7 +688,7 @@ void vIPNetworkUpCalls( struct xNetworkEndPoint * pxEndPoint )
688688
pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 12 ] = 0xFFU;
689689
( void ) memcpy( &pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 13 ], &pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ], 3 );
690690

691-
if( pdTRUE != xAddIGMPReportToList( pxMRD ) )
691+
if( pdTRUE != xAddMulticastReportToList( pxMRD ) )
692692
{
693693
vPortFree( pxMRD );
694694
pxMRD = NULL;

source/FreeRTOS_IP_Timers.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ void vCheckNetworkTimers( void )
334334
/* Is it time to send any IGMP reports? */
335335
if( prvIPTimerCheck( &xIGMPTimer ) != pdFALSE )
336336
{
337-
( void ) xSendIGMPEvent();
337+
( void ) xSendMulticastTimerEvent();
338338
}
339339
}
340340
#endif /* ipconfigSUPPORT_IP_MULTICAST != 0 */
@@ -448,7 +448,7 @@ void vARPTimerReload( TickType_t xTime )
448448
*/
449449
void vIGMPTimerReload( TickType_t xIgmpTickTime )
450450
{
451-
prvIPTimerReload( &xIGMPTimer, pdMS_TO_TICKS( ipIGMP_TIMER_PERIOD_MS ) );
451+
prvIPTimerReload( &xIGMPTimer, pdMS_TO_TICKS( igmpMULTICAST_EVENT_PERIOD_MS ) );
452452
}
453453
#endif /* ipconfigSUPPORT_IP_MULTICAST */
454454
/*-----------------------------------------------------------*/

source/FreeRTOS_Sockets.c

+202
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static int32_t prvSendTo_ActualSend( const FreeRTOS_Socket_t * pxSocket,
377377
int32_t lOptionName,
378378
const void * pvOptionValue,
379379
size_t uxOptionLength );
380+
static void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket );
380381
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
381382

382383
/*-----------------------------------------------------------*/
@@ -6612,4 +6613,205 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )
66126613

66136614
return xReturn;
66146615
}
6616+
6617+
/**
6618+
* @brief Adds or drops a multicast group to/from a socket.
6619+
*
6620+
* @param[in] pxMulticastGroup: The multicast group descriptor. Also holds the socket that this call is for.
6621+
* @param[in] bAction: MUST be eSocketOptAddMembership or eSocketOptDropMembership.
6622+
*/
6623+
void vModifyMulticastMembership( MulticastAction_t * pxMulticastAction,
6624+
uint8_t bAction )
6625+
{
6626+
uint8_t MCastMacBytes[ 6 ];
6627+
FreeRTOS_Socket_t * pxSocket = pxMulticastAction->pxSocket;
6628+
uint8_t bFreeMatchedItem = pdFALSE;
6629+
NetworkInterface_t * pxNetIf = pxMulticastAction->pxInterface;
6630+
BaseType_t bReportItemConsumed = pdFALSE;
6631+
6632+
configASSERT( pxSocket != NULL );
6633+
6634+
/* Note: This function is only called with eSocketOptDropMembership or eSocketOptAddMembership*/
6635+
6636+
/* This TCP stack does NOT support sockets subscribing to more than one multicast group.
6637+
* If the socket is already subscribed to a multicast group, we need to unsubscribe it and remove the
6638+
* IGMP/MLD reports corresponding to that group address. */
6639+
prvDropMulticastMembership( pxSocket );
6640+
6641+
if( eSocketOptAddMembership == bAction )
6642+
{
6643+
/* Store the multicast address. */
6644+
( void ) memcpy( &( pxSocket->u.xUDP.xMulticastAddress ), &( pxMulticastAction->xMulticastGroup ), sizeof( pxSocket->u.xUDP.xMulticastAddress ) );
6645+
6646+
if( pxSocket->bits.bIsIPv6 == pdFALSE )
6647+
{
6648+
vSetMultiCastIPv4MacAddress( pxMulticastAction->xMulticastGroup.ulIP_IPv4, MCastMacBytes );
6649+
}
6650+
else
6651+
{
6652+
vSetMultiCastIPv6MacAddress( &( pxMulticastAction->xMulticastGroup.xIP_IPv6 ), MCastMacBytes );
6653+
}
6654+
6655+
/* Inform the network driver */
6656+
if( pxNetIf )
6657+
{
6658+
if( pxNetIf->pfAddMulticastMAC != NULL )
6659+
{
6660+
pxNetIf->pfAddMulticastMAC( MCastMacBytes );
6661+
}
6662+
}
6663+
else
6664+
{
6665+
/* pxNetIf is NULL. For IPv4 that means "use all interfaces". For IPv6, that means "use the default multicast interface"
6666+
* FreeRTOS+TCP does not have the notion of default multicast interface so for now, subscribe on all. */
6667+
for( pxNetIf = FreeRTOS_FirstNetworkInterface(); pxNetIf != NULL; pxNetIf = FreeRTOS_NextNetworkInterface( pxNetIf ) )
6668+
{
6669+
if( pxNetIf->pfAddMulticastMAC != NULL )
6670+
{
6671+
pxNetIf->pfAddMulticastMAC( MCastMacBytes );
6672+
}
6673+
}
6674+
}
6675+
6676+
/* Remember which interface(s) this socket is subscribed on. */
6677+
pxSocket->u.xUDP.pxMulticastNetIf = pxMulticastAction->pxInterface;
6678+
6679+
/* Since we've added a multicast group to this socket, we need to prepare an IGMP/MLD report
6680+
* for when we receive an IGMP/MLD query. Keep in mind that such a report might already exist.
6681+
* If such an IGMP/MLD report is already present in the list, we will increment it's socket
6682+
* count and free the report we have here. In either case, the MulticastAction_t that we were
6683+
* passed, no longer needs to hold a reference to this multicast report. */
6684+
do
6685+
{
6686+
if( pxMulticastAction->pxMCastReportData == NULL )
6687+
{
6688+
break;
6689+
}
6690+
6691+
if( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIs_IPv6 == pdTRUE )
6692+
{
6693+
/* RFC2710 end of section section 5 and RFC3810 section 6:
6694+
* ff02::1 is a special case and we do not send reports for it. */
6695+
static const struct xIPv6_Address FreeRTOS_in6addr_allnodes = { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } };
6696+
6697+
if( memcmp( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes, FreeRTOS_in6addr_allnodes.ucBytes, sizeof( IPv6_Address_t ) ) == 0 )
6698+
{
6699+
break;
6700+
}
6701+
6702+
/* RFC2710 end of section section 5 and RFC3810 section 6:
6703+
* Never send reports for multicast scopes of: 0 (reserved) or 1 (node-local).
6704+
* Note: the address was already checked to be a valid multicast in FreeRTOS_setsockopt()*/
6705+
if( ( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 1 ] & 0x0FU ) <= 1 )
6706+
{
6707+
break;
6708+
}
6709+
}
6710+
else
6711+
{
6712+
/* RFC2236 end of section 6:
6713+
* 224.0.0.1 is a special case and we do not send reports for it. */
6714+
if( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIPAddress.ulIP_IPv4 == igmpIGMP_IP_ADDR )
6715+
{
6716+
break;
6717+
}
6718+
}
6719+
6720+
bReportItemConsumed = xAddMulticastReportToList( pxMulticastAction->pxMCastReportData );
6721+
} while( pdFALSE );
6722+
6723+
/* If the report was a special case address or was not consumed by
6724+
* xAddMulticastReportToList(), free the multicast report. */
6725+
if( bReportItemConsumed == pdFALSE )
6726+
{
6727+
vPortFree( pxMulticastAction->pxMCastReportData );
6728+
pxMulticastAction->pxMCastReportData = NULL;
6729+
}
6730+
}
6731+
6732+
/* Free the message that was sent to us. */
6733+
vPortFree( pxMulticastAction );
6734+
}
6735+
6736+
static void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket )
6737+
{
6738+
uint8_t MCastMacBytes[ 6 ];
6739+
UBaseType_t uxLeaveGroup = pdFALSE_UNSIGNED;
6740+
NetworkInterface_t * pxNetIf = pxSocket->u.xUDP.pxMulticastNetIf;
6741+
6742+
if( pxSocket->bits.bIsIPv6 == pdTRUE_UNSIGNED )
6743+
{
6744+
/* IPv6 */
6745+
if( xIsIPv6AllowedMulticast( &( pxSocket->u.xUDP.xMulticastAddress.xIP_IPv6 ) ) )
6746+
{
6747+
uxLeaveGroup = pdTRUE_UNSIGNED;
6748+
6749+
if( pxNetIf )
6750+
{
6751+
if( pxNetIf->pfRemoveMulticastMAC != NULL )
6752+
{
6753+
vSetMultiCastIPv6MacAddress( &( pxSocket->u.xUDP.xMulticastAddress.xIP_IPv6 ), MCastMacBytes );
6754+
pxNetIf->pfRemoveMulticastMAC( MCastMacBytes );
6755+
}
6756+
}
6757+
else
6758+
{
6759+
}
6760+
}
6761+
else
6762+
{
6763+
/* Whatever is stored in pxSocket->u.xUDP.xMulticastAddress is not a valid multicast group
6764+
* or prvDropMulticastMembership was called for a socket that is not still subscribed to a multicast group.
6765+
* Do nothing. */
6766+
}
6767+
}
6768+
else
6769+
{
6770+
/* IPv4 */
6771+
if( xIsIPv4Multicast( pxSocket->u.xUDP.xMulticastAddress.ulIP_IPv4 ) )
6772+
{
6773+
uxLeaveGroup = pdTRUE_UNSIGNED;
6774+
6775+
vSetMultiCastIPv4MacAddress( pxSocket->u.xUDP.xMulticastAddress.ulIP_IPv4, MCastMacBytes );
6776+
6777+
if( pxNetIf )
6778+
{
6779+
if( pxNetIf->pfRemoveMulticastMAC != NULL )
6780+
{
6781+
pxNetIf->pfRemoveMulticastMAC( MCastMacBytes );
6782+
}
6783+
}
6784+
else
6785+
{
6786+
/* pxNetIf is NULL. For IPv4 that means "all interfaces", so unsubscribe from all. */
6787+
for( pxNetIf = FreeRTOS_FirstNetworkInterface(); pxNetIf != NULL; pxNetIf = FreeRTOS_NextNetworkInterface( pxNetIf ) )
6788+
{
6789+
if( pxNetIf->pfRemoveMulticastMAC != NULL )
6790+
{
6791+
pxNetIf->pfRemoveMulticastMAC( MCastMacBytes );
6792+
}
6793+
}
6794+
}
6795+
}
6796+
else
6797+
{
6798+
/* Whatever is stored in pxSocket->u.xUDP.xMulticastAddress is not a valid multicast group
6799+
* or prvDropMulticastMembership was called for a socket that is not still subscribed to a multicast group.
6800+
* Do nothing. */
6801+
}
6802+
}
6803+
6804+
if( uxLeaveGroup == pdTRUE_UNSIGNED )
6805+
{
6806+
/* Locate the IGMP/MLD report for this group. Decrement its socket count and
6807+
* if it becomes zero, remove it from the list and free it. */
6808+
vRemoveMulticastReportFromList( &( pxSocket->u.xUDP.xMulticastAddress ), ( UBaseType_t ) pxSocket->bits.bIsIPv6 );
6809+
}
6810+
6811+
/* Invalidate the multicast group address to prevent erroneous matches if someone calls
6812+
* FREERTOS_SO_IP_DROP_MEMBERSHIP multiple times. */
6813+
memset( &pxSocket->u.xUDP.xMulticastAddress, 0x00, sizeof( pxSocket->u.xUDP.xMulticastAddress ) );
6814+
pxSocket->u.xUDP.pxMulticastNetIf = NULL; /* not really needed, but just looks cleaner when debugging. */
6815+
}
6816+
66156817
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */

source/include/FreeRTOSIPConfigDefaults.h

+18
Original file line numberDiff line numberDiff line change
@@ -3321,6 +3321,24 @@
33213321

33223322
/*---------------------------------------------------------------------------*/
33233323

3324+
/*
3325+
* ipconfigPERIODIC_MULTICAST_REPORT_INTERVAL
3326+
*
3327+
* Type: BaseType_t
3328+
* Unit: count of igmpMULTICAST_EVENT_PERIOD_MS
3329+
*
3330+
* When set to -1, no periodic unsolicited multicast reports are sent out.
3331+
* This is the correct behavior. For debug purposes, set to > 0 to cause
3332+
* periodic sending of multicast reports even if there are no IGMP/MLD
3333+
* queries heard. Example: 150 = 15.0 seconds.
3334+
* Note: Maybe remove that ?
3335+
*/
3336+
#ifndef ipconfigPERIODIC_MULTICAST_REPORT_INTERVAL
3337+
#define ipconfigPERIODIC_MULTICAST_REPORT_INTERVAL ( -1 )
3338+
#endif
3339+
3340+
/*---------------------------------------------------------------------------*/
3341+
33243342
/*
33253343
* ipconfigMULTICAST_DEFAULT_TTL
33263344
*

source/include/FreeRTOS_IGMP.h

+11-15
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,26 @@
4646
#include "event_groups.h"
4747

4848

49-
/** @brief IGMP times events at 100ms. */
50-
#define ipIGMP_TIMER_PERIOD_MS ( 100U )
49+
/** @brief IGMP times events at 100ms. Use this interval for MLD as well. */
50+
#define igmpMULTICAST_EVENT_PERIOD_MS ( 100U )
5151

5252
/* IGMP protocol definitions. */
53-
#define ipIGMP_MEMBERSHIP_QUERY ( ( uint8_t ) 0x11U ) /**< IGMP membership query. */
54-
#define ipIGMP_MEMBERSHIP_REPORT_V1 ( ( uint8_t ) 0x12U ) /**< IGMP v1 and v2 membership report. */
55-
#define ipIGMP_MEMBERSHIP_REPORT_V2 ( ( uint8_t ) 0x16U ) /**< IGMP v1 and v2 membership report. */
56-
#define ipIGMP_MEMBERSHIP_REPORT_V3 ( ( uint8_t ) 0x22U ) /**< IGMP v3 membership report. */
57-
#define ipIGMP_LEAVE_GROUP ( ( uint8_t ) 0x17U ) /**< IGMP leave group */
53+
#define igmpIGMP_MEMBERSHIP_QUERY ( ( uint8_t ) 0x11U ) /**< IGMP membership query. */
54+
#define igmpIGMP_MEMBERSHIP_REPORT_V1 ( ( uint8_t ) 0x12U ) /**< IGMP v1 and v2 membership report. */
55+
#define igmpIGMP_MEMBERSHIP_REPORT_V2 ( ( uint8_t ) 0x16U ) /**< IGMP v1 and v2 membership report. */
56+
#define igmpIGMP_MEMBERSHIP_REPORT_V3 ( ( uint8_t ) 0x22U ) /**< IGMP v3 membership report. */
57+
#define igmpIGMP_LEAVE_GROUP ( ( uint8_t ) 0x17U ) /**< IGMP leave group */
5858

5959
#if ( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
60-
#define ipIGMP_IP_ADDR 0xE0000001UL
60+
#define igmpIGMP_IP_ADDR 0xE0000001UL
6161
#else
62-
#define ipIGMP_IP_ADDR 0x010000E0UL
62+
#define igmpIGMP_IP_ADDR 0x010000E0UL
6363
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */
6464

6565
#include "pack_struct_start.h"
6666
struct xIGMP_HEADER
6767
{
68-
uint8_t ucTypeOfMessage; /**< The IGMP type 0 + 1 = 1 */
68+
uint8_t ucMessageType; /**< The IGMP type 0 + 1 = 1 */
6969
uint8_t ucMaxResponseTime; /**< Maximum time (sec) for responses. 1 + 1 = 2 */
7070
uint16_t usChecksum; /**< The checksum of whole IGMP packet 2 + 2 = 4 */
7171
uint32_t ulGroupAddress; /**< The multicast group address 4 + 4 = 8 */
@@ -84,14 +84,10 @@
8484
typedef struct xIGMP_PACKET IGMPPacket_t;
8585

8686
void vIGMP_Init( void );
87-
void vModifyMulticastMembership( MulticastAction_t * pxMulticastAction,
88-
uint8_t bAction );
89-
BaseType_t xSendIGMPEvent( void );
9087
void vHandleIGMP_Event( void );
91-
BaseType_t xAddIGMPReportToList( MCastReportData_t * pNewEntry );
88+
BaseType_t xAddMulticastReportToList( MCastReportData_t * pNewEntry );
9289
eFrameProcessingResult_t eProcessIGMPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
9390
void vProcessMLDPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
94-
void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket ); /* move to Sockets.c as static */
9591

9692

9793
#ifdef __cplusplus

source/include/FreeRTOS_IP_Private.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ typedef enum
8787
eSocketSetDeleteEvent, /*13: A socket set must be deleted. */
8888
eSocketOptAddMembership, /*14: Register a UDP socket to a multicast group. */
8989
eSocketOptDropMembership, /*15: Unregister a UDP socket from a multicast group. */
90-
eIGMPEvent, /*16: */
90+
eMulticastTimerEvent, /*16: Handles the sending of scheduled IGMP/MLD multicast reports. */
9191
} eIPEvent_t;
9292

9393
/**
@@ -892,6 +892,15 @@ BaseType_t xIsCallingFromIPTask( void );
892892

893893
#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
894894

895+
#if ( ipconfigSUPPORT_IP_MULTICAST == 1 )
896+
struct xMCastGroupDesc;
897+
void vModifyMulticastMembership( struct xMCastGroupDesc * pxMulticastAction,
898+
uint8_t bAction );
899+
void vRemoveMulticastReportFromList( IP_Address_t * pxMulticastAddress,
900+
UBaseType_t xIsIPv6 );
901+
BaseType_t xSendMulticastTimerEvent( void );
902+
#endif /* ipconfigSUPPORT_IP_MULTICAST */
903+
895904
/* Send the network-up event and start the ARP timer. */
896905
void vIPNetworkUpCalls( struct xNetworkEndPoint * pxEndPoint );
897906

0 commit comments

Comments
 (0)