@@ -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 ) */
0 commit comments