Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
476
EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c
Normal file
476
EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c
Normal file
@@ -0,0 +1,476 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) 2006, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
|
||||
|
||||
#define RAND_MAX 0x10000
|
||||
#include "bc.h"
|
||||
|
||||
//
|
||||
// Definitions for internet group management protocol version 2 message
|
||||
// structure Per RFC 2236, November 1997
|
||||
//
|
||||
STATIC UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 };
|
||||
STATIC IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } };
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
STATIC
|
||||
VOID
|
||||
ClearGroupTimer (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
UINTN TimerId
|
||||
)
|
||||
{
|
||||
if (Private == NULL) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (TimerId >= Private->MCastGroupCount) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (Private->IgmpGroupEvent[TimerId] == NULL) {
|
||||
return ;
|
||||
}
|
||||
|
||||
gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
|
||||
Private->IgmpGroupEvent[TimerId] = NULL;
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
STATIC
|
||||
VOID
|
||||
SetGroupTimer (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
UINTN TimerId,
|
||||
UINTN MaxRespTime
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Set IGMP response timeout value.
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
TimerId := Timer ID#
|
||||
MaxRespTime := Base response timeout value in tenths of seconds
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
EFI_STATUS EfiStatus;
|
||||
|
||||
if (Private == NULL) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (TimerId >= Private->MCastGroupCount) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (Private->IgmpGroupEvent[TimerId] != NULL) {
|
||||
gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
|
||||
}
|
||||
|
||||
EfiStatus = gBS->CreateEvent (
|
||||
EFI_EVENT_TIMER,
|
||||
EFI_TPL_CALLBACK,
|
||||
NULL,
|
||||
NULL,
|
||||
&Private->IgmpGroupEvent[TimerId]
|
||||
);
|
||||
|
||||
if (EFI_ERROR (EfiStatus)) {
|
||||
Private->IgmpGroupEvent[TimerId] = NULL;
|
||||
return ;
|
||||
}
|
||||
|
||||
EfiStatus = gBS->SetTimer (
|
||||
Private->IgmpGroupEvent[TimerId],
|
||||
TimerRelative,
|
||||
MaxRespTime * 1000000 + Random (Private) % RAND_MAX
|
||||
);
|
||||
|
||||
if (EFI_ERROR (EfiStatus)) {
|
||||
gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
|
||||
Private->IgmpGroupEvent[TimerId] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
STATIC
|
||||
VOID
|
||||
SendIgmpMessage (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
UINT8 Type,
|
||||
INTN GroupId
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Send an IGMP message
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
Type := Message type opcode
|
||||
GroupId := Group ID#
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
Private->IgmpMessage.Type = Type;
|
||||
Private->IgmpMessage.MaxRespTime = 0;
|
||||
Private->IgmpMessage.Checksum = 0;
|
||||
Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId];
|
||||
Private->IgmpMessage.Checksum = IpChecksum (
|
||||
(UINT16 *) &Private->IgmpMessage,
|
||||
sizeof Private->IgmpMessage
|
||||
);
|
||||
|
||||
Ipv4SendWOp (
|
||||
Private,
|
||||
0,
|
||||
(UINT8 *) &Private->IgmpMessage,
|
||||
sizeof Private->IgmpMessage,
|
||||
PROT_IGMP,
|
||||
RouterAlertOption,
|
||||
sizeof RouterAlertOption,
|
||||
((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress),
|
||||
EFI_PXE_BASE_CODE_FUNCTION_IGMP
|
||||
);
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
STATIC
|
||||
VOID
|
||||
ReportIgmp (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
INTN GroupId
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Send an IGMP report message.
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
GroupId := Group ID#
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// if version 1 querier, send v1 report
|
||||
//
|
||||
UINT8 Type;
|
||||
|
||||
if (Private->Igmpv1TimeoutEvent != NULL) {
|
||||
if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
|
||||
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
|
||||
Private->Igmpv1TimeoutEvent = NULL;
|
||||
Private->UseIgmpv1Reporting = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT);
|
||||
|
||||
SendIgmpMessage (Private, Type, GroupId);
|
||||
ClearGroupTimer (Private, GroupId);
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
VOID
|
||||
IgmpCheckTimers (
|
||||
PXE_BASECODE_DEVICE *Private
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Check IGMP timers and send reports for all groups that have expired.
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
UINTN GroupId;
|
||||
|
||||
if (Private == NULL) {
|
||||
return ;
|
||||
}
|
||||
|
||||
for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
|
||||
if (Private->IgmpGroupEvent[GroupId] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) {
|
||||
//
|
||||
// send a report
|
||||
//
|
||||
ReportIgmp (Private, GroupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
STATIC
|
||||
INTN
|
||||
FindMulticastGroup (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
UINT32 GroupAddress
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Fund group ID# (index).
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
GroupAddress := Group multicast address
|
||||
|
||||
Returns:
|
||||
0 := Group not found
|
||||
other := Group ID#
|
||||
--*/
|
||||
{
|
||||
UINTN GroupId;
|
||||
|
||||
for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
|
||||
if (Private->MCastGroup[GroupId] == GroupAddress) {
|
||||
return GroupId + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
VOID
|
||||
IgmpJoinGroup (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
EFI_IP_ADDRESS *GroupPtr
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Join multicast group.
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
GroupPtr := Pointer to group mutlicast IP address.
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
UINT32 Grp;
|
||||
|
||||
Grp = *(UINT32 *) GroupPtr;
|
||||
|
||||
#if SUPPORT_IPV6
|
||||
if (Private->EfiBc.Mode->UsingIpv6) {
|
||||
//
|
||||
// TBD
|
||||
//
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// see if we already have it or if we can't take anymore
|
||||
//
|
||||
if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) {
|
||||
return ;
|
||||
}
|
||||
//
|
||||
// add the group
|
||||
//
|
||||
Private->MCastGroup[Private->MCastGroupCount] = Grp;
|
||||
|
||||
ReportIgmp (Private, Private->MCastGroupCount);
|
||||
//
|
||||
// send a report
|
||||
// so it will get sent again per RFC 2236
|
||||
//
|
||||
SetGroupTimer (
|
||||
Private,
|
||||
Private->MCastGroupCount++,
|
||||
UNSOLICITED_REPORT_INTERVAL * 10
|
||||
);
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
VOID
|
||||
IgmpLeaveGroup (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
EFI_IP_ADDRESS *GroupPtr
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Leave multicast group.
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
GroupPtr := Mutlicast group IP address.
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
UINT32 Grp;
|
||||
UINTN GroupId;
|
||||
|
||||
Grp = *(UINT32 *) GroupPtr;
|
||||
|
||||
#if SUPPORT_IPV6
|
||||
if (Private->EfiBc.Mode->UsingIpv6) {
|
||||
//
|
||||
// TBD
|
||||
//
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// if not in group, ignore
|
||||
//
|
||||
GroupId = FindMulticastGroup (Private, Grp);
|
||||
|
||||
if (GroupId == 0) {
|
||||
return ;
|
||||
}
|
||||
//
|
||||
// if not v1 querrier, send leave group IGMP message
|
||||
//
|
||||
if (Private->Igmpv1TimeoutEvent != NULL) {
|
||||
if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
|
||||
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
|
||||
Private->Igmpv1TimeoutEvent = NULL;
|
||||
Private->UseIgmpv1Reporting = TRUE;
|
||||
} else {
|
||||
SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1);
|
||||
}
|
||||
}
|
||||
|
||||
while (GroupId < Private->MCastGroupCount) {
|
||||
Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId];
|
||||
Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId];
|
||||
++GroupId;
|
||||
}
|
||||
|
||||
--Private->MCastGroupCount;
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
VOID
|
||||
HandleIgmp (
|
||||
PXE_BASECODE_DEVICE *Private,
|
||||
IGMPV2_MESSAGE *IgmpMessagePtr,
|
||||
UINTN IgmpLength
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Handle received IGMP packet
|
||||
|
||||
Parameters:
|
||||
Private := Pointer to PxeBc interface
|
||||
IgmpMessagePtr := Pointer to IGMP packet
|
||||
IgmpLength := packet length in bytes
|
||||
|
||||
Returns:
|
||||
--*/
|
||||
{
|
||||
EFI_STATUS EfiStatus;
|
||||
UINTN GroupId;
|
||||
INTN MaxRespTime;
|
||||
|
||||
if (Private == NULL) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (Private->MCastGroupCount == 0) {
|
||||
//
|
||||
// if we don't belong to any multicast groups, ignore
|
||||
//
|
||||
return ;
|
||||
}
|
||||
//
|
||||
// verify checksum
|
||||
//
|
||||
if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) {
|
||||
//
|
||||
// bad checksum - ignore packet
|
||||
//
|
||||
return ;
|
||||
}
|
||||
|
||||
switch (IgmpMessagePtr->Type) {
|
||||
case IGMP_TYPE_QUERY:
|
||||
//
|
||||
// if a version 1 querier, note the fact and set max resp time
|
||||
//
|
||||
MaxRespTime = IgmpMessagePtr->MaxRespTime;
|
||||
|
||||
if (MaxRespTime == 0) {
|
||||
Private->UseIgmpv1Reporting = TRUE;
|
||||
|
||||
if (Private->Igmpv1TimeoutEvent != NULL) {
|
||||
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
|
||||
}
|
||||
|
||||
EfiStatus = gBS->CreateEvent (
|
||||
EFI_EVENT_TIMER,
|
||||
EFI_TPL_CALLBACK,
|
||||
NULL,
|
||||
NULL,
|
||||
&Private->Igmpv1TimeoutEvent
|
||||
);
|
||||
|
||||
if (EFI_ERROR (EfiStatus)) {
|
||||
Private->Igmpv1TimeoutEvent = NULL;
|
||||
} else {
|
||||
EfiStatus = gBS->SetTimer (
|
||||
Private->Igmpv1TimeoutEvent,
|
||||
TimerRelative,
|
||||
(UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
|
||||
);
|
||||
}
|
||||
|
||||
MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10;
|
||||
}
|
||||
//
|
||||
// if a general query (!GroupAddress), set all our group timers
|
||||
//
|
||||
if (!IgmpMessagePtr->GroupAddress) {
|
||||
for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
|
||||
SetGroupTimer (Private, GroupId, MaxRespTime);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// specific query - set only specific group
|
||||
//
|
||||
GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
|
||||
|
||||
if (GroupId != 0) {
|
||||
SetGroupTimer (Private, GroupId - 1, MaxRespTime);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// if we have a timer running for this group, clear it
|
||||
//
|
||||
case IGMP_TYPE_V1REPORT:
|
||||
case IGMP_TYPE_REPORT:
|
||||
GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
|
||||
|
||||
if (GroupId != 0) {
|
||||
ClearGroupTimer (Private, GroupId - 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF - pxe_bc_igmp.c */
|
Reference in New Issue
Block a user