ip4driver.c

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

C
957
字号
  //
  mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());

  Ip4SetVariableData (IpSb);

  return Status;

UNINSTALL_PROTOCOL:
  gBS->UninstallProtocolInterface (
         ControllerHandle,
         &gEfiIp4ServiceBindingProtocolGuid,
         &IpSb->ServiceBinding
         );

FREE_SERVICE:
  Ip4CleanService (IpSb);
  NetFreePool (IpSb);

  return Status;
}

EFI_STATUS
EFIAPI
Ip4DriverBindingStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN  EFI_HANDLE                   ControllerHandle,
  IN  UINTN                        NumberOfChildren,
  IN  EFI_HANDLE                   *ChildHandleBuffer
  )
/*++

  Routine Description:
    Stop this driver on ControllerHandle.

  Arguments:
    This              - Protocol instance pointer.
    ControllerHandle  - Handle of device to stop driver on 
    NumberOfChildren  - Number of Handles in ChildHandleBuffer. If 
                        number of children is zero stop the entire 
                        bus driver.
    ChildHandleBuffer - List of Child Handles to Stop.

  Returns:
    EFI_SUCCES          - This driver is removed ControllerHandle
    other               - This driver was not removed from this device

--*/
{
  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
  IP4_SERVICE                   *IpSb;
  IP4_PROTOCOL                  *IpInstance;
  EFI_HANDLE                    NicHandle;
  EFI_STATUS                    Status;
  EFI_TPL                       OldTpl;
  INTN                          State;

  //
  // IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
  // by driver. So the ControllerHandle may be the MNP child handle, ARP child
  // handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
  // in the NIC handle.
  //
  //
  // First, check whether it is the IP4_CONFIG protocol being uninstalled.
  // IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
  // to clean up the default configuration if IP4_CONFIG is being stopped.
  //
  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiIp4ConfigProtocolGuid,
                  NULL,
                  This->DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
                  );

  if (Status == EFI_SUCCESS) {
    //
    // Retrieve the IP4 service binding protocol. If failed, it is
    // likely that Ip4 ServiceBinding is uninstalled already. In this
    // case, return immediately.
    //
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiIp4ServiceBindingProtocolGuid,
                    (VOID **) &ServiceBinding,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );

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

    IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);

    OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);

    if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {

      IpSb->Ip4Config->Stop (IpSb->Ip4Config);

      Status = gBS->CloseProtocol (
                      ControllerHandle,
                      &gEfiIp4ConfigProtocolGuid,
                      IpSb->Image,
                      ControllerHandle
                      );

      if (EFI_ERROR (Status)) {
        NET_RESTORE_TPL (OldTpl);
        return Status;
      }
      
      //
      // If the auto configure hasn't complete, mark it as not started.
      //
      if (IpSb->State == IP4_SERVICE_STARTED) {
        IpSb->State = IP4_SERVICE_UNSTARTED;
      }

      IpSb->Ip4Config = NULL;
      gBS->CloseEvent (IpSb->DoneEvent);
      gBS->CloseEvent (IpSb->ReconfigEvent);
    }

    NET_RESTORE_TPL (OldTpl);
    return EFI_SUCCESS;
  }
  
  //
  // Either MNP or ARP protocol is being uninstalled. The controller
  // handle is either the MNP child or ARP child. But, the IP4's
  // service binding is installed on the NIC handle. So, need to open
  // the protocol info to find the NIC handle.
  //
  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);

  if (NicHandle == NULL) {
    NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
  }

  if (NicHandle == NULL) {
    return EFI_SUCCESS;
  }
  
  //
  // Retrieve the IP4 service binding protocol
  //
  Status = gBS->OpenProtocol (
                  NicHandle,
                  &gEfiIp4ServiceBindingProtocolGuid,
                  (VOID **) &ServiceBinding,
                  This->DriverBindingHandle,
                  NicHandle,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );

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

  IpSb   = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);

  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);

  if (IpSb->InDestory) {
    NET_RESTORE_TPL (OldTpl);
    return EFI_SUCCESS;
  }

  IpSb->InDestory = TRUE;

  State           = IpSb->State;
  IpSb->State     = IP4_SERVICE_DESTORY;

  //
  // Destory all the children first. If not all children are destoried,
  // the IP driver can operate correctly, so restore it state. Don't 
  // use NET_LIST_FOR_EACH_SAFE here, because it will cache the next
  // pointer, which may point to the child that has already been destoried.
  // For example, if there are two child in the list, the first is UDP
  // listen child, the send is the MTFTP's child. When Udp child is 
  // destoried, it will destory the MTFTP's child. Then Next point to 
  // a invalid child.
  //
  while (!NetListIsEmpty (&IpSb->Children)) {
    IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
    Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);
  }

  if (IpSb->NumChildren != 0) {
    IpSb->State = State;
    Status      = EFI_DEVICE_ERROR;
    goto ON_ERROR;
  }

  //
  // Clear the variable data.
  //
  Ip4ClearVariableData (IpSb);

  //
  // OK, clean other resources then uninstall the service binding protocol.
  //
  Status = Ip4CleanService (IpSb);

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

  Status = gBS->UninstallProtocolInterface (
                  NicHandle,
                  &gEfiIp4ServiceBindingProtocolGuid,
                  ServiceBinding
                  );

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

  NET_RESTORE_TPL (OldTpl);
  NetFreePool (IpSb);
  return EFI_SUCCESS;

ON_ERROR:
  IpSb->InDestory = FALSE;
  NET_RESTORE_TPL (OldTpl);
  return Status;
}

EFI_STATUS
EFIAPI
Ip4ServiceBindingCreateChild (
  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                    *ChildHandle
  )
/*++

  Routine Description:
    Creates a child handle with a set of I/O services.

  Arguments:
    This         - Protocol instance pointer.
    ChildHandle  - Pointer to the handle of the child to create.  
                   If it is NULL, then a new handle is created.  
                   If it is not NULL, then the I/O services are 
                   added to the existing child handle.

  Returns:
    EFI_SUCCES           - The child handle was created with the I/O services
    EFI_OUT_OF_RESOURCES - There are not enough resources availabe to create 
                           the child
    other                - The child handle was not created

--*/
{
  IP4_SERVICE               *IpSb;
  IP4_PROTOCOL              *IpInstance;
  EFI_TPL                   OldTpl;
  EFI_STATUS                Status;
  VOID                      *Mnp;

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

  IpSb       = IP4_SERVICE_FROM_PROTOCOL (This);
  IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));

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

  Ip4InitProtocol (IpSb, IpInstance);

  //
  // Install Ip4 onto ChildHandle
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  ChildHandle,
                  &gEfiIp4ProtocolGuid,
                  &IpInstance->Ip4Proto,
                  NULL
                  );

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

  IpInstance->Handle = *ChildHandle;

  //
  // Open the Managed Network protocol BY_CHILD.
  //
  Status = gBS->OpenProtocol (
                  IpSb->MnpChildHandle,
                  &gEfiManagedNetworkProtocolGuid,
                  (VOID **) &Mnp,
                  gIp4DriverBinding.DriverBindingHandle,
                  IpInstance->Handle,
                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
                  );
  if (EFI_ERROR (Status)) {
    gBS->UninstallMultipleProtocolInterfaces (
           ChildHandle,
           &gEfiIp4ProtocolGuid,
           &IpInstance->Ip4Proto,
           NULL
           );

    goto ON_ERROR;
  }

  //
  // Insert it into the service binding instance.
  //
  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);

  NetListInsertTail (&IpSb->Children, &IpInstance->Link);
  IpSb->NumChildren++;

  NET_RESTORE_TPL (OldTpl);

ON_ERROR:

  if (EFI_ERROR (Status)) {

    Ip4CleanProtocol (IpInstance);

    NetFreePool (IpInstance);
  }

  return Status;
}

EFI_STATUS
EFIAPI
Ip4ServiceBindingDestroyChild (
  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                    ChildHandle
  )
/*++

  Routine Description:
    Destroys a child handle with a set of I/O services.

  Arguments:
    This         - Protocol instance pointer.
    ChildHandle  - Handle of the child to destroy

  Returns:
    EFI_SUCCES            - The I/O services were removed from the child handle
    EFI_UNSUPPORTED       - The child handle does not support the I/O services 
                            that are being removed
    EFI_INVALID_PARAMETER - Child handle is not a valid EFI Handle.
    EFI_ACCESS_DENIED     - The child handle could not be destroyed because its 
                            I/O services are being used.
    other                 - The child handle was not destroyed

--*/
{
  EFI_STATUS                Status;
  IP4_SERVICE               *IpSb;
  IP4_PROTOCOL              *IpInstance;
  EFI_IP4_PROTOCOL          *Ip4;
  EFI_TPL                   OldTpl;
  INTN                      State;

  if ((This == NULL) || (ChildHandle == NULL)) {
    return EFI_INVALID_PARAMETER;
  }
  
  //
  // Retrieve the private context data structures
  //
  IpSb   = IP4_SERVICE_FROM_PROTOCOL (This);

  Status = gBS->OpenProtocol (
                  ChildHandle,
                  &gEfiIp4ProtocolGuid,
                  (VOID **) &Ip4,
                  gIp4DriverBinding.DriverBindingHandle,
                  ChildHandle,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );

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

  IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);

  if (IpInstance->Service != IpSb) {
    return EFI_INVALID_PARAMETER;
  }

  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);

  //
  // A child can be destoried more than once. For example, 
  // Ip4DriverBindingStop will destory all of its children. 
  // when UDP driver is being stopped, it will destory all 
  // the IP child it opens.
  //
  if (IpInstance->State == IP4_STATE_DESTORY) {
    NET_RESTORE_TPL (OldTpl);
    return EFI_SUCCESS;
  }

  State             = IpInstance->State;
  IpInstance->State = IP4_STATE_DESTORY;

  //
  // Close the Managed Network protocol.
  //
  gBS->CloseProtocol (
         IpSb->MnpChildHandle,
         &gEfiManagedNetworkProtocolGuid,
         gIp4DriverBinding.DriverBindingHandle,
         ChildHandle
         );

  //
  // Uninstall the IP4 protocol first. Many thing happens during
  // this:
  // 1. The consumer of the IP4 protocol will be stopped if it
  // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
  // stopped, IP driver's stop function will be called, and uninstall
  // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
  // makes it possible to create the network stack bottom up, and
  // stop it top down.
  // 2. the upper layer will recycle the received packet. The recycle
  // event's TPL is higher than this function. The recycle events
  // will be called back before preceeding. If any packets not recycled,
  // that means there is a resource leak.
  //
  Status = gBS->UninstallProtocolInterface (
                  ChildHandle,
                  &gEfiIp4ProtocolGuid,
                  &IpInstance->Ip4Proto
                  );

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

  Status = Ip4CleanProtocol (IpInstance);

  Ip4SetVariableData (IpSb);

  if (EFI_ERROR (Status)) {
    gBS->InstallMultipleProtocolInterfaces (
           &ChildHandle, 
           &gEfiIp4ProtocolGuid, 
           Ip4, 
           NULL
           );
    
    goto ON_ERROR;
  }

  NetListRemoveEntry (&IpInstance->Link);
  IpSb->NumChildren--;

  NET_RESTORE_TPL (OldTpl);

  NetFreePool (IpInstance);
  return EFI_SUCCESS;

ON_ERROR:
  IpInstance->State = State;
  NET_RESTORE_TPL (OldTpl);

  return Status;
}

⌨️ 快捷键说明

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