diff --git a/source/FreeRTOS_DNS_Parser.c b/source/FreeRTOS_DNS_Parser.c index dbe426f50d..e07bddd1f1 100644 --- a/source/FreeRTOS_DNS_Parser.c +++ b/source/FreeRTOS_DNS_Parser.c @@ -936,6 +936,26 @@ } xUDPPacket_IPv6->xUDPHeader.usLength = FreeRTOS_htons( ( uint16_t ) lNetLength + ipSIZE_OF_UDP_HEADER ); + + if( xUDPPacket_IPv6->xUDPHeader.usDestinationPort == FreeRTOS_ntohs( ipMDNS_PORT ) ) + { + /* RFC6762, section 11 */ + xUDPPacket_IPv6->xIPHeader.ucHopLimit = 255U; + } + else if( xUDPPacket_IPv6->xUDPHeader.usDestinationPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) + { + /* LLMNR: RFC4795 section 2.5 recommends UDP requests and responses use TTL of 255 */ + + /* Theoretically, LLMNR replies can go "off-link" and create a DDoS scenario. That should be preventable + * by settings our rely's TTL/HopLimit to 1. Please note that in certain situations ( I think unicast + * responses), Wireshark flags some LLMNR packets that have TTL of 1 as too low. */ + xUDPPacket_IPv6->xIPHeader.ucHopLimit = 1U; + } + else + { + xUDPPacket_IPv6->xIPHeader.ucHopLimit = ipconfigUDP_TIME_TO_LIVE; + } + vFlip_16( pxUDPHeader->usSourcePort, pxUDPHeader->usDestinationPort ); uxDataLength = ( size_t ) lNetLength + ipSIZE_OF_IPv6_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER; } @@ -951,8 +971,18 @@ /* HT:endian: should not be translated, copying from packet to packet */ if( pxIPHeader->ulDestinationIPAddress == ipMDNS_IP_ADDRESS ) { + /* RFC6762, section 11 */ pxIPHeader->ucTimeToLive = ipMDNS_TIME_TO_LIVE; } + else if( pxUDPHeader->usDestinationPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) + { + /* LLMNR: RFC4795 section 2.5 recommends UDP requests and responses use TTL of 255 */ + + /* Theoretically, LLMNR replies can go "off-link" and create a DDoS scenario. That should be preventable + * by settings our rely's TTL/HopLimit to 1. Please note that in certain situations ( I think unicast + * responses), Wireshark flags some LLMNR packets that have TTL of 1 as too low. */ + pxIPHeader->ucTimeToLive = 1; + } else { pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress; diff --git a/source/FreeRTOS_IGMP.c b/source/FreeRTOS_IGMP.c index 5179fa1361..46edcfe0c5 100644 --- a/source/FreeRTOS_IGMP.c +++ b/source/FreeRTOS_IGMP.c @@ -28,20 +28,24 @@ * @brief Implements the optional IGMP functionality of the FreeRTOS+TCP network stack. */ -/* ToDo List ( remove the items below as progress is made ) +/* ToDo List ( remove the items below as progress is made ) * - Rename this file * - netif: netif-pointer in the setsockopt struct, null means "all interfaces" * - Check task to task multicast ( maybe the network driver can handle to loop * - Rework the sockopt structures to be the same and use IP_Address_t or IPv46_Address_t * - Write a demo and add to https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS-Plus/Demo - * - Sockets cannot handle v4 and v6 at the same time, so enforce this for setsockopt multicast calls + * - Sockets cannot handle v4 and v6 at the same time, so enforce this for setsockopt multicast calls + * - Documentation: Caution about calling FREERTOS_SO_IP_ADD_MEMBERSHIP followed by FREERTOS_SO_IP_DROP_MEMBERSHIP + * in close succession. The DROP may fail because the IP task hasn't handled the ADD yet. + * - Documentation: The values used for FREERTOS_SO_IP_ADD_MEMBERSHIP and FREERTOS_SO_IP_DROP_MEMBERSHIP + * must be exactly the same. This includes the interface pointer! * Topics to discuss over email or in a conference call: * - Integration with other hardware. For now, only SAME70 target has the proper functions for receive multicasts. * - Is task to task multicast really needed? In order to get that feature, we need code that handles every outgoing * multicast as if it were an incoming packet and possibly duplicates it. I don't think this functionality is - * really needed and this may only be needed if we want a send/receive demo to work on a single device. Maybe + * really needed and this may only be needed if we want a send/receive demo to work on a single device. Maybe * it's better to have a demo that sends to multicast_A and receives multicast_B and then have a PC-based - * python script that does the opposite to complete the demo application. + * python script that does the opposite to complete the demo application. */ /* Standard includes. */ @@ -654,7 +658,7 @@ void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket ) { uint8_t MCastMacBytes[ 6 ]; UBaseType_t uxLeaveGroup = pdFALSE_UNSIGNED; - NetworkInterface_t * pxNetIf = ( pxSocket->pxEndPoint != NULL && pxSocket->pxEndPoint->pxNetworkInterface != NULL ) ? pxSocket->pxEndPoint->pxNetworkInterface : NULL; + NetworkInterface_t * pxNetIf = pxSocket->u.xUDP.pxMulticastNetIf; if( pxSocket->bits.bIsIPv6 == pdTRUE_UNSIGNED ) { @@ -725,7 +729,10 @@ void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket ) prvRemoveMulticastReportFromList( &( pxSocket->u.xUDP.xMulticastAddress ), ( UBaseType_t ) pxSocket->bits.bIsIPv6 ); } + /* Invalidate the multicast group address to prevent erroneous matches if someone calls + * FREERTOS_SO_IP_DROP_MEMBERSHIP multiple times. */ memset( &pxSocket->u.xUDP.xMulticastAddress, 0x00, sizeof( pxSocket->u.xUDP.xMulticastAddress ) ); + pxSocket->u.xUDP.pxMulticastNetIf = NULL; /* not really needed, but just looks cleaner when debugging. */ } /** @@ -734,21 +741,22 @@ void prvDropMulticastMembership( FreeRTOS_Socket_t * pxSocket ) * @param[in] pxMulticastGroup: The multicast group descriptor. Also holds the socket that this call is for. * @param[in] bAction: eSocketOptAddMembership or eSocketOptDropMembership. */ -void vModifyMulticastMembership( MCastGroupDesc_t * pxMulticastGroup, +void vModifyMulticastMembership( MulticastAction_t * pxMulticastAction, uint8_t bAction ) { - if( ( eSocketOptAddMembership != bAction ) && ( eSocketOptDropMembership != bAction ) ) - { - return; - } - uint8_t MCastMacBytes[ 6 ]; - FreeRTOS_Socket_t * pxSocket = pxMulticastGroup->pxSocket; + FreeRTOS_Socket_t * pxSocket = pxMulticastAction->pxSocket; uint8_t bFreeMatchedItem = pdFALSE; - NetworkInterface_t * pxNetIf = ( pxSocket->pxEndPoint != NULL && pxSocket->pxEndPoint->pxNetworkInterface != NULL ) ? pxSocket->pxEndPoint->pxNetworkInterface : NULL; + NetworkInterface_t * pxNetIf = pxMulticastAction->pxInterface; + BaseType_t bReportItemConsumed = pdFALSE; configASSERT( pxSocket != NULL ); + if( ( eSocketOptAddMembership != bAction ) && ( eSocketOptDropMembership != bAction ) ) + { + return; + } + /* This TCP stack does NOT support sockets subscribing to more than one multicast group. * If the socket is already subscribed to a multicast group, we need to unsubscribe it and remove the * IGMP/MLD reports corresponding to that group address. */ @@ -757,15 +765,15 @@ void vModifyMulticastMembership( MCastGroupDesc_t * pxMulticastGroup, if( eSocketOptAddMembership == bAction ) { /* Store the multicast address. */ - ( void ) memcpy( &( pxSocket->u.xUDP.xMulticastAddress ), &( pxMulticastGroup->xMulticastGroup.xIPAddress ), sizeof( pxSocket->u.xUDP.xMulticastAddress ) ); + ( void ) memcpy( &( pxSocket->u.xUDP.xMulticastAddress ), &( pxMulticastAction->xMulticastGroup ), sizeof( pxSocket->u.xUDP.xMulticastAddress ) ); - if( pxMulticastGroup->xMulticastGroup.xIs_IPv6 == pdFALSE ) + if( pxSocket->bits.bIsIPv6 == pdFALSE ) { - vSetMultiCastIPv4MacAddress( pxMulticastGroup->xMulticastGroup.xIPAddress.ulIP_IPv4, MCastMacBytes ); + vSetMultiCastIPv4MacAddress( pxMulticastAction->xMulticastGroup.ulIP_IPv4, MCastMacBytes ); } else { - vSetMultiCastIPv6MacAddress( &( pxMulticastGroup->xMulticastGroup.xIPAddress.xIP_IPv6 ), MCastMacBytes ); + vSetMultiCastIPv6MacAddress( &( pxMulticastAction->xMulticastGroup.xIP_IPv6 ), MCastMacBytes ); } /* Inform the network driver */ @@ -789,30 +797,65 @@ void vModifyMulticastMembership( MCastGroupDesc_t * pxMulticastGroup, } } + /* Remember which interface(s) this socket is subscribed on. */ + pxSocket->u.xUDP.pxMulticastNetIf = pxMulticastAction->pxInterface; + /* Since we've added a multicast group to this socket, we need to prepare an IGMP/MLD report * for when we receive an IGMP/MLD query. Keep in mind that such a report might already exist. * If such an IGMP/MLD report is already present in the list, we will increment it's socket - * count and free the report we have here. In either case, the MCastGroupDesc_t that we were - * passed, no longer needs to hold a reference to this IGMP report. */ - if( pxMulticastGroup->pxMCastReportData ) + * count and free the report we have here. In either case, the MulticastAction_t that we were + * passed, no longer needs to hold a reference to this multicast report. */ + do { - /* ToDo: Add and exception for ff02::1 If someone subscribes to it, do not add report. */ + if( pxMulticastAction->pxMCastReportData == NULL ) + { + break; + } - BaseType_t bReportItemConsumed = xAddIGMPReportToList( pxMulticastGroup->pxMCastReportData ); + if( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIs_IPv6 == pdTRUE ) + { + /* RFC2710 end of section section 5 and RFC3810 section 6: + * ff02::1 is a special case and we do not send reports for it. */ + static const struct xIPv6_Address FreeRTOS_in6addr_allnodes = { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }; - if( pdTRUE != bReportItemConsumed ) + if( memcmp( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes, FreeRTOS_in6addr_allnodes.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) + { + break; + } + + /* RFC2710 end of section section 5 and RFC3810 section 6: + * Never send reports for multicast scopes of: 0 (reserved) or 1 (node-local). + * Note: the address was already checked to be a valid multicast in FreeRTOS_setsockopt()*/ + if( ( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 1 ] & 0x0FU ) <= 1 ) + { + break; + } + } + else { - /* If adding to the list did not consume the item that we sent, that means a duplicate - * was found and its socket count was incremented instead of adding the item we sent. - * Free the item that was passed to us. */ - vPortFree( pxMulticastGroup->pxMCastReportData ); - pxMulticastGroup->pxMCastReportData = NULL; + /* RFC2236 end of section 6: + * 224.0.0.1 is a special case and we do not send reports for it. */ + if( pxMulticastAction->pxMCastReportData->xMCastGroupAddress.xIPAddress.ulIP_IPv4 == ipIGMP_IP_ADDR ) + { + break; + } } + + bReportItemConsumed = xAddIGMPReportToList( pxMulticastAction->pxMCastReportData ); + } while( pdFALSE ); + + /* If the report either a special case address or was not consumed by xAddIGMPReportToList() because there was + * a duplicate found and its socket count was incremented instead of adding the report to the global list. + * In either case, free the multicast report. */ + if( bReportItemConsumed == pdFALSE ) + { + vPortFree( pxMulticastAction->pxMCastReportData ); + pxMulticastAction->pxMCastReportData = NULL; } } /* Free the message that was sent to us. */ - vPortFree( pxMulticastGroup ); + vPortFree( pxMulticastAction ); } static portBASE_TYPE xSendIGMP( uint32_t uiBlockTime, diff --git a/source/FreeRTOS_IP.c b/source/FreeRTOS_IP.c index 4b79c14e0e..69b435ec0a 100644 --- a/source/FreeRTOS_IP.c +++ b/source/FreeRTOS_IP.c @@ -474,8 +474,8 @@ static void prvProcessIPEventsAndTimers( void ) case eSocketOptAddMembership: case eSocketOptDropMembership: { - MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) xReceivedEvent.pvData; - ( void ) vModifyMulticastMembership( pxMCG, xReceivedEvent.eEventType ); + MulticastAction_t * pxMCA = ( MulticastAction_t * ) xReceivedEvent.pvData; + ( void ) vModifyMulticastMembership( pxMCA, xReceivedEvent.eEventType ); break; } @@ -1400,6 +1400,7 @@ void FreeRTOS_SetEndPointConfiguration( const uint32_t * pulIPAddress, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT; pxNetworkBuffer->xIPAddress.ulIP_IPv4 = ulIPAddress; pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA; + pxNetworkBuffer->ucMaximumHops = ipconfigICMP_TIME_TO_LIVE; /* xDataLength is the size of the total packet, including the Ethernet header. */ pxNetworkBuffer->xDataLength = uxTotalLength; diff --git a/source/FreeRTOS_ND.c b/source/FreeRTOS_ND.c index 88b8508268..e63fca2efb 100644 --- a/source/FreeRTOS_ND.c +++ b/source/FreeRTOS_ND.c @@ -77,7 +77,7 @@ /* MISRA Ref 8.9.1 [File scoped variables] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */ /* coverity[misra_c_2012_rule_8_9_violation] */ - static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_IP[ ipSIZE_OF_IPv6_ADDRESS ] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; /* ff02:1 */ + static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_IP[ ipSIZE_OF_IPv6_ADDRESS ] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; /* ff02::1 */ /** @brief All nodes on the local network segment: MAC address. */ static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_MAC[ ipMAC_ADDRESS_LENGTH_BYTES ] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 }; @@ -801,6 +801,7 @@ ( void ) memcpy( pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); /* Let vProcessGeneratedUDPPacket() know that this is an ICMP packet. */ pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA; + pxNetworkBuffer->ucMaximumHops = ipconfigICMP_TIME_TO_LIVE; /* 'uxPacketLength' is initialised due to the flow of the program. */ pxNetworkBuffer->xDataLength = uxPacketLength; diff --git a/source/FreeRTOS_Sockets.c b/source/FreeRTOS_Sockets.c index 1c0f06f57d..692e2aea09 100644 --- a/source/FreeRTOS_Sockets.c +++ b/source/FreeRTOS_Sockets.c @@ -372,11 +372,11 @@ static int32_t prvSendTo_ActualSend( const FreeRTOS_Socket_t * pxSocket, #endif #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - static BaseType_t prvSetMulticastSocketOption( Socket_t xSocket, - int32_t lLevel, - int32_t lOptionName, - const void * pvOptionValue, - size_t uxOptionLength ); + static BaseType_t prvSetOptionMulticast( Socket_t xSocket, + int32_t lLevel, + int32_t lOptionName, + const void * pvOptionValue, + size_t uxOptionLength ); #endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */ /*-----------------------------------------------------------*/ @@ -749,7 +749,7 @@ Socket_t FreeRTOS_socket( BaseType_t xDomain, #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */ #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - pxSocket->u.xUDP.xMulticastTTL = ipconfigMULTICAST_DEFAULT_TTL; + pxSocket->u.xUDP.ucMulticastMaxHops = ipconfigMULTICAST_DEFAULT_TTL; memset( &( pxSocket->u.xUDP.xMulticastAddress ), 0, sizeof( pxSocket->u.xUDP.xMulticastAddress ) ); #endif } @@ -1427,12 +1427,38 @@ static int32_t prvSendUDPPacket( const FreeRTOS_Socket_t * pxSocket, #if ( ipconfigUSE_IPv6 != 0 ) case FREERTOS_AF_INET6: ( void ) xSend_UDP_Update_IPv6( pxNetworkBuffer, pxDestinationAddress ); + #if ( ipconfigSUPPORT_IP_MULTICAST == 1 ) + /* _EP_ Verify if using xIsIPv6AllowedMulticast is appropriate or if we need to check for any multicast */ + if( xIsIPv6AllowedMulticast( &( pxDestinationAddress->sin_address.xIP_IPv6 ) ) ) + { + /* Sending a multicast, so use whatever outgoing multicast HopLimit value was configured. */ + pxNetworkBuffer->ucMaximumHops = ( uint8_t ) pxSocket->u.xUDP.ucMulticastMaxHops; + } + else + #endif /* ( ipconfigSUPPORT_IP_MULTICAST == 1 ) */ + { + /* If multicasts are not enabled or if the destination is an unicast, use the default TTL value. */ + pxNetworkBuffer->ucMaximumHops = ipconfigUDP_TIME_TO_LIVE; + } break; #endif /* ( ipconfigUSE_IPv6 != 0 ) */ #if ( ipconfigUSE_IPv4 != 0 ) case FREERTOS_AF_INET4: ( void ) xSend_UDP_Update_IPv4( pxNetworkBuffer, pxDestinationAddress ); + + #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) + if( xIsIPv4Multicast( pxDestinationAddress->sin_address.ulIP_IPv4 ) ) + { + /* Sending a multicast, so use whatever outgoing multicast TTL value was configured. */ + pxNetworkBuffer->ucMaximumHops = ( uint8_t ) pxSocket->u.xUDP.ucMulticastMaxHops; + } + else + #endif /* ( ipconfigSUPPORT_IP_MULTICAST == 1 ) */ + { + /* If multicasts are not enabled or if the destination is an unicast, use the default TTL value. */ + pxNetworkBuffer->ucMaximumHops = ipconfigUDP_TIME_TO_LIVE; + } break; #endif /* ( ipconfigUSE_IPv4 != 0 ) */ @@ -1445,16 +1471,6 @@ static int32_t prvSendUDPPacket( const FreeRTOS_Socket_t * pxSocket, pxNetworkBuffer->usPort = pxDestinationAddress->sin_port; pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket ); - #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - if( xIsIPv4Multicast( pxDestinationAddress->sin_address.ulIP_IPv4 ) ) - { - pxNetworkBuffer->ucSendTTL = ( uint8_t ) pxSocket->u.xUDP.xMulticastTTL; - } - else - { - pxNetworkBuffer->ucSendTTL = ipconfigUDP_TIME_TO_LIVE; - } - #endif /* The socket options are passed to the IP layer in the * space that will eventually get used by the Ethernet header. */ @@ -2962,12 +2978,9 @@ BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) case FREERTOS_SO_IP_MULTICAST_TTL: - case FREERTOS_SO_IPV6_MULTICAST_HOPS: case FREERTOS_SO_IP_ADD_MEMBERSHIP: - case FREERTOS_SO_IPV6_ADD_MEMBERSHIP: case FREERTOS_SO_IP_DROP_MEMBERSHIP: - case FREERTOS_SO_IPV6_DROP_MEMBERSHIP: - xReturn = prvSetMulticastSocketOption( xSocket, lLevel, lOptionName, pvOptionValue, uxOptionLength ); + xReturn = prvSetOptionMulticast( xSocket, lLevel, lOptionName, pvOptionValue, uxOptionLength ); break; #endif /* (ipconfigSUPPORT_IP_MULTICAST != 0) */ @@ -6391,11 +6404,11 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket ) * @return If the option can be set with the given value, then 0 is returned. Else, * an error code is returned. */ - static BaseType_t prvSetMulticastSocketOption( Socket_t xSocket, - int32_t lLevel, - int32_t lOptionName, - const void * pvOptionValue, - size_t uxOptionLength ) + static BaseType_t prvSetOptionMulticast( Socket_t xSocket, + int32_t lLevel, + int32_t lOptionName, + const void * pvOptionValue, + size_t uxOptionLength ) { BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL; FreeRTOS_Socket_t * pxSocket; @@ -6406,7 +6419,7 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket ) * sockets standard, but this implementation does not use all the parameters. */ ( void ) lLevel; - if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) || ( pxSocket->ucProtocol != ipPROTOCOL_UDP ) ) + if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) || ( pxSocket->ucProtocol != ipPROTOCOL_UDP ) || ( pvOptionValue == NULL ) ) { xReturn = -pdFREERTOS_ERRNO_EINVAL; return xReturn; @@ -6416,71 +6429,51 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket ) { case FREERTOS_SO_IP_MULTICAST_TTL: - { - uint8_t ucValue = *( ( uint8_t * ) pvOptionValue ); - - if( ( ( pxSocket->bits.bIsIPv6 == pdTRUE_UNSIGNED ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) ) || ( uxOptionLength != sizeof( ucValue ) ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - /* Override the default TTL value with this one. */ - pxSocket->u.xUDP.xMulticastTTL = ( BaseType_t ) ucValue; - - xReturn = 0; - } - break; - - case FREERTOS_SO_IPV6_MULTICAST_HOPS: - { - BaseType_t xValue = *( ( BaseType_t * ) pvOptionValue ); - - if( ( pxSocket->bits.bIsIPv6 == pdFALSE_UNSIGNED ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || ( uxOptionLength != sizeof( BaseType_t ) ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } + if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || + ( uxOptionLength != sizeof( uint8_t ) ) ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } - if( ( xValue < -1 ) || ( xValue > 255 ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - else if( xValue == -1 ) - { - /* Set the default TTL value. */ - pxSocket->u.xUDP.xMulticastTTL = ipconfigUDP_TIME_TO_LIVE; - } - else - { - /* Override the default TTL value with this one. */ - pxSocket->u.xUDP.xMulticastTTL = xValue; - } + /* Set the new TTL/HOPS value. */ + pxSocket->u.xUDP.ucMulticastMaxHops = *( ( uint8_t * ) pvOptionValue ); - xReturn = 0; - } - break; + xReturn = pdFREERTOS_ERRNO_NONE; + break; case FREERTOS_SO_IP_ADD_MEMBERSHIP: { - struct freertos_ip_mreq * pMReq = ( struct freertos_ip_mreq * ) pvOptionValue; + IP_MReq_t * pMReq = ( IP_MReq_t * ) pvOptionValue; IPStackEvent_t xSockOptsEvent = { eSocketOptAddMembership, NULL }; if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || - ( uxOptionLength != sizeof( struct freertos_ip_mreq ) ) || - ( pxSocket->bits.bIsIPv6 != pdFALSE ) ) + ( uxOptionLength != sizeof( IP_MReq_t ) ) ) { break; /* will return -pdFREERTOS_ERRNO_EINVAL */ } - if( pdFALSE == xIsIPv4Multicast( pMReq->imr_multiaddr.s_addr ) ) + if( pxSocket->bits.bIsIPv6 == pdTRUE ) { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + if( pdFALSE == xIsIPv6AllowedMulticast( &( pMReq->xMulticastGroup.xIP_IPv6 ) ) ) + { + /* Invalid multicast group address */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + } + else + { + if( pdFALSE == xIsIPv4Multicast( pMReq->xMulticastGroup.ulIP_IPv4 ) ) + { + /* Invalid multicast group address */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } } - /* Allocate some RAM to remember the multicast group that is being registered */ - MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) pvPortMalloc( sizeof( MCastGroupDesc_t ) ); + /* Allocate some RAM to remember what the user code is requesting */ + MulticastAction_t * pxMCA = ( MulticastAction_t * ) pvPortMalloc( sizeof( MulticastAction_t ) ); MCastReportData_t * pxMRD = ( MCastReportData_t * ) pvPortMalloc( sizeof( MCastReportData_t ) ); - if( NULL == pxMCG ) + if( NULL == pxMCA ) { xReturn = -pdFREERTOS_ERRNO_ENOMEM; break; @@ -6489,213 +6482,125 @@ void * pvSocketGetSocketID( const ConstSocket_t xSocket ) if( NULL == pxMRD ) { xReturn = -pdFREERTOS_ERRNO_ENOMEM; - vPortFree( pxMCG ); - pxMCG = NULL; + vPortFree( pxMCA ); + pxMCA = NULL; break; } - pxMCG->pxSocket = pxSocket; - pxMCG->xMulticastGroup.xIs_IPv6 = pdFALSE; - pxMCG->xMulticastGroup.xIPAddress.ulIP_IPv4 = pMReq->imr_multiaddr.s_addr; - pxMCG->pxInterface = NULL; /* ToDo: Assign a specific interface if requested by the user */ + pxMCA->pxSocket = pxSocket; + pxMCA->pxInterface = NULL; /* ToDo: Assign a specific interface if requested by the user */ - /* Init the IGMP report description. It needs to hold the same membership information - * and it will eventually be added to the IGMP list. - * Note: fields like xNumSockets and xCountDown don't need to be initialized. They will + /* Store the multicast address in the action and report structs. + * Note: multicast report fields like xNumSockets and xCountDown don't need to be initialized. They will * be set to their proper values if this reports is added to the global list. */ - pxMRD->xMCastGroupAddress.xIs_IPv6 = pdFALSE_UNSIGNED; - pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 = pMReq->imr_multiaddr.s_addr; - listSET_LIST_ITEM_OWNER( &( pxMRD->xListItem ), ( void * ) pxMRD ); - /* Quick and dirty assignment of end-point. This will probably have to be re-designed and re-done. */ - pxMRD->pxEndPoint = ( pxSocket->bits.bIsIPv6 ) ? FreeRTOS_FirstEndPoint_IPv6( FreeRTOS_FirstNetworkInterface() ) : FreeRTOS_FirstEndPoint( FreeRTOS_FirstNetworkInterface() ); - - - /* Pass the multicast report data inside the multicast group descriptor, - * so we can easily pass it to the IP task in one message. */ - pxMCG->pxMCastReportData = pxMRD; - - xSockOptsEvent.pvData = ( void * ) pxMCG; - - if( xSendEventStructToIPTask( &( xSockOptsEvent ), portMAX_DELAY ) != pdPASS ) + if( pxSocket->bits.bIsIPv6 == pdTRUE ) { - vPortFree( pxMCG ); - vPortFree( pxMRD ); - xReturn = -1; + memcpy( pxMCA->xMulticastGroup.xIP_IPv6.ucBytes, pMReq->xMulticastGroup.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + memcpy( pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes, pMReq->xMulticastGroup.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); } else { - xReturn = 0; + pxMCA->xMulticastGroup.ulIP_IPv4 = pMReq->xMulticastGroup.ulIP_IPv4; + pxMRD->xMCastGroupAddress.xIPAddress.ulIP_IPv4 = pMReq->xMulticastGroup.ulIP_IPv4; } - } - break; - - case FREERTOS_SO_IP_DROP_MEMBERSHIP: - { - struct freertos_ip_mreq * pMReq = ( struct freertos_ip_mreq * ) pvOptionValue; - IPStackEvent_t xSockOptsEvent = { eSocketOptDropMembership, NULL }; - if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || - ( uxOptionLength != sizeof( struct freertos_ip_mreq ) ) || - ( pxSocket->bits.bIsIPv6 != pdFALSE ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( pdFALSE == xIsIPv4Multicast( pMReq->imr_multiaddr.s_addr ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( pxSocket->u.xUDP.xMulticastAddress.ulIP_IPv4 != pMReq->imr_multiaddr.s_addr ) - { - /* The socket was is not subscribed to this multicast group. */ - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - /* Allocate some RAM to remember the multicast group that is being dropped */ - MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) pvPortMalloc( sizeof( MCastGroupDesc_t ) ); - - if( NULL == pxMCG ) - { - xReturn = -pdFREERTOS_ERRNO_ENOMEM; - break; - } - - pxMCG->pxSocket = pxSocket; - - /* When dropping memberships, we don't need a multicast report descriptor. */ - pxMCG->pxMCastReportData = NULL; - - xSockOptsEvent.pvData = ( void * ) pxMCG; - - if( xSendEventStructToIPTask( &( xSockOptsEvent ), portMAX_DELAY ) != pdPASS ) - { - vPortFree( pxMCG ); - xReturn = -1; - } - else - { - xReturn = 0; - } - } - break; - - case FREERTOS_SO_IPV6_ADD_MEMBERSHIP: - { - struct freertos_ipv6_mreq * pMReq = ( struct freertos_ipv6_mreq * ) pvOptionValue; - IPStackEvent_t xSockOptsEvent = { eSocketOptAddMembership, NULL }; - - if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || - ( uxOptionLength != sizeof( struct freertos_ipv6_mreq ) ) || - ( pxSocket->bits.bIsIPv6 != pdTRUE ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( pdFALSE == xIsIPv6AllowedMulticast( &( pMReq->ipv6mr_multiaddr.s6_addr ) ) ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - /* Allocate some RAM to remember the multicast group that is being registered */ - MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) pvPortMalloc( sizeof( MCastGroupDesc_t ) ); - MCastReportData_t * pxMRD = ( MCastReportData_t * ) pvPortMalloc( sizeof( MCastReportData_t ) ); - - if( NULL == pxMCG ) - { - xReturn = -pdFREERTOS_ERRNO_ENOMEM; - break; - } - - if( NULL == pxMRD ) - { - xReturn = -pdFREERTOS_ERRNO_ENOMEM; - vPortFree( pxMCG ); - pxMCG = NULL; - break; - } - - pxMCG->pxSocket = pxSocket; - pxMCG->xMulticastGroup.xIs_IPv6 = pdTRUE; - memcpy( pxMCG->xMulticastGroup.xIPAddress.xIP_IPv6.ucBytes, pMReq->ipv6mr_multiaddr.s6_addr.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); - pxMCG->pxInterface = NULL; /* ToDo: Assign a specific interface if requested by the user */ - - /* Init the MLD report description. It needs to hold the same membership information - * and it will eventually be added to the global list. - * Note: fields like xNumSockets and xCountDown don't need to be initialized. They will - * be set to their proper values if this reports is added to the global list. */ - pxMRD->xMCastGroupAddress.xIs_IPv6 = pdTRUE; - memcpy( pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes, pMReq->ipv6mr_multiaddr.s6_addr.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + /* There is no direct link between a multicast report and the socket(s) that require it. + * Store the IP version information in the report so the timer event knows whether to send an IGMP or MLD report. */ + pxMRD->xMCastGroupAddress.xIs_IPv6 = pxSocket->bits.bIsIPv6; listSET_LIST_ITEM_OWNER( &( pxMRD->xListItem ), ( void * ) pxMRD ); /* Quick and dirty assignment of end-point. This will probably have to be re-designed and re-done. */ pxMRD->pxEndPoint = ( pxSocket->bits.bIsIPv6 ) ? FreeRTOS_FirstEndPoint_IPv6( FreeRTOS_FirstNetworkInterface() ) : FreeRTOS_FirstEndPoint( FreeRTOS_FirstNetworkInterface() ); /* Pass the multicast report data inside the multicast group descriptor, * so we can easily pass it to the IP task in one message. */ - pxMCG->pxMCastReportData = pxMRD; + pxMCA->pxMCastReportData = pxMRD; - xSockOptsEvent.pvData = ( void * ) pxMCG; + xSockOptsEvent.pvData = ( void * ) pxMCA; if( xSendEventStructToIPTask( &( xSockOptsEvent ), portMAX_DELAY ) != pdPASS ) { - vPortFree( pxMCG ); - xReturn = -1; + vPortFree( pxMCA ); + xReturn = -pdFREERTOS_ERRNO_ECANCELED; } else { - xReturn = 0; + xReturn = pdFREERTOS_ERRNO_NONE; } } break; - case FREERTOS_SO_IPV6_DROP_MEMBERSHIP: + case FREERTOS_SO_IP_DROP_MEMBERSHIP: { + IP_MReq_t * pMReq = ( IP_MReq_t * ) pvOptionValue; IPStackEvent_t xSockOptsEvent = { eSocketOptDropMembership, NULL }; - struct freertos_ipv6_mreq * pMReq = ( struct freertos_ipv6_mreq * ) pvOptionValue; - if( ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) || - ( uxOptionLength != sizeof( struct freertos_ipv6_mreq ) ) || - ( pxSocket->bits.bIsIPv6 != pdTRUE ) ) + ( uxOptionLength != sizeof( IP_MReq_t ) ) ) { break; /* will return -pdFREERTOS_ERRNO_EINVAL */ } - if( pdFALSE == xIsIPv6AllowedMulticast( &( pMReq->ipv6mr_multiaddr.s6_addr ) ) ) + /* When unsubscribing from a multicast group, the socket option values must + * be exactly the same as when the user subscribed to the multicast group */ + if( pxSocket->bits.bIsIPv6 == pdTRUE ) { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + if( pdFALSE == xIsIPv6AllowedMulticast( &( pMReq->xMulticastGroup.xIP_IPv6 ) ) ) + { + /* Invalid multicast group address */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( memcmp( pxSocket->u.xUDP.xMulticastAddress.xIP_IPv6.ucBytes, pMReq->xMulticastGroup.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) != 0 ) + { + /* The socket was not subscribed to this multicast group. */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + } + else + { + if( pdFALSE == xIsIPv4Multicast( pMReq->xMulticastGroup.ulIP_IPv4 ) ) + { + /* Invalid multicast group address */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( pxSocket->u.xUDP.xMulticastAddress.ulIP_IPv4 != pMReq->xMulticastGroup.ulIP_IPv4 ) + { + /* The socket was not subscribed to this multicast group. */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } } - if( memcmp( pxSocket->u.xUDP.xMulticastAddress.xIP_IPv6.ucBytes, pMReq->ipv6mr_multiaddr.s6_addr.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) != 0 ) + if( pMReq->pxMulticastNetIf != pxSocket->u.xUDP.pxMulticastNetIf ) { - /* The socket was is not subscribed to this multicast group. */ - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + /* The socket was not subscribed on this interface. */ + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ } /* Allocate some RAM to remember the multicast group that is being dropped */ - MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) pvPortMalloc( sizeof( MCastGroupDesc_t ) ); + MulticastAction_t * pxMCA = ( MulticastAction_t * ) pvPortMalloc( sizeof( MulticastAction_t ) ); - if( NULL == pxMCG ) + if( NULL == pxMCA ) { xReturn = -pdFREERTOS_ERRNO_ENOMEM; break; } - pxMCG->pxSocket = pxSocket; + pxMCA->pxSocket = pxSocket; - /* When dropping memberships, we don't need a multicast report descriptor. */ - pxMCG->pxMCastReportData = NULL; + /* When dropping memberships, we don't need a multicast report data. */ + pxMCA->pxMCastReportData = NULL; - xSockOptsEvent.pvData = ( void * ) pxMCG; + xSockOptsEvent.pvData = ( void * ) pxMCA; if( xSendEventStructToIPTask( &( xSockOptsEvent ), portMAX_DELAY ) != pdPASS ) { - vPortFree( pxMCG ); - xReturn = -1; + vPortFree( pxMCA ); + xReturn = -pdFREERTOS_ERRNO_ECANCELED; } else { - xReturn = 0; + xReturn = pdFREERTOS_ERRNO_NONE; } } break; diff --git a/source/FreeRTOS_UDP_IPv4.c b/source/FreeRTOS_UDP_IPv4.c index f51243ebdb..741390cd24 100644 --- a/source/FreeRTOS_UDP_IPv4.c +++ b/source/FreeRTOS_UDP_IPv4.c @@ -183,6 +183,8 @@ void vProcessGeneratedUDPPacket_IPv4( NetworkBufferDescriptor_t * const pxNetwor pvCopyDest = &pxNetworkBuffer->pucEthernetBuffer[ sizeof( MACAddress_t ) ]; ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartUDPPacketHeader ) ); + pxIPHeader->ucTimeToLive = pxNetworkBuffer->ucMaximumHops; + #if ipconfigSUPPORT_OUTGOING_PINGS == 1 if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA ) { @@ -212,33 +214,6 @@ void vProcessGeneratedUDPPacket_IPv4( NetworkBufferDescriptor_t * const pxNetwor pxIPHeader->usFragmentOffset = 0U; #endif - #if ( ipconfigUSE_LLMNR == 1 ) - { - /* LLMNR messages are typically used on a LAN and they're - * not supposed to cross routers */ - if( pxNetworkBuffer->xIPAddress.ulIP_IPv4 == ipLLMNR_IP_ADDR ) - { - pxIPHeader->ucTimeToLive = 0x01; - } - } - #endif - #if ( ipconfigUSE_MDNS == 1 ) - { - /* mDNS messages have a hop-count of 255, see RFC 6762, section 11. */ - if( pxNetworkBuffer->xIPAddress.ulIP_IPv4 == ipMDNS_IP_ADDRESS ) - { - pxIPHeader->ucTimeToLive = 0xffU; - } - } - #endif - - #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - if( ( pxNetworkBuffer->xIPAddress.ulIP_IPv4 != ipLLMNR_IP_ADDR ) && ( pxNetworkBuffer->xIPAddress.ulIP_IPv4 == ipMDNS_IP_ADDRESS ) ) - { - pxIPHeader->ucTimeToLive = pxNetworkBuffer->ucSendTTL; - } - #endif - #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) { pxIPHeader->usHeaderChecksum = 0U; diff --git a/source/FreeRTOS_UDP_IPv6.c b/source/FreeRTOS_UDP_IPv6.c index f146752edb..e6d894d6ff 100644 --- a/source/FreeRTOS_UDP_IPv6.c +++ b/source/FreeRTOS_UDP_IPv6.c @@ -254,6 +254,8 @@ void vProcessGeneratedUDPPacket_IPv6( NetworkBufferDescriptor_t * const pxNetwor pxNetworkBuffer->pxEndPoint = pxEndPoint; + pxIPHeader_IPv6->ucHopLimit = pxNetworkBuffer->ucMaximumHops; + #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) /* Is it possible that the packet is not actually a UDP packet @@ -262,7 +264,6 @@ void vProcessGeneratedUDPPacket_IPv6( NetworkBufferDescriptor_t * const pxNetwor { pxIPHeader_IPv6->ucVersionTrafficClass = 0x60; pxIPHeader_IPv6->ucNextHeader = ipPROTOCOL_ICMP_IPv6; - pxIPHeader_IPv6->ucHopLimit = 128; } else #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ @@ -274,7 +275,6 @@ void vProcessGeneratedUDPPacket_IPv6( NetworkBufferDescriptor_t * const pxNetwor pxIPHeader_IPv6->ucVersionTrafficClass = 0x60; pxIPHeader_IPv6->ucTrafficClassFlow = 0; pxIPHeader_IPv6->usFlowLabel = 0; - pxIPHeader_IPv6->ucHopLimit = 255; pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength - ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ) ); pxIPHeader_IPv6->ucNextHeader = ipPROTOCOL_UDP; diff --git a/source/include/FreeRTOS_IGMP.h b/source/include/FreeRTOS_IGMP.h index 9106723da8..eb0b188542 100644 --- a/source/include/FreeRTOS_IGMP.h +++ b/source/include/FreeRTOS_IGMP.h @@ -84,7 +84,7 @@ typedef struct xIGMP_PACKET IGMPPacket_t; void vIGMP_Init( void ); - void vModifyMulticastMembership( MCastGroupDesc_t * pxMulticastGroup, + void vModifyMulticastMembership( MulticastAction_t * pxMulticastAction, uint8_t bAction ); BaseType_t xSendIGMPEvent( void ); void vHandleIGMP_Event( void ); diff --git a/source/include/FreeRTOS_IP.h b/source/include/FreeRTOS_IP.h index e9dcc64704..b50f530216 100644 --- a/source/include/FreeRTOS_IP.h +++ b/source/include/FreeRTOS_IP.h @@ -167,9 +167,7 @@ typedef struct xNETWORK_BUFFER #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) struct xNETWORK_BUFFER * pxNextBuffer; /**< Possible optimisation for expert users - requires network driver support. */ #endif - #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - uint8_t ucSendTTL; /**< Outgoing TimeToLive value. Required for multicasts. */ - #endif + uint8_t ucMaximumHops; /**< TTL/HopLimit value for outgoing multicast/unicast UDP/ICMP/ICMPv6 frames. */ #define ul_IPAddress xIPAddress.xIP_IPv4 #define x_IPv6Address xIPAddress.xIP_IPv6 diff --git a/source/include/FreeRTOS_IP_Common.h b/source/include/FreeRTOS_IP_Common.h index 64081af475..af4e4254e1 100644 --- a/source/include/FreeRTOS_IP_Common.h +++ b/source/include/FreeRTOS_IP_Common.h @@ -55,37 +55,19 @@ typedef struct xxIPv46_Address BaseType_t xIs_IPv6; /**< pdTRUE if IPv6 address. */ } IPv46_Address_t; -#if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - /** @brief The structure represents an IPv4 address. */ - typedef struct freertos_in_addr - { - uint32_t s_addr; /**< IPv4 address in network byte order */ - } In_Addr_t; +struct xNetworkEndPoint; +struct xNetworkInterface; -/** @brief The structure is used to join/leave an IPv4 multicast group. */ +#if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) +/** @brief The structure is used to join/leave an IPv4/IPv6 multicast group. */ typedef struct freertos_ip_mreq { - In_Addr_t imr_multiaddr; /**< The address of the multicast group */ - In_Addr_t imr_interface; /**< The address of the network interface on which the multicast group is to be joined or left */ + IP_Address_t xMulticastGroup; /**< The address of the multicast group */ + struct xNetworkInterface * pxMulticastNetIf; /**< A pointer to the network interface on which the above + * multicast group is to be joined or left. NULL means "on all interfaces" */ } IP_MReq_t; - -/** @brief The structure represents an IPv6 address. */ - typedef struct freertos_in6_addr - { - IPv6_Address_t s6_addr; /**< IPv6 address */ - } In6_Addr_t; - -/** @brief The structure is used to join/leave an IPv6 multicast group. */ - typedef struct freertos_ipv6_mreq - { - In6_Addr_t ipv6mr_multiaddr; /**< The address of the multicast group */ - uint32_t ipv6mr_interface; /**< The network interface index on which the multicast group is to be joined or left. 0 means use the default multicast interface. */ - } IP6_MReq_t; #endif /* if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */ -struct xNetworkEndPoint; -struct xNetworkInterface; - /* Return true if a given end-point is up and running. * When FreeRTOS_IsNetworkUp() is called with NULL as a parameter, * it will return pdTRUE when all end-points are up. */ diff --git a/source/include/FreeRTOS_IP_Private.h b/source/include/FreeRTOS_IP_Private.h index 91b68f66b6..a4411a55c5 100644 --- a/source/include/FreeRTOS_IP_Private.h +++ b/source/include/FreeRTOS_IP_Private.h @@ -647,16 +647,15 @@ typedef struct UDPSOCKET FOnUDPSent_t pxHandleSent; /**< Function pointer to handle the events after a successful send. */ #endif /* ipconfigUSE_CALLBACKS */ #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) - IP_Address_t xMulticastAddress; /**< Holds the multicast group address that the socket may have subscribed to receive. */ - 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. - * Note that the options are of different sizes for IPv4 and IPv6. - * Example: - * uint8_t ttl = 1; - * FreeRTOS_setsockopt( MCastSendSock, 0, FREERTOS_SO_IP_MULTICAST_TTL, ( void * ) &ttl, sizeof( ttl ) ); - * IPv6 Example: - * BaseType_t hops = 1; - * FreeRTOS_setsockopt( MCastSendSock_v6, 0, FREERTOS_SO_IPV6_MULTICAST_HOPS, ( void * ) &hops, sizeof( hops ) ); - */ + IP_Address_t xMulticastAddress; /**< Holds the multicast group address that the socket may have subscribed to receive. */ + NetworkInterface_t * pxMulticastNetIf; /**< The interface on which multicasts are to be received. NULL for all interfaces. */ + uint8_t ucMulticastMaxHops; /**< Allows for multicast sockets to use a TTL/Hops value that is different than for unicast packets + * in order to limit the reach of multicast packets. + * Defaults to ipconfigMULTICAST_DEFAULT_TTL. For local network use, it is recommended to use a TTL of 1. + * Example: + * uint8_t ttl = 1; + * FreeRTOS_setsockopt( MCastSendSock, 0, FREERTOS_SO_IP_MULTICAST_TTL, ( void * ) &ttl, sizeof( ttl ) ); + */ #endif } IPUDPSocket_t; diff --git a/source/include/FreeRTOS_IP_Utils.h b/source/include/FreeRTOS_IP_Utils.h index 6fe720ea2c..f5ea5dfc39 100644 --- a/source/include/FreeRTOS_IP_Utils.h +++ b/source/include/FreeRTOS_IP_Utils.h @@ -69,21 +69,26 @@ /** @brief A structure holding information about a multicast group address. Used during generation of IGMP/ICMPv6 reports. */ typedef struct MCastReportDescription { - IPv46_Address_t xMCastGroupAddress; /**< Holds the IPv4/IPv6 multicast group address */ + IPv46_Address_t xMCastGroupAddress; /**< Holds the IPv4/IPv6 multicast group address. xMCastGroupAddress.xIs_IPv6 denotes whether this represents and IGMP or MLD report. */ ListItem_t xListItem; /**< List item for adding to the global list of reports. */ 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. */ BaseType_t xNumSockets; /**< The number of sockets that are subscribed to this multicast group. */ BaseType_t xCountDown; } MCastReportData_t; -/** @brief The structure to hold a "descriptor" for a multicast group that a socket has registered to. */ +/** @brief A structure to hold all data related to an multicast socket option "action". When someone calls FreeRTOS_setsockopt() + * with one of the multicast socket options, the code allocates a structure like this and stores all the relevant information. + * The structure is then passed to the IP task for handling. This approach allows us to return an error if we don't have enough + * memory for a multicast report and allows all actual manipulations to happen within the IP task therefore avoiding the need + * for critical sections. An exception to this is setting the TTL/HopLimit as it can be done straight from the user task. as + * an atomic write operation. */ typedef struct xMCastGroupDesc { - IPv46_Address_t xMulticastGroup; /**< Holds the IPv4/IPv6 multicast group address */ + IP_Address_t xMulticastGroup; /**< Holds the IPv4/IPv6 multicast group address */ NetworkInterface_t * pxInterface; /**< Not implemented yet, but should point to a specific interface or NULL for all/default interface */ - FreeRTOS_Socket_t * pxSocket; - MCastReportData_t * pxMCastReportData; /**< Used to hold the allocated IGMP report descriptor while passing from user code to the IP Task. */ - } MCastGroupDesc_t; + FreeRTOS_Socket_t * pxSocket; /**< The socket this action is applied to */ + MCastReportData_t * pxMCastReportData; /**< Holds the allocated IGMP report descriptor while passing from user code to the IP Task. */ + } MulticastAction_t; #endif /* ( ipconfigSUPPORT_IP_MULTICAST == 1 ) */ diff --git a/source/include/FreeRTOS_Sockets.h b/source/include/FreeRTOS_Sockets.h index 9f5918be07..f5749cd568 100644 --- a/source/include/FreeRTOS_Sockets.h +++ b/source/include/FreeRTOS_Sockets.h @@ -154,12 +154,7 @@ #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) #define FREERTOS_SO_IP_MULTICAST_TTL ( 19 ) /* TTL value to me used when sending multicast packets. Defaults to ipconfigMULTICAST_DEFAULT_TTL */ #define FREERTOS_SO_IP_ADD_MEMBERSHIP ( 20 ) /* Mark the socket as able to receive multicast messages from a multicast group address */ - #define FREERTOS_SO_IP_ADD_SOURCE_MEMBERSHIP ( 21 ) /* not implemented */ - #define FREERTOS_SO_IP_DROP_MEMBERSHIP ( 22 ) /* Remove membership from a multicast group address */ - #define FREERTOS_SO_IP_DROP_SOURCE_MEMBERSHIP ( 23 ) /* not implemented */ - #define FREERTOS_SO_IPV6_ADD_MEMBERSHIP ( 24 ) /* Same as FREERTOS_SO_IP_ADD_MEMBERSHIP but for IPv6 */ - #define FREERTOS_SO_IPV6_DROP_MEMBERSHIP ( 25 ) /* Same as FREERTOS_SO_IP_DROP_MEMBERSHIP but for IPv6 */ - #define FREERTOS_SO_IPV6_MULTICAST_HOPS ( 26 ) /* Similar to FREERTOS_SO_IP_MULTICAST_TTL but for IPv6. Defaults to ipconfigMULTICAST_DEFAULT_TTL */ + #define FREERTOS_SO_IP_DROP_MEMBERSHIP ( 21 ) /* Remove membership from a multicast group address */ #endif /* (ipconfigSUPPORT_IP_MULTICAST != 0) */ #define FREERTOS_INADDR_ANY ( 0U ) /* The 0.0.0.0 IPv4 address. */