Skip to content

Commit 11ffd69

Browse files
author
Emil Popov
committed
Begins processing MLD Queries and schedules MLD v1 reports in the amount of time requested by the query.
Rewrites prvScheduleIgmpReports to work for both IPv4 IGMP an IPv6 MLD reports Sends unsolicited IGMP and MLD reports on network-up events. Simplifies the randomization of the multicast report random send times.
1 parent 24c55f6 commit 11ffd69

10 files changed

+480
-315
lines changed

source/FreeRTOS_IGMP.c

+370-240
Large diffs are not rendered by default.

source/FreeRTOS_IP.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,17 @@ void vIPNetworkUpCalls( struct xNetworkEndPoint * pxEndPoint )
716716
}
717717
}
718718
}
719-
}
719+
} /* if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED ) */
720+
721+
/* Reschedule all multicast reports associated with this end-point.
722+
* /* Note: countdown is in increments of ipIGMP_TIMER_PERIOD_MS. It's a good idea to spread out all reports a little.
723+
* 200 to 500ms ( xMaxCountdown of 2 - 5 ) should be a good happy medium. If the network we just connected to has a IGMP/MLD querier,
724+
* they will soon ask us for reports anyways, so sending these unsolicited reports is not required. It simply enhances the user
725+
* experience by shortening the time it takes before we begin receiving the multicasts that we care for. */
726+
/* _EP_: vRescheduleAllMulticastReports() is NOT declared in header files because I don't want to expose it to the user */
727+
extern void vRescheduleAllMulticastReports( NetworkEndPoint_t * pxEndPoint,
728+
BaseType_t xMaxCountdown );
729+
vRescheduleAllMulticastReports( pxEndPoint, 5 );
720730
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
721731

722732
#if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )

source/FreeRTOS_ND.c

+20
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,26 @@
11121112
break;
11131113
#endif /* ( ipconfigUSE_RA != 0 ) */
11141114

1115+
#if ( ipconfigSUPPORT_IP_MULTICAST == 1 )
1116+
case ipICMP_MULTICAST_LISTENER_QUERY:
1117+
case ipICMP_MULTICAST_LISTENER_REPORT_V1:
1118+
case ipICMP_MULTICAST_LISTENER_REPORT_V2:
1119+
1120+
/* Note: prvProcessIPPacket() stripped the extension headers, so this packet struct is defined without them and they cannot be checked.
1121+
* per RFC, MLD packets must use the RouterAlert option in a Hop By Hop extension header. */
1122+
/* All MLD packets are at least as large as a v1 query packet. */
1123+
uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + ipSIZE_OF_ICMPv6_HEADER );
1124+
1125+
if( uxNeededSize > pxNetworkBuffer->xDataLength )
1126+
{
1127+
FreeRTOS_printf( ( "Too small\n" ) );
1128+
break;
1129+
}
1130+
1131+
vProcessMLDPacket( pxNetworkBuffer );
1132+
break;
1133+
#endif /* if ( ipconfigSUPPORT_IP_MULTICAST == 1 ) */
1134+
11151135
default:
11161136
/* All possible values are included here above. */
11171137
break;

source/FreeRTOS_Sockets.c

+14-18
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ Socket_t FreeRTOS_socket( BaseType_t xDomain,
751751

752752
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
753753
pxSocket->u.xUDP.xMulticastTTL = ipconfigMULTICAST_DEFAULT_TTL;
754-
vListInitialise( &pxSocket->u.xUDP.xMulticastGroupsList );
754+
memset( &( pxSocket->u.xUDP.xMulticastAddress ), 0, sizeof( pxSocket->u.xUDP.xMulticastAddress ) );
755755
#endif
756756
}
757757

@@ -2161,12 +2161,7 @@ void * vSocketClose( FreeRTOS_Socket_t * pxSocket )
21612161
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
21622162
if( pxSocket->ucProtocol == ipPROTOCOL_UDP )
21632163
{
2164-
/* Un-register all multicast groups that might have been added. */
2165-
while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xMulticastGroupsList ) ) > 0U )
2166-
{
2167-
MCastGroupDesc_t * pMCD = ( MCastGroupDesc_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xMulticastGroupsList ) );
2168-
( void ) vModifyMulticastMembership( pMCD, eSocketOptDropMembership );
2169-
}
2164+
prvDropMulticastMembership( pxSocket );
21702165
}
21712166
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
21722167

@@ -6466,7 +6461,9 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )
64666461

64676462
case FREERTOS_SO_IP_ADD_MEMBERSHIP:
64686463
{
6469-
if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || ( uxOptionLength != sizeof( struct freertos_ip_mreq ) ) )
6464+
if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) ||
6465+
( uxOptionLength != sizeof( struct freertos_ip_mreq ) ) ||
6466+
( pxSocket->bits.bIsIPv6 != pdFALSE ) )
64706467
{
64716468
break; /* will return -pdFREERTOS_ERRNO_EINVAL */
64726469
}
@@ -6496,22 +6493,20 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )
64966493
break;
64976494
}
64986495

6499-
/* Store this whole option in case we are later called to drop this membership.
6500-
* This data also needs to be stored so that incoming packets can be filtered properly.
6501-
* This can be done more efficiently, but storing the whole struct will be more portable
6502-
* in the multi-interface, dual-stack case.*/
6496+
/* Store this whole option so we can pass it to the IP task. */
65036497
( void ) memcpy( ( void * ) &pxMCG->mreq, pvOptionValue, uxOptionLength );
6504-
listSET_LIST_ITEM_OWNER( &( pxMCG->xListItem ), ( void * ) pxMCG );
65056498
pxMCG->pxSocket = pxSocket;
6499+
pxMCG->xMulticastGroup.xIs_IPv6 = pdFALSE;
6500+
pxMCG->xMulticastGroup.xIPAddress.ulIP_IPv4 = pMReq->imr_multiaddr.s_addr;
65066501

65076502
/* Init the IGMP report description. It needs to hold the same membership information
6508-
* and it will eventually be added to the IGMP list. */
6503+
* and it will eventually be added to the IGMP list.
6504+
* Note: fileds like xNumSockets and ucCountDown don't need to be initialized. They will
6505+
* be set to their proper values if this reports is added to the global list. */
65096506
pxMRD->xMCastGroupAddress.xIs_IPv6 = pdFALSE_UNSIGNED;
65106507
pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 = pMReq->imr_multiaddr.s_addr;
65116508
pxMRD->pxEndPoint = NULL;
65126509
listSET_LIST_ITEM_OWNER( &( pxMRD->xListItem ), ( void * ) pxMRD );
6513-
pxMRD->xNumSockets = 0;
6514-
pxMRD->ucCountDown = 0;
65156510
/* Quick and dirty assignment of end-point. This will probably have to be re-designed and re-done. */
65166511
pxMRD->pxEndPoint = ( pxSocket->bits.bIsIPv6 ) ? FreeRTOS_FirstEndPoint_IPv6( FreeRTOS_FirstNetworkInterface() ) : FreeRTOS_FirstEndPoint( FreeRTOS_FirstNetworkInterface() );
65176512

@@ -6537,7 +6532,9 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )
65376532

65386533
case FREERTOS_SO_IP_DROP_MEMBERSHIP:
65396534
{
6540-
if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || ( uxOptionLength != sizeof( struct freertos_ip_mreq ) ) )
6535+
if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) ||
6536+
( uxOptionLength != sizeof( struct freertos_ip_mreq ) ) ||
6537+
( pxSocket->bits.bIsIPv6 != pdFALSE ) )
65416538
{
65426539
break; /* will return -pdFREERTOS_ERRNO_EINVAL */
65436540
}
@@ -6563,7 +6560,6 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )
65636560
* This can be done more efficiently, but storing the whole struct will be more portable
65646561
* in the multi-interface, dual-stack case.*/
65656562
( void ) memcpy( ( void * ) &pxMCG->mreq, pvOptionValue, uxOptionLength );
6566-
listSET_LIST_ITEM_OWNER( &( pxMCG->xListItem ), ( void * ) pxMCG );
65676563
pxMCG->pxSocket = pxSocket;
65686564

65696565
/* When dropping memberships, we don't need an IGMP report descriptor. */

source/FreeRTOS_UDP_IPv4.c

+26-33
Original file line numberDiff line numberDiff line change
@@ -374,44 +374,37 @@ BaseType_t xProcessReceivedUDPPacket_IPv4( NetworkBufferDescriptor_t * pxNetwork
374374

375375
*pxIsWaitingForARPResolution = pdFALSE;
376376

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 ) ) )
377+
do
378+
{
379+
if( pxSocket != NULL )
385380
{
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 );
381+
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
396382

397-
if( pxMCG->mreq.imr_multiaddr.s_addr == pxUDPPacket->xIPHeader.ulDestinationIPAddress )
383+
/* If this incoming packet is a multicast, we may have a socket for the port, but we still need
384+
* to ensure the socket is subscribed to that particular multicast group. Note: Since this stack
385+
* does not support port reusing, we don't have to worry about two UDP sockets bound to the exact same
386+
* local port, but subscribed to different multicast groups. If this was allowed, this check
387+
* would have to be moved to the pxUDPSocketLookup() function itself. */
388+
if( xIsIPv4Multicast( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) )
398389
{
399-
break;
390+
if( pxSocket->u.xUDP.xMulticastAddress.ulIP_IPv4 != pxUDPPacket->xIPHeader.ulDestinationIPAddress )
391+
{
392+
/* This socket is not subscribed to this multicast group. Nullify the result from pxUDPSocketLookup().
393+
* Setting the socket to NULL is not strictly necessary. Leave here for clarity and insurance. */
394+
pxSocket = NULL;
395+
/* return pdFAIL so the buffer can be released */
396+
xReturn = pdFAIL;
397+
/* Do not continue parsing */
398+
break;
399+
}
400400
}
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 ) */
401+
else
402+
{
403+
/* The incoming packet is not a multicast and we already know it
404+
* matches this socket's port number, so just proceed */
405+
}
406+
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
410407

411-
do
412-
{
413-
if( pxSocket != NULL )
414-
{
415408
if( ( pxEndpoint != NULL ) && ( pxEndpoint->ipv4_settings.ulIPAddress != 0U ) )
416409
{
417410
if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )

source/include/FreeRTOS_DNS.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ uint32_t ulDNSHandlePacket( const NetworkBufferDescriptor_t * pxNetworkBuffer );
6767

6868
#if ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 )
6969

70-
/* The MDNS IPv6 address is ff02::1:3 */
70+
/* The MDNS IPv6 address is ff02::fb */
7171
extern const IPv6_Address_t ipMDNS_IP_ADDR_IPv6;
7272

73-
/* The MDNS IPv6 MAC address is 33:33:00:01:00:03 */
73+
/* The MDNS IPv6 MAC address is 33:33:00:00:00:fb */
7474
extern const MACAddress_t xMDNS_MACAddressIPv6;
7575
#endif /* ipconfigUSE_MDNS */
7676

source/include/FreeRTOS_IGMP.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,13 @@
6262
#define ipIGMP_IP_ADDR 0x010000E0UL
6363
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */
6464

65-
6665
#include "pack_struct_start.h"
6766
struct xIGMP_HEADER
6867
{
6968
uint8_t ucTypeOfMessage; /**< The IGMP type 0 + 1 = 1 */
7069
uint8_t ucMaxResponseTime; /**< Maximum time (sec) for responses. 1 + 1 = 2 */
7170
uint16_t usChecksum; /**< The checksum of whole IGMP packet 2 + 2 = 4 */
72-
uint32_t uiGroupAddress; /**< The multicast group address 4 + 4 = 8 */
71+
uint32_t ulGroupAddress; /**< The multicast group address 4 + 4 = 8 */
7372
}
7473
#include "pack_struct_end.h"
7574
typedef struct xIGMP_HEADER IGMPHeader_t;
@@ -89,16 +88,17 @@
8988
uint8_t bAction );
9089
BaseType_t xSendIGMPEvent( void );
9190
void vHandleIGMP_Event( void );
92-
void vRemoveIGMPReportFromList( struct freertos_ip_mreq * pMCastGroup );
9391
BaseType_t xAddIGMPReportToList( MCastReportData_t * pNewEntry );
9492
eFrameProcessingResult_t eProcessIGMPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
93+
void vProcessMLDPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
9594
BaseType_t xSendMulticastListenerReport_v1( const IPv6_Address_t * pxGroupAddress,
9695
NetworkEndPoint_t * pxEndPoint,
9796
TickType_t uxBlockTimeTicks );
97+
void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket ); /* move to Sockets.c as static */
9898

9999

100100
#ifdef __cplusplus
101-
} /* extern "C" */
101+
} /* extern "C" */
102102
#endif
103103

104104
#endif /* FREERTOS_IP_PRIVATE_H */

source/include/FreeRTOS_IP_Private.h

+10-10
Original file line numberDiff line numberDiff line change
@@ -648,16 +648,16 @@ typedef struct UDPSOCKET
648648
FOnUDPSent_t pxHandleSent; /**< Function pointer to handle the events after a successful send. */
649649
#endif /* ipconfigUSE_CALLBACKS */
650650
#if ( ipconfigSUPPORT_IP_MULTICAST != 0 )
651-
List_t xMulticastGroupsList;
652-
BaseType_t xMulticastTTL; /**< Allows for multicast sockets to use a different TTL value to limit the scope of the multicast packet. Usually set to 1.
653-
* Note that the options are of different sizes for IPv4 and IPv6.
654-
* Example:
655-
* uint8_t ttl = 1;
656-
* FreeRTOS_setsockopt( MCastSendSock, 0, FREERTOS_SO_IP_MULTICAST_TTL, ( void * ) &ttl, sizeof( ttl ) );
657-
* IPv6 Example:
658-
* BaseType_t hops = 1;
659-
* FreeRTOS_setsockopt( MCastSendSock_v6, 0, FREERTOS_SO_IPV6_MULTICAST_HOPS, ( void * ) &hops, sizeof( hops ) );
660-
*/
651+
IP_Address_t xMulticastAddress; /**< Holds the multicast group address that the socket may have subscribed to receive. */
652+
BaseType_t xMulticastTTL; /**< Allows for multicast sockets to use a different TTL value to limit the scope of the multicast packet. Usually set to 1.
653+
* Note that the options are of different sizes for IPv4 and IPv6.
654+
* Example:
655+
* uint8_t ttl = 1;
656+
* FreeRTOS_setsockopt( MCastSendSock, 0, FREERTOS_SO_IP_MULTICAST_TTL, ( void * ) &ttl, sizeof( ttl ) );
657+
* IPv6 Example:
658+
* BaseType_t hops = 1;
659+
* FreeRTOS_setsockopt( MCastSendSock_v6, 0, FREERTOS_SO_IPV6_MULTICAST_HOPS, ( void * ) &hops, sizeof( hops ) );
660+
*/
661661
#endif
662662
} IPUDPSocket_t;
663663

source/include/FreeRTOS_IP_Utils.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,14 @@
7373
ListItem_t xListItem; /**< List item for adding to the global list of reports. */
7474
NetworkEndPoint_t * pxEndPoint; /**< The end-point whose source address will be send for sending this report. NULL to send on the first end-point of every interface. */
7575
BaseType_t xNumSockets; /**< The number of sockets that are subscribed to this multicast group. */
76-
uint8_t ucCountDown;
76+
BaseType_t xCountDown;
7777
} MCastReportData_t;
7878

7979
/** @brief The structure to hold a "descriptor" for a multicast group that a socket has registered to. */
8080
typedef struct xMCastGroupDesc
8181
{
82+
IPv46_Address_t xMulticastGroup; /**< Holds the IPv4/IPv6 multicast group address */
8283
struct freertos_ip_mreq mreq; /**< Struct for storing the original mreq structure that was sent to setsockopts() */
83-
struct xLIST_ITEM xListItem; /**< List struct. */
8484
FreeRTOS_Socket_t * pxSocket;
8585
MCastReportData_t * pxIGMPReportDesc; /**< Optional. used to hold the allocated IGMP report descriptor while passing from user code to the IP Task. */
8686
} MCastGroupDesc_t;

source/include/FreeRTOS_IPv6_Private.h

+21-5
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ typedef struct xICMPRouterSolicitation_IPv6 ICMPRouterSolicitation_IPv6_t;
236236
typedef struct xIP_HOP_BY_HOP_EXT_ROUTER_ALERT_IPv6 IPHopByHopExtRouterAlert_IPv6_t;
237237

238238
#include "pack_struct_start.h"
239-
struct xICMPv6_MLD_REPORTv1
239+
struct xICMPv6_MLDv1
240240
{
241241
uint8_t ucTypeOfMessage; /**< The message type. 0 + 1 = 1 */
242242
uint8_t ucTypeOfService; /**< Type of service. 1 + 1 = 2 */
@@ -246,17 +246,33 @@ typedef struct xICMPRouterSolicitation_IPv6 ICMPRouterSolicitation_IPv6_t;
246246
IPv6_Address_t xGroupAddress; /**< The IPv6 address. 8 + 16 = 24 */
247247
}
248248
#include "pack_struct_end.h"
249-
typedef struct xICMPv6_MLD_REPORTv1 ICMPv6_MLDReportv1_t;
249+
typedef struct xICMPv6_MLDv1 ICMPv6_MLDv1_t;
250250

251-
struct xICMPv6_MLD_REPORTv1_PACKET
251+
/* Note: MLD packets are required to use the Router-Alert option
252+
* in an IPv6 extension header. */
253+
#include "pack_struct_start.h"
254+
struct xICMPv6_MLDv1_TX_PACKET
252255
{
253256
EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */
254257
IPHeader_IPv6_t xIPHeader; /* 14 + 40 = 54 */
255258
IPHopByHopExtRouterAlert_IPv6_t xRAOption; /* 54 + 8 = 62 */
256-
ICMPv6_MLDReportv1_t xICMPv6_MLDReport; /* 62 + 24 = 86 */
259+
ICMPv6_MLDv1_t xMLD; /* 62 + 24 = 86 */
260+
}
261+
#include "pack_struct_end.h"
262+
typedef struct xICMPv6_MLDv1_TX_PACKET MLDv1_Tx_Packet_t;
263+
264+
/* This TCP stack strips the extension headers from IPv6 packets, so even though
265+
* MLD packets include a Router-Alert option in an IPv6 extension header, the ICMP
266+
* layer will not see it in the packet prvProcessIPPacket() stripped the extension headers. */
267+
#include "pack_struct_start.h"
268+
struct xICMPv6_MLDv1_RX_PACKET
269+
{
270+
EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */
271+
IPHeader_IPv6_t xIPHeader; /* 14 + 40 = 54 */
272+
ICMPv6_MLDv1_t xMLD; /* 54 + 24 = 78 */
257273
}
258274
#include "pack_struct_end.h"
259-
typedef struct xICMPv6_MLD_REPORTv1_PACKET MLDReportPacket_v1_t;
275+
typedef struct xICMPv6_MLDv1_RX_PACKET MLDv1_Rx_Packet_t;
260276

261277
/** @brief Options that can be sent in a Multicast Listener Report packet.
262278
* more info at https://www.rfc-editor.org/rfc/rfc2711#section-2.0 */

0 commit comments

Comments
 (0)