summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/PxeDhcp4Dxe
diff options
context:
space:
mode:
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-30 02:37:10 +0000
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-30 02:37:10 +0000
commit772db4bb33ae66fa20e39f786b5f80d107d450a5 (patch)
tree206a2d4756e0f7e245e08ca75f3ba10df2e1cf7a /MdeModulePkg/Universal/Network/PxeDhcp4Dxe
parenteca7eaf49be5f23e3c79270621df7097ef585349 (diff)
downloadedk2-772db4bb33ae66fa20e39f786b5f80d107d450a5.zip
edk2-772db4bb33ae66fa20e39f786b5f80d107d450a5.tar.gz
edk2-772db4bb33ae66fa20e39f786b5f80d107d450a5.tar.bz2
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/Network/PxeDhcp4Dxe')
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/ComponentName.c169
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.c355
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.h353
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf64
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.msa78
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4InitSelect.c784
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Release.c247
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4RenewRebind.c408
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Run.c191
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Setup.c258
-rw-r--r--MdeModulePkg/Universal/Network/PxeDhcp4Dxe/Support.c1086
11 files changed, 3993 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/ComponentName.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/ComponentName.c
new file mode 100644
index 0000000..7186a9f
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/ComponentName.c
@@ -0,0 +1,169 @@
+/** @file
+
+Copyright (c) 2004 - 2007, 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:
+ ComponentName.c
+
+Abstract:
+ PxeDhcp4 component name protocol declarations
+
+
+**/
+
+#include "PxeDhcp4.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+PxeDhcp4ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName = {
+ PxeDhcp4ComponentNameGetDriverName,
+ PxeDhcp4ComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mPxeDhcp4DriverNameTable[] = {
+ {
+ "eng",
+ L"PXE DHCPv4 Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ Language - A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ DriverName - A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ Returns:
+ EFI_SUCCESS - The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - DriverName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return LookupUnicodeString (
+ Language,
+ gPxeDhcp4ComponentName.SupportedLanguages,
+ mPxeDhcp4DriverNameTable,
+ DriverName
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ ControllerHandle - The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ ChildHandle - The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ ControllerName - A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language from the point of view of the driver specified
+ by This.
+
+ Returns:
+ EFI_SUCCESS - The Unicode string for the user readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ControllerName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
+
+/* EOF - ComponentName.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.c
new file mode 100644
index 0000000..fe4da51
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.c
@@ -0,0 +1,355 @@
+/** @file
+
+Copyright (c) 2004 - 2005, 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:
+ PxeDhcp4.c
+
+Abstract:
+
+
+**/
+
+
+#include "PxeDhcp4.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// PXE DHCP Protocol Interface
+//
+EFI_DRIVER_BINDING_PROTOCOL gPxeDhcp4DriverBinding = {
+ PxeDhcp4DriverBindingSupported,
+ PxeDhcp4DriverBindingStart,
+ PxeDhcp4DriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// PxeDhcp4 Driver Entry point funtion
+//
+
+/**
+ Register Driver Binding protocol for this driver.
+
+ @param entry EFI_IMAGE_ENTRY_POINT)
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gPxeDhcp4DriverBinding,
+ NULL,
+ COMPONENT_NAME,
+ NULL,
+ NULL
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that contains a PxeBaseCode protocol can be
+ supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPxeBaseCodeProtocolGuid,
+ (VOID **) &PxeBc,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test.
+ //
+ return gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPxeBaseCodeProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+ Start this driver on ControllerHandle by opening a PxeBaseCode
+ protocol and installing a PxeDhcp4 protocol on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to.
+ @param RemainingDevicePath Not used, always produce all possible children.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ PXE_DHCP4_PRIVATE_DATA *Private;
+
+ //
+ // Connect to the PxeBaseCode interface on ControllerHandle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPxeBaseCodeProtocolGuid,
+ (VOID **) &PxeBc,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // BaseCode has already grabbed the SimpleNetwork interface
+ // so just do a HandleProtocol() to get it.
+ //
+ Status = gBS->HandleProtocol (
+ ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &Snp
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto error_exit;
+ }
+
+ ASSERT (Snp);
+
+ //
+ // Initialize the PXE DHCP device instance.
+ //
+ Private = AllocateZeroPool (sizeof (PXE_DHCP4_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto error_exit;
+ }
+
+ Private->Signature = PXE_DHCP4_PRIVATE_DATA_SIGNATURE;
+ Private->PxeBc = PxeBc;
+ Private->Snp = Snp;
+ Private->Handle = ControllerHandle;
+ Private->PxeDhcp4.Revision = EFI_PXE_DHCP4_PROTOCOL_REVISION;
+ Private->PxeDhcp4.Run = PxeDhcp4Run;
+ Private->PxeDhcp4.Setup = PxeDhcp4Setup;
+ Private->PxeDhcp4.Init = PxeDhcp4Init;
+ Private->PxeDhcp4.Select = PxeDhcp4Select;
+ Private->PxeDhcp4.Renew = PxeDhcp4Renew;
+ Private->PxeDhcp4.Rebind = PxeDhcp4Rebind;
+ Private->PxeDhcp4.Release = PxeDhcp4Release;
+ Private->PxeDhcp4.Data = NULL;
+
+ //
+ // Install protocol interfaces for the PXE DHCP device.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &ControllerHandle,
+ &gEfiPxeDhcp4ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Private->PxeDhcp4
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+error_exit: ;
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPxeBaseCodeProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+ Stop this driver on ControllerHandle by removing PXE DHCP
+ protocol and closing the PXE Base Code protocol on
+ ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on.
+ @param NumberOfChildren Not used.
+ @param ChildHandleBuffer Not used.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_PXE_DHCP4_PROTOCOL *PxeDhcp4;
+ PXE_DHCP4_PRIVATE_DATA *Private;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPxeDhcp4ProtocolGuid,
+ (VOID **) &PxeDhcp4,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (PxeDhcp4);
+
+ //
+ // Release allocated resources
+ //
+ if (Private->PxeDhcp4.Data) {
+ FreePool (Private->PxeDhcp4.Data);
+ Private->PxeDhcp4.Data = NULL;
+ }
+ //
+ // Uninstall our protocol
+ //
+ Status = gBS->UninstallProtocolInterface (
+ ControllerHandle,
+ &gEfiPxeDhcp4ProtocolGuid,
+ &Private->PxeDhcp4
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Close any consumed protocols
+ //
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPxeBaseCodeProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Release our private data
+ //
+ FreePool (Private);
+
+ return Status;
+}
+
+/* EOF - PxeDhcp4.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.h b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.h
new file mode 100644
index 0000000..b33ed3e
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.h
@@ -0,0 +1,353 @@
+/** @file
+
+Copyright (c) 2004 - 2007, 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:
+ PxeDhcp4.h
+
+Abstract:
+ Common header for PxeDhcp4 protocol driver
+
+
+**/
+#ifndef _PXEDHCP4_H
+#define _PXEDHCP4_H
+
+
+#include <PiDxe.h>
+
+#include <Protocol/PxeBaseCode.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PxeDhcp4.h>
+#include <Protocol/PxeDhcp4Callback.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// PxeDhcp4 protocol instance data
+//
+typedef struct {
+ //
+ // Signature field used to locate beginning of containment record.
+ //
+ UINTN Signature;
+
+#define PXE_DHCP4_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('p', 'x', 'D', '4')
+ //
+ // Device handle the protocol is bound to.
+ //
+ EFI_HANDLE Handle;
+
+ //
+ // Public PxeDhcp4 protocol interface.
+ //
+ EFI_PXE_DHCP4_PROTOCOL PxeDhcp4;
+
+ //
+ // Consumed PxeBc, Snp and PxeDhcp4Callback protocol interfaces.
+ //
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_PXE_DHCP4_CALLBACK_PROTOCOL *callback;
+
+ //
+ // PxeDhcp4 called function for PxeDhcp4Callback.
+ //
+ EFI_PXE_DHCP4_FUNCTION function;
+
+ //
+ // Timeout event and flag for PxeDhcp4Callback.
+ //
+ EFI_EVENT TimeoutEvent;
+ BOOLEAN TimeoutOccurred;
+
+ //
+ // Periodic event and flag for PxeDhcp4Callback.
+ //
+ EFI_EVENT PeriodicEvent;
+ BOOLEAN PeriodicOccurred;
+
+ //
+ // DHCP server IP address.
+ //
+ UINT32 ServerIp;
+
+ //
+ // DHCP renewal and rebinding times, in seconds.
+ //
+ UINT32 RenewTime;
+ UINT32 RebindTime;
+ UINT32 LeaseTime;
+
+ //
+ // Number of offers received & allocated offer list.
+ //
+ UINTN offers;
+ DHCP4_PACKET *offer_list;
+
+ //
+ //
+ //
+ BOOLEAN StopPxeBc;
+
+} PXE_DHCP4_PRIVATE_DATA;
+
+#define PXE_DHCP4_PRIVATE_DATA_FROM_THIS(a) CR (a, PXE_DHCP4_PRIVATE_DATA, PxeDhcp4, PXE_DHCP4_PRIVATE_DATA_SIGNATURE)
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Protocol function prototypes.
+//
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Run (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN OPTIONAL UINTN OpLen,
+ IN OPTIONAL VOID *OpList
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Setup (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN EFI_PXE_DHCP4_DATA *Data
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Init (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ OUT UINTN *offer_list_entries,
+ OUT DHCP4_PACKET **offer_list
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Select (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ IN DHCP4_PACKET *offer_list
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Renew (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ UINTN seconds_timeout
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Rebind (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ UINTN seconds_timeout
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Release (
+ IN EFI_PXE_DHCP4_PROTOCOL *This
+ )
+;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Support function prototypes.
+//
+extern
+UINT16
+htons (
+ UINTN n
+ )
+;
+
+extern
+UINT32
+htonl (
+ UINTN n
+ )
+;
+
+extern
+VOID
+EFIAPI
+timeout_notify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+extern
+VOID
+EFIAPI
+periodic_notify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+extern
+EFI_STATUS
+find_opt (
+ IN DHCP4_PACKET *Packet,
+ IN UINT8 OpCode,
+ IN UINTN Skip,
+ OUT DHCP4_OP **OpPtr
+ )
+;
+
+extern
+EFI_STATUS
+add_opt (
+ IN DHCP4_PACKET *Packet,
+ IN DHCP4_OP *OpPtr
+ )
+;
+
+extern
+EFI_STATUS
+start_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OPTIONAL EFI_IP_ADDRESS *station_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *subnet_mask
+ )
+;
+
+extern
+VOID
+stop_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private
+ )
+;
+
+extern
+EFI_STATUS
+start_receive_events (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN UINTN seconds_timeout
+ )
+;
+
+extern
+VOID
+stop_receive_events (
+ IN PXE_DHCP4_PRIVATE_DATA *Private
+ )
+;
+
+extern
+EFI_STATUS
+tx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN EFI_IP_ADDRESS *dest_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
+ IN EFI_IP_ADDRESS *src_ip,
+ IN VOID *buffer,
+ IN UINTN BufferSize
+ )
+;
+
+extern
+EFI_STATUS
+rx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ OUT VOID *buffer,
+ OUT UINTN *BufferSize,
+ IN OUT EFI_IP_ADDRESS *dest_ip,
+ IN OUT EFI_IP_ADDRESS *src_ip,
+ IN UINT16 op_flags
+ )
+;
+
+extern
+EFI_STATUS
+tx_rx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OUT EFI_IP_ADDRESS *ServerIp,
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *client_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *subnet_mask,
+ IN DHCP4_PACKET *tx_pkt,
+ OUT DHCP4_PACKET *rx_pkt,
+ IN INTN
+ (
+ *rx_vfy)
+ (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN DHCP4_PACKET *tx_pkt,
+ IN DHCP4_PACKET *rx_pkt,
+ IN UINTN rx_pkt_size
+ ),
+ IN UINTN seconds_timeout
+ )
+;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Global variable definitions.
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName;
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+ Register Driver Binding protocol for this driver.
+
+Arguments:
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
+
+Returns:
+ EFI_SUCCESS - Driver loaded.
+ other - Driver not loaded.
+
+--*/
+;
+
+#ifdef EFI_SIZE_REDUCTION_APPLIED
+ #define COMPONENT_NAME_CODE(code)
+ #define COMPONENT_NAME NULL
+#else
+ #define COMPONENT_NAME_CODE(code) code
+ #define COMPONENT_NAME &gPxeDhcp4ComponentName
+#endif
+
+#endif /* _PXEDHCP4_H */
+
+/* EOF - PxeDhcp4.h */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf
new file mode 100644
index 0000000..70daa05
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf
@@ -0,0 +1,64 @@
+#/** @file
+# Component name for module PxeDhcp4
+#
+# Copyright (c) 2007, 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PxeDhcp4Dxe
+ FILE_GUID = a46c3330-be36-4977-9d24-a7cf92eef0fe
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = PxeDhcp4DriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ support.c
+ PxeDhcp4Release.c
+ PxeDhcp4Setup.c
+ ComponentName.c
+ PxeDhcp4RenewRebind.c
+ PxeDhcp4.h
+ PxeDhcp4.c
+ PxeDhcp4InitSelect.c
+ PxeDhcp4Run.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+
+
+[Protocols]
+ gEfiPxeBaseCodeProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPxeDhcp4CallbackProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPxeDhcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.msa b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.msa
new file mode 100644
index 0000000..5db7cf4
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.msa
@@ -0,0 +1,78 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>PxeDhcp4</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>a46c3330-be36-4977-9d24-a7cf92eef0fe</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module PxeDhcp4</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>PxeDhcp4</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>PxeDhcp4Run.c</Filename>
+ <Filename>PxeDhcp4InitSelect.c</Filename>
+ <Filename>PxeDhcp4Entry.c</Filename>
+ <Filename>PxeDhcp4.c</Filename>
+ <Filename>PxeDhcp4.h</Filename>
+ <Filename>PxeDhcp4RenewRebind.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>PxeDhcp4Setup.c</Filename>
+ <Filename>PxeDhcp4Release.c</Filename>
+ <Filename>support.c</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPxeDhcp4ProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPxeDhcp4CallbackProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPxeBaseCodeProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>PxeDhcp4DriverEntryPoint</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea> \ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4InitSelect.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4InitSelect.c
new file mode 100644
index 0000000..b7849d0
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4InitSelect.c
@@ -0,0 +1,784 @@
+/** @file
+
+Copyright (c) 2004, 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:
+ PxeDhcp4InitSelect.c
+
+Abstract:
+
+
+**/
+
+
+#include "PxeDhcp4.h"
+
+#define DebugPrint(x)
+//
+// #define DebugPrint(x) Aprint x
+//
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+**/
+STATIC
+INTN
+offer_verify (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN DHCP4_PACKET *tx_pkt,
+ IN DHCP4_PACKET *rx_pkt,
+ IN UINTN rx_pkt_size
+ )
+{
+ EFI_STATUS EfiStatus;
+ DHCP4_PACKET *tmp;
+ DHCP4_OP *msg_type_op;
+ DHCP4_OP *srvid_op;
+ UINT32 magik;
+
+ //
+ // Verify parameters. Touch unused parameters to keep
+ // compiler happy.
+ //
+ ASSERT (Private);
+ ASSERT (rx_pkt);
+
+ if (Private == NULL || rx_pkt == NULL) {
+ return -2;
+ }
+
+ tx_pkt = tx_pkt;
+ rx_pkt_size = rx_pkt_size;
+
+ //
+ // This may be a BOOTP Reply or DHCP Offer packet.
+ // If there is no DHCP magik number, assume that
+ // this is a BOOTP Reply packet.
+ //
+ magik = htonl (DHCP4_MAGIK_NUMBER);
+
+ while (!CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
+ //
+ // If there is no DHCP message type option, assume
+ // this is a BOOTP reply packet and cache it.
+ //
+ EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ break;
+ }
+ //
+ // If there is a DHCP message type option, it must be a
+ // DHCP offer packet
+ //
+ if (msg_type_op->len != 1) {
+ return -1;
+ }
+
+ if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
+ return -1;
+ }
+ //
+ // There must be a server identifier option.
+ //
+ EfiStatus = find_opt (
+ rx_pkt,
+ DHCP4_SERVER_IDENTIFIER,
+ 0,
+ &srvid_op
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ return -1;
+ }
+
+ if (srvid_op->len != 4) {
+ return -1;
+ }
+ //
+ // Good DHCP offer packet.
+ //
+ break;
+ }
+ //
+ // Good DHCP (or BOOTP) packet. Cache it!
+ //
+ EfiStatus = gBS->AllocatePool (
+ EfiBootServicesData,
+ (Private->offers + 1) * sizeof (DHCP4_PACKET),
+ (VOID **) &tmp
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ return -2;
+ }
+
+ ASSERT (tmp);
+
+ if (Private->offers != 0) {
+ CopyMem (
+ tmp,
+ Private->offer_list,
+ Private->offers * sizeof (DHCP4_PACKET)
+ );
+
+ gBS->FreePool (Private->offer_list);
+ }
+
+ CopyMem (&tmp[Private->offers++], rx_pkt, sizeof (DHCP4_PACKET));
+
+ Private->offer_list = tmp;
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+**/
+STATIC
+INTN
+acknak_verify (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN DHCP4_PACKET *tx_pkt,
+ IN DHCP4_PACKET *rx_pkt,
+ IN UINTN rx_pkt_size
+ )
+{
+ EFI_STATUS EfiStatus;
+ DHCP4_OP *msg_type_op;
+ DHCP4_OP *srvid_op;
+ DHCP4_OP *renew_op;
+ DHCP4_OP *rebind_op;
+ DHCP4_OP *lease_time_op;
+ UINT32 magik;
+
+ //
+ // Verify parameters. Touch unused parameters to
+ // keep compiler happy.
+ //
+ ASSERT (Private);
+ ASSERT (rx_pkt);
+
+ if (Private == NULL || rx_pkt == NULL) {
+ return -2;
+ }
+
+ tx_pkt = tx_pkt;
+ rx_pkt_size = rx_pkt_size;
+
+ //
+ // This must be a DHCP Ack message.
+ //
+ magik = htonl (DHCP4_MAGIK_NUMBER);
+
+ if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
+ return -1;
+ }
+
+ EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ return -1;
+ }
+
+ if (msg_type_op->len != 1) {
+ return -1;
+ }
+
+ if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {
+ return -1;
+ }
+ //
+ // There must be a server identifier.
+ //
+ EfiStatus = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ return -1;
+ }
+
+ if (srvid_op->len != 4) {
+ return -1;
+ }
+ //
+ // There should be a renewal time.
+ // If there is not, we will default to the 7/8 of the rebinding time.
+ //
+ EfiStatus = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ renew_op = NULL;
+ } else if (renew_op->len != 4) {
+ renew_op = NULL;
+ }
+ //
+ // There should be a rebinding time.
+ // If there is not, we will default to 7/8 of the lease time.
+ //
+ EfiStatus = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ rebind_op = NULL;
+ } else if (rebind_op->len != 4) {
+ rebind_op = NULL;
+ }
+ //
+ // There should be a lease time.
+ // If there is not, we will default to one week.
+ //
+ EfiStatus = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ lease_time_op = NULL;
+ } else if (lease_time_op->len != 4) {
+ lease_time_op = NULL;
+ }
+ //
+ // Packet looks good. Double check the renew, rebind and lease times.
+ //
+ CopyMem (&Private->ServerIp, srvid_op->data, 4);
+
+ if (renew_op != NULL) {
+ CopyMem (&Private->RenewTime, renew_op->data, 4);
+ Private->RenewTime = htonl (Private->RenewTime);
+ } else {
+ Private->RenewTime = 0;
+ }
+
+ if (rebind_op != NULL) {
+ CopyMem (&Private->RebindTime, rebind_op->data, 4);
+ Private->RebindTime = htonl (Private->RebindTime);
+ } else {
+ Private->RebindTime = 0;
+ }
+
+ if (lease_time_op != NULL) {
+ CopyMem (&Private->LeaseTime, lease_time_op->data, 4);
+ Private->LeaseTime = htonl (Private->LeaseTime);
+ } else {
+ Private->LeaseTime = 0;
+ }
+
+ if (Private->LeaseTime < 60) {
+ Private->LeaseTime = 7 * 86400;
+ }
+
+ if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {
+ Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;
+ }
+
+ if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {
+ Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;
+ }
+
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4Init (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ OUT UINTN *Offers,
+ OUT DHCP4_PACKET **OfferList
+ )
+{
+ PXE_DHCP4_PRIVATE_DATA *Private;
+ DHCP4_PACKET offer;
+ EFI_IP_ADDRESS bcast_ip;
+ EFI_STATUS EfiStatus;
+
+ //
+ // Verify parameters and protocol state.
+ //
+ if (This == NULL ||
+ seconds_timeout < DHCP4_MIN_SECONDS ||
+ seconds_timeout > DHCP4_MAX_SECONDS ||
+ Offers == NULL ||
+ OfferList == NULL
+ ) {
+ //
+ // Return parameters are not initialized when
+ // parameters are invalid!
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Offers = 0;
+ *OfferList = NULL;
+
+ //
+ // Check protocol state.
+ //
+ if (This->Data == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (!This->Data->SetupCompleted) {
+ return EFI_NOT_READY;
+ }
+
+#if 0
+ if (!is_good_discover (&This->Data->Discover)) {
+ //
+ // %%TBD - check discover packet fields
+ //
+ }
+#endif
+ //
+ // Get pointer to our instance data.
+ //
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Setup variables...
+ //
+ Private->offers = 0;
+ Private->offer_list = NULL;
+
+ EfiStatus = gBS->HandleProtocol (
+ Private->Handle,
+ &gEfiPxeDhcp4CallbackProtocolGuid,
+ (VOID *) &Private->callback
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->callback = NULL;
+ }
+
+ Private->function = EFI_PXE_DHCP4_FUNCTION_INIT;
+
+ //
+ // Increment the transaction ID.
+ //
+ {
+ UINT32 xid;
+
+ CopyMem (&xid, &This->Data->Discover.dhcp4.xid, sizeof (UINT32));
+
+ xid = htonl (htonl (xid) + 1);
+
+ CopyMem (&This->Data->Discover.dhcp4.xid, &xid, sizeof (UINT32));
+ }
+ //
+ // Transmit discover and wait for offers...
+ //
+ SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
+
+ EfiStatus = tx_rx_udp (
+ Private,
+ &bcast_ip,
+ NULL,
+ NULL,
+ NULL,
+ &This->Data->Discover,
+ &offer,
+ &offer_verify,
+ seconds_timeout
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ if (Private->offer_list) {
+ gBS->FreePool (Private->offer_list);
+ }
+
+ Private->offers = 0;
+ Private->offer_list = NULL;
+ Private->callback = NULL;
+
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
+ return EfiStatus;
+ }
+
+ *Offers = Private->offers;
+ *OfferList = Private->offer_list;
+
+ Private->offers = 0;
+ Private->offer_list = NULL;
+ Private->callback = NULL;
+
+ This->Data->InitCompleted = TRUE;
+ This->Data->SelectCompleted = FALSE;
+ This->Data->IsBootp = FALSE;
+ This->Data->IsAck = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4Select (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ IN DHCP4_PACKET *Offer
+ )
+{
+ PXE_DHCP4_PRIVATE_DATA *Private;
+ EFI_STATUS EfiStatus;
+ DHCP4_PACKET request;
+ DHCP4_PACKET acknak;
+ EFI_IP_ADDRESS bcast_ip;
+ EFI_IP_ADDRESS zero_ip;
+ EFI_IP_ADDRESS local_ip;
+ DHCP4_OP *srvid;
+ DHCP4_OP *op;
+ UINT32 dhcp4_magik;
+ UINT8 buf[16];
+ BOOLEAN is_bootp;
+
+ //
+ // Verify parameters.
+ //
+ if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS || Offer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check protocol state.
+ //
+ if (This->Data == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (!This->Data->SetupCompleted) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Get pointer to instance data.
+ //
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+#if 0
+ if (!is_good_discover (&This->Data->Discover)) {
+ //
+ // %%TBD - check discover packet fields
+ //
+ }
+#endif
+ //
+ // Setup useful variables...
+ //
+ SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
+
+ ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
+
+ ZeroMem (&local_ip, sizeof (EFI_IP_ADDRESS));
+ local_ip.v4.Addr[0] = 127;
+ local_ip.v4.Addr[3] = 1;
+
+ This->Data->SelectCompleted = FALSE;
+ This->Data->IsBootp = FALSE;
+ This->Data->IsAck = FALSE;
+
+ EfiStatus = gBS->HandleProtocol (
+ Private->Handle,
+ &gEfiPxeDhcp4CallbackProtocolGuid,
+ (VOID *) &Private->callback
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->callback = NULL;
+ }
+
+ Private->function = EFI_PXE_DHCP4_FUNCTION_SELECT;
+
+ //
+ // Verify offer packet fields.
+ //
+ if (Offer->dhcp4.op != BOOTP_REPLY) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Offer->dhcp4.htype != This->Data->Discover.dhcp4.htype) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Offer->dhcp4.hlen != This->Data->Discover.dhcp4.hlen) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompareMem (&Offer->dhcp4.xid, &This->Data->Discover.dhcp4.xid, 4)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!CompareMem (&Offer->dhcp4.yiaddr, &bcast_ip, 4)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!CompareMem (&Offer->dhcp4.yiaddr, &zero_ip, 4)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!CompareMem (&Offer->dhcp4.yiaddr, &local_ip, 4)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompareMem (
+ &Offer->dhcp4.chaddr,
+ &This->Data->Discover.dhcp4.chaddr,
+ 16
+ )) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // DHCP option checks
+ //
+ dhcp4_magik = htonl (DHCP4_MAGIK_NUMBER);
+ is_bootp = TRUE;
+
+ if (!CompareMem (&Offer->dhcp4.magik, &dhcp4_magik, 4)) {
+ //
+ // If present, DHCP message type must be offer.
+ //
+ EfiStatus = find_opt (Offer, DHCP4_MESSAGE_TYPE, 0, &op);
+
+ if (!EFI_ERROR (EfiStatus)) {
+ if (op->len != 1 || op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ is_bootp = FALSE;
+ }
+ //
+ // If present, DHCP max message size must be valid.
+ //
+ EfiStatus = find_opt (Offer, DHCP4_MAX_MESSAGE_SIZE, 0, &op);
+
+ if (!EFI_ERROR (EfiStatus)) {
+ if (op->len != 2 || ((op->data[0] << 8) | op->data[1]) < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // If present, DHCP server identifier must be valid.
+ //
+ EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &op);
+
+ if (!EFI_ERROR (EfiStatus)) {
+ if (op->len != 4 || !CompareMem (op->data, &bcast_ip, 4) || !CompareMem (op->data, &zero_ip, 4)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // If present, DHCP subnet mask must be valid.
+ //
+ EfiStatus = find_opt (
+ Offer,
+ DHCP4_SUBNET_MASK,
+ 0,
+ &op
+ );
+
+ if (!EFI_ERROR (EfiStatus)) {
+ if (op->len != 4) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ //
+ // Early out for BOOTP.
+ //
+ This->Data->IsBootp = is_bootp;
+ if (is_bootp) {
+ //
+ // Copy offer packet to instance data.
+ //
+ CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
+
+ //
+ // Copy discover to request and offer to acknak.
+ //
+ CopyMem (
+ &This->Data->Request,
+ &This->Data->Discover,
+ sizeof (DHCP4_PACKET)
+ );
+
+ CopyMem (
+ &This->Data->AckNak,
+ &This->Data->Offer,
+ sizeof (DHCP4_PACKET)
+ );
+
+ //
+ // Set state flags.
+ //
+ This->Data->SelectCompleted = TRUE;
+ This->Data->IsAck = TRUE;
+
+ Private->callback = NULL;
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy discover packet contents to request packet.
+ //
+ CopyMem (&request, &This->Data->Discover, sizeof (DHCP4_PACKET));
+
+ This->Data->IsAck = FALSE;
+
+ //
+ // Change DHCP message type from discover to request.
+ //
+ EfiStatus = find_opt (&request, DHCP4_MESSAGE_TYPE, 0, &op);
+
+ if (EFI_ERROR (EfiStatus) && EfiStatus != EFI_NOT_FOUND) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EfiStatus == EFI_NOT_FOUND) {
+ EfiStatus = find_opt (&request, DHCP4_END, 0, &op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ op->op = DHCP4_MESSAGE_TYPE;
+ op->len = 1;
+
+ op->data[1] = DHCP4_END;
+ }
+
+ op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;
+
+ //
+ // Copy server identifier option from offer to request.
+ //
+ EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &srvid);
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (srvid->len != 4) {
+ Private->callback = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiStatus = add_opt (&request, srvid);
+
+ if (EFI_ERROR (EfiStatus)) {
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
+ Private->callback = NULL;
+ return EfiStatus;
+ }
+ //
+ // Add requested IP address option to request packet.
+ //
+ op = (DHCP4_OP *) buf;
+ op->op = DHCP4_REQUESTED_IP_ADDRESS;
+ op->len = 4;
+ CopyMem (op->data, &Offer->dhcp4.yiaddr, 4);
+
+ EfiStatus = add_opt (&request, op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
+ Private->callback = NULL;
+ return EfiStatus;
+ }
+ //
+ // Transimit DHCP request and wait for DHCP ack...
+ //
+ SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
+
+ EfiStatus = tx_rx_udp (
+ Private,
+ &bcast_ip,
+ NULL,
+ NULL,
+ NULL,
+ &request,
+ &acknak,
+ &acknak_verify,
+ seconds_timeout
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
+ Private->callback = NULL;
+ return EfiStatus;
+ }
+ //
+ // Set Data->IsAck and return.
+ //
+ EfiStatus = find_opt (&acknak, DHCP4_MESSAGE_TYPE, 0, &op);
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->callback = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (op->len != 1) {
+ Private->callback = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (op->data[0]) {
+ case DHCP4_MESSAGE_TYPE_ACK:
+ This->Data->IsAck = TRUE;
+ break;
+
+ case DHCP4_MESSAGE_TYPE_NAK:
+ This->Data->IsAck = FALSE;
+ break;
+
+ default:
+ Private->callback = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Copy packets into instance data...
+ //
+ CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
+ CopyMem (&This->Data->Request, &request, sizeof (DHCP4_PACKET));
+ CopyMem (&This->Data->AckNak, &acknak, sizeof (DHCP4_PACKET));
+
+ This->Data->SelectCompleted = TRUE;
+
+ Private->callback = NULL;
+ return EFI_SUCCESS;
+}
+
+/* eof - PxeDhcp4InitSelect.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Release.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Release.c
new file mode 100644
index 0000000..119acff
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Release.c
@@ -0,0 +1,247 @@
+/** @file
+
+Copyright (c) 2004, 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:
+ PxeDhcp4Release.c
+
+Abstract:
+ Transmit release packet, free allocations and shutdown PxeDhcp4.
+
+
+**/
+
+
+#include "PxeDhcp4.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4Release (
+ IN EFI_PXE_DHCP4_PROTOCOL *This
+ )
+{
+ PXE_DHCP4_PRIVATE_DATA *Private;
+ EFI_IP_ADDRESS ServerIp;
+ EFI_IP_ADDRESS client_ip;
+ EFI_IP_ADDRESS gateway_ip;
+ EFI_IP_ADDRESS subnet_mask;
+ EFI_STATUS efi_status;
+ DHCP4_OP *op;
+ UINT8 op_list[20];
+
+ //
+ // Check for invalid parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Release does nothing if the protocol has never been setup.
+ //
+ if (This->Data == NULL) {
+ return EFI_NOT_STARTED;
+ }
+ //
+ // Fail if we do not have valid instance data.
+ //
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // If this is a BOOTP session and there is not a DHCP Ack
+ // packet, just release storage and return.
+ //
+ if (This->Data->IsBootp || !This->Data->IsAck) {
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Build option list for DHCP Release packet.
+ // If any errors occur, just release storage and return.
+ //
+ //
+ // Message type is first.
+ //
+ op_list[0] = DHCP4_MESSAGE_TYPE;
+ op_list[1] = 1;
+ op_list[2] = DHCP4_MESSAGE_TYPE_RELEASE;
+
+ //
+ // Followed by server identifier.
+ //
+ efi_status = find_opt (
+ &This->Data->Request,
+ DHCP4_SERVER_IDENTIFIER,
+ 0,
+ &op
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ if (op->len != 4) {
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&ServerIp, op->data, 4);
+
+ op_list[3] = DHCP4_SERVER_IDENTIFIER;
+ op_list[4] = 4;
+ CopyMem (&op_list[5], &ServerIp, 4);
+
+ //
+ // Followed by end.
+ //
+ op_list[9] = DHCP4_END;
+
+ //
+ // We need a subnet mask for IP stack operation.
+ //
+ efi_status = find_opt (
+ &This->Data->AckNak,
+ DHCP4_SUBNET_MASK,
+ 0,
+ &op
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ if (op->len != 4) {
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&subnet_mask, op->data, 4);
+
+ //
+ // Gateway IP address may be needed.
+ //
+ ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);
+
+ //
+ // Client IP address needed for IP stack operation.
+ //
+ ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&client_ip, &This->Data->AckNak.dhcp4.yiaddr, 4);
+
+ //
+ // Enable UDP...
+ //
+ efi_status = start_udp (Private, &client_ip, &subnet_mask);
+
+ if (EFI_ERROR (efi_status)) {
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return efi_status;
+ }
+ //
+ // Gather information out of DHCP request packet needed for
+ // DHCP release packet.
+ //
+ //
+ // Setup DHCP Release packet.
+ //
+ CopyMem (&This->Data->Request.dhcp4.ciaddr, &client_ip, 4);
+
+ ZeroMem (&This->Data->Request.dhcp4.yiaddr, 12);
+
+ ZeroMem (&This->Data->Request.dhcp4.sname, 64 + 128);
+
+ This->Data->Request.dhcp4.hops = 0;
+ This->Data->Request.dhcp4.secs = 0;
+ This->Data->Request.dhcp4.flags = 0;
+
+ ZeroMem (
+ &This->Data->Request.dhcp4.options,
+ sizeof This->Data->Request.dhcp4.options
+ );
+
+ CopyMem (&This->Data->Request.dhcp4.options, op_list, 10);
+
+ //
+ // Transmit DHCP Release packet.
+ //
+ tx_udp (
+ Private,
+ &ServerIp,
+ &gateway_ip,
+ &client_ip,
+ &This->Data->Request,
+ DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)
+ );
+
+ gBS->Stall (1000000); /* 1/10th second */
+
+ //
+ // Shutdown PXE BaseCode and release local storage.
+ //
+ stop_udp (Private);
+
+ gBS->FreePool (This->Data);
+ This->Data = NULL;
+
+ if (Private->StopPxeBc) {
+ Private->PxeBc->Stop (Private->PxeBc);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* eof - PxeDhcp4Release.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4RenewRebind.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4RenewRebind.c
new file mode 100644
index 0000000..193bb18
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4RenewRebind.c
@@ -0,0 +1,408 @@
+/** @file
+
+Copyright (c) 2004, 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:
+ PxeDhcp4RenewRebind.c
+
+Abstract:
+
+
+**/
+
+
+#include "PxeDhcp4.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+ Parameters:
+
+ @return -2 = ignore, stop waiting
+ @return -1 = ignore, keep waiting
+ @return 0 = accept, keep waiting
+ @return 1 = accept, stop waiting
+
+**/
+STATIC
+INTN
+acknak_verify (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN DHCP4_PACKET *tx_pkt,
+ IN DHCP4_PACKET *rx_pkt,
+ IN UINTN rx_pkt_size
+ )
+{
+ EFI_STATUS efi_status;
+ DHCP4_OP *msg_type_op;
+ DHCP4_OP *srvid_op;
+ DHCP4_OP *renew_op;
+ DHCP4_OP *rebind_op;
+ DHCP4_OP *lease_time_op;
+ UINT32 magik;
+
+ //
+ // Verify parameters. Unused parameters are also touched
+ // to make the compiler happy.
+ //
+ ASSERT (Private);
+ ASSERT (rx_pkt);
+
+ if (Private == NULL || rx_pkt == NULL) {
+ return -2;
+ }
+
+ tx_pkt = tx_pkt;
+ rx_pkt_size = rx_pkt_size;
+
+ //
+ // This must be a DHCP Ack message.
+ //
+ magik = htonl (DHCP4_MAGIK_NUMBER);
+
+ if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
+ return -1;
+ }
+
+ efi_status = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
+
+ if (EFI_ERROR (efi_status)) {
+ return -1;
+ }
+
+ if (msg_type_op->len != 1) {
+ return -1;
+ }
+
+ if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {
+ return -1;
+ }
+ //
+ // There must be a server identifier.
+ //
+ efi_status = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);
+
+ if (EFI_ERROR (efi_status)) {
+ return -1;
+ }
+
+ if (srvid_op->len != 4) {
+ return -1;
+ }
+ //
+ // There should be a renewal time.
+ // If there is not, we will default to the 7/8 of the rebinding time.
+ //
+ efi_status = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);
+
+ if (EFI_ERROR (efi_status)) {
+ renew_op = NULL;
+ } else if (renew_op->len != 4) {
+ renew_op = NULL;
+ }
+ //
+ // There should be a rebinding time.
+ // If there is not, we will default to 7/8 of the lease time.
+ //
+ efi_status = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);
+
+ if (EFI_ERROR (efi_status)) {
+ rebind_op = NULL;
+ } else if (rebind_op->len != 4) {
+ rebind_op = NULL;
+ }
+ //
+ // There should be a lease time.
+ // If there is not, we will default to one week.
+ //
+ efi_status = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);
+
+ if (EFI_ERROR (efi_status)) {
+ lease_time_op = NULL;
+ } else if (lease_time_op->len != 4) {
+ lease_time_op = NULL;
+ }
+ //
+ // Packet looks good. Double check the renew, rebind and lease times.
+ //
+ CopyMem (&Private->ServerIp, srvid_op->data, 4);
+
+ if (renew_op != NULL) {
+ CopyMem (&Private->RenewTime, renew_op->data, 4);
+ Private->RenewTime = htonl (Private->RenewTime);
+ } else {
+ Private->RenewTime = 0;
+ }
+
+ if (rebind_op != NULL) {
+ CopyMem (&Private->RebindTime, rebind_op->data, 4);
+ Private->RebindTime = htonl (Private->RebindTime);
+ } else {
+ Private->RebindTime = 0;
+ }
+
+ if (lease_time_op != NULL) {
+ CopyMem (&Private->LeaseTime, lease_time_op->data, 4);
+ Private->LeaseTime = htonl (Private->LeaseTime);
+ } else {
+ Private->LeaseTime = 0;
+ }
+
+ if (Private->LeaseTime < 60) {
+ Private->LeaseTime = 7 * 86400;
+ }
+
+ if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {
+ Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;
+ }
+
+ if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {
+ Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;
+ }
+
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+EFIAPI
+renew_rebind (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ IN BOOLEAN renew
+ )
+{
+ PXE_DHCP4_PRIVATE_DATA *Private;
+ EFI_IP_ADDRESS ServerIp;
+ EFI_IP_ADDRESS client_ip;
+ EFI_IP_ADDRESS subnet_mask;
+ EFI_IP_ADDRESS gateway_ip;
+ DHCP4_PACKET Request;
+ DHCP4_PACKET AckNak;
+ DHCP4_OP *op;
+ EFI_STATUS efi_status;
+
+ //
+ // Check for invalid parameters.
+ //
+ if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check for proper protocol state.
+ //
+ if (This->Data == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (!This->Data->SelectCompleted) {
+ return EFI_NOT_READY;
+ }
+
+ if (This->Data->IsBootp) {
+ return EFI_SUCCESS;
+ }
+
+ if (!This->Data->IsAck) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get pointer to instance data.
+ //
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Copy Discover packet to temporary request packet
+ // to be used for Renew/Rebind operation.
+ //
+ CopyMem (&Request, &This->Data->Discover, sizeof (DHCP4_PACKET));
+
+ CopyMem (&Request.dhcp4.ciaddr, &This->Data->AckNak.dhcp4.yiaddr, 4);
+
+ Request.dhcp4.flags = 0; /* Reply does not need to be broadcast. */
+
+ //
+ // Change message type from discover to request.
+ //
+ efi_status = find_opt (&Request, DHCP4_MESSAGE_TYPE, 0, &op);
+
+ if (EFI_ERROR (efi_status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (op->len != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;
+
+ //
+ // Need a subnet mask.
+ //
+ efi_status = find_opt (
+ &This->Data->AckNak,
+ DHCP4_SUBNET_MASK,
+ 0,
+ &op
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (op->len != 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&subnet_mask, op->data, 4);
+
+ //
+ // Need a server IP address (renew) or a broadcast
+ // IP address (rebind).
+ //
+ ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));
+
+ if (renew) {
+ efi_status = find_opt (
+ &This->Data->AckNak,
+ DHCP4_SERVER_IDENTIFIER,
+ 0,
+ &op
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (op->len != 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&ServerIp, op->data, 4);
+
+ //
+ //
+ //
+ if (CompareMem (&This->Data->AckNak.dhcp4.giaddr, &gateway_ip, 4)) {
+ CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);
+ }
+ } else {
+ SetMem (&ServerIp, sizeof (EFI_IP_ADDRESS), 0xFF);
+ }
+ //
+ // Need a client IP address.
+ //
+ ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&client_ip, &Request.dhcp4.ciaddr, 4);
+
+ //
+ //
+ //
+ efi_status = gBS->HandleProtocol (
+ Private->Handle,
+ &gEfiPxeDhcp4CallbackProtocolGuid,
+ (VOID *) &Private->callback
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ Private->callback = NULL;
+ }
+
+ Private->function = renew ? EFI_PXE_DHCP4_FUNCTION_RENEW : EFI_PXE_DHCP4_FUNCTION_REBIND;
+
+ //
+ // Transimit DHCP request and wait for DHCP ack...
+ //
+ efi_status = tx_rx_udp (
+ Private,
+ &ServerIp,
+ &gateway_ip,
+ &client_ip,
+ &subnet_mask,
+ &Request,
+ &AckNak,
+ &acknak_verify,
+ seconds_timeout
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ Private->callback = NULL;
+ return efi_status;
+ }
+ //
+ // Copy server identifier, renewal time and rebinding time
+ // from temporary ack/nak packet into cached ack/nak packet.
+ //
+ efi_status = find_opt (
+ &This->Data->AckNak,
+ DHCP4_SERVER_IDENTIFIER,
+ 0,
+ &op
+ );
+
+ if (!EFI_ERROR (efi_status)) {
+ if (op->len == 4) {
+ CopyMem (op->data, &Private->ServerIp, 4);
+ }
+ }
+
+ efi_status = find_opt (&This->Data->AckNak, DHCP4_RENEWAL_TIME, 0, &op);
+
+ if (!EFI_ERROR (efi_status)) {
+ if (op->len == 4) {
+ CopyMem (op->data, &Private->RenewTime, 4);
+ }
+ }
+
+ efi_status = find_opt (&This->Data->AckNak, DHCP4_REBINDING_TIME, 0, &op);
+
+ if (!EFI_ERROR (efi_status)) {
+ if (op->len == 4) {
+ CopyMem (op->data, &Private->RebindTime, 4);
+ }
+ }
+
+ Private->callback = NULL;
+ return efi_status;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4Renew (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout
+ )
+{
+ return renew_rebind (This, seconds_timeout, TRUE);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4Rebind (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout
+ )
+{
+ return renew_rebind (This, seconds_timeout, FALSE);
+}
+
+/* eof - PxeDhcp4RenewRebind.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Run.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Run.c
new file mode 100644
index 0000000..e796d12
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Run.c
@@ -0,0 +1,191 @@
+/** @file
+
+Copyright (c) 2004 - 2007, 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:
+ PxeDhcp4Run.c
+
+Abstract:
+ Simplified entry point for starting basic PxeDhcp4 client operation.
+
+
+**/
+
+
+#include "PxeDhcp4.h"
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4Run (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN OPTIONAL UINTN OpLen,
+ IN OPTIONAL VOID *OpList
+ )
+{
+ PXE_DHCP4_PRIVATE_DATA *Private;
+ DHCP4_PACKET *offer_list;
+ EFI_STATUS efi_status;
+ EFI_IP_ADDRESS zero_ip;
+ UINTN offers;
+ UINTN timeout;
+ UINTN n;
+ UINT16 seconds;
+
+ //
+ // Validate parameters.
+ //
+ if (This == NULL || (OpLen != 0 && OpList == NULL) || (OpLen == 0 && OpList != NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (n = 0; n < OpLen;) {
+ switch (((UINT8 *) OpList)[n]) {
+ case DHCP4_PAD:
+ ++n;
+ continue;
+
+ case DHCP4_END:
+ ++n;
+ break;
+
+ default:
+ n += 2 + ((UINT8 *) OpList)[n + 1];
+ continue;
+ }
+
+ break;
+ }
+
+ if (n != OpLen) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get pointer to instance data.
+ //
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Initialize DHCP discover packet.
+ //
+ efi_status = PxeDhcp4Setup (This, NULL);
+
+ if (EFI_ERROR (efi_status)) {
+ return efi_status;
+ }
+
+ for (n = 0; n < OpLen;) {
+ switch (((UINT8 *) OpList)[n]) {
+ case DHCP4_PAD:
+ ++n;
+ continue;
+
+ case DHCP4_END:
+ ++n;
+ break;
+
+ default:
+ efi_status = add_opt (
+ &This->Data->Discover,
+ (DHCP4_OP *) &(((UINT8 *) OpList)[n])
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ return efi_status;
+ }
+
+ n += 2 + ((UINT8 *) OpList)[n + 1];
+ continue;
+ }
+
+ break;
+ }
+ //
+ // Basic DHCP D.O.R.A.
+ // 1, 2, 4, 8, 16 & 32 second timeouts.
+ // Callback routine can be used to break out earlier.
+ //
+ ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
+
+ for (timeout = 1;;) {
+ //
+ // Broadcast DHCP discover and wait for DHCP offers.
+ //
+ efi_status = PxeDhcp4Init (This, timeout, &offers, &offer_list);
+
+ if ((efi_status != EFI_SUCCESS) &&
+ (efi_status != EFI_TIMEOUT) &&
+ (efi_status != EFI_NO_RESPONSE)) {
+ return efi_status;
+ }
+ //
+ // Try to select from each DHCP or BOOTP offer.
+ //
+ for (n = 0; n < offers; ++n) {
+ //
+ // Ignore proxyDHCP offers.
+ //
+ if (!CompareMem (&offer_list[n].dhcp4.yiaddr, &zero_ip, 4)) {
+ continue;
+ }
+ //
+ // Issue DHCP Request and wait for DHCP Ack/Nak.
+ //
+ efi_status = PxeDhcp4Select (
+ This,
+ timeout,
+ &offer_list[n]
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ continue;
+ }
+ //
+ // Exit when we have got our DHCP Ack.
+ //
+ if (This->Data->IsAck) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // No DHCP Acks. Release DHCP Offer list storage.
+ //
+ if (offer_list != NULL) {
+ gBS->FreePool (offer_list);
+ offer_list = NULL;
+ }
+ //
+ // Try again until we have used up >= DHCP4_MAX_SECONDS.
+ //
+ if ((timeout <<= 1) > DHCP4_MAX_SECONDS) {
+ if (!EFI_ERROR (efi_status)) {
+ efi_status = EFI_TIMEOUT;
+ }
+
+ return efi_status;
+ }
+ //
+ // Next timeout value.
+ //
+ CopyMem (&seconds, &This->Data->Discover.dhcp4.secs, 2);
+
+ seconds = htons (htons (seconds) + timeout);
+
+ CopyMem (&This->Data->Discover.dhcp4.secs, &seconds, 2);
+ }
+}
+
+/* eof - PxeDhcp4Run.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Setup.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Setup.c
new file mode 100644
index 0000000..29e4ed0
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Setup.c
@@ -0,0 +1,258 @@
+/** @file
+
+Copyright (c) 2004, 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:
+ PxeDhcp4Setup.c
+
+Abstract:
+
+
+**/
+
+#include "PxeDhcp4.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4Setup (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN EFI_PXE_DHCP4_DATA *Data
+ )
+{
+ PXE_DHCP4_PRIVATE_DATA *Private;
+ DHCP4_HEADER *Packet;
+ EFI_STATUS EfiStatus;
+ UINT8 *OpLen;
+ UINT8 *OpPtr;
+
+ //
+ // Return error if parameters are invalid.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (This->Data != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check contents of provided Data structure.
+ //
+ if (Data != NULL) {
+ //
+ // Do protocol state checks first.
+ //
+ if (Data->SelectCompleted) {
+ if (!Data->InitCompleted || !Data->SetupCompleted) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Data->IsBootp && !Data->IsAck) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (Data->InitCompleted) {
+ if (!Data->SetupCompleted || Data->IsBootp || Data->IsAck) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (Data->SetupCompleted) {
+ if (Data->IsBootp || Data->IsAck) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Do packet content checks.
+ //
+ if (Data->SetupCompleted) {
+ //
+ // %%TBD - check discover packet
+ //
+ }
+
+ if (Data->SelectCompleted) {
+ if (Data->IsBootp) {
+ //
+ // %%TBD - check offer packet
+ //
+ if (CompareMem (
+ &Data->Discover,
+ &Data->Request,
+ sizeof (DHCP4_PACKET)
+ )) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompareMem (
+ &Data->Offer,
+ &Data->AckNak,
+ sizeof (DHCP4_PACKET)
+ )) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // %%TBD - check offer, request & acknak packets
+ //
+ }
+ }
+ }
+ //
+ // Allocate data structure. Return error
+ // if there is not enough available memory.
+ //
+ This->Data = AllocatePool (sizeof (EFI_PXE_DHCP4_DATA));
+ if (This->Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Start PxeBc because we want to use its UdpWrite, UdpRead and
+ // SetFilter calls.
+ //
+ EfiStatus = Private->PxeBc->Start (Private->PxeBc, FALSE);
+
+ if (EFI_ERROR (EfiStatus)) {
+ if (EfiStatus != EFI_ALREADY_STARTED) {
+ FreePool (This->Data);
+ This->Data = NULL;
+ Private->PxeBc->Stop (Private->PxeBc);
+ return EfiStatus;
+ }
+
+ Private->StopPxeBc = FALSE;
+ } else {
+ Private->StopPxeBc = TRUE;
+ }
+ //
+ // Use new data.
+ //
+ if (Data != NULL) {
+ CopyMem (This->Data, Data, sizeof (EFI_PXE_DHCP4_DATA));
+ return EFI_SUCCESS;
+ }
+ //
+ // Initialize new public data structure.
+ //
+ ZeroMem (This->Data, sizeof (EFI_PXE_DHCP4_DATA));
+
+ //
+ // Fill in default DHCP discover packet.
+ // Check for MAC addresses of strange lengths, just in case.
+ //
+ Packet = &This->Data->Discover.dhcp4;
+
+ Packet->op = BOOTP_REQUEST;
+
+ Packet->htype = Private->Snp->Mode->IfType;
+
+ if (Private->Snp->Mode->HwAddressSize > 16) {
+ Packet->hlen = 16;
+ } else {
+ Packet->hlen = (UINT8) Private->Snp->Mode->HwAddressSize;
+ }
+
+ Packet->hops = 0; /* Set to zero per RFC 2131. */
+
+ if (Packet->hlen < sizeof Packet->xid) {
+ if (Packet->hlen != 0) {
+ CopyMem (
+ &Packet->xid,
+ &Private->Snp->Mode->CurrentAddress,
+ Packet->hlen
+ );
+ }
+ } else {
+ CopyMem (
+ &Packet->xid,
+ &Private->Snp->Mode->CurrentAddress.Addr[Packet->hlen - sizeof Packet->xid],
+ sizeof Packet->xid
+ );
+ }
+ //
+ // %%TBD - xid should be randomized
+ //
+ Packet->secs = htons (DHCP4_INITIAL_SECONDS);
+
+ Packet->flags = htons (DHCP4_BROADCAST_FLAG);
+
+ if (Packet->hlen != 0) {
+ CopyMem (Packet->chaddr, &Private->Snp->Mode->CurrentAddress, Packet->hlen);
+ }
+
+ Packet->magik = htonl (DHCP4_MAGIK_NUMBER);
+
+ OpPtr = Packet->options;
+
+ *OpPtr++ = DHCP4_MESSAGE_TYPE;
+ *OpPtr++ = 1;
+ *OpPtr++ = DHCP4_MESSAGE_TYPE_DISCOVER;
+
+ *OpPtr++ = DHCP4_MAX_MESSAGE_SIZE;
+ *OpPtr++ = 2;
+ *OpPtr++ = (UINT8) ((DHCP4_DEFAULT_MAX_MESSAGE_SIZE >> 8) & 0xFF);
+ *OpPtr++ = (UINT8) (DHCP4_DEFAULT_MAX_MESSAGE_SIZE & 0xFF);
+
+ *OpPtr++ = DHCP4_PARAMETER_REQUEST_LIST;
+ OpLen = OpPtr;
+ *OpPtr++ = 0;
+ *OpPtr++ = DHCP4_SUBNET_MASK;
+ *OpPtr++ = DHCP4_TIME_OFFSET;
+ *OpPtr++ = DHCP4_ROUTER_LIST;
+ *OpPtr++ = DHCP4_TIME_SERVERS;
+ *OpPtr++ = DHCP4_NAME_SERVERS;
+ *OpPtr++ = DHCP4_DNS_SERVERS;
+ *OpPtr++ = DHCP4_HOST_NAME;
+ *OpPtr++ = DHCP4_BOOT_FILE_SIZE;
+ *OpPtr++ = DHCP4_MESSAGE_TYPE;
+ *OpPtr++ = DHCP4_DOMAIN_NAME;
+ *OpPtr++ = DHCP4_ROOT_PATH;
+ *OpPtr++ = DHCP4_EXTENSION_PATH;
+ *OpPtr++ = DHCP4_MAX_DATAGRAM_SIZE;
+ *OpPtr++ = DHCP4_DEFAULT_TTL;
+ *OpPtr++ = DHCP4_BROADCAST_ADDRESS;
+ *OpPtr++ = DHCP4_NIS_DOMAIN_NAME;
+ *OpPtr++ = DHCP4_NIS_SERVERS;
+ *OpPtr++ = DHCP4_NTP_SERVERS;
+ *OpPtr++ = DHCP4_VENDOR_SPECIFIC;
+ *OpPtr++ = DHCP4_REQUESTED_IP_ADDRESS;
+ *OpPtr++ = DHCP4_LEASE_TIME;
+ *OpPtr++ = DHCP4_SERVER_IDENTIFIER;
+ *OpPtr++ = DHCP4_RENEWAL_TIME;
+ *OpPtr++ = DHCP4_REBINDING_TIME;
+ *OpPtr++ = DHCP4_CLASS_IDENTIFIER;
+ *OpPtr++ = DHCP4_TFTP_SERVER_NAME;
+ *OpPtr++ = DHCP4_BOOTFILE;
+ *OpPtr++ = 128;
+ *OpPtr++ = 129;
+ *OpPtr++ = 130;
+ *OpPtr++ = 131;
+ *OpPtr++ = 132;
+ *OpPtr++ = 133;
+ *OpPtr++ = 134;
+ *OpPtr++ = 135;
+ *OpLen = (UINT8) ((OpPtr - OpLen) - 1);
+
+ *OpPtr++ = DHCP4_END;
+
+ This->Data->SetupCompleted = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/* eof - PxeDhcp4Setup.c */
diff --git a/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/Support.c b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/Support.c
new file mode 100644
index 0000000..2e75052
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/PxeDhcp4Dxe/Support.c
@@ -0,0 +1,1086 @@
+/** @file
+
+Copyright (c) 2004 - 2005, 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:
+ support.c
+
+Abstract:
+ Miscellaneous support routines for PxeDhcp4 protocol.
+
+
+**/
+
+
+#include "PxeDhcp4.h"
+
+#define DebugPrint(x)
+//
+// #define DebugPrint(x) Aprint x
+//
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+UINT16
+htons (
+ UINTN n
+ )
+{
+ return (UINT16) ((n >> 8) | (n << 8));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+UINT32
+htonl (
+ UINTN n
+ )
+{
+ return (UINT32) ((n >> 24) | ((n >> 8) & 0xFF00) | ((n & 0xFF00) << 8) | (n << 24));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+EFIAPI
+timeout_notify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ASSERT (Context);
+
+ if (Context != NULL) {
+ ((PXE_DHCP4_PRIVATE_DATA *) Context)->TimeoutOccurred = TRUE;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+EFIAPI
+periodic_notify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ASSERT (Context);
+
+ if (Context != NULL) {
+ ((PXE_DHCP4_PRIVATE_DATA *) Context)->PeriodicOccurred = TRUE;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+ @return EFI_SUCCESS := Option was found
+ @return EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
+ @return EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD
+ @return EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0
+ @return EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid
+ @return EFI_NOT_FOUND := op-code was not found in packet
+ @return EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option
+ @return does not have a valid value.
+
+**/
+EFI_STATUS
+find_opt (
+ IN DHCP4_PACKET *Packet,
+ IN UINT8 OpCode,
+ IN UINTN Skip,
+ OUT DHCP4_OP **OpPtr
+ )
+{
+ UINTN msg_size;
+ UINTN buf_len;
+ UINTN n;
+ UINT8 *buf;
+ UINT8 *end_ptr;
+ UINT8 overload;
+
+ //
+ // Verify parameters.
+ //
+ if (Packet == NULL || OpPtr == NULL || OpCode == DHCP4_PAD || (OpCode == DHCP4_END && Skip != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Packet->dhcp4.magik != htonl (DHCP4_MAGIK_NUMBER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize search variables.
+ //
+ *OpPtr = NULL;
+
+ msg_size = DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
+
+ overload = 0;
+ end_ptr = NULL;
+
+ buf = Packet->dhcp4.options;
+ buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);
+
+ //
+ // Start searching for requested option.
+ //
+ for (n = 0;;) {
+ //
+ // If match is found, decrement skip count and return
+ // when desired match is found.
+ //
+ if (buf[n] == OpCode) {
+ *OpPtr = (DHCP4_OP *) &buf[n];
+
+ if (Skip-- == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Skip past current option. Check for option overload
+ // and message size options since these will affect the
+ // amount of data to be searched.
+ //
+ switch (buf[n]) {
+ case DHCP4_PAD:
+ //
+ // Remember the first pad byte of a group. This
+ // could be the end of a badly formed packet.
+ //
+ if (end_ptr == NULL) {
+ end_ptr = &buf[n];
+ }
+
+ ++n;
+ break;
+
+ case DHCP4_END:
+ //
+ // If we reach the end we are done.
+ //
+ end_ptr = NULL;
+ return EFI_NOT_FOUND;
+
+ case DHCP4_OPTION_OVERLOAD:
+ //
+ // Remember the option overload value since it
+ // could cause the search to continue into
+ // the fname and sname fields.
+ //
+ end_ptr = NULL;
+
+ if (buf[n + 1] == 1) {
+ overload = buf[n + 2];
+ }
+
+ n += 2 + buf[n + 1];
+ break;
+
+ case DHCP4_MAX_MESSAGE_SIZE:
+ //
+ // Remember the message size value since it could
+ // change the amount of option buffer to search.
+ //
+ end_ptr = NULL;
+
+ if (buf[n + 1] == 2 && buf == Packet->dhcp4.options) {
+ msg_size = ((buf[n + 2] << 8) | buf[n + 3]) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
+
+ if (msg_size < 328) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);
+
+ if (n + 2 + buf[n + 1] > buf_len) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ /* fall thru */
+ default:
+ end_ptr = NULL;
+
+ n += 2 + buf[n + 1];
+ }
+ //
+ // Keep searching until the end of the buffer is reached.
+ //
+ if (n < buf_len) {
+ continue;
+ }
+ //
+ // Reached end of current buffer. Check if we are supposed
+ // to search the fname and sname buffers.
+ //
+ if (buf == Packet->dhcp4.options &&
+ (overload == DHCP4_OVERLOAD_FNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)
+ ) {
+ buf = Packet->dhcp4.fname;
+ buf_len = 128;
+ n = 0;
+ continue;
+ }
+
+ if (buf != Packet->dhcp4.sname && (overload == DHCP4_OVERLOAD_SNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)) {
+ buf = Packet->dhcp4.sname;
+ buf_len = 64;
+ n = 0;
+ continue;
+ }
+ //
+ // End of last buffer reached. If this was a search
+ // for the end of the options, go back to the start
+ // of the current pad block.
+ //
+ if (OpCode == DHCP4_END && end_ptr != NULL) {
+ *OpPtr = (DHCP4_OP *) end_ptr;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+ @return EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
+ @return EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END
+ @return EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid
+ @return EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and
+ @return is not valid
+ @return EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and
+ @return is not valid
+ @return EFI_DEVICE_ERROR := Cannot determine end of packet
+ @return EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option
+ @return EFI_SUCCESS := Option added to DHCP packet
+
+**/
+EFI_STATUS
+add_opt (
+ IN DHCP4_PACKET *Packet,
+ IN DHCP4_OP *OpPtr
+ )
+{
+ EFI_STATUS efi_status;
+ DHCP4_OP *msg_size_op;
+ DHCP4_OP *overload_op;
+ DHCP4_OP *op;
+ UINTN msg_size;
+ UINTN buf_len;
+ UINT32 magik;
+ UINT8 *buf;
+
+ //
+ // Verify parameters.
+ //
+ ASSERT (Packet);
+ ASSERT (OpPtr);
+
+ if (Packet == NULL || OpPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (OpPtr->op) {
+ case DHCP4_PAD:
+ case DHCP4_END:
+ //
+ // No adding PAD or END.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check the DHCP magik number.
+ //
+ CopyMem (&magik, &Packet->dhcp4.magik, 4);
+
+ if (magik != htonl (DHCP4_MAGIK_NUMBER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Find the DHCP message size option.
+ //
+ msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;
+
+ efi_status = find_opt (
+ Packet,
+ DHCP4_MAX_MESSAGE_SIZE,
+ 0,
+ &msg_size_op
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ if (efi_status != EFI_NOT_FOUND) {
+ DebugPrint (
+ ("%s:%d:%r\n",
+ __FILE__,
+ __LINE__,
+ efi_status)
+ );
+ return efi_status;
+ }
+
+ msg_size_op = NULL;
+ } else {
+ CopyMem (&msg_size, msg_size_op->data, 2);
+ msg_size = htons (msg_size);
+
+ if (msg_size < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Find the DHCP option overload option.
+ //
+ efi_status = find_opt (
+ Packet,
+ DHCP4_OPTION_OVERLOAD,
+ 0,
+ &overload_op
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ if (efi_status != EFI_NOT_FOUND) {
+ DebugPrint (
+ ("%s:%d:%r\n",
+ __FILE__,
+ __LINE__,
+ efi_status)
+ );
+ return efi_status;
+ }
+
+ overload_op = NULL;
+ } else {
+ if (overload_op->len != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (overload_op->data[0]) {
+ case 1:
+ case 2:
+ case 3:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Find the end of the packet.
+ //
+ efi_status = find_opt (Packet, DHCP4_END, 0, &op);
+
+ if (EFI_ERROR (efi_status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Find which buffer the end is in.
+ //
+ if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.options)) {
+ buf_len = (msg_size - ((UINT8 *) &Packet->dhcp4.options - (UINT8 *) &Packet->raw)) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
+ } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.fname)) {
+ buf_len = 128;
+ } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.sname)) {
+ buf_len = 64;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Add option to current buffer if there is no overlow.
+ //
+ if ((UINTN) ((&op->op - buf) + 3 + op->len) < buf_len) {
+ CopyMem (op, OpPtr, OpPtr->len + 2);
+
+ op->data[op->len] = DHCP4_END;
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Error if there is no space for option.
+ //
+ return EFI_BUFFER_TOO_SMALL;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+ @return EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL
+ @return EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given
+ @return EFI_SUCCESS := UDP stack is ready
+ @return other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp()
+
+**/
+EFI_STATUS
+start_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OPTIONAL EFI_IP_ADDRESS *StationIp,
+ IN OPTIONAL EFI_IP_ADDRESS *SubnetMask
+ )
+{
+ EFI_PXE_BASE_CODE_IP_FILTER bcast_filter;
+ EFI_STATUS efi_status;
+
+ //
+ //
+ //
+ ASSERT (Private);
+ ASSERT (Private->PxeBc);
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->PxeBc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (StationIp != NULL && SubnetMask == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (StationIp == NULL && SubnetMask != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Setup broadcast receive filter...
+ //
+ ZeroMem (&bcast_filter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
+
+ bcast_filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
+ bcast_filter.IpCnt = 0;
+
+ efi_status = Private->PxeBc->SetIpFilter (
+ Private->PxeBc,
+ &bcast_filter
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ return efi_status;
+ }
+ //
+ // Configure station IP address and subnet mask...
+ //
+ efi_status = Private->PxeBc->SetStationIp (
+ Private->PxeBc,
+ StationIp,
+ SubnetMask
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ }
+
+ return efi_status;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+stop_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private
+ )
+{
+ //
+ //
+ //
+ ASSERT (Private);
+ ASSERT (Private->PxeBc);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+
+**/
+EFI_STATUS
+start_receive_events (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN UINTN SecondsTimeout
+ )
+{
+ EFI_STATUS efi_status;
+ UINTN random;
+
+ //
+ //
+ //
+ ASSERT (Private);
+ ASSERT (SecondsTimeout);
+
+ if (Private == NULL || SecondsTimeout == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Need a bettern randomizer...
+ // For now adjust the timeout value by the least significant
+ // digit in the MAC address.
+ //
+ random = 0;
+
+ if (Private->PxeDhcp4.Data != NULL) {
+ if (Private->PxeDhcp4.Data->Discover.dhcp4.hlen != 0 && Private->PxeDhcp4.Data->Discover.dhcp4.hlen <= 16) {
+ random = 0xFFF & Private->PxeDhcp4.Data->Discover.dhcp4.chaddr[Private->PxeDhcp4.Data->Discover.dhcp4.hlen - 1];
+ }
+ }
+ //
+ // Setup timeout event and start timer.
+ //
+ efi_status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ &timeout_notify,
+ Private,
+ &Private->TimeoutEvent
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ return efi_status;
+ }
+
+ efi_status = gBS->SetTimer (
+ Private->TimeoutEvent,
+ TimerRelative,
+ SecondsTimeout * 10000000 + random
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ gBS->CloseEvent (Private->TimeoutEvent);
+ return efi_status;
+ }
+
+ Private->TimeoutOccurred = FALSE;
+
+ //
+ // Setup periodic event for callbacks
+ //
+ efi_status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ &periodic_notify,
+ Private,
+ &Private->PeriodicEvent
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ gBS->CloseEvent (Private->TimeoutEvent);
+ return efi_status;
+ }
+
+ efi_status = gBS->SetTimer (
+ Private->PeriodicEvent,
+ TimerPeriodic,
+ 1000000
+ ); /* 1/10th second */
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ gBS->CloseEvent (Private->TimeoutEvent);
+ gBS->CloseEvent (Private->PeriodicEvent);
+ return efi_status;
+ }
+
+ Private->PeriodicOccurred = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+stop_receive_events (
+ IN PXE_DHCP4_PRIVATE_DATA *Private
+ )
+{
+ //
+ //
+ //
+ ASSERT (Private);
+
+ if (Private == NULL) {
+ return ;
+ }
+ //
+ //
+ //
+ gBS->CloseEvent (Private->TimeoutEvent);
+ Private->TimeoutOccurred = FALSE;
+
+ //
+ //
+ //
+ gBS->CloseEvent (Private->PeriodicEvent);
+ Private->PeriodicOccurred = FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+ @return EFI_INVALID_PARAMETER := Private == NULL || dest_ip == NULL ||
+ @return buffer == NULL || BufferSize < 300 || Private->PxeBc == NULL
+ @return EFI_SUCCESS := Buffer was transmitted
+ @return other := Return from PxeBc->UdpWrite()
+
+**/
+EFI_STATUS
+tx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN EFI_IP_ADDRESS *dest_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
+ IN EFI_IP_ADDRESS *src_ip,
+ IN VOID *buffer,
+ IN UINTN BufferSize
+ )
+{
+ EFI_PXE_BASE_CODE_UDP_PORT dest_port;
+ EFI_PXE_BASE_CODE_UDP_PORT src_port;
+ EFI_IP_ADDRESS zero_ip;
+
+ //
+ //
+ //
+ ASSERT (Private);
+ ASSERT (dest_ip);
+ ASSERT (buffer);
+ ASSERT (BufferSize >= 300);
+
+ if (Private == NULL || dest_ip == NULL || buffer == NULL || BufferSize < 300) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT (Private->PxeBc);
+
+ if (Private->PxeBc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Transmit DHCP discover packet...
+ //
+ ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
+
+ if (src_ip == NULL) {
+ src_ip = &zero_ip;
+ }
+
+ dest_port = DHCP4_SERVER_PORT;
+ src_port = DHCP4_CLIENT_PORT;
+
+ return Private->PxeBc->UdpWrite (
+ Private->PxeBc,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
+ dest_ip,
+ &dest_port,
+ gateway_ip,
+ src_ip,
+ &src_port,
+ NULL,
+ NULL,
+ &BufferSize,
+ buffer
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/**
+
+ @return EFI_INVALID_PARAMETER :=
+ @return EFI_SUCCESS := Packet received
+ @return other := Return from PxeBc->UdpRead()
+
+**/
+EFI_STATUS
+rx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ OUT VOID *buffer,
+ IN OUT UINTN *BufferSize,
+ IN OUT EFI_IP_ADDRESS *dest_ip,
+ IN OUT EFI_IP_ADDRESS *src_ip,
+ IN UINT16 op_flags
+ )
+{
+ EFI_PXE_BASE_CODE_UDP_PORT dest_port;
+ EFI_PXE_BASE_CODE_UDP_PORT src_port;
+
+ //
+ //
+ //
+ ASSERT (Private);
+ ASSERT (buffer);
+ ASSERT (dest_ip);
+ ASSERT (src_ip);
+
+ if (Private == NULL || buffer == NULL || dest_ip == NULL || src_ip == NULL || BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT (Private->PxeBc);
+
+ if (Private->PxeBc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check for packet
+ //
+ *BufferSize = sizeof (DHCP4_PACKET);
+
+ dest_port = DHCP4_CLIENT_PORT;
+ src_port = DHCP4_SERVER_PORT;
+
+ return Private->PxeBc->UdpRead (
+ Private->PxeBc,
+ op_flags,
+ dest_ip,
+ &dest_port,
+ src_ip,
+ &src_port,
+ NULL,
+ NULL,
+ BufferSize,
+ buffer
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+tx_rx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OUT EFI_IP_ADDRESS *ServerIp,
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *client_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *SubnetMask,
+ IN DHCP4_PACKET *tx_pkt,
+ OUT DHCP4_PACKET *rx_pkt,
+ IN INTN (*rx_vfy)(
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN DHCP4_PACKET *tx_pkt,
+ IN DHCP4_PACKET *rx_pkt,
+ IN UINTN rx_pkt_size
+ ),
+ IN UINTN SecondsTimeout
+ )
+/*++
+Routine description:
+ Transmit DHCP packet and wait for replies.
+
+Parameters:
+ Private := Pointer to PxeDhcp4 private data
+ ServerIp := Pointer to server IP address
+ gateway_ip := Pointer to gateway IP address or NULL
+ client_ip := Pointer to client IP address or NULL
+ SubnetMask := Pointer to subnet mask or NULL
+ tx_pkt := Pointer to DHCP packet to transmit
+ rx_pkt := Pointer to DHCP packet receive buffer
+ rx_vfy := Pointer to DHCP packet receive verification routine
+ SecondsTimeout := Number of seconds until timeout
+
+Returns:
+ EFI_INVALID_PARAMETER := Private == NULL || ServerIp == NULL ||
+ tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL || Private->PxeBc == NULL
+ EFI_ABORTED := Receive aborted
+ EFI_TIMEOUT := No packets received
+ EFI_SUCCESS := Packet(s) received
+ other := Returns from other PxeDhcp4 support routines
+--*/
+{
+ EFI_PXE_DHCP4_CALLBACK_STATUS CallbackStatus;
+ EFI_IP_ADDRESS dest_ip;
+ EFI_IP_ADDRESS src_ip;
+ EFI_STATUS efi_status;
+ DHCP4_OP *msg_size_op;
+ UINTN pkt_size;
+ UINTN n;
+ UINT16 msg_size;
+ UINT16 op_flags;
+ BOOLEAN done_flag;
+ BOOLEAN got_packet;
+
+ //
+ // Bad programmer check...
+ //
+ ASSERT (Private);
+ ASSERT (ServerIp);
+ ASSERT (tx_pkt);
+ ASSERT (rx_pkt);
+ ASSERT (rx_vfy);
+
+ if (Private == NULL || ServerIp == NULL || tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT (Private->PxeBc);
+
+ if (Private->PxeBc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Enable UDP...
+ //
+ efi_status = start_udp (Private, client_ip, SubnetMask);
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ return efi_status;
+ }
+ //
+ // Get length of transmit packet...
+ //
+ msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;
+
+ efi_status = find_opt (
+ tx_pkt,
+ DHCP4_MAX_MESSAGE_SIZE,
+ 0,
+ &msg_size_op
+ );
+
+ if (!EFI_ERROR (efi_status)) {
+ CopyMem (&msg_size, msg_size_op->data, 2);
+
+ if ((msg_size = htons (msg_size)) < 328) {
+ msg_size = 328;
+ }
+ }
+ //
+ // Transmit packet...
+ //
+ efi_status = tx_udp (
+ Private,
+ ServerIp,
+ gateway_ip,
+ client_ip,
+ tx_pkt,
+ msg_size - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)
+ );
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ stop_udp (Private);
+ return efi_status;
+ }
+ //
+ // Enable periodic and timeout events...
+ //
+ efi_status = start_receive_events (Private, SecondsTimeout);
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ stop_udp (Private);
+ return efi_status;
+ }
+ //
+ // Wait for packet(s)...
+ //
+#if 0
+ if (!client_ip) {
+ Aprint ("client_ip == NULL ");
+ } else {
+ Aprint (
+ "client_ip == %d.%d.%d.%d ",
+ client_ip->v4.Addr[0],
+ client_ip->v4.Addr[1],
+ client_ip->v4.Addr[2],
+ client_ip->v4.Addr[3]
+ );
+ }
+
+ if (!ServerIp) {
+ Aprint ("ServerIp == NULL\n");
+ } else {
+ Aprint (
+ "ServerIp == %d.%d.%d.%d\n",
+ ServerIp->v4.Addr[0],
+ ServerIp->v4.Addr[1],
+ ServerIp->v4.Addr[2],
+ ServerIp->v4.Addr[3]
+ );
+ }
+#endif
+
+ done_flag = FALSE;
+ got_packet = FALSE;
+
+ while (!done_flag) {
+ //
+ // Check for timeout event...
+ //
+ if (Private->TimeoutOccurred) {
+ efi_status = EFI_SUCCESS;
+ break;
+ }
+ //
+ // Check for periodic event...
+ //
+ if (Private->PeriodicOccurred && Private->callback != NULL) {
+ CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE;
+
+ if (Private->callback->Callback != NULL) {
+ CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, 0, NULL);
+ }
+
+ switch (CallbackStatus) {
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE:
+ break;
+
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT:
+ default:
+ stop_receive_events (Private);
+ stop_udp (Private);
+ return EFI_ABORTED;
+ }
+
+ Private->PeriodicOccurred = FALSE;
+ }
+ //
+ // Check for packet...
+ //
+ if (client_ip == NULL) {
+ SetMem (&dest_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
+ } else {
+ CopyMem (&dest_ip, client_ip, sizeof (EFI_IP_ADDRESS));
+ }
+
+ SetMem (&src_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
+
+ if (CompareMem (&src_ip, &ServerIp, sizeof (EFI_IP_ADDRESS))) {
+ ZeroMem (&src_ip, sizeof (EFI_IP_ADDRESS));
+ op_flags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP;
+ } else {
+ op_flags = 0;
+ }
+
+ efi_status = rx_udp (
+ Private,
+ rx_pkt,
+ &pkt_size,
+ &dest_ip,
+ &src_ip,
+ op_flags
+ );
+
+ if (efi_status == EFI_TIMEOUT) {
+ efi_status = EFI_SUCCESS;
+ continue;
+ }
+
+ if (EFI_ERROR (efi_status)) {
+ break;
+ }
+ //
+ // Some basic packet sanity checks..
+ //
+ if (pkt_size < 300) {
+ continue;
+ }
+
+ if (rx_pkt->dhcp4.op != BOOTP_REPLY) {
+ continue;
+ }
+
+ if (tx_pkt->dhcp4.htype != rx_pkt->dhcp4.htype) {
+ continue;
+ }
+
+ if ((n = tx_pkt->dhcp4.hlen) != rx_pkt->dhcp4.hlen) {
+ continue;
+ }
+
+ if (CompareMem (&tx_pkt->dhcp4.xid, &rx_pkt->dhcp4.xid, 4)) {
+ continue;
+ }
+
+ if (n != 0) {
+ if (n >= 16) {
+ n = 16;
+ }
+
+ if (CompareMem (tx_pkt->dhcp4.chaddr, rx_pkt->dhcp4.chaddr, n)) {
+ continue;
+ }
+ }
+ //
+ // Internal callback packet verification...
+ //
+ switch ((*rx_vfy) (Private, tx_pkt, rx_pkt, pkt_size)) {
+ case -2: /* ignore and stop */
+ stop_receive_events (Private);
+ stop_udp (Private);
+ return EFI_ABORTED;
+
+ case -1: /* ignore and wait */
+ continue;
+
+ case 0: /* accept and wait */
+ break;
+
+ case 1: /* accept and stop */
+ done_flag = TRUE;
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ //
+ // External callback packet verification...
+ //
+ CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE;
+
+ if (Private->callback != NULL) {
+ if (Private->callback->Callback != NULL) {
+ CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, (UINT32) pkt_size, rx_pkt);
+ }
+ }
+
+ switch (CallbackStatus) {
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE:
+ continue;
+
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT:
+ done_flag = TRUE;
+ break;
+
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT:
+ stop_receive_events (Private);
+ stop_udp (Private);
+ return EFI_ABORTED;
+
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE:
+ default:
+ break;
+ }
+ //
+ // We did! We did get a packet!
+ //
+ got_packet = TRUE;
+ }
+ //
+ //
+ //
+ stop_receive_events (Private);
+ stop_udp (Private);
+
+ if (EFI_ERROR (efi_status)) {
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
+ return efi_status;
+ }
+
+ if (got_packet) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_TIMEOUT;
+ }
+}
+
+/* eof - support.c */