ip4igmp.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 692 行 · 第 1/2 页

C
692
字号
/*++

Copyright (c) 2005 - 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. 


Module Name:

  Ip4Igmp.c

Abstract:

  This file implements the RFC2236: IGMP v2

--*/

#include "Ip4Impl.h"

//
// Route Alert option in IGMP report to direct routers to
// examine the packet more closely.
//
UINT32  mRouteAlertOption = 0x00000494;

EFI_STATUS
Ip4InitIgmp (
  IN IP4_SERVICE            *IpSb
  )
/*++

Routine Description:

  Init the IGMP control data of the IP4 service instance, configure 
  MNP to receive ALL SYSTEM multicast.

Arguments:

  IpSb  - The IP4 service whose IGMP is to be initialized.

Returns:

  EFI_OUT_OF_RESOURCES - Failed to allocate resource to initialize IGMP.
  Others               - Failed to initialize the IGMP of IpSb.
  EFI_SUCCESS          - IGMP of the IpSb is successfully initialized.

--*/
{
  IGMP_SERVICE_DATA             *IgmpCtrl;
  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
  IGMP_GROUP                    *Group;
  EFI_STATUS                    Status;

  IgmpCtrl = &IpSb->IgmpCtrl;

  //
  // Configure MNP to receive ALL_SYSTEM multicast
  //
  Group    = NetAllocatePool (sizeof (IGMP_GROUP));

  if (Group == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  Mnp               = IpSb->Mnp;

  Group->Address    = IP4_ALLSYSTEM_ADDRESS;
  Group->RefCnt     = 1;
  Group->DelayTime  = 0;
  Group->ReportByUs = FALSE;

  Status = Ip4GetMulticastMac (Mnp, IP4_ALLSYSTEM_ADDRESS, &Group->Mac);

  if (EFI_ERROR (Status)) {
    goto ON_ERROR;
  }

  Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);

  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
    goto ON_ERROR;
  }

  NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);
  return EFI_SUCCESS;

ON_ERROR:
  NetFreePool (Group);
  return Status;
}

IGMP_GROUP *
Ip4FindGroup (
  IN IGMP_SERVICE_DATA      *IgmpCtrl,
  IN IP4_ADDR               Address
  )
/*++

Routine Description:

  Find the IGMP_GROUP structure which contains the status of multicast
  group Address in this IGMP control block

Arguments:

  IgmpCtrl  - The IGMP control block to search from
  Address   - The multicast address to search

Returns:

  NULL if the multicast address isn't in the IGMP control block. Otherwise
  the point to the IGMP_GROUP which contains the status of multicast group
  for Address.
  

--*/
{
  NET_LIST_ENTRY            *Entry;
  IGMP_GROUP                *Group;

  NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
    Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);

    if (Group->Address == Address) {
      return Group;
    }
  }

  return NULL;
}

INTN
Ip4FindMac (
  IN IGMP_SERVICE_DATA      *IgmpCtrl,
  IN EFI_MAC_ADDRESS        *Mac
  )
/*++

Routine Description:

  Count the number of IP4 multicast groups that are mapped to the 
  same MAC address. Several IP4 multicast address may be mapped to 
  the same MAC address. 

Arguments:

  IgmpCtrl  - The IGMP control block to search in
  Mac       - The MAC address to search

Returns:

  The number of the IP4 multicast group that mapped to the same
  multicast group Mac.

--*/
{
  NET_LIST_ENTRY            *Entry;
  IGMP_GROUP                *Group;
  INTN                      Count;

  Count = 0;

  NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
    Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);

    if (NET_MAC_EQUAL (&Group->Mac, Mac, sizeof (EFI_MAC_ADDRESS))) {
      Count++;
    }
  }

  return Count;
}

EFI_STATUS
Ip4SendIgmpMessage (
  IN IP4_SERVICE            *IpSb,
  IN IP4_ADDR               Dst,
  IN UINT8                  Type,
  IN IP4_ADDR               Group
  )
/*++

Routine Description:

  Send an IGMP protocol message to the Dst, such as IGMP v1 membership report.  

Arguments:

  IpSb  - The IP4 service instance that requests the transmission
  Dst   - The destinaton to send to 
  Type  - The IGMP message type, such as IGMP v2 membership report
  Group - The group address in the IGMP message head.

Returns:

  EFI_OUT_OF_RESOURCES - Failed to allocate memory to build the message
  EFI_SUCCESS          - The IGMP message is successfully send
  Others               - Failed to send the IGMP message.

--*/
{
  IP4_HEAD                  Head;
  NET_BUF                   *Packet;
  IGMP_HEAD                 *Igmp;

  //
  // Allocate a net buffer to hold the message
  //
  Packet = NetbufAlloc (IP4_MAX_HEADLEN + sizeof (IGMP_HEAD));

  if (Packet == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Fill in the IGMP and IP header, then transmit the message
  //
  NetbufReserve (Packet, IP4_MAX_HEADLEN);
  
  Igmp = (IGMP_HEAD *) NetbufAllocSpace (Packet, sizeof (IGMP_HEAD), FALSE);

  Igmp->Type        = Type;
  Igmp->MaxRespTime = 0;
  Igmp->Checksum    = 0;
  Igmp->Group       = HTONL (Group);
  Igmp->Checksum    = ~NetblockChecksum ((UINT8 *) Igmp, sizeof (IGMP_HEAD));

  Head.Tos          = 0;
  Head.Protocol     = IP4_PROTO_IGMP;
  Head.Ttl          = 1;
  Head.Fragment     = 0;
  Head.Dst          = Dst;
  Head.Src          = IP4_ALLZERO_ADDRESS;

  return Ip4Output (
           IpSb,
           NULL,
           Packet,
           &Head,
           (UINT8 *) &mRouteAlertOption,
           sizeof (UINT32),
           IP4_ALLZERO_ADDRESS,
           Ip4SysPacketSent,
           NULL
           );
}

EFI_STATUS
Ip4SendIgmpReport (
  IN IP4_SERVICE            *IpSb,
  IN IP4_ADDR               Group
  )
/*++

Routine Description:

  Send an IGMP membership report. Depends on whether the server is 
  v1 or v2, it will send either a V1 or V2 membership report.

Arguments:

  IpSb  - The IP4 service instance that requests the transmission.
  Group - The group address to report

Returns:

  EFI_OUT_OF_RESOURCES - Failed to allocate memory to build the message
  EFI_SUCCESS          - The IGMP report message is successfully send
  Others               - Failed to send the report.

--*/
{
  if (IpSb->IgmpCtrl.Igmpv1QuerySeen != 0) {
    return Ip4SendIgmpMessage (IpSb, Group, IGMP_V1_MEMBERSHIP_REPORT, Group);
  } else {
    return Ip4SendIgmpMessage (IpSb, Group, IGMP_V2_MEMBERSHIP_REPORT, Group);
  }
}

EFI_STATUS
Ip4JoinGroup (
  IN IP4_PROTOCOL           *IpInstance,
  IN IP4_ADDR               Address
  )
/*++

Routine Description:

  Join the multicast group on behavior of this IP4 child

Arguments:

  IpInstance  - The IP4 child that wants to join the group
  Address     - The group to join

Returns:

  EFI_SUCCESS          - Successfully join the multicast group
  EFI_OUT_OF_RESOURCES - Failed to allocate resources 
  Others               - Failed to join the multicast group.

--*/
{
  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
  IP4_SERVICE                   *IpSb;
  IGMP_SERVICE_DATA             *IgmpCtrl;
  IGMP_GROUP                    *Group;
  EFI_STATUS                    Status;

  IpSb      = IpInstance->Service;
  IgmpCtrl  = &IpSb->IgmpCtrl;
  Mnp       = IpSb->Mnp;

  //
  // If the IP service already is a member in the group, just
  // increase the refernce count and return.
  //
  Group     = Ip4FindGroup (IgmpCtrl, Address);

  if (Group != NULL) {
    Group->RefCnt++;
    return EFI_SUCCESS;
  }

  //
  // Otherwise, create a new IGMP_GROUP,  Get the multicast's MAC address, 
  // send a report, then direct MNP to receive the multicast.
  //
  Group = NetAllocatePool (sizeof (IGMP_GROUP));

  if (Group == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  Group->Address    = Address;
  Group->RefCnt     = 1;
  Group->DelayTime  = IGMP_UNSOLICIATED_REPORT;
  Group->ReportByUs = TRUE;

  Status = Ip4GetMulticastMac (Mnp, Address, &Group->Mac);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?