|
59 | 59 | #include "FreeRTOS_DNS.h"
|
60 | 60 | #include "FreeRTOS_Routing.h"
|
61 | 61 | #include "FreeRTOS_ND.h"
|
| 62 | +#if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) |
| 63 | + #include "FreeRTOS_IGMP.h" |
| 64 | +#endif |
62 | 65 |
|
63 | 66 | /** @brief Time delay between repeated attempts to initialise the network hardware. */
|
64 | 67 | #ifndef ipINITIALISATION_RETRY_DELAY
|
@@ -467,6 +470,20 @@ static void prvProcessIPEventsAndTimers( void )
|
467 | 470 | /* xQueueReceive() returned because of a normal time-out. */
|
468 | 471 | break;
|
469 | 472 |
|
| 473 | + #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) |
| 474 | + case eSocketOptAddMembership: |
| 475 | + case eSocketOptDropMembership: |
| 476 | + { |
| 477 | + MCastGroupDesc_t * pxMCG = ( MCastGroupDesc_t * ) xReceivedEvent.pvData; |
| 478 | + ( void ) vModifyMulticastMembership( pxMCG, xReceivedEvent.eEventType ); |
| 479 | + break; |
| 480 | + } |
| 481 | + |
| 482 | + case eIGMPEvent: |
| 483 | + ( void ) vHandleIGMP_Event(); |
| 484 | + break; |
| 485 | + #endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0) */ |
| 486 | + |
470 | 487 | default:
|
471 | 488 | /* Should not get here. */
|
472 | 489 | break;
|
@@ -526,6 +543,11 @@ static void prvIPTask_Initialise( void )
|
526 | 543 | }
|
527 | 544 | #endif /* ( ( ipconfigUSE_DNS_CACHE != 0 ) && ( ipconfigUSE_DNS != 0 ) ) */
|
528 | 545 |
|
| 546 | + /* Init the list that will hold scheduled IGMP reports. */ |
| 547 | + #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) |
| 548 | + ( void ) vIGMP_Init(); |
| 549 | + #endif |
| 550 | + |
529 | 551 | /* Initialisation is complete and events can now be processed. */
|
530 | 552 | xIPTaskInitialised = pdTRUE;
|
531 | 553 | }
|
@@ -631,8 +653,76 @@ TaskHandle_t FreeRTOS_GetIPTaskHandle( void )
|
631 | 653 | */
|
632 | 654 | void vIPNetworkUpCalls( struct xNetworkEndPoint * pxEndPoint )
|
633 | 655 | {
|
| 656 | + #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) |
| 657 | + MCastReportData_t * pxMRD; |
| 658 | + IPv6_Type_t xAddressType; |
| 659 | + MACAddress_t xMACAddress; |
| 660 | + #endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */ |
| 661 | + |
634 | 662 | pxEndPoint->bits.bEndPointUp = pdTRUE_UNSIGNED;
|
635 | 663 |
|
| 664 | + #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) |
| 665 | + if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED ) |
| 666 | + { |
| 667 | + /* Now that the network is up, pxEndPoint->ipv6_settings should hold the actual address of this |
| 668 | + * end-point. For unicast addresses, generate the solicited-node multicast address that corresponds |
| 669 | + * to the address and generate an MLD report for it. |
| 670 | + * ToDo: Figure out what the proper place is to remove multicast addresses that are no longer valid. For |
| 671 | + * example when a DHCPv6 lease expires. */ |
| 672 | + xAddressType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) ); |
| 673 | + |
| 674 | + if( ( xAddressType == eIPv6_LinkLocal ) || ( xAddressType == eIPv6_SiteLocal ) || ( xAddressType == eIPv6_Global ) ) |
| 675 | + { |
| 676 | + if( NULL != ( pxMRD = ( MCastReportData_t * ) pvPortMalloc( sizeof( MCastReportData_t ) ) ) ) |
| 677 | + { |
| 678 | + listSET_LIST_ITEM_OWNER( &( pxMRD->xListItem ), ( void * ) pxMRD ); |
| 679 | + pxMRD->pxEndPoint = pxEndPoint; |
| 680 | + pxMRD->xMCastGroupAddress.xIs_IPv6 = pdTRUE_UNSIGNED; |
| 681 | + |
| 682 | + /* Generate the solicited-node multicast address in the form of |
| 683 | + * ff02::1:ffnn:nnnn, where nn:nnnn are the last 3 bytes of the IPv6 address. */ |
| 684 | + pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 0 ] = 0xFFU; |
| 685 | + pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 1 ] = 0x02U; |
| 686 | + ( void ) memset( &pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 2 ], 0x00, 9 ); |
| 687 | + pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 11 ] = 0x01U; |
| 688 | + pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 12 ] = 0xFFU; |
| 689 | + ( void ) memcpy( &pxMRD->xMCastGroupAddress.xIPAddress.xIP_IPv6.ucBytes[ 13 ], &pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ], 3 ); |
| 690 | + |
| 691 | + if( pdTRUE != xAddIGMPReportToList( pxMRD ) ) |
| 692 | + { |
| 693 | + vPortFree( pxMRD ); |
| 694 | + pxMRD = NULL; |
| 695 | + } |
| 696 | + else |
| 697 | + { |
| 698 | + /* The report was consumed, therefore it was added to the list. Tell the network |
| 699 | + * driver to begin receiving the associated MAC address */ |
| 700 | + if( pxEndPoint->pxNetworkInterface && ( pxEndPoint->pxNetworkInterface->pfAddMulticastMAC != NULL ) ) |
| 701 | + { |
| 702 | + xMACAddress.ucBytes[ 0 ] = 0x33; |
| 703 | + xMACAddress.ucBytes[ 1 ] = 0x33; |
| 704 | + xMACAddress.ucBytes[ 2 ] = 0xFF; |
| 705 | + xMACAddress.ucBytes[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ]; |
| 706 | + xMACAddress.ucBytes[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ]; |
| 707 | + xMACAddress.ucBytes[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ]; |
| 708 | + pxEndPoint->pxNetworkInterface->pfAddMulticastMAC( xMACAddress.ucBytes ); |
| 709 | + } |
| 710 | + } |
| 711 | + } |
| 712 | + } |
| 713 | + } /* if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED ) */ |
| 714 | + |
| 715 | + /* Reschedule all multicast reports associated with this end-point. |
| 716 | + * /* Note: countdown is in increments of ipIGMP_TIMER_PERIOD_MS. It's a good idea to spread out all reports a little. |
| 717 | + * 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, |
| 718 | + * they will soon ask us for reports anyways, so sending these unsolicited reports is not required. It simply enhances the user |
| 719 | + * experience by shortening the time it takes before we begin receiving the multicasts that we care for. */ |
| 720 | + /* _EP_: vRescheduleAllMulticastReports() is NOT declared in header files because I don't want to expose it to the user */ |
| 721 | + extern void vRescheduleAllMulticastReports( NetworkEndPoint_t * pxEndPoint, |
| 722 | + BaseType_t xMaxCountdown ); |
| 723 | + vRescheduleAllMulticastReports( pxEndPoint, 5 ); |
| 724 | + #endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */ |
| 725 | + |
636 | 726 | #if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
|
637 | 727 | #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
|
638 | 728 | {
|
@@ -1976,6 +2066,13 @@ static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacke
|
1976 | 2066 | break;
|
1977 | 2067 | #endif /* ( ipconfigUSE_IPv6 != 0 ) */
|
1978 | 2068 |
|
| 2069 | + #if ( ipconfigSUPPORT_IP_MULTICAST != 0 ) |
| 2070 | + case ipPROTOCOL_IGMP: |
| 2071 | + /* The IP packet contained an IGMP frame. */ |
| 2072 | + eReturn = eProcessIGMPPacket( pxNetworkBuffer ); |
| 2073 | + break; |
| 2074 | + #endif /* ( ipconfigSUPPORT_IP_MULTICAST != 0 ) */ |
| 2075 | + |
1979 | 2076 | case ipPROTOCOL_UDP:
|
1980 | 2077 | /* The IP packet contained a UDP frame. */
|
1981 | 2078 |
|
|
0 commit comments