ip4impl.c

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

C
2,133
字号
/*++

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:

  Ip4Impl.c

Abstract:

--*/

#include "Ip4Impl.h"

STATIC
EFI_STATUS
EFIAPI
EfiIp4GetModeData (
  IN EFI_IP4_PROTOCOL                 *This,
  OUT EFI_IP4_MODE_DATA               *Ip4ModeData,    OPTIONAL
  OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData,  OPTIONAL 
  OUT EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL
  )
/*++

Routine Description:

  Get the IP child's current operational data. This can
  all be used to get the underlying MNP and SNP data.

Arguments:

  This          - The IP4 protocol instance
  Ip4ModeData   - The IP4 operation data
  MnpConfigData - The MNP configure data
  SnpModeData   - The SNP operation data

Returns:

  EFI_INVALID_PARAMETER - The parameter is invalid because This == NULL
  EFI_SUCCESS           - The operational parameter is returned.
  Others                - Failed to retrieve the IP4 route table.

--*/
{
  IP4_PROTOCOL              *IpInstance;
  IP4_SERVICE               *IpSb;
  EFI_IP4_CONFIG_DATA       *Config;
  EFI_STATUS                Status;
  EFI_TPL                   OldTpl;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  OldTpl     = NET_RAISE_TPL (NET_TPL_LOCK);
  IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
  IpSb       = IpInstance->Service;

  if (Ip4ModeData != NULL) {
    //
    // IsStarted is "whether the EfiIp4Configure has been called".
    // IsConfigured is "whether the station address has been configured"
    //
    Ip4ModeData->IsStarted     = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);
    Ip4ModeData->ConfigData    = IpInstance->ConfigData;
    Ip4ModeData->IsConfigured  = FALSE;

    Ip4ModeData->GroupCount    = IpInstance->GroupCount;
    Ip4ModeData->GroupTable    = (EFI_IPv4_ADDRESS *) IpInstance->Groups;

    Ip4ModeData->IcmpTypeCount = 23;
    Ip4ModeData->IcmpTypeList  = mIp4SupportedIcmp;

    Ip4ModeData->RouteTable    = NULL;
    Ip4ModeData->RouteCount    = 0;

    //
    // return the current station address for this IP child. So, 
    // the user can get the default address through this. Some 
    // application wants to know it station address even it is 
    // using the default one, such as a ftp server.
    //
    if (Ip4ModeData->IsStarted) {
      Config  = &Ip4ModeData->ConfigData;
      
      EFI_IP4 (Config->StationAddress) = HTONL (IpInstance->Interface->Ip);
      EFI_IP4 (Config->SubnetMask)     = HTONL (IpInstance->Interface->SubnetMask);
      Ip4ModeData->IsConfigured        = IpInstance->Interface->Configured;

      //
      // Build a EFI route table for user from the internal route table.
      //
      Status = Ip4BuildEfiRouteTable (IpInstance);

      if (EFI_ERROR (Status)) {
        NET_RESTORE_TPL (OldTpl);
        return Status;
      }

      Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;
      Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;
    }
  }

  if (MnpConfigData != NULL) {
    *MnpConfigData = IpSb->MnpConfigData;
  }

  if (SnpModeData != NULL) {
    *SnpModeData = IpSb->SnpMode;
  }

  NET_RESTORE_TPL (OldTpl);
  return EFI_SUCCESS;
}

EFI_STATUS
Ip4ServiceConfigMnp (
  IN IP4_SERVICE            *IpSb,
  IN BOOLEAN                Force
  )
/*++

Routine Description:

  Config the MNP parameter used by IP. The IP driver use one MNP 
  child to transmit/receive frames. By default, it configures MNP
  to receive unicast/multicast/broadcast. And it will enable/disable
  the promiscous receive according to whether there is IP child 
  enable that or not. If Force isn't false, it will iterate through 
  all the IP children to check whether the promiscuous receive 
  setting has been changed. If it hasn't been changed, it won't 
  reconfigure the MNP. If Force is true, the MNP is configured no 
  matter whether that is changed or not.

Arguments:

  IpSb  - The IP4 service instance that is to be changed.
  Force - Force the configuration or not.

Returns:

  EFI_SUCCESS - The MNP is successfully configured/reconfigured.
  Others      - Configuration failed.

--*/
{
  NET_LIST_ENTRY            *Entry;
  NET_LIST_ENTRY            *ProtoEntry;
  IP4_INTERFACE             *IpIf;
  IP4_PROTOCOL              *IpInstance;
  BOOLEAN                   Reconfig;
  BOOLEAN                   PromiscReceive;
  EFI_STATUS                Status;

  Reconfig       = FALSE;
  PromiscReceive = FALSE;

  if (!Force) {
    //
    // Iterate through the IP children to check whether promiscuous 
    // receive setting has been changed. Update the interface's receive 
    // filter also.
    //
    NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {

      IpIf              = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
      IpIf->PromiscRecv = FALSE;

      NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
        IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);

        if (IpInstance->ConfigData.AcceptPromiscuous) {
          IpIf->PromiscRecv = TRUE;
          PromiscReceive    = TRUE;
        }
      }
    }
    
    //
    // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
    //
    if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
      return EFI_SUCCESS;
    }

    Reconfig  = TRUE;
    IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
  }

  Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);

  //
  // recover the original configuration if failed to set the configure.
  //
  if (EFI_ERROR (Status) && Reconfig) {
    IpSb->MnpConfigData.EnablePromiscuousReceive = !PromiscReceive;
  }

  return Status;
}

VOID
EFIAPI
Ip4AutoConfigCallBack (
  IN EFI_EVENT              Event,
  IN VOID                   *Context
  )
/*++

Routine Description:

  The event handle for IP4 auto configuration. If IP is asked
  to reconfigure the default address. The original default 
  interface and route table are removed as the default. If there
  is active IP children using the default address, the interface
  will remain valid until all the children have freed their 
  references. If IP is signalled when auto configuration is done,
  it will configure the default interface and default route table
  with the configuration information retrieved by IP4_CONFIGURE.

Arguments:

  Event   - The event that is signalled.
  Context - The IP4 service binding instance.

Returns:

  None

--*/
{
  EFI_IP4_CONFIG_PROTOCOL   *Ip4Config;
  EFI_IP4_IPCONFIG_DATA     *Data;
  EFI_IP4_ROUTE_TABLE       *RouteEntry;
  IP4_SERVICE               *IpSb;
  IP4_ROUTE_TABLE           *RouteTable;
  IP4_INTERFACE             *IpIf;
  EFI_STATUS                Status;
  UINTN                     Len;
  UINT32                    Index;

  IpSb      = (IP4_SERVICE *) Context;
  NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
  
  Ip4Config = IpSb->Ip4Config;

  //
  // IP is asked to do the reconfiguration. If the default interface
  // has been configured, release the default interface and route
  // table, then create a new one. If there are some IP children
  // using it, the interface won't be physically freed until all the
  // children have released their reference to it. Also remember to
  // restart the receive on the default address. IP4 driver only receive
  // frames on the default address, and when the default interface is 
  // freed, Ip4AcceptFrame won't be informed.
  //
  if (Event == IpSb->ReconfigEvent) {
    
    if (IpSb->DefaultInterface->Configured) {
      IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);

      if (IpIf == NULL) {
        return;
      }

      RouteTable = Ip4CreateRouteTable ();

      if (RouteTable == NULL) {
        Ip4FreeInterface (IpIf, NULL);
        return;
      }

      Ip4CancelReceive (IpSb->DefaultInterface);
      Ip4FreeInterface (IpSb->DefaultInterface, NULL);
      Ip4FreeRouteTable (IpSb->DefaultRouteTable);

      IpSb->DefaultInterface  = IpIf;
      NetListInsertHead (&IpSb->Interfaces, &IpIf->Link);

      IpSb->DefaultRouteTable = RouteTable;
      Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
    }
    
    Ip4Config->Stop (Ip4Config);
    Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
    return ;
  }
  
  //
  // Get the configure data in two steps: get the length then the data.
  //
  Len = 0;
  
  if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {
    return ;
  }
  
  Data = NetAllocatePool (Len);

  if (Data == NULL) {
    return ;
  }

  Status = Ip4Config->GetData (Ip4Config, &Len, Data);

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

  IpIf = IpSb->DefaultInterface;

  //
  // If the default address has been configured don't change it.
  // This is unlikely to happen if EFI_IP4_CONFIG protocol has
  // informed us to reconfigure each time it wants to change the
  // configuration parameters.
  //
  if (IpIf->Configured) {
    goto ON_EXIT;
  }
  
  //
  // Set the default interface's address, then add a directed 
  // route for it, that is, the route whose nexthop is zero.
  //
  Status = Ip4SetAddress (
             IpIf,
             EFI_NTOHL (Data->StationAddress),
             EFI_NTOHL (Data->SubnetMask)
             );

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

  Ip4AddRoute (
    IpSb->DefaultRouteTable,
    EFI_NTOHL (Data->StationAddress),
    EFI_NTOHL (Data->SubnetMask),
    IP4_ALLZERO_ADDRESS
    );

  //
  // Add routes returned by EFI_IP4_CONFIG protocol.
  //
  for (Index = 0; Index < Data->RouteTableSize; Index++) {
    RouteEntry = &Data->RouteTable[Index];

    Ip4AddRoute (
      IpSb->DefaultRouteTable,
      EFI_NTOHL (RouteEntry->SubnetAddress),
      EFI_NTOHL (RouteEntry->SubnetMask),
      EFI_NTOHL (RouteEntry->GatewayAddress)
      );
  }

  IpSb->State = IP4_SERVICE_CONFIGED;

  Ip4SetVariableData (IpSb);

ON_EXIT:
  NetFreePool (Data);
}

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

Routine Description:

  Start the auto configuration for this IP service instance. 
  It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the
  auto configuration.

Arguments:

  IpSb  - The IP4 service instance to configure

Returns:

  EFI_SUCCESS - The auto configuration is successfull started
  Others      - Failed to start auto configuration.

--*/
{
  EFI_IP4_CONFIG_PROTOCOL   *Ip4Config;
  EFI_STATUS                Status;

  if (IpSb->State > IP4_SERVICE_UNSTARTED) {
    return EFI_SUCCESS;
  }

  //
  // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG
  //
  Status = gBS->CreateEvent (
                  EFI_EVENT_NOTIFY_SIGNAL,
                  NET_TPL_LOCK,
                  Ip4AutoConfigCallBack,
                  IpSb,
                  &IpSb->DoneEvent
                  );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = gBS->CreateEvent (
                  EFI_EVENT_NOTIFY_SIGNAL,
                  EFI_TPL_CALLBACK,
                  Ip4AutoConfigCallBack,
                  IpSb,
                  &IpSb->ReconfigEvent
                  );

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

  //
  // Open the EFI_IP4_CONFIG protocol then start auto configure
  //
  Status = gBS->OpenProtocol (
                  IpSb->Controller,
                  &gEfiIp4ConfigProtocolGuid,
                  &Ip4Config,
                  IpSb->Image,
                  IpSb->Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
                  );

  if (EFI_ERROR (Status)) {
    Status = EFI_UNSUPPORTED;
    goto CLOSE_RECONFIG_EVENT;
  }

  Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);

  if (EFI_ERROR (Status)) {
    gBS->CloseProtocol (
           IpSb->Controller,
           &gEfiIp4ConfigProtocolGuid,
           IpSb->Image,
           IpSb->Controller
           );

    goto CLOSE_RECONFIG_EVENT;
  }

  IpSb->Ip4Config = Ip4Config;
  IpSb->State     = IP4_SERVICE_STARTED;
  return Status;

CLOSE_RECONFIG_EVENT:
  gBS->CloseEvent (IpSb->ReconfigEvent);
  IpSb->ReconfigEvent = NULL;

CLOSE_DONE_EVENT:
  gBS->CloseEvent (IpSb->DoneEvent);
  IpSb->DoneEvent = NULL;

  return Status;
}

VOID
Ip4InitProtocol (
  IN IP4_SERVICE            *IpSb,
  IN IP4_PROTOCOL           *IpInstance
  )
/*++

Routine Description:

  Intiialize the IP4_PROTOCOL structure to the unconfigured states.

Arguments:

  IpSb        - The IP4 service instance.
  IpInstance  - The IP4 child instance.

Returns:

  None

--*/
{
  ASSERT ((IpSb != NULL) && (IpInstance != NULL));

  NetZeroMem (IpInstance, sizeof (IP4_PROTOCOL));

  IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;
  IpInstance->Ip4Proto  = mEfiIp4ProtocolTemplete;
  IpInstance->State     = IP4_STATE_UNCONFIGED;
  IpInstance->Service   = IpSb;

  NetListInit (&IpInstance->Link);
  NetMapInit  (&IpInstance->RxTokens);
  NetMapInit  (&IpInstance->TxTokens);
  NetListInit (&IpInstance->Received);
  NetListInit (&IpInstance->Delivered);
  NetListInit (&IpInstance->AddrLink);
  
  NET_GLOBAL_LOCK_INIT (&IpInstance->RecycleLock);
}

EFI_STATUS
Ip4ConfigProtocol (
  IN  IP4_PROTOCOL        *IpInstance,
  IN  EFI_IP4_CONFIG_DATA *Config
  )
/*++

Routine Description:

  Configure the IP4 child. If the child is already configured,
  change the configuration parameter. Otherwise configure it
  for the first time. The caller should validate the configuration
  before deliver them to it. It also don't do configure NULL.

Arguments:

  IpInstance  - The IP4 child to configure.

⌨️ 快捷键说明

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