]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.c
Clean codes per ECC.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Impl.c
index e8e9b383f88d1f086e64e016dcaebe7fe81d4fab..6097f0d3d728e59ac24cd12283a8cf71b5708aac 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 \r
-Copyright (c) 2006 - 2007, Intel Corporation\r
+Copyright (c) 2006 - 2008, Intel Corporation\r
 All rights reserved. This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -35,7 +35,6 @@ Abstract:
                                  operation parameter.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4GetModeData (\r
@@ -58,11 +57,7 @@ EfiDhcp4GetModeData (
 \r
   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
 \r
-  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
   DhcpSb  = Instance->Service;\r
 \r
   //\r
@@ -74,28 +69,28 @@ EfiDhcp4GetModeData (
   CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress));\r
 \r
   Ip = HTONL (DhcpSb->ClientAddr);\r
-  NetCopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+  CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
 \r
   Ip = HTONL (DhcpSb->Netmask);\r
-  NetCopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+  CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
 \r
   Ip = HTONL (DhcpSb->ServerAddr);\r
-  NetCopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+  CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
 \r
   Para = DhcpSb->Para;\r
 \r
   if (Para != NULL) {\r
     Ip = HTONL (Para->Router);\r
-    NetCopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+    CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
     Dhcp4ModeData->LeaseTime               = Para->Lease;\r
   } else {\r
-    NetZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
+    ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
     Dhcp4ModeData->LeaseTime               = 0xffffffff;\r
   }\r
 \r
   Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;\r
 \r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -118,24 +113,24 @@ DhcpCleanConfigure (
   UINT32                    Index;\r
 \r
   if (Config->DiscoverTimeout != NULL) {\r
-    NetFreePool (Config->DiscoverTimeout);\r
+    gBS->FreePool (Config->DiscoverTimeout);\r
   }\r
 \r
   if (Config->RequestTimeout != NULL) {\r
-    NetFreePool (Config->RequestTimeout);\r
+    gBS->FreePool (Config->RequestTimeout);\r
   }\r
 \r
   if (Config->OptionList != NULL) {\r
     for (Index = 0; Index < Config->OptionCount; Index++) {\r
       if (Config->OptionList[Index] != NULL) {\r
-        NetFreePool (Config->OptionList[Index]);\r
+        gBS->FreePool (Config->OptionList[Index]);\r
       }\r
     }\r
 \r
-    NetFreePool (Config->OptionList);\r
+    gBS->FreePool (Config->OptionList);\r
   }\r
 \r
-  NetZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
+  ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
 }\r
 \r
 \r
@@ -171,7 +166,7 @@ DhcpCopyConfigure (
   //\r
   if (Src->DiscoverTimeout != NULL) {\r
     Len                   = Src->DiscoverTryCount * sizeof (UINT32);\r
-    Dst->DiscoverTimeout  = NetAllocatePool (Len);\r
+    Dst->DiscoverTimeout  = AllocatePool (Len);\r
 \r
     if (Dst->DiscoverTimeout == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
@@ -187,7 +182,7 @@ DhcpCopyConfigure (
   //\r
   if (Src->RequestTimeout != NULL) {\r
     Len                 = Src->RequestTryCount * sizeof (UINT32);\r
-    Dst->RequestTimeout = NetAllocatePool (Len);\r
+    Dst->RequestTimeout = AllocatePool (Len);\r
 \r
     if (Dst->RequestTimeout == NULL) {\r
       goto ON_ERROR;\r
@@ -204,7 +199,7 @@ DhcpCopyConfigure (
   //\r
   if (Src->OptionList != NULL) {\r
     Len             = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);\r
-    Dst->OptionList = NetAllocateZeroPool (Len);\r
+    Dst->OptionList = AllocateZeroPool (Len);\r
 \r
     if (Dst->OptionList == NULL) {\r
       goto ON_ERROR;\r
@@ -216,13 +211,13 @@ DhcpCopyConfigure (
     for (Index = 0; Index < Src->OptionCount; Index++) {\r
       Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0);\r
 \r
-      DstOptions[Index] = NetAllocatePool (Len);\r
+      DstOptions[Index] = AllocatePool (Len);\r
 \r
       if (DstOptions[Index] == NULL) {\r
         goto ON_ERROR;\r
       }\r
 \r
-      NetCopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
+      CopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
     }\r
   }\r
 \r
@@ -257,14 +252,14 @@ DhcpYieldControl (
   DhcpSb->ActiveChild   = NULL;\r
 \r
   if (Config->DiscoverTimeout != NULL) {\r
-    NetFreePool (Config->DiscoverTimeout);\r
+    gBS->FreePool (Config->DiscoverTimeout);\r
 \r
     Config->DiscoverTryCount  = 0;\r
     Config->DiscoverTimeout   = NULL;\r
   }\r
 \r
   if (Config->RequestTimeout != NULL) {\r
-    NetFreePool (Config->RequestTimeout);\r
+    gBS->FreePool (Config->RequestTimeout);\r
 \r
     Config->RequestTryCount = 0;\r
     Config->RequestTimeout  = NULL;\r
@@ -290,7 +285,6 @@ DhcpYieldControl (
   @retval EFI_SUCCESS            The child is configured.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4Configure (\r
@@ -326,7 +320,7 @@ EfiDhcp4Configure (
       return EFI_INVALID_PARAMETER;\r
     }\r
 \r
-    NetCopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
+    CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
 \r
     if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {\r
 \r
@@ -340,7 +334,7 @@ EfiDhcp4Configure (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
 \r
   DhcpSb  = Instance->Service;\r
   Config  = &DhcpSb->ActiveConfig;\r
@@ -394,7 +388,7 @@ EfiDhcp4Configure (
   }\r
 \r
 ON_EXIT:\r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
@@ -411,7 +405,6 @@ ON_EXIT:
   @retval EFI_SUCCESS            The DHCP process is started.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4Start (\r
@@ -437,7 +430,7 @@ EfiDhcp4Start (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
   DhcpSb  = Instance->Service;\r
 \r
   if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
@@ -468,9 +461,9 @@ EfiDhcp4Start (
   Instance->CompletionEvent = CompletionEvent;\r
 \r
   //\r
-  // Restore the TPL now, don't call poll function at NET_TPL_LOCK.\r
+  // Restore the TPL now, don't call poll function at TPL_CALLBACK.\r
   //\r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   if (CompletionEvent == NULL) {\r
     while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
@@ -483,7 +476,7 @@ EfiDhcp4Start (
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
@@ -501,7 +494,6 @@ ON_ERROR:
   @retval EFI_SUCCESS            The DHCP is renewed/rebound.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4RenewRebind (\r
@@ -528,7 +520,7 @@ EfiDhcp4RenewRebind (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
   DhcpSb  = Instance->Service;\r
 \r
   if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
@@ -571,7 +563,7 @@ EfiDhcp4RenewRebind (
   DhcpSb->IoStatus            = EFI_ALREADY_STARTED;\r
   Instance->RenewRebindEvent  = CompletionEvent;\r
 \r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   if (CompletionEvent == NULL) {\r
     while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
@@ -584,7 +576,7 @@ EfiDhcp4RenewRebind (
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
@@ -601,7 +593,6 @@ ON_ERROR:
   @retval EFI_SUCCESS            The lease is released.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4Release (\r
@@ -627,7 +618,7 @@ EfiDhcp4Release (
   }\r
 \r
   Status  = EFI_SUCCESS;\r
-  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
   DhcpSb  = Instance->Service;\r
 \r
   if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {\r
@@ -653,7 +644,7 @@ EfiDhcp4Release (
   DhcpCleanLease (DhcpSb);\r
 \r
 ON_EXIT:\r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
@@ -668,7 +659,6 @@ ON_EXIT:
   @retval EFI_SUCCESS            The DHCP process is stopped.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4Stop (\r
@@ -692,7 +682,7 @@ EfiDhcp4Stop (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
   DhcpSb  = Instance->Service;\r
 \r
   DhcpCleanLease (DhcpSb);\r
@@ -700,7 +690,7 @@ EfiDhcp4Stop (
   DhcpSb->DhcpState     = Dhcp4Stopped;\r
   DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
 \r
-  NET_RESTORE_TPL (OldTpl);\r
+  gBS->RestoreTPL (OldTpl);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -723,7 +713,6 @@ EfiDhcp4Stop (
   @retval EFI_SUCCESS            The packet is build.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4Build (\r
@@ -766,18 +755,239 @@ EfiDhcp4Build (
            );\r
 }\r
 \r
+EFI_STATUS\r
+Dhcp4InstanceConfigUdpIo (\r
+  IN UDP_IO_PORT  *UdpIo,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  DHCP_PROTOCOL                     *Instance;\r
+  DHCP_SERVICE                      *DhcpSb;\r
+  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;\r
+  EFI_UDP4_CONFIG_DATA              UdpConfigData;\r
+  IP4_ADDR                          Ip;\r
+\r
+  Instance = (DHCP_PROTOCOL *) Context;\r
+  DhcpSb   = Instance->Service;\r
+  Token    = Instance->Token;\r
+\r
+  ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));\r
+\r
+  UdpConfigData.AcceptBroadcast    = TRUE;\r
+  UdpConfigData.AllowDuplicatePort = TRUE;\r
+  UdpConfigData.TimeToLive         = 64;\r
+  UdpConfigData.DoNotFragment      = TRUE;\r
+\r
+  Ip = HTONL (DhcpSb->ClientAddr);\r
+  CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Ip = HTONL (DhcpSb->Netmask);\r
+  CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) {\r
+    UdpConfigData.StationPort = DHCP_CLIENT_PORT;\r
+  } else {\r
+    UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort;\r
+  }\r
+\r
+  return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);\r
+}\r
+\r
+EFI_STATUS\r
+Dhcp4InstanceCreateUdpIo (\r
+  IN DHCP_PROTOCOL  *Instance\r
+  )\r
+{\r
+  DHCP_SERVICE  *DhcpSb;\r
+\r
+  ASSERT (Instance->Token != NULL);\r
+\r
+  DhcpSb          = Instance->Service;\r
+  Instance->UdpIo = UdpIoCreatePort (DhcpSb->Controller, DhcpSb->Image, Dhcp4InstanceConfigUdpIo, Instance);\r
+  if (Instance->UdpIo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+VOID\r
+DhcpDummyExtFree (\r
+  IN VOID                   *Arg\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Release the packet.\r
+\r
+Arguments:\r
+\r
+  Arg - The packet to release\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+}\r
+\r
+VOID\r
+PxeDhcpInput (\r
+  NET_BUF                   *UdpPacket,\r
+  UDP_POINTS                *Points,\r
+  EFI_STATUS                IoStatus,\r
+  VOID                      *Context\r
+  )\r
+{\r
+  DHCP_PROTOCOL                     *Instance;\r
+  DHCP_SERVICE                      *DhcpSb;\r
+  EFI_DHCP4_HEADER                  *Head;\r
+  NET_BUF                           *Wrap;\r
+  EFI_DHCP4_PACKET                  *Packet;\r
+  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;\r
+  UINT32                            Len;\r
+  EFI_STATUS                        Status;\r
+\r
+  Wrap     = NULL;\r
+  Instance = (DHCP_PROTOCOL *) Context;\r
+  Token    = Instance->Token;\r
+  DhcpSb   = Instance->Service;\r
+\r
+  //\r
+  // Don't restart receive if error occurs or DHCP is destoried.\r
+  //\r
+  if (EFI_ERROR (IoStatus)) {\r
+    return ;\r
+  }\r
+\r
+  ASSERT (UdpPacket != NULL);\r
+\r
+  //\r
+  // Validate the packet received\r
+  //\r
+  if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {\r
+    goto RESTART;\r
+  }\r
+\r
+  //\r
+  // Copy the DHCP message to a continuous memory block, make the buffer size\r
+  // of the EFI_DHCP4_PACKET a multiple of 4-byte.\r
+  //\r
+  Len  = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4);\r
+  Wrap = NetbufAlloc (Len);\r
+\r
+  if (Wrap == NULL) {\r
+    goto RESTART;\r
+  }\r
+\r
+  Packet         = (EFI_DHCP4_PACKET *) NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL);\r
+  Packet->Size   = Len;\r
+  Head           = &Packet->Dhcp4.Header;\r
+  Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head);\r
+\r
+  if (Packet->Length != UdpPacket->TotalSize) {\r
+    goto RESTART;\r
+  }\r
+\r
+  //\r
+  // Is this packet the answer to our packet?\r
+  //\r
+  if ((Head->OpCode != BOOTP_REPLY) ||\r
+      (Head->Xid != Token->Packet->Dhcp4.Header.Xid) ||\r
+      (CompareMem (DhcpSb->ClientAddressSendOut, Head->ClientHwAddr, Head->HwAddrLen) != 0)) {\r
+    goto RESTART;\r
+  }\r
+\r
+  //\r
+  // Validate the options and retrieve the interested options\r
+  //\r
+  if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&\r
+      (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&\r
+      EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
+\r
+    goto RESTART;\r
+  }\r
+\r
+  //\r
+  // Keep this packet in the ResponseQueue.\r
+  //\r
+  NET_GET_REF (Wrap);\r
+  NetbufQueAppend (&Instance->ResponseQueue, Wrap);\r
+\r
+RESTART:\r
+\r
+  NetbufFree (UdpPacket);\r
+\r
+  if (Wrap != NULL) {\r
+    NetbufFree (Wrap);\r
+  }\r
+\r
+  Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    PxeDhcpDone (Instance);\r
+  }\r
+}\r
+\r
+VOID\r
+PxeDhcpDone (\r
+  IN DHCP_PROTOCOL  *Instance\r
+  )\r
+{\r
+  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;\r
+\r
+  Token = Instance->Token;\r
+\r
+  Token->ResponseCount = Instance->ResponseQueue.BufNum;\r
+  if (Token->ResponseCount != 0) {\r
+    Token->ResponseList = (EFI_DHCP4_PACKET *) AllocatePool (Instance->ResponseQueue.BufSize);\r
+    if (Token->ResponseList == NULL) {\r
+      Token->Status = EFI_OUT_OF_RESOURCES;\r
+      goto SIGNAL_USER;\r
+    }\r
+\r
+    //\r
+    // Copy the recieved DHCP responses.\r
+    //\r
+    NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *) Token->ResponseList);\r
+    Token->Status = EFI_SUCCESS;\r
+  } else {\r
+    Token->ResponseList = NULL;\r
+    Token->Status       = EFI_TIMEOUT;\r
+  }\r
+\r
+SIGNAL_USER:\r
+  //\r
+  // Clean the resources dedicated for this transmit receive transaction.\r
+  //\r
+  NetbufQueFlush (&Instance->ResponseQueue);\r
+  UdpIoCleanPort (Instance->UdpIo);\r
+  UdpIoFreePort (Instance->UdpIo);\r
+  Instance->UdpIo = NULL;\r
+  Instance->Token = NULL;\r
+\r
+  if (Token->CompletionEvent != NULL) {\r
+    gBS->SignalEvent (Token->CompletionEvent);\r
+  }\r
+}\r
+\r
 \r
 /**\r
-  Transmit and receive a packet through this DHCP service.\r
-  This is unsupported.\r
+  Transmits a DHCP formatted packet and optionally waits for responses.\r
 \r
-  @param  This                   The DHCP protocol instance\r
-  @param  Token                  The transmit and receive instance\r
+  @param  This    Pointer to the EFI_DHCP4_PROTOCOL instance.\r
+  @param  Token   Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.\r
 \r
-  @retval EFI_UNSUPPORTED        It always returns unsupported.\r
+  @retval EFI_SUCCESS           The packet was successfully queued for transmission.\r
+  @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
+  @retval EFI_NOT_READY         The previous call to this function has not finished yet. Try to call\r
+                                this function after collection process completes.\r
+  @retval EFI_NO_MAPPING        The default station address is not available yet.\r
+  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.\r
+  @retval Others                Some other unexpected error occurred.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4TransmitReceive (\r
@@ -785,10 +995,149 @@ EfiDhcp4TransmitReceive (
   IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token\r
   )\r
 {\r
+  DHCP_PROTOCOL  *Instance;\r
+  EFI_TPL        OldTpl;\r
+  EFI_STATUS     Status;\r
+  NET_FRAGMENT   Frag;\r
+  NET_BUF        *Wrap;\r
+  UDP_POINTS     EndPoint;\r
+  IP4_ADDR       Ip;\r
+  DHCP_SERVICE   *DhcpSb;\r
+  IP4_ADDR       Gateway;\r
+  IP4_ADDR       SubnetMask;\r
+\r
+  if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+  DhcpSb   = Instance->Service;\r
+\r
+  if (Instance->Token != NULL) {\r
+    //\r
+    // The previous call to TransmitReceive is not finished.\r
+    //\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
+    (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||\r
+    (Token->TimeoutValue == 0) ||\r
+    ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||\r
+    EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||\r
+    EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)) {\r
+    //\r
+    // The DHCP packet isn't well-formed, the Transaction ID is already used\r
+    // , the timeout value is zero, the ListenPoint is invalid,\r
+    // or the RemoteAddress is zero.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DhcpSb->ClientAddr == 0) {\r
+\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  //\r
+  // Save the token and the timeout value.\r
+  //\r
+  Instance->Token   = Token;\r
+  Instance->Timeout = Token->TimeoutValue;\r
+\r
+  //\r
+  // Create a UDP IO for this transmit receive transaction.\r
+  //\r
+  Status = Dhcp4InstanceCreateUdpIo (Instance);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Save the Client Address is sent out\r
   //\r
-  // This function is for PXE, leave it for now\r
+  CopyMem (&DhcpSb->ClientAddressSendOut[0], &Token->Packet->Dhcp4.Header.ClientHwAddr[0], Token->Packet->Dhcp4.Header.HwAddrLen);\r
+\r
+  //\r
+  // Wrap the DHCP packet into a net buffer.\r
+  //\r
+  Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;\r
+  Frag.Len  = Token->Packet->Length;\r
+  Wrap      = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);\r
+  if (Wrap == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Set the local address and local port.\r
+  //\r
+  EndPoint.LocalAddr = 0;\r
+  EndPoint.LocalPort = 0;\r
+\r
+  //\r
+  // Set the destination address and destination port.\r
   //\r
-  return EFI_UNSUPPORTED;\r
+  CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
+  EndPoint.RemoteAddr = NTOHL (Ip);\r
+\r
+  if (Token->RemotePort == 0) {\r
+    EndPoint.RemotePort = DHCP_SERVER_PORT;\r
+  } else {\r
+    EndPoint.RemotePort = Token->RemotePort;\r
+  }\r
+\r
+  //\r
+  // Get the gateway.\r
+  //\r
+  SubnetMask = DhcpSb->Netmask;\r
+  Gateway    = 0;\r
+  if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr, SubnetMask)) {\r
+    CopyMem (&Gateway, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
+    Gateway = NTOHL (Gateway);\r
+  }\r
+\r
+  //\r
+  // Transmit the DHCP packet.\r
+  //\r
+  Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, Gateway, DhcpOnPacketSent, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    NetbufFree (Wrap);\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Start to receive the DHCP response.\r
+  //\r
+  Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+ON_ERROR:\r
+\r
+  if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {\r
+    UdpIoCleanPort (Instance->UdpIo);\r
+    UdpIoFreePort (Instance->UdpIo);\r
+    Instance->UdpIo = NULL;\r
+    Instance->Token = NULL;\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {\r
+    //\r
+    // Keep polling until timeout if no error happens and the CompletionEvent\r
+    // is NULL.\r
+    //\r
+    while (Instance->Timeout != 0) {\r
+      Instance->UdpIo->Udp->Poll (Instance->UdpIo->Udp);\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 \r
@@ -805,7 +1154,6 @@ EfiDhcp4TransmitReceive (
   @retval EFI_SUCCESS            It always returns EFI_SUCCESS\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 Dhcp4ParseCheckOption (\r
   IN UINT8                  Tag,\r
@@ -847,7 +1195,6 @@ Dhcp4ParseCheckOption (
   @retval EFI_SUCCESS            The options are parsed.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EfiDhcp4Parse (\r
@@ -878,7 +1225,7 @@ EfiDhcp4Parse (
     return EFI_BUFFER_TOO_SMALL;\r
   }\r
 \r
-  NetZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+  ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
 \r
   Context.Option      = PacketOptionList;\r
   Context.OptionCount = *OptionCount;\r
@@ -910,3 +1257,4 @@ EFI_DHCP4_PROTOCOL  mDhcp4ProtocolTemplate = {
   EfiDhcp4TransmitReceive,\r
   EfiDhcp4Parse\r
 };\r
+\r