@@ -377,6 +377,7 @@ static int32_t prvSendTo_ActualSend( const FreeRTOS_Socket_t * pxSocket,
377
377
int32_t lOptionName ,
378
378
const void * pvOptionValue ,
379
379
size_t uxOptionLength );
380
+ static void prvDropMulticastMembership ( FreeRTOS_Socket_t * pxSocket );
380
381
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
381
382
382
383
/*-----------------------------------------------------------*/
@@ -6612,4 +6613,205 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket )
6612
6613
6613
6614
return xReturn ;
6614
6615
}
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
+
6615
6817
#endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */
0 commit comments