Example #1
0
/**
  Parse the DHCP ACK to get Dns6 server information.

  @param  Image            The handle of the driver image.
  @param  Controller       The handle of the controller.
  @param  DnsServerCount   Retrieved Dns6 server Ip count.
  @param  DnsServerList    Retrieved Dns6 server Ip list.

  @retval EFI_SUCCESS           The Dns6 information is got from the DHCP ACK.
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
  @retval EFI_NO_MEDIA          There was a media error.
  @retval Others                Other errors as indicated.

**/
EFI_STATUS
GetDns6ServerFromDhcp6 (
  IN  EFI_HANDLE                 Image,
  IN  EFI_HANDLE                 Controller,
  OUT UINT32                     *DnsServerCount,
  OUT EFI_IPv6_ADDRESS           **DnsServerList
  )
{
  EFI_HANDLE                Dhcp6Handle;
  EFI_DHCP6_PROTOCOL        *Dhcp6;
  EFI_STATUS                Status;
  EFI_STATUS                TimerStatus;
  EFI_DHCP6_PACKET_OPTION   *Oro;
  EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;
  EFI_EVENT                 Timer;
  EFI_STATUS                MediaStatus;
  DNS6_SERVER_INFOR         DnsServerInfor;

  Dhcp6Handle = NULL;
  Dhcp6       = NULL;
  Oro         = NULL;
  Timer       = NULL;

  ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));

  DnsServerInfor.ServerCount = DnsServerCount;

  //
  // Check media status before doing DHCP.
  //
  MediaStatus = EFI_SUCCESS;
  NetLibDetectMediaWaitTimeout (Controller, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
  if (MediaStatus != EFI_SUCCESS) {
    return EFI_NO_MEDIA;
  }

  //
  // Create a DHCP6 child instance and get the protocol.
  //
  Status = NetLibCreateServiceChild (
             Controller,
             Image,
             &gEfiDhcp6ServiceBindingProtocolGuid,
             &Dhcp6Handle
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = gBS->OpenProtocol (
                  Dhcp6Handle,
                  &gEfiDhcp6ProtocolGuid,
                  (VOID **) &Dhcp6,
                  Image,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
  if (Oro == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_EXIT;
  }

  //
  // Ask the server to reply with DNS options.
  // All members in EFI_DHCP6_PACKET_OPTION are in network order.
  //
  Oro->OpCode  = HTONS (DHCP6_TAG_DNS_REQUEST);
  Oro->OpLen   = HTONS (2);
  Oro->Data[1] = DHCP6_TAG_DNS_SERVER;

  InfoReqReXmit.Irt = 4;
  InfoReqReXmit.Mrc = 1;
  InfoReqReXmit.Mrt = 10;
  InfoReqReXmit.Mrd = 30;

  Status = Dhcp6->InfoRequest (
                    Dhcp6,
                    TRUE,
                    Oro,
                    0,
                    NULL,
                    &InfoReqReXmit,
                    NULL,
                    ParseDhcp6Ack,
                    &DnsServerInfor
                    );
  if (Status == EFI_NO_MAPPING) {
    Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
    if (EFI_ERROR (Status)) {
      goto ON_EXIT;
    }

    Status = gBS->SetTimer (
                    Timer,
                    TimerRelative,
                    DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
                    );

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

    do {
      TimerStatus = gBS->CheckEvent (Timer);
      if (!EFI_ERROR (TimerStatus)) {
        Status = Dhcp6->InfoRequest (
                          Dhcp6,
                          TRUE,
                          Oro,
                          0,
                          NULL,
                          &InfoReqReXmit,
                          NULL,
                          ParseDhcp6Ack,
                          &DnsServerInfor
                          );
      }
    } while (TimerStatus == EFI_NOT_READY);
  }

  *DnsServerList  = DnsServerInfor.ServerList;

ON_EXIT:

  if (Oro != NULL) {
    FreePool (Oro);
  }

  if (Timer != NULL) {
    gBS->CloseEvent (Timer);
  }

  if (Dhcp6 != NULL) {
    gBS->CloseProtocol (
           Dhcp6Handle,
           &gEfiDhcp6ProtocolGuid,
           Image,
           Controller
           );
  }

  NetLibDestroyServiceChild (
    Controller,
    Image,
    &gEfiDhcp6ServiceBindingProtocolGuid,
    Dhcp6Handle
    );

  return Status;

}
Example #2
0
/**
  The list process of the ifconfig command.

  @param[in]   IfList    The pointer of IfList(interface list).

  @retval SHELL_SUCCESS  The ifconfig command list processed successfully.
  @retval others         The ifconfig command list process failed.

**/
SHELL_STATUS
IfConfigShowInterfaceInfo (
  IN LIST_ENTRY    *IfList
  )
{
  LIST_ENTRY                   *Entry;
  LIST_ENTRY                   *Next;
  IFCONFIG_INTERFACE_CB        *IfCb;
  EFI_STATUS                    MediaStatus;
  EFI_IPv4_ADDRESS              Gateway;
  UINT32                        Index;

  MediaStatus = EFI_SUCCESS;

  if (IsListEmpty (IfList)) {
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle);
  }

  //
  // Go through the interface list.
  //
  NET_LIST_FOR_EACH_SAFE (Entry, Next, IfList) {
    IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link);

    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_BREAK), gShellNetwork1HiiHandle);

    //
    // Print interface name.
    //
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IF_NAME), gShellNetwork1HiiHandle, IfCb->IfInfo->Name);

    //
    // Get Media State.
    //
    if (EFI_SUCCESS == NetLibDetectMediaWaitTimeout (IfCb->NicHandle, 0, &MediaStatus)) {
      if (MediaStatus != EFI_SUCCESS) {
        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media disconnected");
      } else {
        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media present");
      }
    } else {
      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media state unknown");
    }

    //
    // Print interface config policy.
    //
    if (IfCb->Policy == Ip4Config2PolicyDhcp) {
      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_POLICY_DHCP), gShellNetwork1HiiHandle);
    } else {
      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_POLICY_MAN), gShellNetwork1HiiHandle);
    }

    //
    // Print mac address of the interface.
    //
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MAC_ADDR_HEAD), gShellNetwork1HiiHandle);

    IfConfigPrintMacAddr (
      IfCb->IfInfo->HwAddress.Addr,
      IfCb->IfInfo->HwAddressSize
      );

    //
    // Print IPv4 address list of the interface.
    //
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_HEAD), gShellNetwork1HiiHandle);

    ShellPrintHiiEx(
      -1,
      -1,
      NULL,
      STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY),
      gShellNetwork1HiiHandle,
      (UINTN)IfCb->IfInfo->StationAddress.Addr[0],
      (UINTN)IfCb->IfInfo->StationAddress.Addr[1],
      (UINTN)IfCb->IfInfo->StationAddress.Addr[2],
      (UINTN)IfCb->IfInfo->StationAddress.Addr[3]
      );

    //
    // Print subnet mask list of the interface.
    //
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_SUBNET_MASK_HEAD), gShellNetwork1HiiHandle);

    ShellPrintHiiEx(
      -1,
      -1,
      NULL,
      STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY),
      gShellNetwork1HiiHandle,
      (UINTN)IfCb->IfInfo->SubnetMask.Addr[0],
      (UINTN)IfCb->IfInfo->SubnetMask.Addr[1],
      (UINTN)IfCb->IfInfo->SubnetMask.Addr[2],
      (UINTN)IfCb->IfInfo->SubnetMask.Addr[3]
      );

    //
    // Print default gateway of the interface.
    //
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_GATEWAY_HEAD), gShellNetwork1HiiHandle);

    ZeroMem (&Gateway, sizeof (EFI_IPv4_ADDRESS));

    for (Index = 0; Index < IfCb->IfInfo->RouteTableSize; Index++) {
      if ((CompareMem (&IfCb->IfInfo->RouteTable[Index].SubnetAddress, &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) &&
          (CompareMem (&IfCb->IfInfo->RouteTable[Index].SubnetMask   , &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) ){
        CopyMem (&Gateway, &IfCb->IfInfo->RouteTable[Index].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
      }
    }

    ShellPrintHiiEx(
      -1,
      -1,
      NULL,
      STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY),
      gShellNetwork1HiiHandle,
      (UINTN)Gateway.Addr[0],
      (UINTN)Gateway.Addr[1],
      (UINTN)Gateway.Addr[2],
      (UINTN)Gateway.Addr[3]
      );

    //
    // Print route table entry.
    //
    ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_SIZE), gShellNetwork1HiiHandle, IfCb->IfInfo->RouteTableSize);

    for (Index = 0; Index < IfCb->IfInfo->RouteTableSize; Index++) {
      ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_ENTRY_INDEX), gShellNetwork1HiiHandle, Index);

      ShellPrintHiiEx(
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
        gShellNetwork1HiiHandle,
        L"Subnet ",
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[0],
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[1],
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[2],
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[3]
        );

      ShellPrintHiiEx(
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
        gShellNetwork1HiiHandle,
        L"Netmask",
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[0],
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[1],
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[2],
        (UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[3]
        );

      ShellPrintHiiEx(
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
        gShellNetwork1HiiHandle,
        L"Gateway",
        (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[0],
        (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[1],
        (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[2],
        (UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[3]
        );
    }

    //
    // Print dns server addresses list of the interface if has.
    //
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_DNS_ADDR_HEAD), gShellNetwork1HiiHandle);

    for (Index = 0; Index < IfCb->DnsCnt; Index++) {
      ShellPrintHiiEx(
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_IFCONFIG_INFO_DNS_ADDR_BODY),
        gShellNetwork1HiiHandle,
        (UINTN) IfCb->DnsAddr[Index].Addr[0],
        (UINTN) IfCb->DnsAddr[Index].Addr[1],
        (UINTN) IfCb->DnsAddr[Index].Addr[2],
        (UINTN) IfCb->DnsAddr[Index].Addr[3]
        );

      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_NEWLINE), gShellNetwork1HiiHandle);
    }
  }
Example #3
0
/**
  Parse the DHCP ACK to get Dns4 server information.

  @param  Instance         The DNS instance.
  @param  DnsServerCount   Retrieved Dns4 server Ip count.
  @param  DnsServerList    Retrieved Dns4 server Ip list.

  @retval EFI_SUCCESS           The Dns4 information is got from the DHCP ACK.
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
  @retval EFI_NO_MEDIA          There was a media error.
  @retval Others                Other errors as indicated.

**/
EFI_STATUS
GetDns4ServerFromDhcp4 (
  IN  DNS_INSTANCE               *Instance,
  OUT UINT32                     *DnsServerCount,
  OUT EFI_IPv4_ADDRESS           **DnsServerList
  )
{
  EFI_STATUS                          Status;
  EFI_HANDLE                          Image;
  EFI_HANDLE                          Controller;
  EFI_STATUS                          MediaStatus;
  EFI_HANDLE                          MnpChildHandle;
  EFI_MANAGED_NETWORK_PROTOCOL        *Mnp;
  EFI_MANAGED_NETWORK_CONFIG_DATA     MnpConfigData;
  EFI_HANDLE                          Dhcp4Handle;
  EFI_DHCP4_PROTOCOL                  *Dhcp4;
  EFI_IP4_CONFIG2_PROTOCOL            *Ip4Config2;
  UINTN                               DataSize;
  VOID                                *Data;
  EFI_IP4_CONFIG2_INTERFACE_INFO      *InterfaceInfo;
  EFI_DHCP4_PACKET                    SeedPacket;
  EFI_DHCP4_PACKET_OPTION             *ParaList[2];
  DNS4_SERVER_INFOR                   DnsServerInfor;

  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
  BOOLEAN                             IsDone;
  UINTN                               Index;

  Image                      = Instance->Service->ImageHandle;
  Controller                 = Instance->Service->ControllerHandle;

  MnpChildHandle             = NULL;
  Mnp                        = NULL;

  Dhcp4Handle                = NULL;
  Dhcp4                      = NULL;

  Ip4Config2                 = NULL;
  DataSize                   = 0;
  Data                       = NULL;
  InterfaceInfo              = NULL;

  ZeroMem ((UINT8 *) ParaList, sizeof (ParaList));

  ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));

  ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));

  ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));

  DnsServerInfor.ServerCount = DnsServerCount;

  IsDone = FALSE;

  //
  // Check media.
  //
  MediaStatus = EFI_SUCCESS;
  NetLibDetectMediaWaitTimeout (Controller, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
  if (MediaStatus != EFI_SUCCESS) {
    return EFI_NO_MEDIA;
  }

  //
  // Create a Mnp child instance, get the protocol and config for it.
  //
  Status = NetLibCreateServiceChild (
             Controller,
             Image,
             &gEfiManagedNetworkServiceBindingProtocolGuid,
             &MnpChildHandle
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = gBS->OpenProtocol (
                  MnpChildHandle,
                  &gEfiManagedNetworkProtocolGuid,
                  (VOID **) &Mnp,
                  Image,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  MnpConfigData.ReceivedQueueTimeoutValue = 0;
  MnpConfigData.TransmitQueueTimeoutValue = 0;
  MnpConfigData.ProtocolTypeFilter        = IP4_ETHER_PROTO;
  MnpConfigData.EnableUnicastReceive      = TRUE;
  MnpConfigData.EnableMulticastReceive    = TRUE;
  MnpConfigData.EnableBroadcastReceive    = TRUE;
  MnpConfigData.EnablePromiscuousReceive  = FALSE;
  MnpConfigData.FlushQueuesOnReset        = TRUE;
  MnpConfigData.EnableReceiveTimestamps   = FALSE;
  MnpConfigData.DisableBackgroundPolling  = FALSE;

  Status = Mnp->Configure(Mnp, &MnpConfigData);
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  //
  // Create a DHCP4 child instance and get the protocol.
  //
  Status = NetLibCreateServiceChild (
             Controller,
             Image,
             &gEfiDhcp4ServiceBindingProtocolGuid,
             &Dhcp4Handle
             );
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  Status = gBS->OpenProtocol (
                  Dhcp4Handle,
                  &gEfiDhcp4ProtocolGuid,
                  (VOID **) &Dhcp4,
                  Image,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  //
  // Get Ip4Config2 instance info.
  //
  Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
  if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
    goto ON_EXIT;
  }

  Data = AllocateZeroPool (DataSize);
  if (Data == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_EXIT;
  }

  Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;

  //
  // Build required Token.
  //
  Status = gBS->CreateEvent (
                  EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  DhcpCommonNotify,
                  &IsDone,
                  &Token.CompletionEvent
                  );
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);

  Token.RemotePort = 67;

  Token.ListenPointCount = 1;

  Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
  if (Token.ListenPoints == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_EXIT;
  }

  if (Instance->Dns4CfgData.UseDefaultSetting) {
    CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
    CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
  } else {
    CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
    CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
  }

  Token.ListenPoints[0].ListenPort = 68;

  Token.TimeoutValue = DNS_TIME_TO_GETMAP;

  DnsInitSeedPacket (&SeedPacket, InterfaceInfo);

  ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
  if (ParaList[0] == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_EXIT;
  }

  ParaList[0]->OpCode  = DHCP4_TAG_TYPE;
  ParaList[0]->Length  = 1;
  ParaList[0]->Data[0] = DHCP4_MSG_REQUEST;

  ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
  if (ParaList[1] == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_EXIT;
  }

  ParaList[1]->OpCode  = DHCP4_TAG_PARA_LIST;
  ParaList[1]->Length  = 1;
  ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;

  Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);

  Token.Packet->Dhcp4.Header.Xid      = HTONL(NET_RANDOM (NetRandomInitSeed ()));

  Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);

  if (Instance->Dns4CfgData.UseDefaultSetting) {
    CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
  } else {
    CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
  }

  CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);

  Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);

  //
  // TransmitReceive Token
  //
  Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  //
  // Poll the packet
  //
  do {
    Status = Mnp->Poll (Mnp);
  } while (!IsDone);

  //
  // Parse the ACK to get required information if received done.
  //
  if (IsDone && !EFI_ERROR (Token.Status)) {
    for (Index = 0; Index < Token.ResponseCount; Index++) {
      Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
      if (!EFI_ERROR (Status)) {
        break;
      }
    }

    *DnsServerList = DnsServerInfor.ServerList;
  } else {
    Status = Token.Status;
  }

ON_EXIT:

  if (Data != NULL) {
    FreePool (Data);
  }

  for (Index = 0; Index < 2; Index++) {
    if (ParaList[Index] != NULL) {
      FreePool (ParaList[Index]);
    }
  }

  if (Token.ListenPoints) {
    FreePool (Token.ListenPoints);
  }

  if (Token.Packet) {
    FreePool (Token.Packet);
  }

  if (Token.ResponseList != NULL) {
    FreePool (Token.ResponseList);
  }

  if (Token.CompletionEvent != NULL) {
    gBS->CloseEvent (Token.CompletionEvent);
  }

  if (Dhcp4 != NULL) {
    Dhcp4->Stop (Dhcp4);
    Dhcp4->Configure (Dhcp4, NULL);

    gBS->CloseProtocol (
           Dhcp4Handle,
           &gEfiDhcp4ProtocolGuid,
           Image,
           Controller
           );
  }

  if (Dhcp4Handle != NULL) {
    NetLibDestroyServiceChild (
      Controller,
      Image,
      &gEfiDhcp4ServiceBindingProtocolGuid,
      Dhcp4Handle
      );
  }

  if (Mnp != NULL) {
    Mnp->Configure (Mnp, NULL);

    gBS->CloseProtocol (
           MnpChildHandle,
           &gEfiManagedNetworkProtocolGuid,
           Image,
           Controller
           );
  }

  NetLibDestroyServiceChild (
    Controller,
    Image,
    &gEfiManagedNetworkServiceBindingProtocolGuid,
    MnpChildHandle
    );

  return Status;
}
/**
  Starts the DHCPv6 standard S.A.R.R. process.

  The Start() function starts the DHCPv6 standard process. This function can
  be called only when the state of Dhcp6 instance is in the Dhcp6Init state.
  If the DHCP process completes successfully, the state of the Dhcp6 instance
  will be transferred through Dhcp6Selecting and Dhcp6Requesting to the
  Dhcp6Bound state.
  Refer to rfc-3315 for precise state transitions during this process. At the
  time when each event occurs in this process, the callback function that was set
  by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this
  opportunity to control the process.

  @param[in]  This              The pointer to Dhcp6 protocol.

  @retval EFI_SUCCESS           The DHCPv6 standard process has started, or it has
                                completed when CompletionEvent is NULL.
  @retval EFI_ACCESS_DENIED     The EFI DHCPv6 Child instance hasn't been configured.
  @retval EFI_INVALID_PARAMETER This is NULL.
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
  @retval EFI_TIMEOUT           The DHCPv6 configuration process failed because no
                                response was received from the server within the
                                specified timeout value.
  @retval EFI_ABORTED           The user aborted the DHCPv6 process.
  @retval EFI_ALREADY_STARTED   Some other Dhcp6 instance already started the DHCPv6
                                standard process.
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
  @retval EFI_NO_MEDIA          There was a media error.

**/
EFI_STATUS
EFIAPI
EfiDhcp6Start (
  IN EFI_DHCP6_PROTOCOL        *This
  )
{
  EFI_STATUS                   Status;
  EFI_TPL                      OldTpl;
  DHCP6_INSTANCE               *Instance;
  DHCP6_SERVICE                *Service;
  EFI_STATUS                   MediaStatus;

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

  Instance = DHCP6_INSTANCE_FROM_THIS (This);
  Service  = Instance->Service;

  //
  // The instance hasn't been configured.
  //
  if (Instance->Config == NULL) {
    return EFI_ACCESS_DENIED;
  }

  ASSERT (Instance->IaCb.Ia != NULL);

  //
  // The instance has already been started.
  //
  if (Instance->IaCb.Ia->State != Dhcp6Init) {
    return EFI_ALREADY_STARTED;
  }

  OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);

  //
  // Check Media Satus.
  //
  MediaStatus = EFI_SUCCESS;
  NetLibDetectMediaWaitTimeout (Service->Controller, DHCP_CHECK_MEDIA_WAITING_TIME, &MediaStatus);
  if (MediaStatus != EFI_SUCCESS) {
    Status = EFI_NO_MEDIA;
    goto ON_ERROR;
  }

  Instance->UdpSts = EFI_ALREADY_STARTED;

  //
  // Send the solicit message to start S.A.R.R process.
  //
  Status = Dhcp6SendSolicitMsg (Instance);

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

  //
  // Register receive callback for the stateful exchange process.
  //
  Status = UdpIoRecvDatagram(
             Service->UdpIo,
             Dhcp6ReceivePacket,
             Service,
             0
             );

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

  gBS->RestoreTPL (OldTpl);

  //
  // Poll udp out of the net tpl if synchronous call.
  //
  if (Instance->Config->IaInfoEvent == NULL) {

    while (Instance->UdpSts == EFI_ALREADY_STARTED) {
      Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
    }
    return Instance->UdpSts;
  }

  return EFI_SUCCESS;

ON_ERROR:

  gBS->RestoreTPL (OldTpl);
  return Status;
}