summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Universal/Network
diff options
context:
space:
mode:
authorbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
committerbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
commit878ddf1fc3540a715f63594ed22b6929e881afb4 (patch)
treec56c44dac138137b510e1fba7c3efe5e4d84bea2 /EdkModulePkg/Universal/Network
downloadedk2-878ddf1fc3540a715f63594ed22b6929e881afb4.zip
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.gz
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.bz2
Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkModulePkg/Universal/Network')
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd42
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa94
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c160
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c81
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c2510
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h499
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h627
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h42
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h741
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c617
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c3332
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c476
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c861
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c2391
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c577
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c1697
-rw-r--r--EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h153
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c169
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd41
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa74
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c342
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h307
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c786
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c246
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c408
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c196
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c268
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c1126
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c160
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd41
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa85
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c100
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c613
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c193
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c244
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c167
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c183
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c255
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c411
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c129
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c152
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c1315
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h410
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c191
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c248
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c193
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c120
-rw-r--r--EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c396
51 files changed, 24610 insertions, 0 deletions
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd
new file mode 100644
index 0000000..2262fc6
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.mbd
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>BC</BaseName>
+ <Guid>A3f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa
new file mode 100644
index 0000000..e94492b
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/BC.msa
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>BC</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>A3f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PrintLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>bc.c</Filename>
+ <Filename>pxe_bc_arp.c</Filename>
+ <Filename>pxe_bc_dhcp.c</Filename>
+ <Filename>pxe_bc_igmp.c</Filename>
+ <Filename>pxe_bc_ip.c</Filename>
+ <Filename>pxe_bc_mtftp.c</Filename>
+ <Filename>pxe_bc_udp.c</Filename>
+ <Filename>pxe_loadfile.c</Filename>
+ <Filename>dhcp.h</Filename>
+ <Filename>bc.h</Filename>
+ <Filename>ip.h</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>Print.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">Bis</Protocol>
+ <Protocol Usage="BY_START">LoadFile</Protocol>
+ <Protocol Usage="SOMETIMES_PRODUCED">PxeBaseCodeCallBack</Protocol>
+ <Protocol Usage="TO_START">SimpleNetwork</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">NetworkInterfaceIdentifier</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">NetworkInterfaceIdentifier2</Protocol>
+ <Protocol Usage="BY_START">PxeBaseCode</Protocol>
+ </Protocols>
+ <SystemTables>
+ <SystemTable Usage="SOMETIMES_CONSUMED">
+ <Entry>gEfiSmbiosTableGuid</Entry>
+ </SystemTable>
+ </SystemTables>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>SmbiosTable</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint>InitializeBCDriver</ModuleEntryPoint>
+ <ModuleUnloadImage></ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>gPxeBcDriverBinding</DriverBinding>
+ <ComponentName>gPxeBcComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c
new file mode 100644
index 0000000..2c11dc4
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ComponentName.c
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ ComponentName.c
+
+Abstract:
+
+--*/
+
+
+#include "Bc.h"
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+PxeBcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+PxeBcComponentNameGetControllerName (
+ 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 gPxeBcComponentName = {
+ PxeBcComponentNameGetDriverName,
+ PxeBcComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mPxeBcDriverNameTable[] = {
+ {
+ "eng",
+ (CHAR16 *) L"PXE Base Code Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+PxeBcComponentNameGetDriverName (
+ 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,
+ gPxeBcComponentName.SupportedLanguages,
+ mPxeBcDriverNameTable,
+ DriverName
+ );
+}
+
+EFI_STATUS
+EFIAPI
+PxeBcComponentNameGetControllerName (
+ 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;
+}
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c
new file mode 100644
index 0000000..4ea5cba
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/Print.c
@@ -0,0 +1,81 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ Print.c
+
+Abstract:
+
+--*/
+
+
+#include <Bc.h>
+
+UINTN
+EFIAPI
+AsciiPrint (
+ IN CONST CHAR8 *Format,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ Print function for a maximum of PXE_MAX_PRINT_BUFFER ascii
+ characters.
+
+Arguments:
+
+ Format - Ascii format string see file header for more details.
+
+ ... - Vararg list consumed by processing Format.
+
+Returns:
+
+ Number of characters printed.
+
+--*/
+{
+ UINTN Return;
+ VA_LIST Marker;
+ UINTN Index;
+ UINTN MaxIndex;
+ CHAR16 Buffer[PXE_MAX_PRINT_BUFFER];
+ CHAR16 UnicodeFormat[PXE_MAX_PRINT_BUFFER];
+
+ MaxIndex = AsciiStrLen ((CHAR8 *) Format);
+ if (MaxIndex > PXE_MAX_PRINT_BUFFER) {
+ //
+ // Format string was too long for use to process.
+ //
+ return 0;
+ }
+
+ for (Index = 0; Index < PXE_MAX_PRINT_BUFFER; Index++) {
+ UnicodeFormat[Index] = (CHAR16) Format[Index];
+ }
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer, sizeof (Buffer), UnicodeFormat, Marker);
+ VA_END (Marker);
+
+ //
+ // Need to convert to Unicode to do an OutputString
+ //
+
+ if (gST->ConOut != NULL) {
+ //
+ // To be extra safe make sure ConOut has been initialized
+ //
+ gST->ConOut->OutputString (gST->ConOut, Buffer);
+ }
+
+ return Return;
+}
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c
new file mode 100644
index 0000000..b9f4891
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.c
@@ -0,0 +1,2510 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ bc.c
+
+Abstract:
+
+--*/
+
+#include "bc.h"
+
+//
+//
+//
+EFI_STATUS
+EFIAPI
+PxeBcDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+PxeBcDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+PxeBcDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+extern
+VOID
+InitArpHeader (
+ VOID
+ );
+extern
+VOID
+OptionsStrucInit (
+ VOID
+ );
+
+//
+// helper routines
+//
+VOID
+CvtNum (
+ IN UINTN Number,
+ IN UINT8 *Buffer,
+ IN INTN Length
+ )
+/*++
+
+ Routine Description:
+ Convert number to ASCII value
+
+ Arguments:
+ Number - Numeric value to convert to decimal ASCII value.
+ Buffer - Buffer to place ASCII version of the Number
+ Length - Length of Buffer.
+
+ Returns:
+ none - none
+
+--*/
+{
+ UINTN Remainder;
+
+ while (Length--) {
+ Remainder = Number % 10;
+ Number /= 10;
+ Buffer[Length] = (UINT8) ('0' + Remainder);
+ }
+}
+
+VOID
+UtoA10 (
+ IN UINTN Number,
+ IN UINT8 *Buffer
+ )
+/*++
+
+ Routine Description:
+ Convert number to decimal ASCII value at Buffer location
+
+ Arguments:
+ Number - Numeric value to convert to decimal ASCII value.
+ Buffer - Buffer to place ASCII version of the Number
+
+ Returns:
+ none - none
+
+--*/
+{
+ INTN Index;
+ UINT8 BuffArray[31];
+
+ BuffArray[30] = 0;
+ CvtNum (Number, BuffArray, 30);
+
+ for (Index = 0; Index < 30; ++Index) {
+ if (BuffArray[Index] != '0') {
+ break;
+ }
+ }
+
+ CopyMem (Buffer, BuffArray + Index, 31 - Index);
+}
+
+UINTN
+AtoU (
+ IN UINT8 *Buffer
+ )
+/*++
+
+ Routine Description:
+ Convert ASCII numeric string to a UINTN value
+
+ Arguments:
+ Number - Numeric value to convert to decimal ASCII value.
+ Buffer - Buffer to place ASCII version of the Number
+
+ Returns:
+ Value - UINTN value of the ASCII string.
+
+--*/
+{
+ UINTN Value;
+ INT8 Character;
+
+ Value = 0;
+ Character = *Buffer++;
+ do {
+ Value = Value * 10 + Character - '0';
+ Character = *Buffer++;
+ } while (Character);
+
+ return Value;
+}
+
+UINT64
+AtoU64 (
+ IN UINT8 *Buffer
+ )
+/*++
+
+ Routine Description:
+ Convert ASCII numeric string to a UINTN value
+
+ Arguments:
+ Number - Numeric value to convert to decimal ASCII value.
+ Buffer - Buffer to place ASCII version of the Number
+
+ Returns:
+ Value - UINTN value of the ASCII string.
+
+--*/
+{
+ UINT64 Value;
+ UINT8 Character;
+
+ Value = 0;
+ while ((Character = *Buffer++) != '\0') {
+ Value = MultU64x32 (Value, 10) + (Character - '0');
+ }
+
+ return Value;
+}
+//
+// random number generator
+//
+#define RANDOM_MULTIPLIER 2053
+#define RANDOM_ADD_IN_VALUE 19
+
+VOID
+SeedRandom (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 InitialSeed
+ )
+/*++
+
+ Routine Description:
+ Initialize the Seed for the random number generator
+
+ Arguments:
+
+ Returns:
+ none -
+
+--*/
+{
+ if (Private != NULL) {
+ Private->RandomSeed = InitialSeed;
+ }
+}
+
+UINT16
+Random (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+/*++
+
+ Routine Description:
+ Generate and return a pseudo-random number
+
+ Arguments:
+
+ Returns:
+ Number - UINT16 random number
+
+--*/
+{
+ UINTN Number;
+
+ if (Private != NULL) {
+ Number = -(INTN) Private->RandomSeed * RANDOM_MULTIPLIER + RANDOM_ADD_IN_VALUE;
+
+ return Private->RandomSeed = (UINT16) Number;
+ } else {
+ return 0;
+ }
+}
+//
+// calculate the internet checksum (RFC 1071)
+// return 16 bit ones complement of ones complement sum of 16 bit words
+//
+UINT16
+IpChecksum (
+ IN UINT16 *Packet,
+ IN UINTN Length
+ )
+/*++
+
+ Routine Description:
+ Calculate the internet checksum (see RFC 1071)
+
+ Arguments:
+ Packet - Buffer which contains the data to be checksummed
+ Length - Length to be checksummed
+
+ Returns:
+ Checksum - Returns the 16 bit ones complement of
+ ones complement sum of 16 bit words
+
+--*/
+{
+ UINT32 Sum;
+ UINT8 Odd;
+
+ Sum = 0;
+ Odd = (UINT8) (Length & 1);
+ Length >>= 1;
+ while (Length--) {
+ Sum += *Packet++;
+ }
+
+ if (Odd) {
+ Sum += *(UINT8 *) Packet;
+ }
+
+ Sum = (Sum & 0xffff) + (Sum >> 16);
+ //
+ // in case above carried
+ //
+ Sum += Sum >> 16;
+
+ return (UINT16) (~ (UINT16) Sum);
+}
+
+UINT16
+IpChecksum2 (
+ IN UINT16 *Header,
+ IN UINTN HeaderLen,
+ IN UINT16 *Message,
+ IN UINTN MessageLen
+ )
+/*++
+
+ Routine Description:
+ Calculate the internet checksum (see RFC 1071)
+ on a non contiguous header and data
+
+ Arguments:
+ Header - Buffer which contains the data to be checksummed
+ HeaderLen - Length to be checksummed
+ Message - Buffer which contains the data to be checksummed
+ MessageLen - Length to be checksummed
+
+ Returns:
+ Checksum - Returns the 16 bit ones complement of
+ ones complement sum of 16 bit words
+
+--*/
+{
+ UINT32 Sum;
+
+ Sum = (UINT16)~IpChecksum (Header, HeaderLen) + (UINT16)~IpChecksum (Message, MessageLen);
+
+ //
+ // in case above carried
+ //
+ Sum += Sum >> 16;
+
+ return (UINT16) (~ (UINT16) Sum);
+}
+
+UINT16
+UpdateChecksum (
+ IN UINT16 OldChksum,
+ IN UINT16 OldWord,
+ IN UINT16 NewWord
+ )
+/*++
+
+ Routine Description:
+ Adjust the internet checksum (see RFC 1071) on a single word update.
+
+ Arguments:
+ OldChkSum - Checksum previously calculated
+ OldWord - Value
+ NewWord - New Value
+
+ Returns:
+ Checksum - Returns the 16 bit ones complement of
+ ones complement sum of 16 bit words
+
+--*/
+{
+ UINT32 sum;
+
+ sum = ~OldChksum + NewWord - OldWord;
+ //
+ // in case above carried
+ //
+ sum += sum >> 16;
+ return (UINT16) (~ (UINT16) sum);
+}
+
+STATIC
+BOOLEAN
+SetMakeCallback (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+/*++
+
+ Routine Description:
+ See if a callback is in play
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+
+ Returns:
+ 0 - Callbacks are active on the handle
+ 1 - Callbacks are not active on the handle
+
+--*/
+{
+ Private->EfiBc.Mode->MakeCallbacks = (BOOLEAN) (gBS->HandleProtocol (
+ Private->Handle,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ (VOID *) &Private->CallbackProtocolPtr
+ ) == EFI_SUCCESS);
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nMode->MakeCallbacks == %d ",
+ Private->EfiBc.Mode->MakeCallbacks)
+ );
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nPrivate->CallbackProtocolPtr == %xh ",
+ Private->CallbackProtocolPtr)
+ );
+
+ if (Private->CallbackProtocolPtr != NULL) {
+ DEBUG (
+ (EFI_D_INFO,
+ "\nCallbackProtocolPtr->Revision = %xh ",
+ Private->CallbackProtocolPtr->Revision)
+ );
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nCallbackProtocolPtr->Callback = %xh ",
+ Private->CallbackProtocolPtr->Callback)
+ );
+ }
+
+ return Private->EfiBc.Mode->MakeCallbacks;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+WaitForReceive (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function,
+ IN EFI_EVENT TimeoutEvent,
+ IN OUT UINTN *HeaderSizePtr,
+ IN OUT UINTN *BufferSizePtr,
+ IN OUT UINT16 *ProtocolPtr
+ )
+/*++
+
+ Routine Description:
+ Routine which does an SNP->Receive over a timeout period and doing callbacks
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+ Function - What PXE function to callback
+ TimeoutEvent - Timer event that will trigger when we have waited too
+ long for an incoming packet
+ HeaderSizePtr - Pointer to the size of the Header size
+ BufferSizePtr - Pointer to the size of the Buffer size
+ ProtocolPtr - The protocol to sniff for (namely, UDP/etc)
+
+ Returns:
+ 0 - Something was returned
+ !0 - Like there was nothing to receive (EFI_TIMEOUT/NOT_READY)
+
+--*/
+{
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
+ EFI_PXE_CALLBACK CallbackPtr;
+ EFI_STATUS StatCode;
+ EFI_EVENT CallbackEvent;
+
+ //
+ // Initialize pointer to SNP interface
+ //
+ SnpPtr = Private->SimpleNetwork;
+
+ //
+ // Initialize pointer to PxeBc callback routine - if any
+ //
+ CallbackPtr = (Private->EfiBc.Mode->MakeCallbacks) ? Private->CallbackProtocolPtr->Callback : NULL;
+
+ //
+ // Create callback event and set timer
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &CallbackEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // every 100 milliseconds
+ //
+ StatCode = gBS->SetTimer (
+ CallbackEvent,
+ TimerPeriodic,
+ 1000000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ gBS->CloseEvent (CallbackEvent);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Loop until a packet is received or a receive error is detected or
+ // a callback abort is detected or a timeout event occurs.
+ //
+ for (;;)
+ {
+#if 0
+ //
+ // Check for received packet event.
+ //
+ if (!EFI_ERROR (gBS->CheckEvent (SnpPtr->WaitForPacket))) {
+ //
+ // Packet should be available. Attempt to read it.
+ //
+ *BufferSizePtr = BUFFER_ALLOCATE_SIZE;
+
+ StatCode = SnpPtr->Receive (
+ SnpPtr,
+ HeaderSizePtr,
+ BufferSizePtr,
+ Private->ReceiveBufferPtr,
+ 0,
+ 0,
+ ProtocolPtr
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ break;
+ }
+ //
+ // Packet was received. Make received callback then return.
+ //
+ if (CallbackPtr != NULL) {
+ StatCode = CallbackPtr (
+ Private->CallbackProtocolPtr,
+ Function,
+ TRUE,
+ (UINT32) *BufferSizePtr,
+ (EFI_PXE_BASE_CODE_PACKET *) Private->ReceiveBufferPtr
+ );
+
+ if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
+ StatCode = EFI_ABORTED;
+ } else {
+ StatCode = EFI_SUCCESS;
+ }
+ }
+
+ break;
+ }
+
+#else
+ //
+ // Poll for received packet.
+ //
+ *BufferSizePtr = BUFFER_ALLOCATE_SIZE;
+
+ StatCode = SnpPtr->Receive (
+ SnpPtr,
+ HeaderSizePtr,
+ BufferSizePtr,
+ Private->ReceiveBufferPtr,
+ 0,
+ 0,
+ ProtocolPtr
+ );
+
+ if (!EFI_ERROR (StatCode)) {
+ //
+ // Packet was received. Make received callback then return.
+ //
+ if (CallbackPtr != NULL) {
+ StatCode = CallbackPtr (
+ Private->CallbackProtocolPtr,
+ Function,
+ TRUE,
+ (UINT32) *BufferSizePtr,
+ (EFI_PXE_BASE_CODE_PACKET *) Private->ReceiveBufferPtr
+ );
+
+ if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
+ StatCode = EFI_ABORTED;
+ } else {
+ StatCode = EFI_SUCCESS;
+ }
+ }
+
+ break;
+ }
+
+ if (StatCode != EFI_NOT_READY) {
+ break;
+ }
+#endif
+ //
+ // Check for callback event.
+ //
+ if (!EFI_ERROR (gBS->CheckEvent (CallbackEvent))) {
+ //
+ // Make periodic callback if callback pointer is initialized.
+ //
+ if (CallbackPtr != NULL) {
+ StatCode = CallbackPtr (
+ Private->CallbackProtocolPtr,
+ Function,
+ FALSE,
+ 0,
+ NULL
+ );
+
+ //
+ // Abort if directed to by callback routine.
+ //
+ if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
+ StatCode = EFI_ABORTED;
+ break;
+ }
+ }
+ }
+ //
+ // Check for timeout event.
+ //
+ if (TimeoutEvent == 0) {
+ StatCode = EFI_TIMEOUT;
+ break;
+ }
+
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
+ StatCode = EFI_TIMEOUT;
+ break;
+ }
+ //
+ // Check IGMP timer events.
+ //
+ IgmpCheckTimers (Private);
+ }
+
+ gBS->CloseEvent (CallbackEvent);
+
+ return StatCode;
+}
+
+EFI_STATUS
+SendPacket (
+ PXE_BASECODE_DEVICE *Private,
+ VOID *HeaderPtr,
+ VOID *PacketPtr,
+ INTN PacketLen,
+ VOID *HardwareAddr,
+ UINT16 MediaProtocol,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+/*++
+
+ Routine Description:
+ Routine which does an SNP->Transmit of a buffer
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+ HeaderPtr - Pointer to the buffer
+ PacketPtr - Pointer to the packet to send
+ PacketLen - The length of the entire packet to send
+ HardwareAddr - Pointer to the MAC address of the destination
+ MediaProtocol - What type of frame to create (RFC 1700) - IE. Ethernet
+ Function - What PXE function to callback
+
+ Returns:
+ 0 - Something was sent
+ !0 - An error was encountered during sending of a packet
+
+--*/
+{
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
+ EFI_PXE_CALLBACK CallbackPtr;
+ EFI_STATUS StatCode;
+ EFI_EVENT TimeoutEvent;
+ UINT32 IntStatus;
+ VOID *TxBuf;
+
+ //
+ //
+ //
+ CallbackPtr = Private->EfiBc.Mode->MakeCallbacks ? Private->CallbackProtocolPtr->Callback : 0;
+
+ SnpPtr = Private->SimpleNetwork;
+ SnpModePtr = SnpPtr->Mode;
+
+ //
+ // clear prior interrupt status
+ //
+ StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, 0);
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nSendPacket() Exit #1 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ return StatCode;
+ }
+
+ Private->DidTransmit = FALSE;
+
+ if (CallbackPtr != NULL) {
+ if (CallbackPtr (
+ Private->CallbackProtocolPtr,
+ Function,
+ FALSE,
+ (UINT32) PacketLen,
+ PacketPtr
+ ) != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nSendPacket() Exit #2 %xh (%r)",
+ EFI_ABORTED,
+ EFI_ABORTED)
+ );
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // put packet in transmit queue
+ // headersize should be zero if not filled in
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "Could not create transmit timeout event. %r\n",
+ StatCode)
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // 5 milliseconds
+ //
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ 50000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "Could not set transmit timeout event timer. %r\n",
+ StatCode)
+ );
+ gBS->CloseEvent (TimeoutEvent);
+ return EFI_DEVICE_ERROR;
+ }
+
+ for (;;) {
+ StatCode = SnpPtr->Transmit (
+ SnpPtr,
+ (UINTN) SnpPtr->Mode->MediaHeaderSize,
+ (UINTN) (PacketLen + SnpPtr->Mode->MediaHeaderSize),
+ HeaderPtr,
+ &SnpModePtr->CurrentAddress,
+ (EFI_MAC_ADDRESS *) HardwareAddr,
+ &MediaProtocol
+ );
+
+ if (StatCode != EFI_NOT_READY) {
+ break;
+ }
+
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
+ StatCode = EFI_TIMEOUT;
+ break;
+ }
+ }
+
+ gBS->CloseEvent (TimeoutEvent);
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nSendPacket() Exit #3 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ return StatCode;
+ }
+ //
+ // remove transmit buffer from snp's unused queue
+ // done this way in case someday things are buffered and we don't get it back
+ // immediately
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "Could not create transmit status timeout event. %r\n",
+ StatCode)
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // 5 milliseconds
+ //
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ 50000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "Could not set transmit status timeout event timer. %r\n",
+ StatCode)
+ );
+ gBS->CloseEvent (TimeoutEvent);
+ return EFI_DEVICE_ERROR;
+ }
+
+ for (;;) {
+ StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, &TxBuf);
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nSendPacket() Exit #4 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ break;
+ }
+
+ if (IntStatus & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT) {
+ Private->DidTransmit = TRUE;
+ }
+
+ if (TxBuf != NULL) {
+ break;
+ }
+
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
+ StatCode = EFI_TIMEOUT;
+ break;
+ }
+ }
+
+ gBS->CloseEvent (TimeoutEvent);
+
+ return StatCode;
+}
+//
+//
+//
+EFI_BIS_PROTOCOL *
+PxebcBisStart (
+ IN PXE_BASECODE_DEVICE *Private,
+ OUT BIS_APPLICATION_HANDLE *BisAppHandle,
+ OUT OPTIONAL EFI_BIS_DATA **BisDataSigInfo
+ )
+/*++
+Routine description:
+ Locate BIS interface and if found, try to start it.
+
+Parameters:
+ Private := Pointer to PxeBc protocol
+ BisAppHandle := Pointer to BIS application handle storage
+ BisDataSigInfo := Pointer to BIS signature information storage
+Returns:
+--*/
+{
+ EFI_STATUS EfiStatus;
+ EFI_HANDLE BisHandleBuffer;
+ UINTN BisHandleCount;
+ EFI_BIS_PROTOCOL *BisPtr;
+ EFI_BIS_VERSION BisInterfaceVersion;
+ BOOLEAN BisCheckFlag;
+
+ BisHandleCount = sizeof (EFI_HANDLE);
+ BisCheckFlag = FALSE;
+
+ //
+ // Locate BIS protocol handle (if present).
+ // If BIS protocol handle is not found, return NULL.
+ //
+ DEBUG ((EFI_D_INFO, "\ngBS->LocateHandle() "));
+
+ EfiStatus = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiBisProtocolGuid,
+ NULL,
+ &BisHandleCount,
+ &BisHandleBuffer
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ //
+ // Any error means that there is no BIS.
+ // Note - It could mean that there are more than
+ // one BIS protocols installed, but that scenario
+ // is not yet supported.
+ //
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxebcBisStart()""\n gBS->LocateHandle() %r (%xh)\n",
+ EfiStatus,
+ EfiStatus)
+ );
+
+ return NULL;
+ }
+
+ if (BisHandleCount != sizeof BisHandleBuffer) {
+ //
+ // This really should never happen, but I am paranoid.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nPxebcBisStart() BisHandleCount != %d\n",
+ sizeof BisHandleBuffer)
+ );
+
+ return NULL;
+ }
+
+ DEBUG ((EFI_D_INFO, "BIS handle found."));
+
+ //
+ // Locate BIS protocol interface.
+ // If the BIS protocol interface cannot be found, return NULL.
+ //
+ DEBUG ((EFI_D_INFO, "\ngBS->HandleProtocol() "));
+
+ EfiStatus = gBS->HandleProtocol (
+ BisHandleBuffer,
+ &gEfiBisProtocolGuid,
+ (VOID **) &BisPtr
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxebcBisStart()""\n gBS->HandleProtocol() %r (%xh)\n",
+ EfiStatus,
+ EfiStatus)
+ );
+
+ return NULL;
+ }
+
+ if (BisPtr == NULL) {
+ //
+ // This really should never happen.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nPxebcBisStart()""\n gBS->HandleProtocoL() ""BIS protocol interface pointer is NULL!\n")
+ );
+
+ return NULL;
+ }
+
+ DEBUG ((EFI_D_INFO, "BIS protocol interface found."));
+
+ //
+ // Check that all of the BIS API function pointers are not NULL.
+ //
+ if (BisPtr->Initialize == NULL ||
+ BisPtr->Shutdown == NULL ||
+ BisPtr->Free == NULL ||
+ BisPtr->GetBootObjectAuthorizationCertificate == NULL ||
+ BisPtr->GetBootObjectAuthorizationCheckFlag == NULL ||
+ BisPtr->GetBootObjectAuthorizationUpdateToken == NULL ||
+ BisPtr->GetSignatureInfo == NULL ||
+ BisPtr->UpdateBootObjectAuthorization == NULL ||
+ BisPtr->VerifyBootObject == NULL ||
+ BisPtr->VerifyObjectWithCredential == NULL
+ ) {
+ DEBUG (
+ (
+ EFI_D_NET,
+ "\nPxebcBisStart()""\n BIS protocol interface is invalid."
+ "\n At least one BIS protocol function pointer is NULL.\n"
+ )
+ );
+
+ return NULL;
+ }
+ //
+ // Initialize BIS.
+ // If BIS does not initialize, return NULL.
+ //
+ DEBUG ((EFI_D_INFO, "\nBisPtr->Initialize() "));
+
+ BisInterfaceVersion.Major = BIS_VERSION_1;
+
+ EfiStatus = BisPtr->Initialize (
+ BisPtr,
+ BisAppHandle,
+ &BisInterfaceVersion,
+ NULL
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxebcBisStart()""\n BisPtr->Initialize() %r (%xh)\n",
+ EfiStatus,
+ EfiStatus)
+ );
+
+ return NULL;
+ }
+
+ DEBUG (
+ (EFI_D_INFO,
+ " BIS version: %d.%d",
+ BisInterfaceVersion.Major,
+ BisInterfaceVersion.Minor)
+ );
+
+ //
+ // If the requested BIS API version is not supported,
+ // shutdown BIS and return NULL.
+ //
+ if (BisInterfaceVersion.Major != BIS_VERSION_1) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxebcBisStart()""\n BIS version %d.%d not supported by PXE BaseCode.\n",
+ BisInterfaceVersion.Major,
+ BisInterfaceVersion.Minor)
+ );
+
+ BisPtr->Shutdown (*BisAppHandle);
+ return NULL;
+ }
+ //
+ // Get BIS check flag.
+ // If the BIS check flag cannot be read, shutdown BIS and return NULL.
+ //
+ DEBUG ((EFI_D_INFO, "\nBisPtr->GetBootObjectAuthorizationCheckFlag() "));
+
+ EfiStatus = BisPtr->GetBootObjectAuthorizationCheckFlag (*BisAppHandle, &BisCheckFlag);
+
+ if (EFI_ERROR (EfiStatus)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxebcBisStart()""\n BisPtr->GetBootObjectAuthorizationCheckFlag() %r (%xh)\n",
+ EfiStatus,
+ EfiStatus)
+ );
+
+ BisPtr->Shutdown (*BisAppHandle);
+ return NULL;
+ }
+ //
+ // If the BIS check flag is FALSE, shutdown BIS and return NULL.
+ //
+ if (!BisCheckFlag) {
+ DEBUG ((EFI_D_INFO, "\nBIS check flag is FALSE.\n"));
+ BisPtr->Shutdown (*BisAppHandle);
+ return NULL;
+ } else {
+ DEBUG ((EFI_D_INFO, "\nBIS check flag is TRUE."));
+ }
+ //
+ // Early out if caller does not want signature information.
+ //
+ if (BisDataSigInfo == NULL) {
+ return BisPtr;
+ }
+ //
+ // Get BIS signature information.
+ // If the signature information cannot be read or is invalid,
+ // shutdown BIS and return NULL.
+ //
+ DEBUG ((EFI_D_INFO, "\nBisPtr->GetSignatureInfo() "));
+
+ EfiStatus = BisPtr->GetSignatureInfo (*BisAppHandle, BisDataSigInfo);
+
+ if (EFI_ERROR (EfiStatus)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxebcBisStart()""\n BisPtr_GetSignatureInfo() %r (%xh)\n",
+ EfiStatus,
+ EfiStatus)
+ );
+
+ BisPtr->Shutdown (*BisAppHandle);
+ return NULL;
+ }
+
+ if (*BisDataSigInfo == NULL) {
+ //
+ // This should never happen.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Data pointer is NULL!\n")
+ );
+
+ BisPtr->Shutdown (*BisAppHandle);
+ return NULL;
+ }
+
+ if ((*BisDataSigInfo)->Length < sizeof (EFI_BIS_SIGNATURE_INFO) ||
+ (*BisDataSigInfo)->Length % sizeof (EFI_BIS_SIGNATURE_INFO) ||
+ (*BisDataSigInfo)->Length > sizeof (EFI_BIS_SIGNATURE_INFO) * 63
+ ) {
+ //
+ // This should never happen.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Invalid BIS siginfo length.\n")
+ );
+
+ BisPtr->Free (*BisAppHandle, *BisDataSigInfo);
+ BisPtr->Shutdown (*BisAppHandle);
+ return NULL;
+ }
+
+ return BisPtr;
+}
+
+VOID
+PxebcBisStop (
+ EFI_BIS_PROTOCOL *BisPtr,
+ BIS_APPLICATION_HANDLE BisAppHandle,
+ EFI_BIS_DATA *BisDataSigInfo
+ )
+/*++
+Routine description:
+ Stop the BIS interface and release allocations.
+
+Parameters:
+ BisPtr := Pointer to BIS interface
+ BisAppHandle := BIS application handle
+ BisDataSigInfo := Pointer to BIS signature information data
+
+Returns:
+
+--*/
+{
+ if (BisPtr == NULL) {
+ return ;
+ }
+ //
+ // Free BIS allocated resources and shutdown BIS.
+ // Return TRUE - BIS support is officially detected.
+ //
+ if (BisDataSigInfo != NULL) {
+ BisPtr->Free (BisAppHandle, BisDataSigInfo);
+ }
+
+ BisPtr->Shutdown (BisAppHandle);
+}
+
+BOOLEAN
+PxebcBisVerify (
+ PXE_BASECODE_DEVICE *Private,
+ VOID *FileBuffer,
+ UINTN FileLength,
+ VOID *CredentialBuffer,
+ UINTN CredentialLength
+ )
+/*++
+Routine description:
+ Verify image and credential file.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ FileBuffer := Pointer to image buffer
+ FileLength := Image length in bytes
+ CredentialBuffer := Pointer to credential buffer
+ CredentialLength := Credential length in bytes
+
+Returns:
+ TRUE := verified
+ FALSE := not verified
+--*/
+{
+ EFI_BIS_PROTOCOL *BisPtr;
+ BIS_APPLICATION_HANDLE BisAppHandle;
+ EFI_BIS_DATA FileData;
+ EFI_BIS_DATA CredentialData;
+ EFI_STATUS EfiStatus;
+ BOOLEAN IsVerified;
+
+ if (Private == NULL || FileBuffer == NULL || FileLength == 0 || CredentialBuffer == NULL || CredentialLength == 0) {
+ return FALSE;
+ }
+
+ BisPtr = PxebcBisStart (Private, &BisAppHandle, NULL);
+
+ if (BisPtr == NULL) {
+ return FALSE;
+ }
+
+ FileData.Length = (UINT32) FileLength;
+ FileData.Data = FileBuffer;
+ CredentialData.Length = (UINT32) CredentialLength;
+ CredentialData.Data = CredentialBuffer;
+
+ EfiStatus = BisPtr->VerifyBootObject (
+ BisAppHandle,
+ &CredentialData,
+ &FileData,
+ &IsVerified
+ );
+
+ PxebcBisStop (BisPtr, BisAppHandle, NULL);
+
+ return (BOOLEAN) ((EFI_ERROR (EfiStatus)) ? FALSE : (IsVerified ? TRUE : FALSE));
+}
+
+BOOLEAN
+PxebcBisDetect (
+ PXE_BASECODE_DEVICE *Private
+ )
+/*++
+Routine description:
+ Check for BIS interface presence.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+
+Returns:
+ TRUE := BIS present
+ FALSE := BIS not present
+--*/
+{
+ EFI_BIS_PROTOCOL *BisPtr;
+ BIS_APPLICATION_HANDLE BisAppHandle;
+ EFI_BIS_DATA *BisDataSigInfo;
+
+ BisPtr = PxebcBisStart (Private, &BisAppHandle, &BisDataSigInfo);
+
+ if (BisPtr == NULL) {
+ return FALSE;
+ }
+
+ PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
+
+ return TRUE;
+}
+
+VOID *BCNotifyReg;
+
+EFI_STATUS
+EFIAPI
+BcStart (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN UseIPv6
+ )
+/*++
+
+ Routine Description:
+ Start and initialize the BaseCode protocol, Simple Network protocol and UNDI.
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+ UseIPv6 - Do we want to support IPv6?
+
+ Returns:
+ EFI_SUCCESS
+ EFI_INVALID_PARAMETER
+ EFI_UNSUPPORTED
+ EFI_ALREADY_STARTED
+ EFI_OUT_OF_RESOURCES
+ Status is also returned from SNP.Start() and SNP.Initialize().
+
+--*/
+{
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
+ EFI_STATUS Status;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ //
+ // Make sure BaseCode is not already started.
+ //
+ if (This->Mode->Started) {
+ DEBUG ((EFI_D_WARN, "\nBcStart() BC is already started.\n"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_ALREADY_STARTED;
+ }
+
+#if !SUPPORT_IPV6
+ //
+ // Fail if IPv6 is requested and not supported.
+ //
+ if (UseIPv6) {
+ DEBUG ((EFI_D_WARN, "\nBcStart() IPv6 is not supported.\n"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_UNSUPPORTED;
+ }
+#endif
+ //
+ // Setup shortcuts to SNP protocol and data structure.
+ //
+ SnpPtr = Private->SimpleNetwork;
+ SnpModePtr = SnpPtr->Mode;
+
+ //
+ // Start and initialize SNP.
+ //
+ if (SnpModePtr->State == EfiSimpleNetworkStopped) {
+ StatCode = (*SnpPtr->Start) (SnpPtr);
+
+ if (SnpModePtr->State != EfiSimpleNetworkStarted) {
+ DEBUG ((EFI_D_WARN, "\nBcStart() Could not start SNP.\n"));
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+ }
+ }
+ //
+ // acquire memory for mode and transmit/receive buffers
+ //
+ if (SnpModePtr->State == EfiSimpleNetworkStarted) {
+ StatCode = (*SnpPtr->Initialize) (SnpPtr, 0, 0);
+
+ if (SnpModePtr->State != EfiSimpleNetworkInitialized) {
+ DEBUG ((EFI_D_WARN, "\nBcStart() Could not initialize SNP."));
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+ }
+ }
+ //
+ // Dump debug info.
+ //
+ DEBUG ((EFI_D_INFO, "\nBC Start()"));
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->State %Xh",
+ SnpModePtr->State)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->HwAddressSize %Xh",
+ SnpModePtr->HwAddressSize)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MediaHeaderSize %Xh",
+ SnpModePtr->MediaHeaderSize)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MaxPacketSize %Xh",
+ SnpModePtr->MaxPacketSize)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MacAddressChangeable %Xh",
+ SnpModePtr->MacAddressChangeable)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MultipleTxSupported %Xh",
+ SnpModePtr->MultipleTxSupported)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->CurrentAddress %Xh",
+ *((UINTN *)&SnpModePtr->CurrentAddress))
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->BroadcastAddress %Xh",
+ *((UINTN *)&SnpModePtr->BroadcastAddress))
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->PermanentAddress %Xh",
+ *((UINTN *)&SnpModePtr->PermanentAddress))
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->NvRamSize %Xh",
+ SnpModePtr->NvRamSize)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->NvRamAccessSize %Xh",
+ SnpModePtr->NvRamAccessSize)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->ReceiveFilterMask %Xh",
+ SnpModePtr->ReceiveFilterMask)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->ReceiveFilterSetting %Xh",
+ SnpModePtr->ReceiveFilterSetting)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MCastFilterCount %Xh",
+ SnpModePtr->MCastFilterCount)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MCastFilter %Xh",
+ SnpModePtr->MCastFilter)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->IfType %Xh",
+ SnpModePtr->IfType)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MediaPresentSupported %Xh",
+ SnpModePtr->MediaPresentSupported)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nSnpModePtr->MediaPresent %Xh",
+ SnpModePtr->MediaPresent)
+ );
+
+ //
+ // If media check is supported and there is no media,
+ // return error to caller.
+ //
+ if (SnpModePtr->MediaPresentSupported && !SnpModePtr->MediaPresent) {
+ DEBUG ((EFI_D_WARN, "\nBcStart() Media not present.\n"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NO_MEDIA;
+ }
+ //
+ // Allocate Tx/Rx buffers
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ BUFFER_ALLOCATE_SIZE,
+ (VOID **) &Private->TransmitBufferPtr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (Private->TransmitBufferPtr, BUFFER_ALLOCATE_SIZE);
+ } else {
+ DEBUG ((EFI_D_NET, "\nBcStart() Could not alloc TxBuf.\n"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ BUFFER_ALLOCATE_SIZE,
+ (VOID **) &Private->ReceiveBufferPtr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (Private->ReceiveBufferPtr, BUFFER_ALLOCATE_SIZE);
+ } else {
+ DEBUG ((EFI_D_NET, "\nBcStart() Could not alloc RxBuf.\n"));
+ gBS->FreePool (Private->TransmitBufferPtr);
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ 256,
+ (VOID **) &Private->TftpErrorBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Private->ReceiveBufferPtr);
+ gBS->FreePool (Private->TransmitBufferPtr);
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->AllocatePool (EfiBootServicesData, 256, (VOID **) &Private->TftpAckBuffer);
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Private->TftpErrorBuffer);
+ gBS->FreePool (Private->ReceiveBufferPtr);
+ gBS->FreePool (Private->TransmitBufferPtr);
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initialize private BaseCode instance data
+ //
+ do {
+ Private->RandomPort = (UINT16) (Private->RandomPort + PXE_RND_PORT_LOW + Random (Private));
+ } while (Private->RandomPort < PXE_RND_PORT_LOW);
+
+ Private->Igmpv1TimeoutEvent = NULL;
+ Private->UseIgmpv1Reporting = TRUE;
+ Private->IpLength = IP_ADDRESS_LENGTH (Private->EfiBc.Mode);
+
+ //
+ // Initialize Mode structure
+ //
+ //
+ // check for callback protocol and set boolean
+ //
+ SetMakeCallback (Private);
+ Private->EfiBc.Mode->Started = TRUE;
+ Private->EfiBc.Mode->TTL = DEFAULT_TTL;
+ Private->EfiBc.Mode->ToS = DEFAULT_ToS;
+ Private->EfiBc.Mode->UsingIpv6 = UseIPv6;
+ Private->EfiBc.Mode->DhcpDiscoverValid = FALSE;
+ Private->EfiBc.Mode->DhcpAckReceived = FALSE;
+ Private->EfiBc.Mode->ProxyOfferReceived = FALSE;
+ Private->EfiBc.Mode->PxeDiscoverValid = FALSE;
+ Private->EfiBc.Mode->PxeReplyReceived = FALSE;
+ Private->EfiBc.Mode->PxeBisReplyReceived = FALSE;
+ Private->EfiBc.Mode->IcmpErrorReceived = FALSE;
+ Private->EfiBc.Mode->TftpErrorReceived = FALSE;
+ ZeroMem (&Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));
+ ZeroMem (&Private->EfiBc.Mode->SubnetMask, sizeof (EFI_IP_ADDRESS));
+ Private->EfiBc.Mode->IpFilter.Filters = 0;
+ Private->EfiBc.Mode->IpFilter.IpCnt = 0;
+ Private->EfiBc.Mode->ArpCacheEntries = 0;
+ Private->EfiBc.Mode->RouteTableEntries = 0;
+ ZeroMem (&Private->EfiBc.Mode->IcmpError, sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR));
+ ZeroMem (&Private->EfiBc.Mode->TftpError, sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR));
+
+ //
+ // Set to PXE_TRUE by the BC constructor if this BC implementation
+ // supports IPv6.
+ //
+ Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6;
+
+#if SUPPORT_IPV6
+ Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported;
+#else
+ Private->EfiBc.Mode->Ipv6Available = FALSE;
+#endif
+ //
+ // Set to TRUE by the BC constructor if this BC implementation
+ // supports BIS.
+ //
+ Private->EfiBc.Mode->BisSupported = TRUE;
+ Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private);
+
+ //
+ // This field is set to PXE_TRUE by the BC Start() function. When this
+ // field is PXE_TRUE, ARP packets are sent as needed to get IP and MAC
+ // addresses. This can cause unexpected delays in the DHCP(), Discover()
+ // and MTFTP() functions. Setting this to PXE_FALSE will cause these
+ // functions to fail if the required IP/MAC information is not in the
+ // ARP cache. The value of this field can be changed by an application
+ // at any time.
+ //
+ Private->EfiBc.Mode->AutoArp = TRUE;
+
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BcStop (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This
+ )
+/*++
+
+ Routine Description:
+ Stop the BaseCode protocol, Simple Network protocol and UNDI.
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+
+ Returns:
+
+ 0 - Successfully stopped
+ !0 - Failed
+--*/
+{
+ //
+ // Lock the instance data
+ //
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ PxebcMode = Private->EfiBc.Mode;
+ SnpPtr = Private->SimpleNetwork;
+ SnpModePtr = SnpPtr->Mode;
+
+ //
+ // Issue BC command
+ //
+ StatCode = EFI_NOT_STARTED;
+
+ if (SnpModePtr->State == EfiSimpleNetworkInitialized) {
+ StatCode = (*SnpPtr->Shutdown) (SnpPtr);
+ }
+
+ if (SnpModePtr->State == EfiSimpleNetworkStarted) {
+ StatCode = (*SnpPtr->Stop) (SnpPtr);
+ }
+
+ if (Private->TransmitBufferPtr != NULL) {
+ gBS->FreePool (Private->TransmitBufferPtr);
+ Private->TransmitBufferPtr = NULL;
+ }
+
+ if (Private->ReceiveBufferPtr != NULL) {
+ gBS->FreePool (Private->ReceiveBufferPtr);
+ Private->ReceiveBufferPtr = NULL;
+ }
+
+ if (Private->ArpBuffer != NULL) {
+ gBS->FreePool (Private->ArpBuffer);
+ Private->ArpBuffer = NULL;
+ }
+
+ if (Private->TftpErrorBuffer != NULL) {
+ gBS->FreePool (Private->TftpErrorBuffer);
+ Private->TftpErrorBuffer = NULL;
+ }
+
+ if (Private->TftpAckBuffer != NULL) {
+ gBS->FreePool (Private->TftpAckBuffer);
+ Private->TftpAckBuffer = NULL;
+ }
+
+ if (Private->Igmpv1TimeoutEvent != NULL) {
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
+ Private->Igmpv1TimeoutEvent = NULL;
+ }
+
+ Private->FileSize = 0;
+ Private->EfiBc.Mode->Started = FALSE;
+
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+const IPV4_ADDR AllSystemsGroup = { { 224, 0, 0, 1 } };
+
+EFI_STATUS
+IpFilter (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *Filter
+ )
+/*++
+
+ Routine Description:
+ Set up the IP filter
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+ Filter - Pointer to the filter
+
+ Returns:
+
+ 0 - Successfully set the filter
+ !0 - Failed
+--*/
+{
+ EFI_STATUS StatCode;
+ EFI_MAC_ADDRESS MACadds[PXE_IP_FILTER_SIZE];
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;
+ UINT32 Enable;
+ UINT32 Disable;
+ UINTN Index;
+ UINTN Index2;
+
+ PxebcMode = Private->EfiBc.Mode;
+ SnpPtr = Private->SimpleNetwork;
+ SnpModePtr = SnpPtr->Mode;
+
+ //
+ // validate input parameters
+ // must have a filter
+ // must not have any extra filter bits set
+ //
+ if (Filter == NULL ||
+ (Filter->Filters &~FILTER_BITS)
+ //
+ // must not have a count which is too large or with no IP list
+ //
+ ||
+ (Filter->IpCnt && (!Filter->IpList || Filter->IpCnt > PXE_IP_FILTER_SIZE))
+ //
+ // must not have incompatible filters - promiscuous incompatible with anything else
+ //
+ ||
+ (
+ (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) &&
+ ((Filter->Filters &~EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) || Filter->IpCnt)
+ )
+ ) {
+ DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #1"));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // promiscuous multicast incompatible with multicast in IP list
+ //
+ if (Filter->IpCnt && (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST)) {
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {
+ if (IS_MULTICAST (&Filter->IpList[Index])) {
+ DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #2"));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ //
+ // leave groups for all those multicast which are no longer enabled
+ //
+ for (Index = 0; Index < PxebcMode->IpFilter.IpCnt; ++Index) {
+ if (!IS_MULTICAST (&PxebcMode->IpFilter.IpList[Index])) {
+ continue;
+ }
+
+ for (Index2 = 0; Index2 < Filter->IpCnt; ++Index2) {
+ if (!CompareMem (&PxebcMode->IpFilter.IpList[Index], &Filter->IpList[Index2], IP_ADDRESS_LENGTH (PxebcMode))) {
+ //
+ // still enabled
+ //
+ break;
+ }
+ }
+ //
+ // if we didn't find it, remove from group
+ //
+ if (Index2 == Filter->IpCnt) {
+ IgmpLeaveGroup (Private, &PxebcMode->IpFilter.IpList[Index]);
+ }
+ }
+ //
+ // set enable bits, convert multicast ip adds, join groups
+ // allways leave receive broadcast enabled at hardware layer
+ //
+ Index2 = 0;
+
+ if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {
+ Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ } else {
+ if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) {
+ Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ } else {
+ Enable = EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {
+ CopyMem (&(PxebcMode->IpFilter.IpList[Index]), &(Filter->IpList[Index]), sizeof (EFI_IP_ADDRESS));
+
+ if (IS_MULTICAST (&Filter->IpList[Index])) {
+ EFI_IP_ADDRESS *TmpIp;
+
+ Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+
+ //
+ // if this is the first group, add the all systems group to mcast list
+ //
+ if (!Index2)
+ {
+#if SUPPORT_IPV6
+ if (PxebcMode->UsingIpv6) {
+ //
+ // TBD
+ //
+ } else
+#endif
+ TmpIp = (EFI_IP_ADDRESS *) &AllSystemsGroup;
+ --Index;
+ } else {
+ TmpIp = (EFI_IP_ADDRESS *) &Filter->IpList[Index];
+ }
+ //
+ // get MAC address of IP
+ //
+ StatCode = (*SnpPtr->MCastIpToMac) (SnpPtr, PxebcMode->UsingIpv6, TmpIp, &MACadds[Index2++]);
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_INFO,
+ "\nIpFilter() Exit #2 %Xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ return StatCode;
+ }
+ } else {
+ Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+ }
+ }
+ }
+
+ if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) {
+ Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+ }
+ }
+ //
+ // if nothing changed, just return
+ //
+ DEBUG (
+ (EFI_D_INFO,
+ "\nsnp->ReceiveFilterSetting == %Xh Filter->IpCnt == %Xh",
+ SnpModePtr->ReceiveFilterSetting,
+ Filter->IpCnt)
+ );
+
+ if (SnpModePtr->ReceiveFilterSetting == Enable && !Filter->IpCnt) {
+ DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #4"));
+ return EFI_SUCCESS;
+ }
+ //
+ // disable those currently set but not set in new filter
+ //
+ Disable = SnpModePtr->ReceiveFilterSetting &~Enable;
+
+ StatCode = SnpPtr->ReceiveFilters (SnpPtr, Enable, Disable, FALSE, Index2, MACadds);
+
+ PxebcMode->IpFilter.IpCnt = Filter->IpCnt;
+
+ //
+ // join groups for all multicast in list
+ //
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {
+ if (IS_MULTICAST (&Filter->IpList[Index])) {
+ IgmpJoinGroup (Private, &Filter->IpList[Index]);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "\nIpFilter() Exit #5 %Xh (%r)", StatCode, StatCode));
+
+ return StatCode;
+}
+
+EFI_STATUS
+EFIAPI
+BcIpFilter (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *Filter
+ )
+/*++
+
+ Routine Description:
+ Call the IP filter
+
+ Arguments:
+ Private - Pointer to Pxe BaseCode Protocol
+ Filter - Pointer to the filter
+
+ Returns:
+
+ 0 - Successfully set the filter
+ !0 - Failed
+--*/
+{
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ if (Filter == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Issue BC command
+ //
+ StatCode = IpFilter (Private, Filter);
+
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+EFI_STATUS
+EFIAPI
+BcSetParameters (
+ EFI_PXE_BASE_CODE_PROTOCOL *This,
+ BOOLEAN *AutoArpPtr,
+ BOOLEAN *SendGuidPtr,
+ UINT8 *TimeToLivePtr,
+ UINT8 *TypeOfServicePtr,
+ BOOLEAN *MakeCallbackPtr
+ )
+/*++
+
+ Routine Description:
+ Set the Base Code behavior parameters
+
+ Arguments:
+ This - Pointer to Pxe BaseCode Protocol
+ AutoArpPtr - Boolean to do ARP stuff
+ SendGuidPtr - Boolean whether or not to send GUID info
+ TimeToLivePtr - Value for Total time to live
+ TypeOfServicePtr - Value for Type of Service
+ MakeCallbackPtr - Boolean to determine if we make callbacks
+
+ Returns:
+
+ 0 - Successfully set the parameters
+ !0 - Failed
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ EFI_GUID TmpGuid;
+ CHAR8 *SerialNumberPtr;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "\nSetParameters() Entry. "));
+
+ PxebcMode = Private->EfiBc.Mode;
+ StatCode = EFI_SUCCESS;
+
+ if (SendGuidPtr != NULL) {
+ if (*SendGuidPtr) {
+ if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (&TmpGuid, &SerialNumberPtr) != EFI_SUCCESS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (MakeCallbackPtr != NULL) {
+ if (*MakeCallbackPtr) {
+ if (!SetMakeCallback (Private)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ PxebcMode->MakeCallbacks = *MakeCallbackPtr;
+ }
+
+ if (AutoArpPtr != NULL) {
+ PxebcMode->AutoArp = *AutoArpPtr;
+ }
+
+ if (SendGuidPtr != NULL) {
+ PxebcMode->SendGUID = *SendGuidPtr;
+ }
+
+ if (TimeToLivePtr != NULL) {
+ PxebcMode->TTL = *TimeToLivePtr;
+ }
+
+ if (TypeOfServicePtr != NULL) {
+ PxebcMode->ToS = *TypeOfServicePtr;
+ }
+ //
+ // Unlock the instance data
+ //
+ DEBUG ((EFI_D_INFO, "\nSetparameters() Exit = %xh ", StatCode));
+
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+//
+// //////////////////////////////////////////////////////////
+//
+// BC Set Station IP Routine
+//
+EFI_STATUS
+EFIAPI
+BcSetStationIP (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN EFI_IP_ADDRESS *StationIpPtr,
+ IN EFI_IP_ADDRESS *SubnetMaskPtr
+ )
+/*++
+
+ Routine Description:
+ Set the station IP address
+
+ Arguments:
+ This - Pointer to Pxe BaseCode Protocol
+ StationIpPtr - Pointer to the requested IP address to set in base code
+ SubnetMaskPtr - Pointer to the requested subnet mask for the base code
+
+ Returns:
+
+ EFI_SUCCESS - Successfully set the parameters
+ EFI_NOT_STARTED - BC has not started
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ PxebcMode = Private->EfiBc.Mode;
+
+ if (StationIpPtr != NULL) {
+ CopyMem (&PxebcMode->StationIp, StationIpPtr, sizeof (EFI_IP_ADDRESS));
+ Private->GoodStationIp = TRUE;
+ }
+
+ if (SubnetMaskPtr != NULL) {
+ CopyMem (&PxebcMode->SubnetMask, SubnetMaskPtr, sizeof (EFI_IP_ADDRESS));
+ }
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+
+ return EFI_SUCCESS;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding = {
+ PxeBcDriverSupported,
+ PxeBcDriverStart,
+ PxeBcDriverStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+PxeBcDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+ Routine Description:
+ Test to see if this driver supports Controller. Any Controller
+ than contains a Snp protocol can be supported.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_ALREADY_STARTED - This driver is already running on this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &SnpPtr,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+PxeBcDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+ Routine Description:
+ Start the Base code driver.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_ALREADY_STARTED - This driver is already running on this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ PXE_BASECODE_DEVICE *Private;
+ LOADFILE_DEVICE *pLF;
+
+ //
+ // Allocate structures needed by BaseCode and LoadFile protocols.
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (PXE_BASECODE_DEVICE),
+ (VOID **) &Private
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (Private, sizeof (PXE_BASECODE_DEVICE));
+ } else {
+ DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc PXE_BASECODE_DEVICE structure.\n"));
+ return Status;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (LOADFILE_DEVICE),
+ (VOID **) &pLF
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (pLF, sizeof (LOADFILE_DEVICE));
+ } else {
+ DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc LOADFILE_DEVICE structure.\n"));
+ gBS->FreePool (Private);
+ return Status;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_PXE_BASE_CODE_MODE),
+ (VOID **) &Private->EfiBc.Mode
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (Private->EfiBc.Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
+ } else {
+ DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc Mode structure.\n"));
+ gBS->FreePool (Private);
+ gBS->FreePool (pLF);
+ return Status;
+ }
+ //
+ // Lock access, just in case
+ //
+ EfiInitializeLock (&Private->Lock, EFI_TPL_CALLBACK);
+ EfiAcquireLock (&Private->Lock);
+
+ EfiInitializeLock (&pLF->Lock, EFI_TPL_CALLBACK);
+ EfiAcquireLock (&pLF->Lock);
+
+ //
+ // Initialize PXE structure
+ //
+ //
+ // First initialize the internal 'private' data that the application
+ // does not see.
+ //
+ Private->Signature = PXE_BASECODE_DEVICE_SIGNATURE;
+ Private->Handle = Controller;
+
+ //
+ // Get the NII interface
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &Private->NiiPtr,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ (VOID **) &Private->NiiPtr,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto PxeBcError;
+ }
+ }
+ //
+ // Get the Snp interface
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &Private->SimpleNetwork,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto PxeBcError;
+ }
+
+ //
+ // Next, initialize the external 'public' data that
+ // the application does see.
+ //
+ Private->EfiBc.Revision = EFI_PXE_BASE_CODE_INTERFACE_REVISION;
+ Private->EfiBc.Start = BcStart;
+ Private->EfiBc.Stop = BcStop;
+ Private->EfiBc.Dhcp = BcDhcp;
+ Private->EfiBc.Discover = BcDiscover;
+ Private->EfiBc.Mtftp = BcMtftp;
+ Private->EfiBc.UdpWrite = BcUdpWrite;
+ Private->EfiBc.UdpRead = BcUdpRead;
+ Private->EfiBc.Arp = BcArp;
+ Private->EfiBc.SetIpFilter = BcIpFilter;
+ Private->EfiBc.SetParameters = BcSetParameters;
+ Private->EfiBc.SetStationIp = BcSetStationIP;
+ Private->EfiBc.SetPackets = BcSetPackets;
+
+ //
+ // Initialize BaseCode Mode structure
+ //
+ Private->EfiBc.Mode->Started = FALSE;
+ Private->EfiBc.Mode->TTL = DEFAULT_TTL;
+ Private->EfiBc.Mode->ToS = DEFAULT_ToS;
+ Private->EfiBc.Mode->UsingIpv6 = FALSE;
+ Private->EfiBc.Mode->AutoArp = TRUE;
+
+ //
+ // Set to PXE_TRUE by the BC constructor if this BC
+ // implementation supports IPv6.
+ //
+ Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6;
+
+#if SUPPORT_IPV6
+ Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported;
+#else
+ Private->EfiBc.Mode->Ipv6Available = FALSE;
+#endif
+ //
+ // Set to TRUE by the BC constructor if this BC
+ // implementation supports BIS.
+ //
+ Private->EfiBc.Mode->BisSupported = TRUE;
+ Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private);
+
+ //
+ // Initialize LoadFile structure.
+ //
+ pLF->Signature = LOADFILE_DEVICE_SIGNATURE;
+ pLF->LoadFile.LoadFile = LoadFile;
+ pLF->Private = Private;
+
+ //
+ // Install protocol interfaces.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiPxeBaseCodeProtocolGuid,
+ &Private->EfiBc,
+ &gEfiLoadFileProtocolGuid,
+ &pLF->LoadFile,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ goto PxeBcError;
+ }
+ //
+ // Release locks.
+ //
+ EfiReleaseLock (&pLF->Lock);
+ EfiReleaseLock (&Private->Lock);
+ return Status;
+
+PxeBcError: ;
+ gBS->FreePool (Private->EfiBc.Mode);
+ gBS->FreePool (Private);
+ gBS->FreePool (pLF);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+PxeBcDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+ Routine Description:
+ Stop the Base code driver.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test.
+ NumberOfChildren - Not used
+ ChildHandleBuffer - Not used
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_ALREADY_STARTED - This driver is already running on this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_LOAD_FILE_PROTOCOL *LfProtocol;
+ LOADFILE_DEVICE *LoadDevice;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiLoadFileProtocolGuid,
+ (VOID **) &LfProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ LoadDevice = EFI_LOAD_FILE_DEV_FROM_THIS (LfProtocol);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiLoadFileProtocolGuid,
+ &LoadDevice->LoadFile,
+ &gEfiPxeBaseCodeProtocolGuid,
+ &LoadDevice->Private->EfiBc,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->FreePool (LoadDevice->Private->EfiBc.Mode);
+ gBS->FreePool (LoadDevice->Private);
+ gBS->FreePool (LoadDevice);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+InitializeBCDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+ Routine Description:
+ Initialize the base code drivers and install the driver binding
+
+ Arguments:
+ Standard EFI Image Entry
+
+ Returns:
+ EFI_SUCCESS - This driver was successfully bound
+
+--*/
+{
+ InitArpHeader ();
+ OptionsStrucInit ();
+
+ return EFI_SUCCESS;
+}
+
+/* eof - bc.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h
new file mode 100644
index 0000000..a391709
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/bc.h
@@ -0,0 +1,499 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ bc.h
+
+Abstract:
+
+--*/
+
+#ifndef _BC_H
+#define _BC_H
+
+#ifndef EFI_MIN
+#define EFI_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
+#define CALLBACK_INTERVAL 100 // ten times a second
+#define FILTER_BITS (EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | \
+ EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST | \
+ EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS | \
+ EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST \
+ )
+
+#define WAIT_TX_TIMEOUT 1000
+
+#define SUPPORT_IPV6 0
+
+#define PXE_BASECODE_DEVICE_SIGNATURE EFI_SIGNATURE_32('p','x','e','d')
+
+//
+// Determine the classes of IPv4 address
+//
+#define IS_CLASSA_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0x80) == 0x00)
+#define IS_CLASSB_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0xc0) == 0x80)
+#define IS_CLASSC_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0xe0) == 0xc0)
+#define IS_INADDR_UNICAST(x) ((IS_CLASSA_IPADDR(x) || IS_CLASSB_IPADDR(x) || IS_CLASSC_IPADDR(x)) && (((EFI_IP_ADDRESS*)x)->Addr[0] != 0) )
+
+//
+// Definitions for internet group management protocol version 2 message
+// structure
+// Per RFC 2236, November 1997
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 Type;
+ UINT8 MaxRespTime; // in tenths of a second
+ UINT16 Checksum; // ones complement of ones complement sum of
+ // 16 bit words of message
+ UINT32 GroupAddress; // for general query, all systems group,
+ // for group specific, the group
+} IGMPV2_MESSAGE;
+
+#define IGMP_TYPE_QUERY 0x11
+#define IGMP_TYPE_REPORT 0x16
+#define IGMP_TYPE_V1REPORT 0x12
+#define IGMP_TYPE_LEAVE_GROUP 0x17
+
+#define IGMP_DEFAULT_MAX_RESPONSE_TIME 10 // 10 second default
+#pragma pack()
+
+#define MAX_MCAST_GROUPS 8 // most we allow ourselves to join at once
+#define MAX_OFFERS 16
+
+typedef struct {
+ UINTN Signature;
+ EFI_LOCK Lock;
+ BOOLEAN ShowErrorMessages;
+ EFI_PXE_BASE_CODE_PROTOCOL EfiBc;
+ EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *CallbackProtocolPtr;
+ EFI_HANDLE Handle;
+
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiPtr;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
+ UINT8 *TransmitBufferPtr;
+ UINT8 *ReceiveBufferPtr;
+ EFI_PXE_BASE_CODE_FUNCTION Function;
+
+ UINTN OldestArpEntry;
+ UINTN MCastGroupCount;
+ EFI_EVENT Igmpv1TimeoutEvent;
+ BOOLEAN UseIgmpv1Reporting;
+ EFI_EVENT IgmpGroupEvent[MAX_MCAST_GROUPS];
+ UINT16 RandomPort;
+
+#if SUPPORT_IPV6
+ //
+ // TBD
+ //
+#else
+ UINT32 MCastGroup[MAX_MCAST_GROUPS];
+#endif
+
+ BOOLEAN GoodStationIp;
+ BOOLEAN DidTransmit;
+ UINTN IpLength;
+ VOID *DhcpPacketBuffer;
+ UINTN FileSize;
+ VOID *BootServerReceiveBuffer;
+ EFI_IP_ADDRESS ServerIp;
+
+ //
+ // work area
+ // for dhcp
+ //
+ VOID *ReceiveBuffers;
+ VOID *TransmitBuffer;
+ UINTN NumOffersReceived;
+ UINT16 TotalSeconds;
+
+ //
+ // arrays for different types of offers
+ //
+ UINT8 ServerCount[4];
+ UINT8 OfferCount[4][MAX_OFFERS];
+ UINT8 GotBootp;
+ UINT8 GotProxy[4];
+ UINT8 BinlProxies[MAX_OFFERS];
+
+ UINT8 *ArpBuffer;
+ UINT8 *TftpAckBuffer;
+ UINT8 *TftpErrorBuffer;
+ IGMPV2_MESSAGE IgmpMessage;
+ BOOLEAN BigBlkNumFlag;
+ UINT8 Timeout;
+ UINT16 RandomSeed;
+} PXE_BASECODE_DEVICE;
+
+//
+// type index
+//
+#define DHCP_ONLY_IX 0
+#define PXE10_IX 1
+#define WfM11a_IX 2
+#define BINL_IX 3
+
+#define PXE_RND_PORT_LOW 2070
+
+#define PXE_MAX_PRINT_BUFFER 128
+
+//
+//
+//
+#define LOADFILE_DEVICE_SIGNATURE EFI_SIGNATURE_32('p','x','e','l')
+
+typedef struct {
+ UINTN Signature;
+ EFI_LOCK Lock;
+ EFI_LOAD_FILE_PROTOCOL LoadFile;
+ PXE_BASECODE_DEVICE *Private;
+} LOADFILE_DEVICE;
+
+#define EFI_BASE_CODE_DEV_FROM_THIS(a) CR (a, PXE_BASECODE_DEVICE, efi_bc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+#define EFI_LOAD_FILE_DEV_FROM_THIS(a) CR (a, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE)
+
+EFI_BIS_PROTOCOL *
+PxebcBisStart (
+ PXE_BASECODE_DEVICE *Private,
+ BIS_APPLICATION_HANDLE *BisAppHandle,
+ EFI_BIS_DATA **BisDataSigInfo
+ )
+;
+
+VOID
+PxebcBisStop (
+ EFI_BIS_PROTOCOL *Bis,
+ BIS_APPLICATION_HANDLE BisAppHandle,
+ EFI_BIS_DATA *BisDataSigInfo
+ )
+;
+
+BOOLEAN
+PxebcBisVerify (
+ PXE_BASECODE_DEVICE *Private,
+ VOID *FileBuffer,
+ UINTN FileBufferLength,
+ VOID *CredentialBuffer,
+ UINTN CredentialBufferLength
+ )
+;
+
+BOOLEAN
+PxebcBisDetect (
+ PXE_BASECODE_DEVICE *Private
+ )
+;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPxeBcDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPxeBcComponentName;
+
+//
+// //////////////////////////////////////////////////////////
+//
+// prototypes
+//
+EFI_STATUS
+EFIAPI
+InitializeBCDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcStart (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN UseIpv6
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcStop (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcDhcp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN SortOffers
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcDiscover (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN UINT16 Type,
+ IN UINT16 *Layer,
+ IN BOOLEAN UseBis,
+ IN EFI_PXE_BASE_CODE_DISCOVER_INFO * Info OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcMtftp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
+ IN OUT VOID *BufferPtr,
+ IN BOOLEAN Overwrite,
+ IN OUT UINT64 *BufferSize,
+ IN UINTN *BlockSize OPTIONAL,
+ IN EFI_IP_ADDRESS * ServerIp,
+ IN UINT8 *Filename,
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO * Info OPTIONAL,
+ IN BOOLEAN DontUseBuffer
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcUdpWrite (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN EFI_IP_ADDRESS *DestIp,
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort,
+ IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcUdpRead (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcArp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * IpAddr,
+ IN EFI_MAC_ADDRESS * MacAddr OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcIpFilter (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcSetParameters (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN BOOLEAN *NewAutoArp, OPTIONAL
+ IN BOOLEAN *NewSendGUID, OPTIONAL
+ IN UINT8 *NewTTL, OPTIONAL
+ IN UINT8 *NewToS, OPTIONAL
+ IN BOOLEAN *NewMakeCallback OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcSetStationIP (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * NewStationIp, OPTIONAL
+ IN EFI_IP_ADDRESS * NewSubnetMask OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcSetPackets (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ BOOLEAN *NewDhcpDiscoverValid, OPTIONAL
+ BOOLEAN *NewDhcpAckReceived, OPTIONAL
+ BOOLEAN *NewProxyOfferReceived, OPTIONAL
+ BOOLEAN *NewPxeDiscoverValid, OPTIONAL
+ BOOLEAN *NewPxeReplyReceived, OPTIONAL
+ BOOLEAN *NewPxeBisReplyReceived, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+LoadFile (
+ IN EFI_LOAD_FILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+;
+
+EFI_STATUS
+PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
+ IN EFI_GUID *SystemGuid,
+ OUT CHAR8 **SystemSerialNumber
+ )
+;
+
+UINTN
+EFIAPI
+AsciiPrint (
+ IN CONST CHAR8 *Format,
+ ...
+ )
+;
+
+//
+// Define SMBIOS tables.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 AnchorString[4];
+ UINT8 EntryPointStructureChecksum;
+ UINT8 EntryPointLength;
+ UINT8 MajorVersion;
+ UINT8 MinorVersion;
+ UINT16 MaxStructureSize;
+ UINT8 EntryPointRevision;
+ UINT8 FormattedArea[5];
+ UINT8 IntermediateAnchorString[5];
+ UINT8 IntermediateChecksum;
+ UINT16 TableLength;
+ UINT32 TableAddress;
+ UINT16 NumberOfSmbiosStructures;
+ UINT8 SmbiosBcdRevision;
+} SMBIOS_STRUCTURE_TABLE;
+
+//
+// Please note that SMBIOS structures can be odd byte aligned since the
+// unformated section of each record is a set of arbitrary size strings.
+//
+typedef struct {
+ UINT8 Type;
+ UINT8 Length;
+ UINT8 Handle[2];
+} SMBIOS_HEADER;
+
+typedef UINT8 SMBIOS_STRING;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Vendor;
+ SMBIOS_STRING BiosVersion;
+ UINT8 BiosSegment[2];
+ SMBIOS_STRING BiosReleaseDate;
+ UINT8 BiosSize;
+ UINT8 BiosCharacteristics[8];
+} SMBIOS_TYPE0;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Manufacturer;
+ SMBIOS_STRING ProductName;
+ SMBIOS_STRING Version;
+ SMBIOS_STRING SerialNumber;
+
+ //
+ // always byte copy this data to prevent alignment faults!
+ //
+ EFI_GUID Uuid;
+
+ UINT8 WakeUpType;
+} SMBIOS_TYPE1;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Manufacturer;
+ SMBIOS_STRING ProductName;
+ SMBIOS_STRING Version;
+ SMBIOS_STRING SerialNumber;
+} SMBIOS_TYPE2;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Manufacturer;
+ UINT8 Type;
+ SMBIOS_STRING Version;
+ SMBIOS_STRING SerialNumber;
+ SMBIOS_STRING AssetTag;
+ UINT8 BootupState;
+ UINT8 PowerSupplyState;
+ UINT8 ThermalState;
+ UINT8 SecurityStatus;
+ UINT8 OemDefined[4];
+} SMBIOS_TYPE3;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ UINT8 Socket;
+ UINT8 ProcessorType;
+ UINT8 ProcessorFamily;
+ SMBIOS_STRING ProcessorManufacture;
+ UINT8 ProcessorId[8];
+ SMBIOS_STRING ProcessorVersion;
+ UINT8 Voltage;
+ UINT8 ExternalClock[2];
+ UINT8 MaxSpeed[2];
+ UINT8 CurrentSpeed[2];
+ UINT8 Status;
+ UINT8 ProcessorUpgrade;
+ UINT8 L1CacheHandle[2];
+ UINT8 L2CacheHandle[2];
+ UINT8 L3CacheHandle[2];
+} SMBIOS_TYPE4;
+
+typedef union {
+ SMBIOS_HEADER *Hdr;
+ SMBIOS_TYPE0 *Type0;
+ SMBIOS_TYPE1 *Type1;
+ SMBIOS_TYPE2 *Type2;
+ SMBIOS_TYPE3 *Type3;
+ SMBIOS_TYPE4 *Type4;
+ UINT8 *Raw;
+} SMBIOS_STRUCTURE_POINTER;
+#pragma pack()
+
+#include "ip.h"
+#include "dhcp.h"
+#include "tftp.h"
+
+#endif /* _BC_H */
+
+/* EOF - bc.h */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml b/EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml
new file mode 100644
index 0000000..8ead9ea
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/build.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="BC"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Network\PxeBc\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="BC">
+ <GenBuild baseName="BC" mbdFilename="${MODULE_DIR}\BC.mbd" msaFilename="${MODULE_DIR}\BC.msa"/>
+ </target>
+ <target depends="BC_clean" name="clean"/>
+ <target depends="BC_cleanall" name="cleanall"/>
+ <target name="BC_clean">
+ <OutputDirSetup baseName="BC" mbdFilename="${MODULE_DIR}\BC.mbd" msaFilename="${MODULE_DIR}\BC.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\BC_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\BC_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="BC_cleanall">
+ <OutputDirSetup baseName="BC" mbdFilename="${MODULE_DIR}\BC.mbd" msaFilename="${MODULE_DIR}\BC.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\BC_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\BC_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**BC*"/>
+ </delete>
+ </target>
+</project> \ No newline at end of file
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h
new file mode 100644
index 0000000..cd448b3
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/dhcp.h
@@ -0,0 +1,627 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+--*/
+
+#ifndef _DHCP_H
+#define _DHCP_H
+
+//
+// Definitions for DHCP version 4 UDP packet.
+// The field names in this structure are defined and described in RFC 2131.
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 op;
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY 2
+
+ UINT8 htype;
+ UINT8 hlen;
+ UINT8 hops;
+ UINT32 xid;
+ UINT16 secs;
+ UINT16 flags;
+#define DHCP_BROADCAST_FLAG 0x8000
+
+ UINT32 ciaddr;
+ UINT32 yiaddr;
+ UINT32 siaddr;
+ UINT32 giaddr;
+ UINT8 chaddr[16];
+ UINT8 sname[64];
+ UINT8 file[128];
+ UINT8 options[312];
+#define OP_PAD 0
+#define OP_END 255
+#define OP_SUBNET_MASK 1
+#define OP_TIME_OFFSET 2
+#define OP_ROUTER_LIST 3
+#define OP_TIME_SERVERS 4
+#define OP_NAME_SERVERS 5
+#define OP_DNS_SERVERS 6
+#define OP_LOG_SERVERS 7
+#define OP_COOKIE_SERVERS 8
+#define OP_LPR_SREVERS 9
+#define OP_IMPRESS_SERVERS 10
+#define OP_RES_LOC_SERVERS 11
+#define OP_HOST_NAME 12
+#define OP_BOOT_FILE_SZ 13
+#define OP_DUMP_FILE 14
+#define OP_DOMAIN_NAME 15
+#define OP_SWAP_SERVER 16
+#define OP_ROOT_PATH 17
+#define OP_EXTENSION_PATH 18
+#define OP_IP_FORWARDING 19
+#define OP_NON_LOCAL_SRC_RTE 20
+#define OP_POLICY_FILTER 21
+#define OP_MAX_DATAGRAM_SZ 22
+#define OP_DEFAULT_TTL 23
+#define OP_MTU_AGING_TIMEOUT 24
+#define OP_MTU_SIZES 25
+#define OP_MTU_TO_USE 26
+#define OP_ALL_SUBNETS_LOCAL 27
+#define OP_BROADCAST_ADD 28
+#define OP_PERFORM_MASK_DISCOVERY 29
+#define OP_RESPOND_TO_MASK_REQ 30
+#define OP_PERFORM_ROUTER_DISCOVERY 31
+#define OP_ROUTER_SOLICIT_ADDRESS 32
+#define OP_STATIC_ROUTER_LIST 33
+#define OP_USE_ARP_TRAILERS 34
+#define OP_ARP_CACHE_TIMEOUT 35
+#define OP_ETHERNET_ENCAPSULATION 36
+#define OP_TCP_DEFAULT_TTL 37
+#define OP_TCP_KEEP_ALIVE_INT 38
+#define OP_KEEP_ALIVE_GARBAGE 39
+#define OP_NIS_DOMAIN_NAME 40
+#define OP_NIS_SERVERS 41
+#define OP_NTP_SERVERS 42
+#define OP_VENDOR_SPECIFIC 43
+#define VEND_PXE_MTFTP_IP 1
+#define VEND_PXE_MTFTP_CPORT 2
+#define VEND_PXE_MTFTP_SPORT 3
+#define VEND_PXE_MTFTP_TMOUT 4
+#define VEND_PXE_MTFTP_DELAY 5
+#define VEND_PXE_DISCOVERY_CONTROL 6
+#define VEND_PXE_DISCOVERY_MCAST_ADDR 7
+#define VEND_PXE_BOOT_SERVERS 8
+#define VEND_PXE_BOOT_MENU 9
+#define VEND_PXE_BOOT_PROMPT 10
+#define VEND_PXE_MCAST_ADDRS_ALLOC 11
+#define VEND_PXE_CREDENTIAL_TYPES 12
+#define VEND_PXE_BOOT_ITEM 71
+#define OP_NBNS_SERVERS 44
+#define OP_NBDD_SERVERS 45
+#define OP_NETBIOS_NODE_TYPE 46
+#define OP_NETBIOS_SCOPE 47
+#define OP_XWINDOW_SYSTEM_FONT_SERVERS 48
+#define OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49
+#define OP_DHCP_REQ_IP_ADD 50
+#define OP_DHCP_LEASE_TIME 51
+#define OP_DHCP_OPTION_OVERLOAD 52
+#define OVLD_FILE 1
+#define OVLD_SRVR_NAME 2
+#define OP_DHCP_MESSAGE_TYPE 53
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+#define OP_DHCP_SERVER_IP 54
+#define OP_DHCP_PARM_REQ_LIST 55
+#define OP_DHCP_ERROR_MESSAGE 56
+#define OP_DHCP_MAX_MESSAGE_SZ 57
+#define OP_DHCP_RENEWAL_TIME 58
+#define OP_DHCP_REBINDING_TIME 59
+#define OP_DHCP_CLASS_IDENTIFIER 60
+#define OP_DHCP_CLIENT_IDENTIFIER 61
+#define OP_NISPLUS_DOMAIN_NAME 64
+#define OP_NISPLUS_SERVERS 65
+#define OP_DHCP_TFTP_SERVER_NAME 66
+#define OP_DHCP_BOOTFILE 67
+#define OP_MOBILE_IP_HOME_AGENTS 68
+#define OP_SMPT_SERVERS 69
+#define OP_POP3_SERVERS 70
+#define OP_NNTP_SERVERS 71
+#define OP_WWW_SERVERS 72
+#define OP_FINGER_SERVERS 73
+#define OP_IRC_SERVERS 74
+#define OP_STREET_TALK_SERVERS 75
+#define OP_STREET_TALK_DIR_ASSIST_SERVERS 76
+#define OP_NDS_SERVERS 85
+#define OP_NDS_TREE_NAME 86
+#define OP_NDS_CONTEXT 87
+#define OP_DHCP_SYSTEM_ARCH 93
+#define OP_DHCP_NETWORK_ARCH 94
+#define OP_DHCP_PLATFORM_ID 97
+} DHCPV4_STRUCT;
+
+//
+// DHCPv4 option header
+//
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length;
+ //
+ // followed by Data[]
+ //
+} DHCPV4_OP_HEADER;
+
+//
+// Generic DHCPv4 option (header followed by data)
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Data[1];
+} DHCPV4_OP_STRUCT;
+
+//
+// Maximum DHCP packet size on ethernet
+//
+#define MAX_DHCP_MSG_SZ (MAX_ENET_DATA_SIZE - sizeof (IPV4_HEADER) - sizeof (UDPV4_HEADER))
+
+//
+// Macros used in pxe_bc_dhcp.c and pxe_loadfile.c
+//
+#define DHCPV4_TRANSMIT_BUFFER (*(DHCPV4_STRUCT *) (Private->TransmitBuffer))
+#define DHCPV4_OPTIONS_BUFFER (*(struct optionsstr *) DHCPV4_TRANSMIT_BUFFER.options)
+
+#define DHCPV4_ACK_INDEX 0
+#define PXE_BINL_INDEX 1
+#define PXE_OFFER_INDEX 1
+#define PXE_ACK_INDEX 2
+#define PXE_BIS_INDEX 3
+
+#define DHCPV4_ACK_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[DHCPV4_ACK_INDEX]
+#define PXE_BINL_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_BINL_INDEX]
+#define PXE_OFFER_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_OFFER_INDEX]
+#define PXE_ACK_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_ACK_INDEX]
+#define PXE_BIS_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_BIS_INDEX]
+
+#define DHCPV4_ACK_PACKET DHCPV4_ACK_BUFFER.u.Dhcpv4
+#define PXE_BINL_PACKET PXE_BINL_BUFFER.u.Dhcpv4
+#define PXE_OFFER_PACKET PXE_OFFER_BUFFER.u.Dhcpv4
+#define PXE_ACK_PACKET PXE_ACK_BUFFER.u.Dhcpv4
+#define PXE_BIS_PACKET PXE_BIS_BUFFER.u.Dhcpv4
+
+//
+// network structure definitions
+//
+//
+// some option definitions
+//
+#define DHCPV4_OPTION_LENGTH(type) (sizeof (type) - sizeof (DHCPV4_OP_HEADER))
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Type;
+} DHCPV4_OP_MESSAGE_TYPE;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Overload;
+} DHCPV4_OP_OVERLOAD;
+
+//
+// boot server list structure
+// one or more contained in a pxe boot servers structure
+//
+typedef struct {
+ UINT8 IpCount;
+ EFI_IPv4_ADDRESS IpList[1]; // IP count of IPs
+} PXEV4_SERVER_LIST;
+
+typedef struct {
+ UINT8 IpCount;
+ EFI_IPv6_ADDRESS IpList[1]; // IP count of IPs
+} PXEV6_SERVER_LIST;
+
+typedef union {
+ PXEV4_SERVER_LIST Ipv4List;
+ PXEV6_SERVER_LIST Ipv6List;
+} PXE_SERVER_LISTS;
+
+typedef struct {
+ UINT16 Type;
+ PXE_SERVER_LISTS u;
+} PXE_SERVER_LIST;
+
+//
+// pxe boot servers structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ PXE_SERVER_LIST ServerList[1]; // one or more
+} PXE_OP_SERVER_LIST;
+
+//
+// pxe boot item structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT16 Type;
+ UINT16 Layer;
+} PXE_OP_BOOT_ITEM;
+
+//
+// pxe boot menu item structure
+//
+typedef struct {
+ UINT16 Type;
+ UINT8 DataLen;
+ UINT8 Data[1];
+} PXE_BOOT_MENU_ENTRY;
+
+//
+// pxe boot menu structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ PXE_BOOT_MENU_ENTRY MenuItem[1];
+} PXE_OP_BOOT_MENU;
+
+//
+// pxe boot prompt structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Timeout;
+ UINT8 Prompt[1];
+} PXE_OP_BOOT_PROMPT;
+
+#define PXE_BOOT_PROMPT_AUTO_SELECT 0
+#define PXE_BOOT_PROMPT_NO_TIMEOUT 255
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Class[1];
+} DHCPV4_OP_CLASS;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 File[1];
+} DHCPV4_OP_BOOTFILE;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 VendorOptions[1];
+} DHCPV4_OP_VENDOR_OPTIONS;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 MaxSize[2];
+} DHCPV4_OP_MAX_MESSAGE_SIZE;
+
+typedef struct {
+ UINT8 _OP_SUBNET_MASK; /* 1 */
+ UINT8 _OP_TIME_OFFSET; /* 2 */
+ UINT8 _OP_ROUTER_LIST; /* 3 */
+ UINT8 _OP_TIME_SERVERS; /* 4 */
+ UINT8 _OP_NAME_SERVERS; /* 5 */
+ UINT8 _OP_DNS_SERVERS; /* 6 */
+ UINT8 _OP_HOST_NAME; /* 12 */
+ UINT8 _OP_BOOT_FILE_SZ; /* 13 */
+ UINT8 _OP_DOMAIN_NAME; /* 15 */
+ UINT8 _OP_ROOT_PATH; /* 17 */
+ UINT8 _OP_EXTENSION_PATH; /* 18 */
+ UINT8 _OP_MAX_DATAGRAM_SZ; /* 22 */
+ UINT8 _OP_DEFAULT_TTL; /* 23 */
+ UINT8 _OP_BROADCAST_ADD; /* 28 */
+ UINT8 _OP_NIS_DOMAIN_NAME; /* 40 */
+ UINT8 _OP_NIS_SERVERS; /* 41 */
+ UINT8 _OP_NTP_SERVERS; /* 42 */
+ UINT8 _OP_VENDOR_SPECIFIC; /* 43 */
+ UINT8 _OP_DHCP_REQ_IP_ADD; /* 50 */
+ UINT8 _OP_DHCP_LEASE_TIME; /* 51 */
+ UINT8 _OP_DHCP_SERVER_IP; /* 54 */
+ UINT8 _OP_DHCP_RENEWAL_TIME; /* 58 */
+ UINT8 _OP_DHCP_REBINDING_TIME; /* 59 */
+ UINT8 _OP_DHCP_CLASS_IDENTIFIER; /* 60 */
+ UINT8 _OP_DHCP_TFTP_SERVER_NAME; /* 66 */
+ UINT8 _OP_DHCP_BOOTFILE; /* 67 */
+ UINT8 _OP_DHCP_PLATFORM_ID; /* 97 */
+ UINT8 VendorOption128; // vendor option 128
+ UINT8 VendorOption129; // vendor option 129
+ UINT8 VendorOption130; // vendor option 130
+ UINT8 VendorOption131; // vendor option 131
+ UINT8 VendorOption132; // vendor option 132
+ UINT8 VendorOption133; // vendor option 133
+ UINT8 VendorOption134; // vendor option 134
+ UINT8 VendorOption135; // vendor option 135
+} DHCPV4_REQUESTED_OPTIONS_DATA;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ DHCPV4_REQUESTED_OPTIONS_DATA Data;
+} DHCPV4_OP_REQUESTED_OPTIONS;
+
+typedef struct opipstr {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_IP_ADDRESS;
+
+//
+// ip list structure - e.g. router list
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS IpList[1];
+} DHCPV4_OP_IP_LIST;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Type;
+ UINT8 Guid[sizeof (EFI_GUID)];
+} DHCPV4_OP_CLIENT_ID;
+
+//
+// special options start - someday obsolete ???
+//
+#define DHCPV4_OP_PLATFORM_ID DHCPV4_OP_CLIENT_ID
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Type; // SNP = 2
+ UINT8 MajorVersion;
+ UINT8 MinorVersion;
+} DHCPV4_OP_NETWORK_INTERFACE;
+
+#define UNDI_TYPE 1
+#define SNP_TYPE 2
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT16 Type;
+} DHCPV4_OP_ARCHITECTURE_TYPE;
+//
+// special options end - someday obsolete ???
+//
+typedef struct {
+ UINT8 ClassIdentifier[10]; // PXEClient:
+ UINT8 Lit2[5]; // Arch:
+ UINT8 ArchitectureType[5]; // 00000 - 65536
+ UINT8 Lit3[1]; // :
+ UINT8 InterfaceName[4]; // e.g. UNDI
+ UINT8 Lit4[1]; // :
+ UINT8 UndiMajor[3]; // 000 - 255
+ UINT8 UndiMinor[3]; // 000 - 255
+} DHCPV4_CLASS_ID_DATA;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ DHCPV4_CLASS_ID_DATA Data;
+} DHCPV4_OP_CLASS_ID;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_REQUESTED_IP;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_SERVER_IP;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_SUBNET_MASK;
+
+typedef struct { // oppxedisctlstr {
+ DHCPV4_OP_HEADER Header;
+ UINT8 ControlBits;
+} PXE_OP_DISCOVERY_CONTROL;
+
+#define DISABLE_BCAST (1 << 0)
+#define DISABLE_MCAST (1 << 1)
+#define USE_ACCEPT_LIST (1 << 2)
+#define USE_BOOTFILE (1 << 3)
+
+#pragma pack()
+//
+// definitions of indices to populate option interest array
+//
+#define VEND_PXE_MTFTP_IP_IX 1 // multicast IP address of bootfile for MTFTP listen
+#define VEND_PXE_MTFTP_CPORT_IX 2 // UDP Port to monitor for MTFTP responses - Intel order
+#define VEND_PXE_MTFTP_SPORT_IX 3 // Server UDP Port for MTFTP open - Intel order
+#define VEND_PXE_MTFTP_TMOUT_IX 4 // Listen timeout - secs
+#define VEND_PXE_MTFTP_DELAY_IX 5 // Transmission timeout - secs
+#define VEND_PXE_DISCOVERY_CONTROL_IX 6 // bit field
+#define VEND_PXE_DISCOVERY_MCAST_ADDR_IX 7 // boot server discovery multicast address
+#define VEND_PXE_BOOT_SERVERS_IX 8 // list of boot servers of form tp(2) cnt(1) ips[cnt]
+#define VEND_PXE_BOOT_MENU_IX 9
+#define VEND_PXE_BOOT_PROMPT_IX 10
+#define VEND_PXE_MCAST_ADDRS_ALLOC_IX 0 // not used by PXE client
+#define VEND_PXE_CREDENTIAL_TYPES_IX 11
+#define VEND_13_IX 0 // not used by PXE client
+#define VEND_14_IX 0 // not used by PXE client
+#define VEND_15_IX 0 // not used by PXE client
+#define VEND_16_IX 0 // not used by PXE client
+#define VEND_17_IX 0 // not used by PXE client
+#define VEND_18_IX 0 // not used by PXE client
+#define VEND_19_IX 0 // not used by PXE client
+#define VEND_20_IX 0 // not used by PXE client
+#define VEND_21_IX 0 // not used by PXE client
+#define VEND_22_IX 0 // not used by PXE client
+#define VEND_23_IX 0 // not used by PXE client
+#define VEND_24_IX 0 // not used by PXE client
+#define VEND_25_IX 0 // not used by PXE client
+#define VEND_26_IX 0 // not used by PXE client
+#define VEND_27_IX 0 // not used by PXE client
+#define VEND_28_IX 0 // not used by PXE client
+#define VEND_29_IX 0 // not used by PXE client
+#define VEND_30_IX 0 // not used by PXE client
+#define VEND_31_IX 0 // not used by PXE client
+#define VEND_32_IX 0 // not used by PXE client
+#define VEND_33_IX 0 // not used by PXE client
+#define VEND_34_IX 0 // not used by PXE client
+#define VEND_35_IX 0 // not used by PXE client
+#define VEND_36_IX 0 // not used by PXE client
+#define VEND_37_IX 0 // not used by PXE client
+#define VEND_38_IX 0 // not used by PXE client
+#define VEND_39_IX 0 // not used by PXE client
+#define VEND_40_IX 0 // not used by PXE client
+#define VEND_41_IX 0 // not used by PXE client
+#define VEND_42_IX 0 // not used by PXE client
+#define VEND_43_IX 0 // not used by PXE client
+#define VEND_44_IX 0 // not used by PXE client
+#define VEND_45_IX 0 // not used by PXE client
+#define VEND_46_IX 0 // not used by PXE client
+#define VEND_47_IX 0 // not used by PXE client
+#define VEND_48_IX 0 // not used by PXE client
+#define VEND_49_IX 0 // not used by PXE client
+#define VEND_50_IX 0 // not used by PXE client
+#define VEND_51_IX 0 // not used by PXE client
+#define VEND_52_IX 0 // not used by PXE client
+#define VEND_53_IX 0 // not used by PXE client
+#define VEND_54_IX 0 // not used by PXE client
+#define VEND_55_IX 0 // not used by PXE client
+#define VEND_56_IX 0 // not used by PXE client
+#define VEND_57_IX 0 // not used by PXE client
+#define VEND_58_IX 0 // not used by PXE client
+#define VEND_59_IX 0 // not used by PXE client
+#define VEND_60_IX 0 // not used by PXE client
+#define VEND_61_IX 0 // not used by PXE client
+#define VEND_62_IX 0 // not used by PXE client
+#define VEND_63_IX 0 // not used by PXE client
+#define VEND_64_IX 0 // not used by PXE client
+#define VEND_65_IX 0 // not used by PXE client
+#define VEND_66_IX 0 // not used by PXE client
+#define VEND_67_IX 0 // not used by PXE client
+#define VEND_68_IX 0 // not used by PXE client
+#define VEND_69_IX 0 // not used by PXE client
+#define VEND_70_IX 0 // not used by PXE client
+#define VEND_PXE_BOOT_ITEM_IX 12
+
+#define MAX_OUR_PXE_OPT VEND_PXE_BOOT_ITEM // largest PXE option in which we are interested
+#define MAX_OUR_PXE_IX VEND_PXE_BOOT_ITEM_IX // largest PXE option index
+//
+// define various types by options that are sent
+//
+#define WfM11a_OPTS ((1<<VEND_PXE_MTFTP_IP_IX) | \
+ (1<<VEND_PXE_MTFTP_CPORT_IX) | \
+ (1<<VEND_PXE_MTFTP_SPORT_IX) | \
+ (1<<VEND_PXE_MTFTP_TMOUT_IX) | \
+ (1<<VEND_PXE_MTFTP_DELAY_IX))
+
+#define DISCOVER_OPTS ((1<<VEND_PXE_DISCOVERY_CONTROL_IX) | \
+ (1<<VEND_PXE_DISCOVERY_MCAST_ADDR_IX) | \
+ (1<<VEND_PXE_BOOT_SERVERS_IX) | \
+ (1<<VEND_PXE_BOOT_MENU_IX) | \
+ (1<<VEND_PXE_BOOT_PROMPT_IX) | \
+ (1<<VEND_PXE_BOOT_ITEM_IX))
+
+#define CREDENTIALS_OPT (1 << VEND_PXE_CREDENTIAL_TYPES_IX)
+
+//
+// definitions of indices to populate option interest array
+//
+#define OP_SUBNET_MASK_IX 1
+#define OP_TIME_OFFSET_IX 0 // not used by PXE client
+#define OP_ROUTER_LIST_IX 2
+#define OP_TIME_SERVERS_IX 0 // not used by PXE client
+#define OP_NAME_SERVERS_IX 0 // not used by PXE client
+#define OP_DNS_SERVERS_IX 0 // not used by PXE client
+#define OP_LOG_SERVERS_IX 0 // not used by PXE client
+#define OP_COOKIE_SERVERS_IX 0 // not used by PXE client
+#define OP_LPR_SREVERS_IX 0 // not used by PXE client
+#define OP_IMPRESS_SERVERS_IX 0 // not used by PXE client
+#define OP_RES_LOC_SERVERS_IX 0 // not used by PXE client
+#define OP_HOST_NAME_IX 0 // not used by PXE client
+#define OP_BOOT_FILE_SZ_IX 9
+#define OP_DUMP_FILE_IX 0 // not used by PXE client
+#define OP_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_SWAP_SERVER_IX 0 // not used by PXE client
+#define OP_ROOT_PATH_IX 0 // not used by PXE client
+#define OP_EXTENSION_PATH_IX 0 // not used by PXE client
+#define OP_IP_FORWARDING_IX 0 // not used by PXE client
+#define OP_NON_LOCAL_SRC_RTE_IX 0 // not used by PXE client
+#define OP_POLICY_FILTER_IX 0 // not used by PXE client
+#define OP_MAX_DATAGRAM_SZ_IX 0 // not used by PXE client
+#define OP_DEFAULT_TTL_IX 0 // not used by PXE client
+#define OP_MTU_AGING_TIMEOUT_IX 0 // not used by PXE client
+#define OP_MTU_SIZES_IX 0 // not used by PXE client
+#define OP_MTU_TO_USE_IX 0 // not used by PXE client
+#define OP_ALL_SUBNETS_LOCAL_IX 0 // not used by PXE client
+#define OP_BROADCAST_ADD_IX 0 // not used by PXE client
+#define OP_PERFORM_MASK_DISCOVERY_IX 0 // not used by PXE client
+#define OP_RESPOND_TO_MASK_REQ_IX 0 // not used by PXE client
+#define OP_PERFORM_ROUTER_DISCOVERY_IX 0 // not used by PXE client
+#define OP_ROUTER_SOLICIT_ADDRESS_IX 0 // not used by PXE client
+#define OP_STATIC_ROUTER_LIST_IX 0 // not used by PXE client
+#define OP_USE_ARP_TRAILERS_IX 0 // not used by PXE client
+#define OP_ARP_CACHE_TIMEOUT_IX 0 // not used by PXE client
+#define OP_ETHERNET_ENCAPSULATION_IX 0 // not used by PXE client
+#define OP_TCP_DEFAULT_TTL_IX 0 // not used by PXE client
+#define OP_TCP_KEEP_ALIVE_INT_IX 0 // not used by PXE client
+#define OP_KEEP_ALIVE_GARBAGE_IX 0 // not used by PXE client
+#define OP_NIS_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_NIS_SERVERS_IX 0 // not used by PXE client
+#define OP_NTP_SERVERS_IX 0 // not used by PXE client
+#define OP_VENDOR_SPECIFIC_IX 3
+#define OP_NBNS_SERVERS_IX 0 // not used by PXE client
+#define OP_NBDD_SERVERS_IX 0 // not used by PXE client
+#define OP_NETBIOS_NODE_TYPE_IX 0 // not used by PXE client
+#define OP_NETBIOS_SCOPE_IX 0 // not used by PXE client
+#define OP_XWINDOW_SYSTEM_FONT_SERVERS_IX 0 // not used by PXE client
+#define OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX 0 // not used by PXE client
+// DHCP option indices
+//
+#define OP_DHCP_REQ_IP_ADD_IX 0 // not used by PXE client
+#define OP_DHCP_LEASE_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_OPTION_OVERLOAD_IX 4
+#define OP_DHCP_MESSAGE_TYPE_IX 5
+#define OP_DHCP_SERVER_IP_IX 6
+#define OP_DHCP_PARM_REQ_LIST_IX 0 // not used by PXE client
+#define OP_DHCP_ERROR_MESSAGE_IX 0 // not used by PXE client
+#define OP_DHCP_MAX_MESSAGE_SZ_IX 0 // not used by PXE client
+#define OP_DHCP_RENEWAL_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_REBINDING_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_CLASS_IDENTIFIER_IX 7
+#define OP_DHCP_CLIENT_IDENTIFIER_IX 0 // not used by PXE client
+#define OP_RESERVED62_IX 0 // not used by PXE client
+#define OP_RESERVED63_IX 0 // not used by PXE client
+#define OP_NISPLUS_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_NISPLUS_SERVERS_IX 0 // not used by PXE client
+#define OP_DHCP_TFTP_SERVER_NAME_IX 0 // not used by PXE client
+#define OP_DHCP_BOOTFILE_IX 8
+
+#define MAX_OUR_OPT OP_DHCP_BOOTFILE // largest option in which we are interested
+#define MAX_OUR_IX OP_BOOT_FILE_SZ_IX
+
+typedef struct {
+ DHCPV4_OP_STRUCT *PktOptAdds[MAX_OUR_IX];
+ DHCPV4_OP_STRUCT *PxeOptAdds[MAX_OUR_PXE_IX];
+ UINT8 Status;
+} OPTION_POINTERS;
+
+typedef struct DhcpReceiveBufferStruct {
+ union {
+ UINT8 ReceiveBuffer[MAX_DHCP_MSG_SZ];
+ DHCPV4_STRUCT Dhcpv4;
+ } u;
+
+ OPTION_POINTERS OpAdds;
+} DHCP_RECEIVE_BUFFER;
+
+#define PXE_TYPE (1 << 0)
+#define WfM11a_TYPE (1 << 1)
+#define DISCOVER_TYPE (1 << 2)
+#define CREDENTIALS_TYPE (1 << 3)
+#define USE_THREE_BYTE (1 << 4)
+
+#endif // _DHCP_H
+
+/* EOF - dhcp.h */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h
new file mode 100644
index 0000000..b9000c1
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/hton.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ hton.h
+
+Abstract:
+ Byte swapping macros.
+
+--*/
+
+#ifndef _HTON_H_
+#define _HTON_H_
+
+//
+// Only Intel order functions are defined at this time.
+//
+#define HTONS(v) (UINT16) ((((v) << 8) & 0xff00) + (((v) >> 8) & 0x00ff))
+
+#define HTONL(v) \
+ (UINT32) ((((v) << 24) & 0xff000000) + (((v) << 8) & 0x00ff0000) + (((v) >> 8) & 0x0000ff00) + (((v) >> 24) & 0x000000ff))
+
+#define HTONLL(v) swap64 (v)
+
+#define U8PTR(na) ((UINT8 *) &(na))
+
+#define NTOHS(ns) ((UINT16) (((*U8PTR (ns)) << 8) +*(U8PTR (ns) + 1)))
+
+#define NTOHL(ns) \
+ ((UINT32) (((*U8PTR (ns)) << 24) + ((*(U8PTR (ns) + 1)) << 16) + ((*(U8PTR (ns) + 2)) << 8) +*(U8PTR (ns) + 3)))
+
+#endif /* _HTON_H_ */
+
+/* EOF - hton.h */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h
new file mode 100644
index 0000000..fcfc264
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/ip.h
@@ -0,0 +1,741 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+--*/
+
+#ifndef _IP_H_
+#define _IP_H_
+
+#include "hton.h"
+
+//
+// Client architecture types
+//
+#define IA64 2
+#define SYS_ARCH_EFI32 6
+
+//
+// portability macros
+//
+#define UDP_FILTER_MASK (EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER \
+ )
+
+#define PXE_BOOT_LAYER_MASK 0x7FFF
+#define PXE_BOOT_LAYER_INITIAL 0x0000
+#define PXE_BOOT_LAYER_CREDENTIAL_FLAG 0x8000
+#define MAX_BOOT_SERVERS 32
+
+//
+// macro to evaluate IP address as TRUE if it is a multicast IP address
+//
+#define IS_MULTICAST(ptr) ((*((UINT8 *) ptr) & 0xf0) == 0xe0)
+
+//
+// length macros
+//
+#define IP_ADDRESS_LENGTH(qp) (((qp)->UsingIpv6) ? sizeof (EFI_IPv6_ADDRESS) : sizeof (EFI_IPv4_ADDRESS))
+
+#define MAX_FRAME_DATA_SIZE 1488
+#define ALLOCATE_SIZE(X) (((X) + 7) & 0xfff8)
+#define MODE_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_MODE))
+#define BUFFER_ALLOCATE_SIZE (8192 + 512)
+#define ROUTER_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY) * PXE_ROUTER_TABLE_SIZE))
+#define ARP_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_PXE_BASE_CODE_ARP_ENTRY) * PXE_ARP_CACHE_SIZE))
+#define FILTER_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_IP_ADDRESS) * PXE_IP_FILTER_SIZE))
+#define PXE_ARP_CACHE_SIZE 8
+#define PXE_ROUTER_TABLE_SIZE 8
+#define PXE_IP_FILTER_SIZE 8
+#define ICMP_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR))
+#define TFTP_ERR_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR))
+
+//
+// DHCP discover/request packets are sent to this UDP port. ProxyDHCP
+// servers listen on this port for DHCP discover packets that have a
+// class identifier (option 60) with 'PXEClient' in the first 9 bytes.
+// Bootservers also listen on this port for PXE broadcast discover
+// requests from PXE clients.
+//
+#define DHCP_SERVER_PORT 67
+
+//
+// When DHCP, proxyDHCP and Bootservers respond to DHCP and PXE broadcast
+// discover requests by broadcasting the reply packet, the packet is
+// broadcast to this port.
+//
+#define DHCP_CLIENT_PORT 68
+
+//
+// TFTP servers listen for TFTP open requests on this port.
+//
+#define TFTP_OPEN_PORT 69
+
+//
+// proxyDHCP and Bootservers listen on this port for a PXE unicast and/or
+// multicast discover requests from PXE clients. A PXE discover request
+// looks like a DHCP discover or DHCP request packet.
+//
+#define PXE_DISCOVERY_PORT 4011
+
+//
+// This port is used by the PXE client/server protocol tests.
+//
+#define PXE_PORT_PXETEST_PORT 0x8080
+
+//
+// Definitions for Ethertype protocol numbers and interface types
+// Per RFC 1700,
+//
+#define PXE_PROTOCOL_ETHERNET_IP 0x0800
+#define PXE_PROTOCOL_ETHERNET_ARP 0x0806
+#define PXE_PROTOCOL_ETHERNET_RARP 0x8035
+
+#define PXE_IFTYPE_ETHERNET 0x01
+#define PXE_IFTYPE_TOKENRING 0x04
+#define PXE_IFTYPE_FIBRE_CHANNEL 0x12
+
+//
+// Definitions for internet protocol version 4 header
+// Per RFC 791, September 1981.
+//
+#define IPVER4 4
+
+#pragma pack(1) // make network structures packed byte alignment
+typedef union {
+ UINT8 B[4];
+ UINT32 L;
+} IPV4_ADDR;
+
+#define IPV4_HEADER_LENGTH(IpHeaderPtr) (((IpHeaderPtr)->VersionIhl & 0xf) << 2)
+
+#define SET_IPV4_VER_HDL(IpHeaderPtr, IpHeaderLen) { \
+ (IpHeaderPtr)->VersionIhl = (UINT8) ((IPVER4 << 4) | ((IpHeaderLen) >> 2)); \
+ }
+
+typedef struct {
+ UINT8 VersionIhl;
+ UINT8 TypeOfService;
+ UINT16 TotalLength;
+ UINT16 Id;
+ UINT16 FragmentFields;
+ UINT8 TimeToLive;
+ UINT8 Protocol;
+ UINT16 HeaderChecksum;
+ IPV4_ADDR SrcAddr;
+ IPV4_ADDR DestAddr;
+ //
+ // options are not implemented
+ //
+} IPV4_HEADER;
+
+#define IP_FRAG_RSVD 0x8000 // reserved bit - must be zero
+#define IP_NO_FRAG 0x4000 // do not fragment bit
+#define IP_MORE_FRAG 0x2000 // not last fragment
+#define IP_FRAG_OFF_MSK 0x1fff // fragment offset in 8 byte chunks
+#define DEFAULT_RFC_TTL 64
+
+#define PROT_ICMP 1
+#define PROT_IGMP 2
+#define PROT_TCP 6
+#define PROT_UDP 17
+
+/*
+ * Definitions for internet control message protocol version 4 message
+ * structure. Per RFC 792, September 1981.
+ */
+
+//
+// icmp header for all icmp messages
+//
+typedef struct {
+ UINT8 Type; // message type
+ UINT8 Code; // type specific - 0 for types we implement
+ UINT16 Checksum; // ones complement of ones complement sum of 16 bit words of message
+} ICMPV4_HEADER;
+
+#define ICMP_DEST_UNREACHABLE 3
+#define ICMP_SOURCE_QUENCH 4
+#define ICMP_REDIRECT 5
+#define ICMP_ECHO 8
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ROUTER_ADV 9
+#define ICMP_ROUTER_SOLICIT 10
+#define ICMP_TIME_EXCEEDED 11
+#define ICMP_PARAMETER_PROBLEM 12
+#define ICMP_TIMESTAMP 13
+#define ICMP_TIMESTAMP_REPLY 14
+#define ICMP_INFO_REQ 15
+#define ICMP_INFO_REQ_REPLY 16
+#define ICMP_SUBNET_MASK_REQ 17
+#define ICMP_SUBNET_MASK_REPLY 18
+//
+// other ICMP message types ignored in this implementation
+//
+// icmp general messages
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ //
+ // generally unused except byte [0] for
+ // parameter problem message
+ //
+ UINT8 GenerallyUnused[4];
+ //
+ // original message ip header of plus 64
+ // bits of data
+ //
+ IPV4_HEADER IpHeader;
+} ICMPV4_GENERAL_MESSAGE;
+
+//
+// icmp req/rply message header
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ UINT16 Id;
+ UINT16 SequenceNumber;
+} ICMPV4_REQUEST_REPLY_HEADER;
+
+//
+// icmp echo message
+//
+typedef struct {
+ ICMPV4_REQUEST_REPLY_HEADER Header;
+ UINT8 EchoData[1]; // variable length data to be echoed
+} ICMPV4_ECHO_MESSAGE;
+
+//
+// icmp timestamp message - times are milliseconds since midnight UT -
+// if non std, set high order bit
+//
+typedef struct {
+ ICMPV4_REQUEST_REPLY_HEADER Header;
+ UINT32 OriginalTime; // originating timestamp
+ UINT32 ReceiveTime; // receiving timestamp
+ UINT32 TransmitTime; // transmitting timestamp
+} ICMPV4_TIMESTAMP_MESSAGE;
+
+//
+// icmp info request structure - fill in source and dest net ip address on reply
+//
+typedef struct {
+ ICMPV4_REQUEST_REPLY_HEADER Header;
+} ICMPV4_INFO_MESSAGE;
+
+//
+// Definitions for internet control message protocol version 4 message structure
+// Router discovery
+// Per RFC 1256, September 1991.
+//
+//
+// icmp router advertisement message
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ UINT8 NumberEntries; // number of address entries
+ UINT8 EntrySize; // number of 32 bit words per address entry
+ UINT16 Lifetime; // seconds to consider info valid
+ UINT32 RouterIp;
+ UINT32 Preferance;
+} ICMPV4_ROUTER_ADVERTISE_MESSAGE;
+
+//
+// icmp router solicitation message
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ UINT32 Reserved;
+} ICMPV4_ROUTER_SOLICIT_MESSAGE;
+
+#define MAX_SOLICITATION_DELAY 1 // 1 second
+#define SOLICITATION_INTERVAL 3 // 3 seconds
+#define MAX_SOLICITATIONS 3 // 3 transmissions
+#define V1ROUTER_PRESENT_TIMEOUT 400 // 400 second timeout until v2 reports can be sent
+#define UNSOLICITED_REPORT_INTERVAL 10 // 10 seconds between unsolicited reports
+#define BROADCAST_IPv4 0xffffffff
+
+//
+// Definitions for address resolution protocol message structure
+// Per RFC 826, November 1982
+//
+typedef struct {
+ UINT16 HwType; // hardware type - e.g. ethernet (1)
+ UINT16 ProtType; // protocol type - for ethernet, 0x800 for IP
+ UINT8 HwAddLen; // byte length of a hardware address (e.g. 6 for ethernet)
+ UINT8 ProtAddLen; // byte length of a protocol address (e.g. 4 for ipv4)
+ UINT16 OpCode;
+ //
+ // source and dest hw and prot addresses follow - see example below
+ //
+} ARP_HEADER;
+
+#define ETHERNET_ADD_SPC 1
+
+#define ETHER_TYPE_IP 0x800
+
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+//
+// generic ARP packet
+//
+typedef struct {
+ ARP_HEADER ArpHeader;
+ EFI_MAC_ADDRESS SrcHardwareAddr;
+ EFI_IP_ADDRESS SrcProtocolAddr;
+ EFI_MAC_ADDRESS DestHardwareAddr;
+ EFI_IP_ADDRESS DestProtocolAddr;
+} ARP_PACKET;
+
+#define ENET_HWADDLEN 6
+#define IPV4_PROTADDLEN 4
+
+//
+// Definitions for user datagram protocol version 4 pseudo header & header
+// Per RFC 768, 28 August 1980
+//
+typedef struct {
+ IPV4_ADDR SrcAddr; // source ip address
+ IPV4_ADDR DestAddr; // dest ip address
+ UINT8 Zero; // 0
+ UINT8 Protocol; // protocol
+ UINT16 TotalLength; // UDP length - sizeof udpv4hdr + data length
+} UDPV4_PSEUDO_HEADER;
+
+typedef struct {
+ UINT16 SrcPort; // source port identifier
+ UINT16 DestPort; // destination port identifier
+ UINT16 TotalLength; // total length header plus data
+ //
+ // ones complement of ones complement sum of 16 bit
+ // words of pseudo header, UDP header, and data
+ // zero checksum is transmitted as -0 (ones comp)
+ // zero transmitted means checksum not computed
+ // data follows
+ //
+ UINT16 Checksum;
+} UDPV4_HEADER;
+
+typedef struct {
+ UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;
+ UDPV4_HEADER Udpv4Header;
+} UDPV4_HEADERS;
+
+//
+// Definitions for transmission control protocol header
+// Per RFC 793, September, 1981
+//
+typedef struct {
+ IPV4_ADDR SrcAddr; // source ip address
+ IPV4_ADDR DestAddr; // dest ip address
+ UINT8 Zero; // 0
+ UINT8 Protocol; // protocol
+ UINT16 TotalLength; // TCP length - TCP header length + data length
+} TCPV4_PSEUDO_HEADER;
+
+typedef struct {
+ UINT16 SrcPort; // source port identifier
+ UINT16 DestPort; // destination port identifier
+ UINT32 SeqNumber; // Sequence number
+ UINT32 AckNumber; // Acknowledgement Number
+ //
+ // Nibble of HLEN (length of header in 32-bit multiples)
+ // 6bits of RESERVED
+ // Nibble of Code Bits
+ //
+ UINT16 HlenResCode;
+ UINT16 Window; // Software buffer size (sliding window size) in network-standard byte order
+ //
+ // ones complement of ones complement sum of 16 bit words of
+ // pseudo header, TCP header, and data
+ // zero checksum is transmitted as -0 (ones comp)
+ // zero transmitted means checksum not computed
+ //
+ UINT16 Checksum;
+ UINT16 UrgentPointer; // pointer to urgent data (allows sender to specify urgent data)
+} TCPV4_HEADER;
+
+typedef struct {
+ TCPV4_PSEUDO_HEADER Tcpv4PseudoHeader;
+ TCPV4_HEADER Tcpv4Header;
+} TCPV4_HEADERS;
+
+typedef struct {
+ UINT8 Kind; // one of the following:
+ UINT8 Length; // total option length including Kind and Lth
+ UINT8 Data[1]; // length = Lth - 2
+} TCPV4_OPTION;
+
+#define TCP_OP_END 0 // only used to pad to end of TCP header
+#define TCP_NOP 1 // optional - may be used to pad between options to get alignment
+#define TCP_MAX_SEG 2 // maximum receive segment size - only send at initial connection request
+#define MAX_MEDIA_HDR_SIZE 64
+#define MIN_ENET_DATA_SIZE 64
+#define MAX_ENET_DATA_SIZE 1500 // temp def - make a network based var
+#define MAX_IPV4_PKT_SIZE 65535 // maximum IP packet size
+#define MAX_IPV4_DATA_SIZE (MAX_IPV4_PKT_SIZE - sizeof (IPV4_HEADER))
+#define MAX_IPV4_FRAME_DATA_SIZE (MAX_FRAME_DATA_SIZE - sizeof (IPV4_HEADER))
+#define REAS_IPV4_PKT_SIZE 576 // minimum IP packet size all IP host can handle
+#define REAS_IPV4_DATA_SIZE (REAS_IPV4_PKT_SIZE - sizeof (IPV4_HEADER))
+
+//
+//
+//
+typedef union {
+ UINT8 Data[MAX_ENET_DATA_SIZE];
+ ICMPV4_HEADER IcmpHeader;
+ IGMPV2_MESSAGE IgmpMessage;
+ struct {
+ UDPV4_HEADER UdpHeader;
+ UINT8 Data[1];
+ } Udp;
+ struct {
+ TCPV4_HEADER TcpHeader;
+ UINT8 Data[1];
+ } Tcp;
+} PROTOCOL_UNION;
+
+//
+// out buffer structure
+//
+typedef struct {
+ UINT8 MediaHeader[MAX_MEDIA_HDR_SIZE];
+ IPV4_HEADER IpHeader;
+ //
+ // following union placement only valid if no option IP header
+ //
+ PROTOCOL_UNION u;
+} IPV4_BUFFER;
+
+typedef struct {
+ IPV4_HEADER IpHeader;
+ //
+ // following union placement only valid if no option IP header
+ //
+ PROTOCOL_UNION u;
+} IPV4_STRUCT;
+
+#pragma pack() // reset to default
+
+ ////////////////////////////////////////////////////////////
+//
+// BC IP Filter Routine
+//
+EFI_STATUS
+IpFilter (
+ PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *Filter
+ )
+;
+
+//
+// //////////////////////////////////////////////////////////////////////
+//
+// Udp Write Routine - called by base code - e.g. TFTP - already locked
+//
+EFI_STATUS
+UdpWrite (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 OpFlags,
+ IN EFI_IP_ADDRESS *DestIpPtr,
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortptr,
+ IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSizePtr,
+ IN VOID *BufferPtr
+ )
+;
+
+//
+// /////////////////////////////////////////////////////////////////////
+//
+// Udp Read Routine - called by base code - e.g. TFTP - already locked
+//
+EFI_STATUS
+UdpRead (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPorPtrt, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSizePtr,
+ IN VOID *BufferPtr,
+ IN EFI_EVENT TimeoutEvent
+ )
+;
+
+VOID
+IgmpLeaveGroup (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *
+ )
+;
+
+VOID
+IgmpJoinGroup (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *
+ )
+;
+
+//
+// convert number to zero filled ascii value of length lth
+//
+VOID
+CvtNum (
+ UINTN Number,
+ UINT8 *BufferPtr,
+ INTN BufferLen
+ )
+;
+
+//
+// convert number to ascii string at ptr
+//
+VOID
+UtoA10 (
+ UINTN Number,
+ UINT8 *BufferPtr
+ )
+;
+
+//
+// convert ascii numeric string to UINTN
+//
+UINTN
+AtoU (
+ UINT8 *BufferPtr
+ )
+;
+
+UINT64
+AtoU64 (
+ UINT8 *BufferPtr
+ )
+;
+
+//
+// calculate the internet checksum (RFC 1071)
+// return 16 bit ones complement of ones complement sum of 16 bit words
+//
+UINT16
+IpChecksum (
+ UINT16 *MessagePtr,
+ UINTN ByteLength
+ )
+;
+
+//
+// do checksum on non contiguous header and data
+//
+UINT16
+IpChecksum2 (
+ UINT16 *Header,
+ UINTN HeaderLength,
+ UINT16 *Message,
+ UINTN MessageLength
+ )
+;
+
+//
+// update checksum when only a single word changes
+//
+UINT16
+UpdateChecksum (
+ UINT16 OldChecksum,
+ UINT16 OldWord,
+ UINT16 NewWord
+ )
+;
+
+VOID
+SeedRandom (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 InitialSeed
+ )
+;
+
+UINT16
+Random (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+;
+
+EFI_STATUS
+SendPacket (
+ PXE_BASECODE_DEVICE *Private,
+ VOID *HeaderPtr,
+ VOID *PacketPtr,
+ INTN PacketLength,
+ VOID *HardwareAddress,
+ UINT16 MediaProtocol,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+;
+
+VOID
+HandleArpReceive (
+ PXE_BASECODE_DEVICE *Private,
+ ARP_PACKET *ArpPacketPtr,
+ VOID *HeaderPtr
+ )
+;
+
+VOID
+HandleIgmp (
+ PXE_BASECODE_DEVICE *Private,
+ IGMPV2_MESSAGE *IgmpMessageptr,
+ UINTN IgmpMessageLen
+ )
+;
+
+VOID
+IgmpCheckTimers (
+ PXE_BASECODE_DEVICE *Private
+ )
+; // poll when doing a receive
+// return hw add of IP and TRUE if available, otherwise FALSE
+//
+BOOLEAN
+GetHwAddr (
+ IN PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ProtocolAddressPtr,
+ EFI_MAC_ADDRESS *HardwareAddressPtr
+ )
+;
+
+EFI_STATUS
+DoArp (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_IP_ADDRESS *ProtocolAddressPtr,
+ OUT EFI_MAC_ADDRESS *HardwareAddressptr
+ )
+;
+
+BOOLEAN
+OnSameSubnet (
+ UINTN IpAddressLen,
+ EFI_IP_ADDRESS *Ip1,
+ EFI_IP_ADDRESS *Ip2,
+ EFI_IP_ADDRESS *SubnetMask
+ )
+;
+
+VOID
+IpAddRouter (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *RouterIp
+ )
+;
+
+#define Ip4AddRouter(Private, Ipv4Ptr) IpAddRouter (Private, (EFI_IP_ADDRESS *) Ipv4Ptr)
+
+//
+// routine to send ipv4 packet
+// ipv4 + upper protocol header for length TotHdrLth in xmtbuf, ipv4 header length IpHdrLth
+// routine fills in ipv4hdr Ver_Hdl, TotLth, and Checksum, moves in Data, and gets dest MAC address
+//
+EFI_STATUS
+Ipv4Xmt (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GatewayIP,
+ UINTN IpHeaderLen,
+ UINTN TotalHeaderLen,
+ VOID *Data,
+ UINTN DataLen,
+ EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+;
+
+//
+// send ipv4 packet with ipv4 option
+//
+EFI_STATUS
+Ipv4SendWOp (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GatewayIP,
+ UINT8 *MessagePtr,
+ UINTN MessageLth,
+ UINT8 Protocol,
+ UINT8 *Option,
+ UINTN OptionLen,
+ UINT32 DestIp,
+ EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+;
+
+//
+// send MsgLth message at MsgPtr - higher level protocol header already in xmtbuf, length HdrSize
+//
+EFI_STATUS
+Ip4Send (
+ IN PXE_BASECODE_DEVICE *Private, // pointer to instance data
+ IN UINTN MayFragment, //
+ IN UINT8 Protocol, // protocol
+ IN UINT32 SrcIp, // Source IP address
+ IN UINT32 DestIp, // Destination IP address
+ IN UINT32 GatewayIp, // used if not NULL and needed
+ IN UINTN HeaderSize, // protocol header byte length
+ IN UINT8 *MsgPtr, // pointer to data
+ IN UINTN MsgLength
+ )
+; // data byte length
+// receive up to MsgLth message into MsgPtr for protocol Prot
+// return message length, src/dest ips if select any, and pointer to protocol header
+//
+EFI_STATUS
+IpReceive (
+ IN PXE_BASECODE_DEVICE *Private, // pointer to instance data
+ UINT16 OpFlags, // Flags to determine if filtering on IP addresses
+ EFI_IP_ADDRESS *SrcIpPtr, // if filtering, O if accept any
+ EFI_IP_ADDRESS *DstIpPtr, // if filtering, O if accept any
+ UINT8 Protocol, // protocol
+ VOID *HeaderPtr, // address of where to put protocol header
+ UINTN HeaderSize, // protocol header byte length
+ UINT8 *MsgPtr, // pointer to data buffer
+ UINTN *MsgLenPtr, // pointer to data buffer length/ O - returned data length
+ IN EFI_EVENT TimeoutEvent
+ )
+;
+
+#if 0
+VOID
+WaitForTxComplete (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+;
+#endif
+//
+// routine to cycle waiting for a receive or timeout
+//
+EFI_STATUS
+WaitForReceive (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function,
+ IN EFI_EVENT TimeoutEvent,
+ IN OUT UINTN *HeaderSizePtr,
+ IN OUT UINTN *BufferSizePtr,
+ IN OUT UINT16 *ProtocolPtr
+ )
+;
+
+#endif /* _IP_H_ */
+
+/* EOF - ip.h */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c
new file mode 100644
index 0000000..801f592
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c
@@ -0,0 +1,617 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ pxe_bc_arp.c
+
+Abstract:
+
+--*/
+
+
+#include "bc.h"
+
+//
+// Definitions for ARP
+// Per RFC 826
+//
+STATIC ARP_HEADER ArpHeader;
+
+#pragma pack(1)
+STATIC struct {
+ UINT8 MediaHeader[14];
+ ARP_HEADER ArpHeader;
+ UINT8 ArpData[64];
+} ArpReplyPacket;
+#pragma pack()
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+InitArpHeader (
+ VOID
+ )
+/*++
+Routine description:
+ Initialize ARP packet header.
+
+Parameters:
+ none
+
+Returns:
+ none
+
+--*/
+{
+ ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC);
+ ArpHeader.ProtType = HTONS (ETHER_TYPE_IP);
+ ArpHeader.HwAddLen = ENET_HWADDLEN;
+ ArpHeader.ProtAddLen = IPV4_PROTADDLEN;
+ ArpHeader.OpCode = HTONS (ARP_REQUEST);
+
+ CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+HandleArpReceive (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN ARP_PACKET *ArpPacketPtr,
+ IN VOID *MediaHeader
+ )
+/*++
+Routine description:
+ Process ARP packet.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ ArpPacketPtr := Pointer to ARP packet
+ MediaHeader := Pointer to media header.
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ EFI_MAC_ADDRESS TmpMacAddr;
+ UINTN Index;
+ UINT8 *SrcHwAddr;
+ UINT8 *SrcPrAddr;
+ UINT8 *DstHwAddr;
+ UINT8 *DstPrAddr;
+ UINT8 *TmpPtr;
+
+ //
+ //
+ //
+ PxeBcMode = Private->EfiBc.Mode;
+ SnpMode = Private->SimpleNetwork->Mode;
+
+ //
+ // For now only ethernet addresses are supported.
+ // This will need to be updated when other media
+ // layers are supported by PxeBc, Snp and UNDI.
+ //
+ if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) {
+ return ;
+ }
+ //
+ // For now only IP protocol addresses are supported.
+ // This will need to be updated when other protocol
+ // types are supported by PxeBc, Snp and UNDI.
+ //
+ if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) {
+ return ;
+ }
+ //
+ // For now only SNP hardware address sizes are supported.
+ //
+ if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) {
+ return ;
+ }
+ //
+ // For now only PxeBc protocol address sizes are supported.
+ //
+ if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) {
+ return ;
+ }
+ //
+ // Ignore out of range opcodes
+ //
+ switch (ArpPacketPtr->ArpHeader.OpCode) {
+ case HTONS (ARP_REPLY):
+ case HTONS (ARP_REQUEST):
+ break;
+
+ default:
+ return ;
+ }
+ //
+ // update entry in our ARP cache if we have it
+ //
+ SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr;
+ SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize;
+
+ for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {
+ if (CompareMem (
+ &PxeBcMode->ArpCache[Index].IpAddr,
+ SrcPrAddr,
+ Private->IpLength
+ )) {
+ continue;
+ }
+
+ CopyMem (
+ &PxeBcMode->ArpCache[Index].MacAddr,
+ SrcHwAddr,
+ SnpMode->HwAddressSize
+ );
+
+ break;
+ }
+ //
+ // Done if ARP packet was not for us.
+ //
+ DstHwAddr = SrcPrAddr + Private->IpLength;
+ DstPrAddr = DstHwAddr + SnpMode->HwAddressSize;
+
+ if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) {
+ return ;
+ //
+ // not for us
+ //
+ }
+ //
+ // for us - if we did not update entry, add it
+ //
+ if (Index == PxeBcMode->ArpCacheEntries) {
+ //
+ // if we have a full table, get rid of oldest
+ //
+ if (Index == PXE_ARP_CACHE_SIZE) {
+ Index = Private->OldestArpEntry;
+
+ if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) {
+ Private->OldestArpEntry = 0;
+ }
+ } else {
+ ++PxeBcMode->ArpCacheEntries;
+ }
+
+ CopyMem (
+ &PxeBcMode->ArpCache[Index].MacAddr,
+ SrcHwAddr,
+ SnpMode->HwAddressSize
+ );
+
+ CopyMem (
+ &PxeBcMode->ArpCache[Index].IpAddr,
+ SrcPrAddr,
+ Private->IpLength
+ );
+ }
+ //
+ // if this is not a request or we don't yet have an IP, finished
+ //
+ if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) {
+ return ;
+ }
+ //
+ // Assemble ARP reply.
+ //
+ //
+ // Create media header. [ dest mac | src mac | prot ]
+ //
+ CopyMem (
+ &ArpReplyPacket.MediaHeader[0],
+ SrcHwAddr,
+ SnpMode->HwAddressSize
+ );
+
+ CopyMem (
+ &ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize],
+ &SnpMode->CurrentAddress,
+ SnpMode->HwAddressSize
+ );
+
+ CopyMem (
+ &ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize],
+ &((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize],
+ sizeof (UINT16)
+ );
+
+ //
+ // ARP reply header is almost filled in,
+ // just insert the correct opcode.
+ //
+ ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY);
+
+ //
+ // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]
+ //
+ TmpPtr = ArpReplyPacket.ArpData;
+ CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
+
+ TmpPtr += SnpMode->HwAddressSize;
+ CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength);
+
+ TmpPtr += Private->IpLength;
+ CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize);
+
+ TmpPtr += SnpMode->HwAddressSize;
+ CopyMem (TmpPtr, SrcPrAddr, Private->IpLength);
+
+ //
+ // Now send out the ARP reply.
+ //
+ CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS));
+
+ SendPacket (
+ Private,
+ &ArpReplyPacket.MediaHeader,
+ &ArpReplyPacket.ArpHeader,
+ sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize),
+ &TmpMacAddr,
+ PXE_PROTOCOL_ETHERNET_ARP,
+ EFI_PXE_BASE_CODE_FUNCTION_ARP
+ );
+
+ //
+ // Give time (100 microseconds) for ARP reply to get onto wire.
+ //
+ gBS->Stall (1000);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+BOOLEAN
+GetHwAddr (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_IP_ADDRESS *ProtocolAddrPtr,
+ OUT EFI_MAC_ADDRESS *HardwareAddrPtr
+ )
+/*++
+Routine description:
+ Locate IP address in ARP cache and return MAC address.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ ProtocolAddrPtr := Pointer to IP address
+ HardwareAddrPtr := Pointer to MAC address storage
+
+Returns:
+ TRUE := If IP address was found and MAC address was stored
+ FALSE := If IP address was not found
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ UINTN HardwareAddrLength;
+ UINTN Index;
+
+ PxeBcMode = Private->EfiBc.Mode;
+ HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize;
+
+ for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {
+ if (!CompareMem (
+ ProtocolAddrPtr,
+ &PxeBcMode->ArpCache[Index].IpAddr,
+ Private->IpLength
+ )) {
+ CopyMem (
+ HardwareAddrPtr,
+ &PxeBcMode->ArpCache[Index].MacAddr,
+ HardwareAddrLength
+ );
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+SendRequest (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_IP_ADDRESS *ProtocolAddrPtr,
+ IN EFI_MAC_ADDRESS *HardwareAddrPtr
+ )
+/*++
+Routine description:
+ Transmit ARP request packet
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ ProtocolAddrPtr := Pointer IP address to find
+ HardwareAddrPtr := Pointer to MAC address to find
+
+Returns:
+ EFI_SUCCESS := ARP request sent
+ other := ARP request could not be sent
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ ARP_PACKET *ArpPacket;
+ EFI_STATUS Status;
+ UINTN HardwareAddrLength;
+ UINT8 *SrcProtocolAddrPtr;
+ UINT8 *DestHardwareAddrptr;
+ UINT8 *DestProtocolAddrPtr;
+
+ //
+ //
+ //
+ PxeBcMode = Private->EfiBc.Mode;
+ SnpMode = Private->SimpleNetwork->Mode;
+ HardwareAddrLength = SnpMode->HwAddressSize;
+
+ //
+ // Allocate ARP buffer
+ //
+ if (Private->ArpBuffer == NULL) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ SnpMode->MediaHeaderSize + sizeof (ARP_PACKET),
+ (VOID **) &Private->ArpBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);
+
+ //
+ // for now, only handle one kind of hw and pr address
+ //
+ ArpPacket->ArpHeader = ArpHeader;
+ ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;
+ ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;
+
+ //
+ // rest more generic
+ //
+ SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;
+ DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;
+ DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;
+
+ CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);
+ CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);
+ CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);
+ CopyMem (
+ &ArpPacket->SrcHardwareAddr,
+ &SnpMode->CurrentAddress,
+ HardwareAddrLength
+ );
+
+ return SendPacket (
+ Private,
+ Private->ArpBuffer,
+ ArpPacket,
+ sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),
+ &SnpMode->BroadcastAddress,
+ PXE_PROTOCOL_ETHERNET_ARP,
+ EFI_PXE_BASE_CODE_FUNCTION_ARP
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// check for address - if not there, send ARP request, wait and check again
+// not how it would be done in a full system
+//
+#define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
+
+ ////////////////////////////////////////////////////////////
+//
+// BC Arp Routine
+//
+EFI_STATUS
+EFIAPI
+BcArp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * ProtocolAddrPtr,
+ OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL
+ )
+/*++
+Routine description:
+ PxeBc ARP API.
+
+Parameters:
+ This := Pointer to PxeBc interface
+ ProtocolAddrPtr := Pointer to IP address to find
+ HardwareAddrPtr := Pointer to MAC address found.
+
+Returns:
+--*/
+{
+ EFI_MAC_ADDRESS Mac;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "\nBcArp()"));
+
+ //
+ // Issue BC command
+ //
+ if (ProtocolAddrPtr == NULL) {
+ DEBUG (
+ (EFI_D_INFO,
+ "\nBcArp() Exit #1 %Xh (%r)",
+ EFI_INVALID_PARAMETER,
+ EFI_INVALID_PARAMETER)
+ );
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HardwareAddrPtr == NULL) {
+ HardwareAddrPtr = &Mac;
+ }
+
+ ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);
+
+ if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
+ DEBUG (
+ (EFI_D_INFO,
+ "\nBcArp() Exit #2 %Xh (%r)",
+ EFI_SUCCESS,
+ EFI_SUCCESS)
+ );
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_SUCCESS;
+ }
+
+ StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);
+
+ DEBUG ((EFI_D_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));
+
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+DoArp (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_IP_ADDRESS *ProtocolAddrPtr,
+ OUT EFI_MAC_ADDRESS *HardwareAddrPtr
+ )
+/*++
+Routine description:
+ Internal ARP implementation.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ ProtocolAddrPtr := Pointer to IP address to find
+ HardwareAddrPtr := Pointer to MAC address found
+
+Returns:
+ EFI_SUCCESS := MAC address found
+ other := MAC address could not be found
+--*/
+{
+ EFI_STATUS StatCode;
+ EFI_EVENT TimeoutEvent;
+ UINTN HeaderSize;
+ UINTN BufferSize;
+ UINT16 Protocol;
+
+ DEBUG ((EFI_D_INFO, "\nDoArp()"));
+
+ //
+ //
+ //
+ StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG ((EFI_D_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));
+ return StatCode;
+ }
+ //
+ //
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return StatCode;
+ }
+
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ ARP_REQUEST_TIMEOUT_MS * 10000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return StatCode;
+ }
+ //
+ //
+ //
+ for (;;) {
+ StatCode = WaitForReceive (
+ Private,
+ EFI_PXE_BASE_CODE_FUNCTION_ARP,
+ TimeoutEvent,
+ &HeaderSize,
+ &BufferSize,
+ &Protocol
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ break;
+ }
+
+ if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {
+ continue;
+ }
+
+ HandleArpReceive (
+ Private,
+ (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),
+ Private->ReceiveBufferPtr
+ );
+
+ if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
+ break;
+ }
+ }
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nDoArp() Exit #2 %Xh, (%r)",
+ StatCode,
+ StatCode)
+ );
+
+ gBS->CloseEvent (TimeoutEvent);
+
+ return StatCode;
+}
+
+/* eof - pxe_bc_arp.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c
new file mode 100644
index 0000000..012b61c
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_dhcp.c
@@ -0,0 +1,3332 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ pxe_bc_dhcp.c
+
+Abstract:
+ DHCP and PXE discovery protocol implementations.
+
+--*/
+
+
+#include "bc.h"
+
+STATIC EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort = DHCP_SERVER_PORT;
+STATIC EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort = DHCP_CLIENT_PORT;
+STATIC EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort = PXE_DISCOVERY_PORT;
+#define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort
+STATIC EFI_IP_ADDRESS BroadcastIP = { { 0xffffffff } };
+STATIC EFI_IP_ADDRESS DefaultSubnetMask = { { 0xffffff00 } };
+
+typedef union {
+ DHCPV4_OP_STRUCT *OpPtr;
+ PXE_OP_SERVER_LIST *BootServersStr;
+ PXE_SERVER_LIST *BootServerList;
+ PXE_BOOT_MENU_ENTRY *BootMenuItem;
+ PXE_OP_DISCOVERY_CONTROL *DiscoveryControl;
+ PXE_OP_BOOT_MENU *BootMenu;
+ PXE_OP_BOOT_ITEM *BootItem;
+ DHCPV4_OP_VENDOR_OPTIONS *VendorOptions;
+ DHCPV4_OP_OVERLOAD *Overload;
+ DHCPV4_OP_CLASS *PxeClassStr;
+ DHCPV4_OP_SUBNET_MASK *SubnetMaskStr;
+ DHCPV4_OP_MESSAGE_TYPE *MessageType;
+ UINT8 *BytePtr;
+} UNION_PTR;
+
+//
+// 1 for Itanium-based, 0 for IA32
+//
+#define IA64SZ ((sizeof (UINTN) / sizeof (UINT32)) - 1)
+
+#define SYS_ARCH (SYS_ARCH_EFI32 - (SYS_ARCH_EFI32 - IA64) * IA64SZ)
+
+#pragma pack(1)
+//
+// option structure for DHCPREQUEST at end of DISCOVER options
+// and for DHCPDECLINE
+//
+STATIC const struct requestopendstr {
+ DHCPV4_OP_REQUESTED_IP OpReqIP;
+ DHCPV4_OP_SERVER_IP DhcServerIpPtr;
+ UINT8 End[1];
+}
+RequestOpEndStr = {
+ {
+ {
+ OP_DHCP_REQ_IP_ADD,
+ DHCPV4_OPTION_LENGTH(DHCPV4_OP_REQUESTED_IP)
+ }
+ },
+ {
+ {
+ OP_DHCP_SERVER_IP,
+ DHCPV4_OPTION_LENGTH(DHCPV4_OP_SERVER_IP)
+ }
+ },
+ {
+ OP_END
+ }
+};
+
+#define DHCP_REQ_OPTIONS (*(struct requestopendstr *) DHCPV4_OPTIONS_BUFFER.End)
+
+PXE_OP_BOOT_ITEM DefaultBootItem = {
+ {
+ VEND_PXE_BOOT_ITEM,
+ DHCPV4_OPTION_LENGTH(PXE_OP_BOOT_ITEM)
+ },
+ 0, 0,
+};
+
+//
+// PXE discovery control default structure
+//
+STATIC PXE_OP_DISCOVERY_CONTROL DefaultDisCtl = {
+ { VEND_PXE_DISCOVERY_CONTROL, DHCPV4_OPTION_LENGTH(PXE_OP_DISCOVERY_CONTROL) },
+ 0
+};
+
+//
+// PXE credentials option structure
+//
+typedef struct {
+ UINT8 c[4];
+} PXE_CREDENTIAL;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ PXE_CREDENTIAL Credentials[1];
+} PXE_OP_CREDENTIAL_TYPES;
+
+//
+// option structure for PXE discover (without credentials)
+//
+typedef struct { // discoveropendstr {
+ DHCPV4_OP_HEADER Header; // vendor options
+ PXE_OP_BOOT_ITEM BootItem;
+ UINT8 End[1]; // if credentials option, it starts here
+} PXE_DISCOVER_OPTIONS;
+
+#define DISCOVERoptions (*(PXE_DISCOVER_OPTIONS *) DHCPV4_OPTIONS_BUFFER.End)
+#define DISCREDoptions (*(PXE_OP_CREDENTIAL_TYPES *) DISCOVERoptions.End)
+
+//
+// common option beginning for all our DHCP messages except
+// DHCPDECLINE and DHCPRELEASE
+//
+STATIC struct optionsstr {
+ UINT8 DhcpCookie[4];
+ DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
+ DHCPV4_OP_MAX_MESSAGE_SIZE DhcpMaxMessageSize;
+ DHCPV4_OP_REQUESTED_OPTIONS DhcpRequestedOptions;
+ DHCPV4_OP_PLATFORM_ID DhcpPlatformId;
+ DHCPV4_OP_NETWORK_INTERFACE DhcpNetworkInterface;
+ DHCPV4_OP_ARCHITECTURE_TYPE DhcpClientArchitecture;
+ DHCPV4_OP_CLASS_ID DhcpClassIdentifier;
+ UINT8 End[1];
+} DHCPOpStart;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+OptionsStrucInit (
+ VOID
+ )
+{
+ DHCPOpStart.DhcpCookie[0] = 99;
+ DHCPOpStart.DhcpCookie[1] = 130;
+ DHCPOpStart.DhcpCookie[2] = 83;
+ DHCPOpStart.DhcpCookie[3] = 99;
+ DHCPOpStart.DhcpMessageType.Header.OpCode = OP_DHCP_MESSAGE_TYPE;
+ DHCPOpStart.DhcpMessageType.Header.Length = 1;
+ DHCPOpStart.DhcpMessageType.Type = DHCPDISCOVER;
+ DHCPOpStart.DhcpMaxMessageSize.Header.OpCode = OP_DHCP_MAX_MESSAGE_SZ;
+ DHCPOpStart.DhcpMaxMessageSize.Header.Length = 2;
+ DHCPOpStart.DhcpMaxMessageSize.MaxSize[0] = MAX_DHCP_MSG_SZ >> 8;
+ DHCPOpStart.DhcpMaxMessageSize.MaxSize[1] = MAX_DHCP_MSG_SZ & 0xff;
+ DHCPOpStart.DhcpRequestedOptions.Header.OpCode = OP_DHCP_PARM_REQ_LIST;
+ DHCPOpStart.DhcpRequestedOptions.Header.Length = sizeof (DHCPV4_REQUESTED_OPTIONS_DATA);
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_SUBNET_MASK = OP_SUBNET_MASK; /* 1 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_OFFSET = OP_TIME_OFFSET; /* 2 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_ROUTER_LIST = OP_ROUTER_LIST; /* 3 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_SERVERS = OP_TIME_SERVERS; /* 4 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NAME_SERVERS = OP_NAME_SERVERS; /* 5 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DNS_SERVERS = OP_DNS_SERVERS; /* 6 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_HOST_NAME = OP_HOST_NAME; /* 12 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_BOOT_FILE_SZ = OP_BOOT_FILE_SZ; /* 13 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DOMAIN_NAME = OP_DOMAIN_NAME; /* 15 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_ROOT_PATH = OP_ROOT_PATH; /* 17 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_EXTENSION_PATH = OP_EXTENSION_PATH; /* 18 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_MAX_DATAGRAM_SZ = OP_MAX_DATAGRAM_SZ; /* 22 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DEFAULT_TTL = OP_DEFAULT_TTL; /* 23 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_BROADCAST_ADD = OP_BROADCAST_ADD; /* 28 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_DOMAIN_NAME = OP_NIS_DOMAIN_NAME; /* 40 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_SERVERS = OP_NIS_SERVERS; /* 41 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NTP_SERVERS = OP_NTP_SERVERS; /* 42 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_VENDOR_SPECIFIC = OP_VENDOR_SPECIFIC; /* 43 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REQ_IP_ADD = OP_DHCP_REQ_IP_ADD; /* 50 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_LEASE_TIME = OP_DHCP_LEASE_TIME; /* 51 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_SERVER_IP = OP_DHCP_SERVER_IP; /* 54 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_RENEWAL_TIME = OP_DHCP_RENEWAL_TIME; /* 58 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REBINDING_TIME = OP_DHCP_REBINDING_TIME; /* 59 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_CLASS_IDENTIFIER = OP_DHCP_CLASS_IDENTIFIER; /* 60 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_TFTP_SERVER_NAME = OP_DHCP_TFTP_SERVER_NAME; /* 66 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_BOOTFILE = OP_DHCP_BOOTFILE; /* 67 */
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_PLATFORM_ID = OP_DHCP_PLATFORM_ID; /* 97 */
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption128 = 128;
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption129 = 129;
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption130 = 130;
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption131 = 131;
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption132 = 132;
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption133 = 133, DHCPOpStart.DhcpRequestedOptions.Data.VendorOption134 = 134;
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption135 = 135;
+ DHCPOpStart.DhcpPlatformId.Header.OpCode = OP_DHCP_PLATFORM_ID;
+ DHCPOpStart.DhcpPlatformId.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_PLATFORM_ID);
+ DHCPOpStart.DhcpNetworkInterface.Header.OpCode = OP_DHCP_NETWORK_ARCH;
+ DHCPOpStart.DhcpNetworkInterface.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_NETWORK_INTERFACE);
+ DHCPOpStart.DhcpNetworkInterface.Type = 0;
+ DHCPOpStart.DhcpNetworkInterface.MajorVersion = 0;
+ DHCPOpStart.DhcpNetworkInterface.MinorVersion = 0;
+ DHCPOpStart.DhcpClientArchitecture.Header.OpCode = OP_DHCP_SYSTEM_ARCH;
+ DHCPOpStart.DhcpClientArchitecture.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_ARCHITECTURE_TYPE);
+ DHCPOpStart.DhcpClientArchitecture.Type = HTONS (SYS_ARCH);
+ DHCPOpStart.DhcpClassIdentifier.Header.OpCode = OP_DHCP_CLASS_IDENTIFIER;
+ DHCPOpStart.DhcpClassIdentifier.Header.Length = sizeof (DHCPV4_CLASS_ID_DATA);
+ CopyMem (
+ DHCPOpStart.DhcpClassIdentifier.Data.ClassIdentifier,
+ "PXEClient:",
+ sizeof ("PXEClient:")
+ );
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit2, "Arch:", sizeof ("Arch:"));
+ CopyMem (
+ DHCPOpStart.DhcpClassIdentifier.Data.ArchitectureType,
+ "xxxxx",
+ sizeof ("xxxxx")
+ );
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit3, ":", sizeof (":"));
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.InterfaceName, "XXXX", sizeof ("XXXX"));
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit4, ":", sizeof (":"));
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMajor, "yyy", sizeof ("yyy"));
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMinor, "xxx", sizeof ("xxx"));
+ DHCPOpStart.End[0] = OP_END;
+};
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// DHCPDECLINE option structure
+//
+struct opdeclinestr {
+ UINT8 DhcpCookie[4];
+ DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
+ struct requestopendstr OpDeclineEnd;
+};
+
+#define DHCPDECLINEoptions (*(struct opdeclinestr *) DHCPV4_TRANSMIT_BUFFER.options)
+
+//
+// DHCPRELEASE option structure
+//
+struct opreleasestr {
+ UINT8 DhcpCookie[4];
+ DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;
+ DHCPV4_OP_SERVER_IP DhcServerIpPtr;
+ UINT8 End[1];
+};
+
+#define DHCPRELEASEoptions (*(struct opreleasestr *) DHCPV4_TRANSMIT_BUFFER.options)
+
+//
+// array of PXE vendor options in which we are interested
+// value 0 -> not of interest, else value is index into PXE OPTION array
+// option values from 1 to MAX_OUR_PXE_OPT
+//
+STATIC UINT8 ourPXEopts[MAX_OUR_PXE_OPT] = {
+ VEND_PXE_MTFTP_IP_IX, // multicast IP address of bootfile for MTFTP listen
+ VEND_PXE_MTFTP_CPORT_IX, // UDP Port to monitor for MTFTP responses - Intel order
+ VEND_PXE_MTFTP_SPORT_IX, // Server UDP Port for MTFTP open - Intel order
+ VEND_PXE_MTFTP_TMOUT_IX, // Listen timeout - secs
+ VEND_PXE_MTFTP_DELAY_IX, // Transmission timeout - secs
+ VEND_PXE_DISCOVERY_CONTROL_IX, // bit field
+ VEND_PXE_DISCOVERY_MCAST_ADDR_IX, // boot server discovery multicast address
+ VEND_PXE_BOOT_SERVERS_IX, // list of boot servers of form tp(2) cnt(1) ips[cnt]
+ VEND_PXE_BOOT_MENU_IX,
+ VEND_PXE_BOOT_PROMPT_IX,
+ VEND_PXE_MCAST_ADDRS_ALLOC_IX, // not used by client
+ VEND_PXE_CREDENTIAL_TYPES_IX,
+ VEND_13_IX, // not used by client
+ VEND_14_IX, // not used by client
+ VEND_15_IX, // not used by client
+ VEND_16_IX, // not used by client
+ VEND_17_IX, // not used by client
+ VEND_18_IX, // not used by client
+ VEND_19_IX, // not used by client
+ VEND_20_IX, // not used by client
+ VEND_21_IX, // not used by client
+ VEND_22_IX, // not used by client
+ VEND_23_IX, // not used by client
+ VEND_24_IX, // not used by client
+ VEND_25_IX, // not used by client
+ VEND_26_IX, // not used by client
+ VEND_27_IX, // not used by client
+ VEND_28_IX, // not used by client
+ VEND_29_IX, // not used by client
+ VEND_30_IX, // not used by client
+ VEND_31_IX, // not used by client
+ VEND_32_IX, // not used by client
+ VEND_33_IX, // not used by client
+ VEND_34_IX, // not used by client
+ VEND_35_IX, // not used by client
+ VEND_36_IX, // not used by client
+ VEND_37_IX, // not used by client
+ VEND_38_IX, // not used by client
+ VEND_39_IX, // not used by client
+ VEND_40_IX, // not used by client
+ VEND_41_IX, // not used by client
+ VEND_42_IX, // not used by client
+ VEND_43_IX, // not used by client
+ VEND_44_IX, // not used by client
+ VEND_45_IX, // not used by client
+ VEND_46_IX, // not used by client
+ VEND_47_IX, // not used by client
+ VEND_48_IX, // not used by client
+ VEND_49_IX, // not used by client
+ VEND_50_IX, // not used by client
+ VEND_51_IX, // not used by client
+ VEND_52_IX, // not used by client
+ VEND_53_IX, // not used by client
+ VEND_54_IX, // not used by client
+ VEND_55_IX, // not used by client
+ VEND_56_IX, // not used by client
+ VEND_57_IX, // not used by client
+ VEND_58_IX, // not used by client
+ VEND_59_IX, // not used by client
+ VEND_60_IX, // not used by client
+ VEND_61_IX, // not used by client
+ VEND_62_IX, // not used by client
+ VEND_63_IX, // not used by client
+ VEND_64_IX, // not used by client
+ VEND_65_IX, // not used by client
+ VEND_66_IX, // not used by client
+ VEND_67_IX, // not used by client
+ VEND_68_IX, // not used by client
+ VEND_69_IX, // not used by client
+ VEND_70_IX, // not used by client
+ VEND_PXE_BOOT_ITEM_IX
+};
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// array of options in which we are interested
+// value 0 -> not of interest, else value is index into OPTION array
+// option values from 1 to MAX_OUR_OPT
+//
+STATIC UINT8 OurDhcpOptions[MAX_OUR_OPT] = {
+ OP_SUBNET_MASK_IX, // OP_SUBNET_MASK 1 // data is the subnet mask
+ OP_TIME_OFFSET_IX, // OP_TIME_OFFSET 2 // data is the time offset of subnet to UTC in seconds
+ OP_ROUTER_LIST_IX, // OP_ROUTER_LIST 3 // list of routers on subnet
+ OP_TIME_SERVERS_IX, // OP_TIME_SERVERS 4 // list of time servers available
+ OP_NAME_SERVERS_IX, // OP_NAME_SERVERS 5 // list of name servers available
+ OP_DNS_SERVERS_IX, // OP_DNS_SERVERS 6 // list of DNS servers available
+ OP_LOG_SERVERS_IX, // OP_LOG_SERVERS 7
+ OP_COOKIE_SERVERS_IX, // OP_COOKIE_SERVERS 8
+ OP_LPR_SREVERS_IX, // OP_LPR_SREVERS 9
+ OP_IMPRESS_SERVERS_IX, // OP_IMPRESS_SERVERS 10
+ OP_RES_LOC_SERVERS_IX, // OP_RES_LOC_SERVERS 11
+ OP_HOST_NAME_IX, // OP_HOST_NAME 12 // client name
+ OP_BOOT_FILE_SZ_IX, // OP_BOOT_FILE_SZ 13 // number of 512 blocks of boot file
+ OP_DUMP_FILE_IX, // OP_DUMP_FILE 14 // path name of dump file if client crashes
+ OP_DOMAIN_NAME_IX, // OP_DOMAIN_NAME 15 // domain name to use
+ OP_SWAP_SERVER_IX, // OP_SWAP_SERVER 16
+ OP_ROOT_PATH_IX, // OP_ROOT_PATH 17 // path name containing root disk
+ OP_EXTENSION_PATH_IX, // OP_EXTENSION_PATH 18 // name of TFTP downloadable file of form of OP
+ OP_IP_FORWARDING_IX, // OP_IP_FORWARDING 19 // enable/disable IP packet forwarding
+ OP_NON_LOCAL_SRC_RTE_IX, // OP_NON_LOCAL_SRC_RTE 20 // enable/disable non local source routing
+ OP_POLICY_FILTER_IX, // OP_POLICY_FILTER 21 // policy filters for non local source routing
+ OP_MAX_DATAGRAM_SZ_IX, // OP_MAX_DATAGRAM_SZ 22 // maximum datagram reassembly size
+ OP_DEFAULT_TTL_IX, // OP_DEFAULT_TTL 23 // default IP time to live
+ OP_MTU_AGING_TIMEOUT_IX, // OP_MTU_AGING_TIMEOUT 24
+ OP_MTU_SIZES_IX, // OP_MTU_SIZES 25
+ OP_MTU_TO_USE_IX, // OP_MTU_TO_USE 26
+ OP_ALL_SUBNETS_LOCAL_IX, // OP_ALL_SUBNETS_LOCAL 27
+ OP_BROADCAST_ADD_IX, // OP_BROADCAST_ADD 28 // broadcast address used on subnet
+ OP_PERFORM_MASK_DISCOVERY_IX, // OP_PERFORM_MASK_DISCOVERY 29 // perform mask discovery using ICMP
+ OP_RESPOND_TO_MASK_REQ_IX, // OP_RESPOND_TO_MASK_REQ 30 // respond to subnet mask requests using ICMP
+ OP_PERFORM_ROUTER_DISCOVERY_IX, // OP_PERFORM_ROUTER_DISCOVERY 31
+ OP_ROUTER_SOLICIT_ADDRESS_IX, // OP_ROUTER_SOLICIT_ADDRESS 32
+ OP_STATIC_ROUTER_LIST_IX, // OP_STATIC_ROUTER_LIST 33 // list of dest/route pairs
+ OP_USE_ARP_TRAILERS_IX, // OP_USE_ARP_TRAILERS 34
+ OP_ARP_CACHE_TIMEOUT_IX, // OP_ARP_CACHE_TIMEOUT 35
+ OP_ETHERNET_ENCAPSULATION_IX, // OP_ETHERNET_ENCAPSULATION 36 // 0 -> RFC 894, 1 -> IEEE 802.3 (RFC 1042)
+ OP_TCP_DEFAULT_TTL_IX, // OP_TCP_DEFAULT_TTL 37 // default time to live when sending TCP segments
+ OP_TCP_KEEP_ALIVE_INT_IX, // OP_TCP_KEEP_ALIVE_INT 38 // keep alive interval in seconds
+ OP_KEEP_ALIVE_GARBAGE_IX, // OP_KEEP_ALIVE_GARBAGE 39
+ OP_NIS_DOMAIN_NAME_IX, // OP_NIS_DOMAIN_NAME 40
+ OP_NIS_SERVERS_IX, // OP_NIS_SERVERS 41
+ OP_NTP_SERVERS_IX, // OP_NTP_SERVERS 42
+ OP_VENDOR_SPECIFIC_IX, // OP_VENDOR_SPECIFIC 43
+ OP_NBNS_SERVERS_IX, // OP_NBNS_SERVERS 44
+ OP_NBDD_SERVERS_IX, // OP_NBDD_SERVERS 45
+ OP_NETBIOS_NODE_TYPE_IX, // OP_NETBIOS_NODE_TYPE 46
+ OP_NETBIOS_SCOPE_IX, // OP_NETBIOS_SCOPE 47
+ OP_XWINDOW_SYSTEM_FONT_SERVERS_IX, // OP_XWINDOW_SYSTEM_FONT_SERVERS 48
+ OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX, // OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49
+ OP_DHCP_REQ_IP_ADD_IX, // OP_DHCP_REQ_IP_ADD 50 // requested IP address - in DHCPDISCOVER
+ OP_DHCP_LEASE_TIME_IX, // OP_DHCP_LEASE_TIME 51 // lease time requested/granted
+ OP_DHCP_OPTION_OVERLOAD_IX, // OP_DHCP_OPTION_OVERLOAD 52 // file/server name/both used to hold options
+ OP_DHCP_MESSAGE_TYPE_IX, // OP_DHCP_MESSAGE_TYPE 53 // message type
+ OP_DHCP_SERVER_IP_IX, // OP_DHCP_SERVER_IP 54 // IP of server
+ OP_DHCP_PARM_REQ_LIST_IX, // OP_DHCP_PARM_REQ_LIST 55 // list of requested parameters
+ OP_DHCP_ERROR_MESSAGE_IX, // OP_DHCP_ERROR_MESSAGE 56 // in DHCPNAK or DECLINE messages
+ OP_DHCP_MAX_MESSAGE_SZ_IX, // OP_DHCP_MAX_MESSAGE_SZ 57 // maximum DHCP message size client will accept
+ OP_DHCP_RENEWAL_TIME_IX, // OP_DHCP_RENEWAL_TIME 58 // time in seconds before transitioning to RENEWING state
+ OP_DHCP_REBINDING_TIME_IX, // OP_DHCP_REBINDING_TIME 59 // time in seconds before transitioning to REBINDING state
+ OP_DHCP_CLASS_IDENTIFIER_IX, // OP_DHCP_CLASS_IDENTIFIER 60
+ OP_DHCP_CLIENT_IDENTIFIER_IX, // OP_DHCP_CLIENT_IDENTIFIER 61
+ OP_RESERVED62_IX, // OP_RESERVED62
+ OP_RESERVED63_IX, // OP_RESERVED63
+ OP_NISPLUS_DOMAIN_NAME_IX, // OP_NISPLUS_DOMAIN_NAME 64
+ OP_NISPLUS_SERVERS_IX, // OP_NISPLUS_SERVERS 65
+ OP_DHCP_TFTP_SERVER_NAME_IX, // OP_DHCP_TFTP_SERVER_NAME 66
+ OP_DHCP_BOOTFILE_IX // OP_DHCP_BOOTFILE 67
+};
+
+#define RxBuf ((DHCP_RECEIVE_BUFFER *) (Private->ReceiveBuffers))
+
+#pragma pack()
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+CHAR8 *
+PxeBcLibGetSmbiosString (
+ IN SMBIOS_STRUCTURE_POINTER *Smbios,
+ IN UINT16 StringNumber
+ )
+/*++
+Routine description:
+ Return SMBIOS string given the string number.
+
+Arguments:
+ Smbios - Pointer to SMBIOS structure
+ StringNumber - String number to return. 0 is used to skip all strings and
+ point to the next SMBIOS structure.
+
+Returns:
+ Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0
+--*/
+{
+ UINT16 Index;
+ CHAR8 *String;
+
+ //
+ // Skip over formatted section
+ //
+ String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);
+
+ //
+ // Look through unformated section
+ //
+ for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {
+ if (StringNumber == Index) {
+ return String;
+ }
+ //
+ // Skip string
+ //
+ for (; *String != 0; String++)
+ ;
+ String++;
+
+ if (*String == 0) {
+ //
+ // If double NULL then we are done.
+ // Return pointer to next structure in Smbios.
+ // if you pass in a 0 you will always get here
+ //
+ Smbios->Raw = (UINT8 *)++String;
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+EFI_STATUS
+PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
+ IN EFI_GUID *SystemGuid,
+ OUT CHAR8 **SystemSerialNumber
+ )
+/*++
+
+Routine Description:
+ This function gets system guid and serial number from the smbios table
+
+Arguments:
+ SystemGuid - The pointer of returned system guid
+ SystemSerialNumber - The pointer of returned system serial number
+
+Returns:
+ EFI_SUCCESS - Successfully get the system guid and system serial number
+ EFI_NOT_FOUND - Not find the SMBIOS table
+--*/
+{
+ EFI_STATUS Status;
+ SMBIOS_STRUCTURE_TABLE *SmbiosTable;
+ SMBIOS_STRUCTURE_POINTER Smbios;
+ SMBIOS_STRUCTURE_POINTER SmbiosEnd;
+ UINT16 Index;
+
+ Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Smbios.Hdr = (SMBIOS_HEADER *) (UINTN) SmbiosTable->TableAddress;
+ SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
+
+ for (Index = 0; Index < SmbiosTable->TableLength; Index++) {
+ if (Smbios.Hdr->Type == 1) {
+ if (Smbios.Hdr->Length < 0x19) {
+ //
+ // Older version did not support Guid and Serial number
+ //
+ continue;
+ }
+ //
+ // SMBIOS tables are byte packed so we need to do a byte copy to
+ // prevend alignment faults on Itanium-based platform.
+ //
+ CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
+ *SystemSerialNumber = PxeBcLibGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Make Smbios point to the next record
+ //
+ PxeBcLibGetSmbiosString (&Smbios, 0);
+
+ if (Smbios.Raw >= SmbiosEnd.Raw) {
+ //
+ // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.
+ // given this we must double check against the lenght of
+ // the structure.
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// add router list to list
+//
+STATIC
+VOID
+Ip4AddRouterList (
+ PXE_BASECODE_DEVICE *Private,
+ DHCPV4_OP_IP_LIST *IpListPtr
+ )
+{
+ EFI_IP_ADDRESS TmpIp;
+ INTN Index;
+ INTN num;
+
+ if (IpListPtr == NULL) {
+ return ;
+ }
+
+ for (Index = 0, num = IpListPtr->Header.Length >> 2; Index < num; ++Index) {
+ CopyMem (&TmpIp, &IpListPtr->IpList[Index], 4);
+ Ip4AddRouter (Private, &TmpIp);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// send ARP for our IP - fail if someone has it
+//
+STATIC
+BOOLEAN
+SetStationIP (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ EFI_MAC_ADDRESS DestMac;
+ EFI_STATUS EfiStatus;
+
+ ZeroMem (&DestMac, sizeof DestMac);
+
+ if (GetHwAddr(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac)
+ || DoArp(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) == EFI_SUCCESS) {
+ return FALSE; // somebody else has this IP
+ }
+
+ CopyMem (
+ (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->StationIp,
+ &DHCP_REQ_OPTIONS.OpReqIP.Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ Private->GoodStationIp = TRUE;
+
+ if (!Private->UseIgmpv1Reporting) {
+ return TRUE;
+ }
+
+ if (Private->Igmpv1TimeoutEvent != NULL) {
+ return TRUE;
+ }
+
+ EfiStatus = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Private->Igmpv1TimeoutEvent
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->Igmpv1TimeoutEvent = NULL;
+ return TRUE;
+ }
+
+ EfiStatus = gBS->SetTimer (
+ Private->Igmpv1TimeoutEvent,
+ TimerRelative,
+ (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
+ ); /* 400 seconds */
+
+ if (EFI_ERROR (EfiStatus)) {
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
+ Private->Igmpv1TimeoutEvent = NULL;
+ }
+
+ return TRUE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+AddRouters (
+ PXE_BASECODE_DEVICE *Private,
+ DHCP_RECEIVE_BUFFER *RxBufPtr
+ )
+{
+ Ip4AddRouter (Private, &RxBufPtr->u.Dhcpv4.giaddr);
+
+ Ip4AddRouterList (
+ Private,
+ (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1]
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+DoUdpWrite (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_IP_ADDRESS *ClientIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr
+ )
+{
+ UINTN Len;
+
+ Len = sizeof DHCPV4_TRANSMIT_BUFFER;
+
+ return UdpWrite (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
+ ServerIpPtr,
+ ServerPortPtr,
+ 0,
+ ClientIpPtr,
+ ClientPortPtr,
+ 0,
+ 0,
+ &Len,
+ Private->TransmitBuffer
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// initialize the DHCP structure
+//
+typedef struct {
+ UINT8 x[4];
+} C4Str;
+
+STATIC
+VOID
+InitDhcpv4TxBuf (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ UINTN HwAddrLen;
+ UINT8 *String;
+ CHAR8 *SystemSerialNumber;
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+
+ PxebcMode = Private->EfiBc.Mode;
+
+ ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT));
+ DHCPV4_TRANSMIT_BUFFER.op = BOOTP_REQUEST;
+ DHCPV4_TRANSMIT_BUFFER.htype = Private->SimpleNetwork->Mode->IfType;
+ DHCPV4_TRANSMIT_BUFFER.flags = HTONS (DHCP_BROADCAST_FLAG);
+ CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart));
+
+ //
+ // default to hardware address
+ //
+ HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize;
+
+ if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) {
+ HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr;
+ }
+
+ String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress;
+
+ if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
+ (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid,
+ &SystemSerialNumber
+ ) == EFI_SUCCESS) {
+ if (PxebcMode->SendGUID) {
+ HwAddrLen = sizeof (EFI_GUID);
+ String = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid;
+ }
+ } else {
+ //
+ // GUID not yet set - send all 0xff's to show programable (via SetVariable)
+ // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
+ // GUID not yet set - send all 0's to show not programable
+ //
+ ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID));
+ }
+
+ DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen;
+ CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen);
+
+ CvtNum (
+ SYS_ARCH,
+ (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType,
+ sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType
+ );
+
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type = Private->NiiPtr->Type;
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion = Private->NiiPtr->MajorVer;
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion = Private->NiiPtr->MinorVer;
+
+ *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId;
+
+ CvtNum (
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion,
+ (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor,
+ sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor
+ );
+
+ CvtNum (
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion,
+ (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor,
+ sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+UINT32
+DecodePxeOptions (
+ DHCP_RECEIVE_BUFFER *RxBufPtr,
+ UINT8 *ptr,
+ INTN Len
+ )
+{
+ UINT8 Op;
+ UINT8 *EndPtr;
+ INTN Index;
+ UNION_PTR LocalPtr;
+ UINT32 status;
+
+ status = 0;
+
+ for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
+ Op = ptr[0];
+ Len = ptr[1];
+
+ switch (Op) {
+ case OP_PAD:
+ Len = -1;
+ break;
+
+ case OP_END:
+ return status;
+
+ default:
+ LocalPtr.BytePtr = ptr;
+ if (Op <= MAX_OUR_PXE_OPT) {
+ Index = ourPXEopts[Op - 1];
+ if (Index) {
+ RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr;
+ status |= 1 << Index;
+ if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) {
+ RxBufPtr->OpAdds.Status |= USE_THREE_BYTE;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return status;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+DecodeOptions (
+ DHCP_RECEIVE_BUFFER *RxBufPtr,
+ UINT8 *ptr,
+ INTN Len
+ )
+{
+ UINT8 Op;
+ UINT8 *EndPtr;
+ INTN Index;
+ UNION_PTR LocalPtr;
+
+ for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {
+ Op = ptr[0];
+ Len = ptr[1];
+
+ switch (Op) {
+ case OP_PAD:
+ Len = -1;
+ break;
+
+ case OP_END:
+ return ;
+
+ default:
+ LocalPtr.BytePtr = ptr;
+ if (Op <= MAX_OUR_OPT) {
+ Index = OurDhcpOptions[Op - 1];
+ if (Index) {
+ RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr;
+ if (Index == OP_VENDOR_SPECIFIC_IX) {
+ UINT32 status;
+ status = DecodePxeOptions (
+ RxBufPtr,
+ (UINT8 *) LocalPtr.VendorOptions->VendorOptions,
+ LocalPtr.VendorOptions->Header.Length
+ );
+ if (status) {
+ RxBufPtr->OpAdds.Status |= PXE_TYPE;
+ //
+ // check for all the MTFTP info options present - any missing is a nogo
+ //
+ if ((status & WfM11a_OPTS) == WfM11a_OPTS) {
+ RxBufPtr->OpAdds.Status |= WfM11a_TYPE;
+ }
+
+ if (status & DISCOVER_OPTS) {
+ RxBufPtr->OpAdds.Status |= DISCOVER_TYPE;
+ }
+
+ if (status & CREDENTIALS_OPT) {
+ RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+Parse (
+ DHCP_RECEIVE_BUFFER *RxBufPtr,
+ INTN Len
+ )
+{
+ UNION_PTR LocalPtr;
+
+ //
+ // initialize
+ //
+ SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0);
+
+ DecodeOptions (
+ RxBufPtr,
+ RxBufPtr->u.Dhcpv4.options + 4,
+ Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4)
+ );
+
+ LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1];
+
+ if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) {
+ DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname);
+ }
+
+ if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) {
+ DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file);
+ } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) {
+ RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER));
+
+ RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen ((CHAR8 *)RxBufPtr->u.Dhcpv4.file);
+ }
+
+ LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1];
+
+ if ((LocalPtr.OpPtr) &&
+ LocalPtr.PxeClassStr->Header.Length >= 9 &&
+ !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9)
+ ) {
+ RxBufPtr->OpAdds.Status |= PXE_TYPE;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+CopyParseRxBuf (
+ PXE_BASECODE_DEVICE *Private,
+ INTN RxBufIndex,
+ INTN PacketIndex
+ )
+{
+ DHCP_RECEIVE_BUFFER *RxBufPtr;
+
+ RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex];
+
+ CopyMem (
+ &RxBufPtr->u.Dhcpv4,
+ &RxBuf[RxBufIndex].u.Dhcpv4,
+ sizeof (RxBuf[RxBufIndex].u.Dhcpv4)
+ );
+
+ Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+CopyProxyRxBuf (
+ PXE_BASECODE_DEVICE *Private,
+ INTN RxBufIndex
+ )
+{
+ Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
+ CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+CopyParse (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_PXE_BASE_CODE_PACKET *PacketPtr,
+ EFI_PXE_BASE_CODE_PACKET *NewPacketPtr,
+ INTN Index
+ )
+{
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;
+
+ DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index];
+
+ CopyMem (
+ (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4,
+ NewPacketPtr,
+ sizeof (*NewPacketPtr)
+ );
+
+ CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr));
+
+ Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+BOOLEAN
+AckEdit (
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf
+ )
+{
+ UNION_PTR LocalPtr;
+
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
+
+ //
+ // check that an ACK
+ // if a DHCP type, must be DHCPOFFER and must have server id
+ //
+ return (BOOLEAN)
+ (
+ (LocalPtr.OpPtr) &&
+ (LocalPtr.MessageType->Type == DHCPACK) &&
+ DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// if a discover type packet, make sure all required fields are present
+//
+BOOLEAN
+DHCPOfferAckEdit (
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf
+ )
+{
+ PXE_OP_SERVER_LIST *BootServerOpPtr;
+ UNION_PTR LocalPtr;
+
+ if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) {
+ return TRUE;
+ }
+
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
+
+ if (LocalPtr.OpPtr == NULL) {
+ LocalPtr.OpPtr = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
+ DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;
+ }
+ //
+ // make sure all required fields are here
+ // if mucticast enabled, need multicast address
+ //
+ if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) &&
+ (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1] || !IS_MULTICAST (((DHCPV4_OP_STRUCT *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Data))
+ ) {
+ return FALSE;
+ //
+ // missing required field
+ //
+ }
+ //
+ // if a list, it better be good
+ //
+ BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1];
+
+ if (BootServerOpPtr != NULL) {
+ PXE_SERVER_LIST *BootServerListPtr;
+ INTN ServerListLen;
+ INTN ServerEntryLen;
+
+ BootServerListPtr = BootServerOpPtr->ServerList;
+ ServerListLen = BootServerOpPtr->Header.Length;
+
+ do {
+ EFI_IPv4_ADDRESS *IpListPtr;
+ INTN IpCnt;
+
+ IpCnt = BootServerListPtr->u.Ipv4List.IpCount;
+
+ ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS);
+
+ if (ServerListLen < ServerEntryLen) {
+ //
+ // missing required field
+ //
+ return FALSE;
+ }
+
+ IpListPtr = BootServerListPtr->u.Ipv4List.IpList;
+
+ while (IpCnt--) {
+ if (IS_MULTICAST (IpListPtr)) {
+ //
+ // missing required field
+ //
+ return FALSE;
+ } else {
+ ++IpListPtr;
+ }
+ }
+
+ BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr;
+ } while (ServerListLen -= ServerEntryLen);
+ }
+ //
+ // else there must be a list if use list enabled or multicast and
+ // broadcast disabled
+ //
+ else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) ||
+ ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
+ ) {
+ //
+ // missing required field
+ //
+ return FALSE;
+ }
+ //
+ // if not USE_BOOTFILE or no bootfile given, must have menu stuff
+ //
+ if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) ||
+ !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
+ ) {
+ INTN MenuLth;
+
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
+
+ if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) {
+ //
+ // missing required field
+ //
+ return FALSE;
+ }
+ //
+ // make sure menu valid
+ //
+ MenuLth = LocalPtr.BootMenu->Header.Length;
+ LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem;
+
+ do {
+ INTN MenuItemLen;
+
+ MenuItemLen = LocalPtr.BootMenuItem->DataLen;
+
+ if (MenuItemLen == 0) {
+ //
+ // missing required field
+ //
+ return FALSE;
+ }
+
+ MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data);
+
+ MenuLth -= MenuItemLen;
+ LocalPtr.BytePtr += MenuItemLen;
+ } while (MenuLth > 0);
+
+ if (MenuLth != 0) {
+ //
+ // missing required field
+ //
+ return FALSE;
+ }
+ }
+
+ if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
+ DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem;
+ }
+
+ return TRUE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+BOOLEAN
+DHCPAckEdit (
+ DHCP_RECEIVE_BUFFER *RxBufPtr
+ )
+{
+ return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// get an offer/ack
+//
+EFI_STATUS
+GetOfferAck (
+ PXE_BASECODE_DEVICE *Private,
+ BOOLEAN (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf),
+ UINT16 OpFlags, // for Udp read
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_IP_ADDRESS *ClientIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr,
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf,
+ EFI_EVENT TimeoutEvent
+ )
+/*++
+Routine description:
+ Wait for an OFFER/ACK packet.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ ExtraEdit := Pointer to extra option checking function
+ OpFlags := UdpRead() option flags
+ ServerIpPtr :=
+ ServerPortPtr :=
+ ClientIpPtr :=
+ ClientPortPtr :=
+ DhcpRxBuf :=
+ TimeoutEvent :=
+
+Returns:
+--*/
+{
+ EFI_IP_ADDRESS ServerIp;
+ EFI_STATUS StatCode;
+ INTN RxBufLen;
+
+ for (;;) {
+ //
+ // Wait until we get a UDP packet.
+ //
+ ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
+ RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer;
+
+ if ((StatCode = UdpRead (
+ Private,
+ OpFlags,
+ ClientIpPtr,
+ ClientPortPtr,
+ ServerIpPtr,
+ ServerPortPtr,
+ 0,
+ 0,
+ (UINTN *) &RxBufLen,
+ &DhcpRxBuf->u.Dhcpv4,
+ TimeoutEvent
+ )) != EFI_SUCCESS) {
+ if (StatCode == EFI_TIMEOUT) {
+ StatCode = EFI_NO_RESPONSE;
+ }
+
+ break;
+ }
+ //
+ // got a packet - see if a good offer
+ //
+ if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) {
+ continue;
+ }
+
+ if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) {
+ continue;
+ }
+
+ if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) {
+ continue;
+ }
+
+ if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) {
+ continue;
+ }
+
+ if (CompareMem (
+ DhcpRxBuf->u.Dhcpv4.chaddr,
+ DHCPV4_TRANSMIT_BUFFER.chaddr,
+ sizeof DhcpRxBuf->u.Dhcpv4.chaddr
+ )) {
+ //
+ // no good
+ //
+ continue;
+ }
+
+ Parse (DhcpRxBuf, RxBufLen);
+
+ if (!(*ExtraEdit) (DhcpRxBuf)) {
+ continue;
+ }
+ //
+ // Good DHCP packet.
+ //
+ StatCode = EFI_SUCCESS;
+ break;
+ }
+
+ return StatCode;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// get DHCPOFFER's
+//
+EFI_STATUS
+GetOffers (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ EFI_IP_ADDRESS ClientIp;
+ EFI_IP_ADDRESS ServerIp;
+ EFI_STATUS StatCode;
+ EFI_EVENT TimeoutEvent;
+ INTN NumOffers;
+ INTN Index;
+
+ //
+ //
+ //
+ ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
+ NumOffers = 0;
+
+ for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) {
+ Private->ServerCount[Index] = 0;
+ Private->GotProxy[Index] = 0;
+ }
+
+ Private->GotBootp = 0;
+ //
+ // these we throw away
+ //
+ Private->GotProxy[DHCP_ONLY_IX] = 1;
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return StatCode;
+ }
+
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ Private->Timeout * 10000000 + 1000000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return StatCode;
+ }
+ //
+ // get offers
+ //
+ for (;;) {
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;
+ UNION_PTR LocalPtr;
+
+ DhcpRxBuf = &RxBuf[NumOffers];
+
+ if ((
+ StatCode = GetOfferAck (
+ Private,
+ DHCPOfferAckEdit,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP |
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ &ServerIp,
+ &DhcpServerPort,
+ &ClientIp,
+ &DHCPClientPort,
+ DhcpRxBuf,
+ TimeoutEvent
+ )
+) != EFI_SUCCESS
+ ) {
+ break;
+ }
+
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];
+
+ //
+ // check type of offer
+ //
+ if (LocalPtr.OpPtr == NULL) {
+ //
+ // bootp - we only need one and make sure has bootfile
+ //
+ if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
+ continue;
+ }
+
+ Private->GotBootp = (UINT8) (NumOffers + 1);
+ }
+ //
+ // if a DHCP type, must be DHCPOFFER and must have server id
+ //
+ else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) {
+ continue;
+ } else {
+ INTN TypeIx;
+
+ //
+ // get type - PXE10, WfM11a, or BINL
+ //
+ if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) {
+ TypeIx = PXE10_IX;
+ } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) {
+ //
+ // WfM - make sure it has a bootfile
+ //
+ if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
+ continue;
+ }
+
+ TypeIx = WfM11a_IX;
+ } else {
+ TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX;
+ }
+ //
+ // check DHCP or proxy
+ //
+ if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) {
+ //
+ // proxy - only need one of each type if not BINL
+ // and must have at least PXE_TYPE
+ //
+ if (TypeIx == BINL_IX) {
+ Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers;
+ } else if (Private->GotProxy[TypeIx]) {
+ continue;
+ } else {
+ Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1);
+ }
+ } else {
+ Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers;
+ }
+ }
+
+ if (++NumOffers == MAX_OFFERS) {
+ break;
+ }
+ }
+
+ gBS->CloseEvent (TimeoutEvent);
+ Private->NumOffersReceived = NumOffers;
+
+ return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// send DHCPDECLINE
+//
+STATIC
+VOID
+DeclineOffer (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ UINT16 SaveSecs;
+
+ PxebcMode = Private->EfiBc.Mode;
+ SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
+
+ DHCPV4_TRANSMIT_BUFFER.secs = 0;
+ DHCPV4_TRANSMIT_BUFFER.flags = 0;
+ SetMem (
+ DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr),
+ sizeof (DHCPOpStart) - sizeof (struct opdeclinestr),
+ OP_PAD
+ );
+ DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE;
+ CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (struct requestopendstr));
+ // DHCPDECLINEoptions.OpDeclineEnd = DHCP_REQ_OPTIONS;
+
+ {
+ EFI_IP_ADDRESS TmpIp;
+
+ CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp);
+
+ DoUdpWrite (
+ Private,
+ &TmpIp,
+ &DhcpServerPort,
+ &PxebcMode->StationIp,
+ &DHCPClientPort
+ );
+ }
+
+ InitDhcpv4TxBuf (Private);
+ DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
+ Private->GoodStationIp = FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// send DHCPRELEASE
+//
+STATIC
+BOOLEAN
+Release (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ UINT16 SaveSecs;
+ DHCPV4_OP_SERVER_IP *Point;
+
+ PxebcMode = Private->EfiBc.Mode;
+ SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
+ DHCPV4_TRANSMIT_BUFFER.secs = 0;
+
+ SetMem (
+ DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr),
+ sizeof (DHCPOpStart) - sizeof (struct opreleasestr),
+ OP_PAD
+ );
+
+ DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE;
+ Point = (DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1];
+ CopyMem (
+ &DHCPRELEASEoptions.DhcServerIpPtr,
+ &Point,
+ sizeof DHCPRELEASEoptions.DhcServerIpPtr
+ );
+
+ DHCPRELEASEoptions.End[0] = OP_END;
+
+ {
+ EFI_IP_ADDRESS TmpIp;
+
+ CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp);
+
+ DoUdpWrite (
+ Private,
+ &TmpIp,
+ &DhcpServerPort,
+ &PxebcMode->StationIp,
+ &DHCPClientPort
+ );
+ }
+
+ InitDhcpv4TxBuf (Private);
+
+ DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
+ Private->GoodStationIp = FALSE;
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+BOOLEAN
+GetBINLAck (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ServerIpPtr
+ )
+{
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;
+ EFI_STATUS StatCode;
+ EFI_EVENT TimeoutEvent;
+
+ //
+ //
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return FALSE;
+ }
+
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ Private->Timeout * 10000000 + 1000000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return FALSE;
+ }
+ //
+ //
+ //
+ DhcpRxBuf = &PXE_BINL_BUFFER;
+
+ for (;;) {
+ EFI_PXE_BASE_CODE_UDP_PORT BINLSrvPort;
+
+ BINLSrvPort = 0;
+
+ if (GetOfferAck (
+ Private,
+ AckEdit,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ ServerIpPtr,
+ &BINLSrvPort,
+ &Private->EfiBc.Mode->StationIp,
+ &PSEUDO_DHCP_CLIENT_PORT,
+ DhcpRxBuf,
+ TimeoutEvent
+ ) != EFI_SUCCESS) {
+ break;
+ }
+ //
+ // make sure from whom we wanted
+ //
+ if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem (
+ &ServerIpPtr->v4,
+ &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
+ sizeof (ServerIpPtr->v4)
+ )) {
+ gBS->CloseEvent (TimeoutEvent);
+ //
+ // got an ACK from server
+ //
+ return TRUE;
+ }
+ }
+
+ gBS->CloseEvent (TimeoutEvent);
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// make sure we can get BINL
+// send DHCPREQUEST to PXE server
+//
+STATIC
+BOOLEAN
+TryBINL (
+ PXE_BASECODE_DEVICE *Private,
+ INTN OfferIx
+ )
+{
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;
+ EFI_IP_ADDRESS ServerIp;
+ UINT16 SaveSecs;
+ INTN Index;
+
+ DhcpRxBuf = &RxBuf[OfferIx];
+
+ //
+ // send DHCP request
+ // if fail return false
+ //
+ CopyMem (
+ ((EFI_IPv4_ADDRESS *) &ServerIp),
+ &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ //
+ // client IP address - filled in by client if it knows it
+ //
+ CopyMem (
+ ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr),
+ &DHCP_REQ_OPTIONS.OpReqIP.Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD);
+ DHCPV4_TRANSMIT_BUFFER.flags = 0;
+ DHCPV4_OPTIONS_BUFFER.End[0] = OP_END;
+ AddRouters (Private, DhcpRxBuf);
+ SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;
+
+ for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) {
+ DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
+
+ //
+ // unicast DHCPREQUEST to PXE server
+ //
+ if (DoUdpWrite (
+ Private,
+ &ServerIp,
+ &PseudoDhcpServerPort,
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
+ &PSEUDO_DHCP_CLIENT_PORT
+ ) != EFI_SUCCESS) {
+ break;
+ }
+
+ if (!GetBINLAck (Private, &ServerIp)) {
+ continue;
+ }
+ //
+ // early exit failures
+ // make sure a good ACK
+ //
+ if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || (
+ !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
+ )
+ ) {
+ break;
+ }
+
+ Private->EfiBc.Mode->ProxyOfferReceived = TRUE;
+ return TRUE;
+ }
+ //
+ // failed - reset seconds field, etc.
+ //
+ Private->EfiBc.Mode->RouteTableEntries = 0;
+ //
+ // reset
+ //
+ DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+BOOLEAN
+TryFinishBINL (
+ PXE_BASECODE_DEVICE *Private,
+ INTN OfferIx
+ )
+{
+ if (TryBINL (Private, OfferIx)) {
+ return TRUE;
+ }
+
+ return Release (Private);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+BOOLEAN
+TryFinishProxyBINL (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) {
+ if (TryBINL (Private, Private->BinlProxies[Index])) {
+ return TRUE;
+ }
+ }
+
+ return Release (Private);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// try to finish DORA - send DHCP request, wait for ACK, check with ARP
+//
+STATIC
+BOOLEAN
+TryFinishDORA (
+ PXE_BASECODE_DEVICE *Private,
+ INTN OfferIx
+ )
+{
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;
+ EFI_IP_ADDRESS ClientIp;
+ EFI_IP_ADDRESS ServerIp;
+ EFI_STATUS StatCode;
+ UNION_PTR LocalPtr;
+ EFI_EVENT TimeoutEvent;
+
+ //
+ // send DHCP request
+ // if fail return false
+ //
+ DhcpRxBuf = &DHCPV4_ACK_BUFFER;
+ DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
+ CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (RequestOpEndStr));
+// DHCP_REQ_OPTIONS = RequestOpEndStr;
+ DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[OfferIx].u.Dhcpv4.yiaddr;
+
+ CopyMem (
+ &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
+ &((DHCPV4_OP_SERVER_IP *) RxBuf[OfferIx].OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
+ sizeof DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip
+ );
+
+ CopyMem (
+ Private->EfiBc.Mode->SubnetMask.Addr,
+ &DefaultSubnetMask,
+ 4
+ );
+
+ //
+ // broadcast DHCPREQUEST
+ //
+ if (DoUdpWrite (
+ Private,
+ &BroadcastIP,
+ &DhcpServerPort,
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
+ &DHCPClientPort
+ ) != EFI_SUCCESS) {
+ return FALSE;
+ }
+ //
+ //
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return FALSE;
+ }
+
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerPeriodic,
+ Private->Timeout * 10000000 + 1000000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return FALSE;
+ }
+ //
+ // wait for ACK
+ //
+ for (;;) {
+ if (GetOfferAck (
+ Private,
+ DHCPAckEdit,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,
+ &ServerIp,
+ &DhcpServerPort,
+ &ClientIp,
+ &DHCPClientPort,
+ DhcpRxBuf,
+ TimeoutEvent
+ ) != EFI_SUCCESS) {
+ break;
+ }
+ //
+ // check type of response - need DHCPACK
+ //
+ if (CompareMem (
+ &DHCP_REQ_OPTIONS.OpReqIP.Ip,
+ &DhcpRxBuf->u.Dhcpv4.yiaddr,
+ sizeof (EFI_IPv4_ADDRESS)
+ ) || CompareMem (
+ &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,
+ &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ )) {
+ continue;
+ }
+ //
+ // got ACK
+ // check with ARP that IP unused - good return true
+ //
+ if (!SetStationIP (Private)) {
+ //
+ // fail - send DHCPDECLINE and return false
+ //
+ DeclineOffer (Private);
+ break;
+ }
+
+ LocalPtr.OpPtr = DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
+
+ if (LocalPtr.OpPtr != NULL) {
+ CopyMem (
+ (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask,
+ &LocalPtr.SubnetMaskStr->Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ }
+
+ AddRouters (Private, DhcpRxBuf);
+ gBS->CloseEvent (TimeoutEvent);
+ return TRUE;
+ }
+
+ gBS->CloseEvent (TimeoutEvent);
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// try a DHCP server of appropriate type
+//
+STATIC
+BOOLEAN
+TryDHCPFinishDORA (
+ PXE_BASECODE_DEVICE *Private,
+ INTN TypeIx
+ )
+{
+ INTN Index;
+
+ //
+ // go through the DHCP servers of the requested type
+ //
+ for (Index = 0; Index < Private->ServerCount[TypeIx]; ++Index) {
+ if (TryFinishDORA (Private, Index = Private->OfferCount[TypeIx][Index])) {
+ if (TypeIx == BINL_IX && !TryFinishBINL (Private, Index)) {
+ continue;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// try a DHCP only server and a proxy of appropriate type
+//
+STATIC
+BOOLEAN
+TryProxyFinishDORA (
+ PXE_BASECODE_DEVICE *Private,
+ INTN TypeIx
+ )
+{
+ INTN Index;
+
+ if (!Private->GotProxy[TypeIx]) {
+ //
+ // no proxies of the type wanted
+ //
+ return FALSE;
+ }
+ //
+ // go through the DHCP only servers
+ //
+ for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
+ if (TryFinishDORA (Private, Private->OfferCount[DHCP_ONLY_IX][Index])) {
+ if (TypeIx != BINL_IX) {
+ CopyProxyRxBuf (Private, Private->GotProxy[TypeIx] - 1);
+ } else if (!TryFinishProxyBINL (Private)) {
+ //
+ // if didn't work with this DHCP, won't work with any
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// getting to the bottom of the barrel
+//
+STATIC
+BOOLEAN
+TryAnyWithBootfileFinishDORA (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ //
+ // try a DHCP only server who has a bootfile
+ //
+ UNION_PTR LocalPtr;
+ INTN Index;
+
+ for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {
+ INTN offer;
+
+ offer = Private->OfferCount[DHCP_ONLY_IX][Index];
+
+ if (RxBuf[offer].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && TryFinishDORA (Private, offer)) {
+ return TRUE;
+ }
+ }
+ //
+ // really at bottom - see if be have any bootps
+ //
+ if (!Private->GotBootp) {
+ return FALSE;
+ }
+
+ DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[Private->GotBootp - 1].u.Dhcpv4.yiaddr;
+
+ if (!SetStationIP (Private)) {
+ return FALSE;
+ }
+ //
+ // treat BOOTP response as DHCP ACK packet
+ //
+ CopyParseRxBuf (Private, Private->GotBootp - 1, DHCPV4_ACK_INDEX);
+
+ LocalPtr.OpPtr = RxBuf[Private->GotBootp - 1].OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];
+
+ if (LocalPtr.OpPtr != NULL) {
+ *(EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask = LocalPtr.SubnetMaskStr->Ip;
+ }
+
+ return TRUE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* DoDhcpDora()
+ */
+STATIC
+EFI_STATUS
+DoDhcpDora (
+ PXE_BASECODE_DEVICE *Private,
+ BOOLEAN SortOffers
+ )
+{
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;
+ EFI_STATUS StatCode;
+ INTN NumOffers;
+
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
+
+ Filter.IpCnt = 0;
+ Filter.reserved = 0;
+
+ //
+ // set filter unicast or broadcast
+ //
+ if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
+ return StatCode;
+ }
+ //
+ // seed random number with hardware address
+ //
+ SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
+
+ for (Private->Timeout = 1;
+ Private->Timeout < 17;
+ Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), Private->Timeout <<= 1
+ ) {
+ INTN Index;
+
+ InitDhcpv4TxBuf (Private);
+ DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
+ DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
+
+ //
+ // broadcast DHCPDISCOVER
+ //
+ StatCode = DoUdpWrite (
+ Private,
+ &BroadcastIP,
+ &DhcpServerPort,
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
+ &DHCPClientPort
+ );
+
+ if (StatCode != EFI_SUCCESS) {
+ return StatCode;
+ }
+
+ CopyMem (
+ &Private->EfiBc.Mode->DhcpDiscover,
+ (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
+ sizeof (EFI_PXE_BASE_CODE_PACKET)
+ );
+
+ //
+ // get DHCPOFFER's
+ //
+ if ((StatCode = GetOffers (Private)) != EFI_SUCCESS) {
+ if (StatCode != EFI_NO_RESPONSE) {
+ return StatCode;
+ }
+
+ continue;
+ }
+ //
+ // select offer and reply DHCPREQUEST
+ //
+ if (SortOffers) {
+ if (TryDHCPFinishDORA(Private, PXE10_IX) || // try DHCP with PXE10
+ TryDHCPFinishDORA(Private, WfM11a_IX) || // no - try with WfM
+ TryProxyFinishDORA(Private, PXE10_IX) || // no - try DHCP only and proxy with PXE10
+ TryProxyFinishDORA(Private, WfM11a_IX) || // no - try DHCP only and proxy with WfM
+ TryDHCPFinishDORA(Private, BINL_IX) || // no - try with WfM
+ TryProxyFinishDORA(Private, BINL_IX) || // no - try DHCP only and proxy with PXE10
+ TryAnyWithBootfileFinishDORA(Private))
+ {
+ return EFI_SUCCESS;
+ }
+
+ continue;
+ }
+ //
+ // FIFO order
+ //
+ NumOffers = Private->NumOffersReceived;
+
+ for (Index = 0; Index < NumOffers; ++Index) {
+ //
+ // ignore proxies
+ //
+ if (!RxBuf[Index].u.Dhcpv4.yiaddr) {
+ continue;
+ }
+ //
+ // check if a bootp server
+ //
+ if (!RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]) {
+ //
+ // it is - just check ARP
+ //
+ if (!SetStationIP (Private)) {
+ continue;
+ }
+ }
+ //
+ // else check if a DHCP only server
+ //
+ else if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE))) {
+ //
+ // it is a normal DHCP offer (without any PXE options), just finish the D.O.R.A by sending DHCP request.
+ //
+ if (!TryFinishDORA (Private, Index)) {
+ continue;
+ }
+ } else if (TryFinishDORA (Private, Index)) {
+ if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) && !TryFinishBINL (Private, Index)) {
+ continue;
+ }
+ }
+
+ DEBUG ((EFI_D_WARN, "\nDoDhcpDora() Got packets. "));
+ return EFI_SUCCESS;
+ }
+ //
+ // now look for DHCP onlys and a Proxy
+ //
+ for (Index = 0; Index < NumOffers; ++Index) {
+ INT8 Index2;
+
+ //
+ // ignore proxies, bootps, non DHCP onlys, and bootable DHCPS
+ //
+ if (!RxBuf[Index].u.Dhcpv4.yiaddr ||
+ !RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1] ||
+ RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE) ||
+ RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]
+ ) {
+ continue;
+ }
+ //
+ // found non bootable DHCP only - try to find a proxy
+ //
+ for (Index2 = 0; Index2 < NumOffers; ++Index2) {
+ if (!RxBuf[Index2].u.Dhcpv4.yiaddr) {
+ if (!TryFinishDORA (Private, Index)) {
+ //
+ // DHCP no ACK
+ //
+ break;
+ }
+
+ if (RxBuf[Index2].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) {
+ CopyProxyRxBuf (Private, Index2);
+ } else if (!TryFinishBINL (Private, Index2)) {
+ continue;
+ }
+
+ DEBUG ((EFI_D_WARN, "\nDoDhcpDora() Got packets. "));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_NO_RESPONSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// determine if the server ip is in the ip list
+//
+BOOLEAN
+InServerList (
+ EFI_IP_ADDRESS *ServerIpPtr,
+ PXE_SERVER_LISTS *ServerListPtr
+ )
+{
+ UINTN Index;
+
+ if (!ServerListPtr || !ServerListPtr->Ipv4List.IpCount) {
+ return TRUE;
+ }
+
+ for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
+ if (!CompareMem (
+ ServerIpPtr,
+ &ServerListPtr->Ipv4List.IpList[Index],
+ sizeof (EFI_IPv4_ADDRESS)
+ )) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+BOOLEAN
+ExtractBootServerList (
+ UINT16 Type,
+ DHCPV4_OP_STRUCT *ptr,
+ PXE_SERVER_LISTS **ServerListPtr
+ )
+{
+ UNION_PTR LocalPtr;
+ INTN ServerListLen;
+
+ LocalPtr.OpPtr = ptr;
+ ServerListLen = LocalPtr.BootServersStr->Header.Length;
+
+ //
+ // find type
+ //
+ LocalPtr.BootServerList = LocalPtr.BootServersStr->ServerList;
+
+ while (ServerListLen) {
+ INTN ServerEntryLen;
+
+ ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (LocalPtr.BootServerList->u.Ipv4List.IpCount - 1) *
+ sizeof (EFI_IPv4_ADDRESS);
+
+ if (NTOHS (LocalPtr.BootServerList->Type) == Type) {
+ *ServerListPtr = &LocalPtr.BootServerList->u;
+ return TRUE;
+ }
+
+ (LocalPtr.BytePtr) += ServerEntryLen;
+ ServerListLen -= ServerEntryLen;
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+FreeMem (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ if (Private->TransmitBuffer != NULL) {
+ gBS->FreePool (Private->TransmitBuffer);
+ Private->TransmitBuffer = NULL;
+ }
+
+ if (Private->ReceiveBuffers != NULL) {
+ gBS->FreePool (Private->ReceiveBuffers);
+ Private->ReceiveBuffers = NULL;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+BOOLEAN
+GetMem (
+ PXE_BASECODE_DEVICE *Private
+ )
+{
+ EFI_STATUS Status;
+
+ if (Private->DhcpPacketBuffer == NULL) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
+ &Private->DhcpPacketBuffer
+ );
+
+ if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
+ Private->DhcpPacketBuffer = NULL;
+ FreeMem (Private);
+ return FALSE;
+ }
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_PXE_BASE_CODE_PACKET),
+ &Private->TransmitBuffer
+ );
+
+ if (EFI_ERROR (Status) || Private->TransmitBuffer == NULL) {
+ gBS->FreePool (Private->DhcpPacketBuffer);
+ Private->DhcpPacketBuffer = NULL;
+ Private->TransmitBuffer = NULL;
+ FreeMem (Private);
+ return FALSE;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS),
+ &Private->ReceiveBuffers
+ );
+
+ if (EFI_ERROR (Status) || Private->ReceiveBuffers == NULL) {
+ gBS->FreePool (Private->TransmitBuffer);
+ gBS->FreePool (Private->DhcpPacketBuffer);
+ Private->DhcpPacketBuffer = NULL;
+ Private->TransmitBuffer = NULL;
+ Private->ReceiveBuffers = NULL;
+ FreeMem (Private);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+BcDhcp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN SortOffers
+ )
+/*++
+Routine description:
+ standard DHCP Discover/Offer/Request/Ack session
+ broadcast DHCPDISCOVER
+ receive DHCPOFFER's
+ broadcast DHCPREQUEST
+ receive DHCPACK
+ check (ARP) good IP
+
+Parameters:
+ This := Pointer to PxeBc interface
+ SortOffers :=
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ PXE_BASECODE_DEVICE *Private;
+ EFI_STATUS StatCode;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
+ Filter.IpCnt = 0;
+ Filter.reserved = 0;
+
+ DEBUG ((EFI_D_INFO, "\nBcDhcp() Enter. "));
+
+ PxebcMode = Private->EfiBc.Mode;
+
+ if (!GetMem (Private)) {
+ DEBUG ((EFI_D_ERROR, "\nBcDhcp() GetMem() failed.\n"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PxebcMode->DhcpDiscoverValid = FALSE;
+ PxebcMode->DhcpAckReceived = FALSE;
+ PxebcMode->ProxyOfferReceived = FALSE;
+
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
+
+ //
+ // Issue BC command
+ //
+ if (Private->TotalSeconds == 0) {
+ //
+ // put in seconds field of DHCP send packets
+ //
+ Private->TotalSeconds = 4;
+ }
+
+ if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) {
+ //
+ // success - copy packets
+ //
+ PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE;
+
+ CopyMem (
+ &PxebcMode->DhcpAck,
+ (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET,
+ sizeof (EFI_PXE_BASE_CODE_PACKET)
+ );
+
+ if (PxebcMode->ProxyOfferReceived) {
+ CopyMem (
+ &PxebcMode->ProxyOffer,
+ (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET,
+ sizeof (EFI_PXE_BASE_CODE_PACKET)
+ );
+ }
+ }
+ //
+ // set filter back to unicast
+ //
+ IpFilter (Private, &Filter);
+
+ FreeMem (Private);
+
+ //
+ // Unlock the instance data
+ //
+ DEBUG ((EFI_D_WARN, "\nBcDhcp() Exit = %xh ", StatCode));
+
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+BOOLEAN
+VerifyCredentialOption (
+ UINT8 *tx,
+ UINT8 *rx
+ )
+{
+ UINTN n;
+
+ //
+ // Fail verification if either pointer is NULL.
+ //
+ if (tx == NULL || rx == NULL) {
+ return FALSE;
+ }
+ //
+ // Fail verification if tx[0] is not a credential type option
+ // or if the length is zero or not a multiple of four.
+ //
+ if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) {
+ return FALSE;
+ }
+ //
+ // Fail verification if rx[0] is not a credential type option
+ // or if the length is not equal to four.
+ //
+ if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) {
+ return FALSE;
+ }
+ //
+ // Look through transmitted credential types for a copy
+ // of the received credential type.
+ //
+ for (n = 0; n < tx[1]; n += 4) {
+ if (!CompareMem (&tx[n + 2], &rx[2], 4)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+DoDiscover (
+ PXE_BASECODE_DEVICE *Private,
+ UINT16 OpFlags,
+ IN UINT16 Type,
+ IN UINT16 *LayerPtr,
+ IN BOOLEAN UseBis,
+ EFI_IP_ADDRESS *DestPtr,
+ PXE_SERVER_LISTS *ServerListPtr
+ )
+/*++
+Routine description:
+ This function tries to complete the PXE Bootserver and/or boot image
+ discovery sequence. When this command completes successfully, the
+ PXEdiscover and PXEreply fields in the BC instance data structure are
+ updated. If the Info pointer is set to NULL, the discovery information
+ in the DHCPack and ProxyOffer packets must be valid and will be used.
+ If Info is not set to NULL, the discovery methods in the Info field
+ must be set and will be used. When discovering any layer number other
+ than zero (the credential flag does not count), only unicast discovery
+ is used.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ OpFlags :=
+ Type :=
+ LayerPtr :=
+ UseBis :=
+ DestPtr :=
+ ServerListPtr :=
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_UDP_PORT ClientPort;
+ EFI_PXE_BASE_CODE_UDP_PORT ServerPort;
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ EFI_STATUS StatCode;
+ EFI_EVENT TimeoutEvent;
+ UINT8 OpLen;
+
+ PxebcMode = Private->EfiBc.Mode;
+
+ if (DestPtr->Addr[0] == 0) {
+ DEBUG ((EFI_D_WARN, "\nDoDiscover() !DestPtr->Addr[0]"));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // seed random number with hardware address
+ //
+ SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);
+
+ if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) {
+ ClientPort = DHCPClientPort;
+ ServerPort = DhcpServerPort;
+ } else {
+ ClientPort = PSEUDO_DHCP_CLIENT_PORT;
+ ServerPort = PseudoDhcpServerPort;
+ }
+
+ if (UseBis) {
+ *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG;
+ } else {
+ *LayerPtr &= PXE_BOOT_LAYER_MASK;
+ }
+
+ for (Private->Timeout = 1;
+ Private->Timeout < 5;
+ Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout
+ ) {
+ InitDhcpv4TxBuf (Private);
+ //
+ // initialize DHCP message structure
+ //
+ DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);
+ DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);
+ CopyMem (
+ &DHCPV4_TRANSMIT_BUFFER.ciaddr,
+ &PxebcMode->StationIp,
+ sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr
+ );
+
+ DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;
+ DISCOVERoptions.Header.OpCode = OP_VENDOR_SPECIFIC;
+ DISCOVERoptions.BootItem.Header.OpCode = VEND_PXE_BOOT_ITEM;
+ DISCOVERoptions.BootItem.Header.Length = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM);
+ DISCOVERoptions.BootItem.Type = HTONS (Type);
+ DISCOVERoptions.BootItem.Layer = HTONS (*LayerPtr);
+
+ if (UseBis) {
+ EFI_BIS_PROTOCOL *BisPtr;
+ BIS_APPLICATION_HANDLE BisAppHandle;
+ EFI_BIS_DATA *BisDataSigInfo;
+ EFI_BIS_SIGNATURE_INFO *BisSigInfo;
+ UINTN Index;
+ UINTN Index2;
+
+ BisPtr = PxebcBisStart (
+ Private,
+ &BisAppHandle,
+ &BisDataSigInfo
+ );
+
+ if (BisPtr == NULL) {
+ //
+ // %%TBD - In order to get here, BIS must have
+ // been present when PXEBC.Start() was called.
+ // BIS had to be shutdown/removed/damaged
+ // before PXEBC.Discover() was called.
+ // Do we need to document a specific error
+ // for this case?
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Compute number of credential types.
+ //
+ Index2 = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO);
+
+ DISCREDoptions.Header.OpCode = VEND_PXE_CREDENTIAL_TYPES;
+
+ DISCREDoptions.Header.Length = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL));
+
+ OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length);
+
+ BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data;
+
+ for (Index = 0; Index < Index2; ++Index) {
+ UINT32 x;
+
+ CopyMem (&x, &BisSigInfo[Index], sizeof x);
+ x = HTONL (x);
+ CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x);
+ }
+
+ PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);
+ } else {
+ OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS);
+ }
+
+ DISCOVERoptions.Header.Length = OpLen;
+
+ ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END;
+ ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen] = OP_END;
+
+ StatCode = DoUdpWrite (
+ Private,
+ DestPtr,
+ &ServerPort,
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
+ &ClientPort
+ );
+
+ if (StatCode != EFI_SUCCESS) {
+ return StatCode;
+ }
+ //
+ //
+ //
+ StatCode = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return StatCode;
+ }
+
+ StatCode = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ Private->Timeout * 10000000 + 1000000
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return StatCode;
+ }
+ //
+ // wait for ACK
+ //
+ for (;;) {
+ DHCP_RECEIVE_BUFFER *RxBufPtr;
+ UINT16 TmpType;
+ UINT16 TmpLayer;
+
+ RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER;
+ ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
+
+ if (GetOfferAck (
+ Private,
+ AckEdit,
+ OpFlags,
+ (EFI_IP_ADDRESS *) &Private->ServerIp,
+ 0,
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,
+ &ClientPort,
+ RxBufPtr,
+ TimeoutEvent
+ ) != EFI_SUCCESS) {
+ break;
+ }
+ //
+ // check type of response - need PXEClient DHCPACK of proper type with bootfile
+ //
+ if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) ||
+ (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) ||
+ !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] ||
+ !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] ||
+ !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) {
+
+ continue;
+ }
+
+ TmpType = TmpLayer = 0;
+
+ if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {
+ TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type);
+
+ if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) {
+ TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8);
+ } else {
+ TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer);
+ }
+ }
+
+ if (TmpType != Type) {
+ continue;
+ }
+
+ if (UseBis) {
+ if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) {
+ continue;
+ }
+
+ if (!VerifyCredentialOption (
+ (UINT8 *) &DISCREDoptions.Header,
+ (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]
+ )) {
+ continue;
+ }
+ }
+
+ *LayerPtr = TmpLayer;
+
+ if (UseBis) {
+ CopyMem (
+ &PxebcMode->PxeBisReply,
+ &RxBufPtr->u.Dhcpv4,
+ sizeof (EFI_PXE_BASE_CODE_PACKET)
+ );
+
+ PxebcMode->PxeBisReplyReceived = TRUE;
+
+ StatCode = DoDiscover (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ Type,
+ LayerPtr,
+ FALSE,
+ &Private->ServerIp,
+ 0
+ );
+
+ gBS->CloseEvent (TimeoutEvent);
+ return StatCode;
+ }
+
+ PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE;
+
+ CopyMem (
+ &PxebcMode->PxeDiscover,
+ &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,
+ sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER)
+ );
+
+ CopyMem (
+ &PxebcMode->PxeReply,
+ &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4,
+ sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4)
+ );
+
+ AddRouters (Private, RxBufPtr);
+
+ gBS->CloseEvent (TimeoutEvent);
+ return EFI_SUCCESS;
+ }
+
+ gBS->CloseEvent (TimeoutEvent);
+ }
+ //
+ // end for loop
+ //
+ return EFI_TIMEOUT;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+Discover (
+ PXE_BASECODE_DEVICE *Private,
+ IN UINT16 Type,
+ IN UINT16 *LayerPtr,
+ IN BOOLEAN UseBis,
+ IN EFI_PXE_BASE_CODE_DISCOVER_INFO *DiscoverInfoPtr,
+ PXE_SERVER_LISTS *McastServerListPtr,
+ PXE_SERVER_LISTS *ServerListPtr
+ )
+/*++
+Routine Description:
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ Type :=
+ LayerPtr :=
+ UseBis :=
+ DiscoverInfoPtr :=
+ McastServerListPtr :=
+ ServerListPtr :=
+
+Returns:
+--*/
+{
+ EFI_IP_ADDRESS DestIp;
+ EFI_STATUS StatCode;
+
+ DEBUG ((EFI_D_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr));
+
+ if (UseBis) {
+ DEBUG ((EFI_D_INFO, "BIS "));
+ }
+ //
+ // get dest IP addr - mcast, bcast, or unicast
+ //
+ if (DiscoverInfoPtr->UseMCast) {
+ DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4;
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nDiscover() MCast %d.%d.%d.%d ",
+ DestIp.v4.Addr[0],
+ DestIp.v4.Addr[1],
+ DestIp.v4.Addr[2],
+ DestIp.v4.Addr[3])
+ );
+
+ if ((StatCode = DoDiscover (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ Type,
+ LayerPtr,
+ UseBis,
+ &DestIp,
+ McastServerListPtr
+ )) != EFI_TIMEOUT) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nDiscover() status == %r (%Xh)",
+ StatCode,
+ StatCode)
+ );
+
+ return StatCode;
+ }
+ }
+
+ if (DiscoverInfoPtr->UseBCast) {
+ DEBUG ((EFI_D_INFO, "\nDiscver() BCast "));
+
+ if ((StatCode = DoDiscover (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ Type,
+ LayerPtr,
+ UseBis,
+ &BroadcastIP,
+ McastServerListPtr
+ )) != EFI_TIMEOUT) {
+
+ DEBUG ((EFI_D_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode));
+
+ return StatCode;
+ }
+ }
+
+ if (DiscoverInfoPtr->UseUCast) {
+ UINTN Index;
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nDiscover() UCast IP#=%d ",
+ ServerListPtr->Ipv4List.IpCount)
+ );
+
+ for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {
+ CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4);
+
+ DEBUG (
+ (EFI_D_INFO,
+ "\nDiscover() UCast %d.%d.%d.%d ",
+ DestIp.v4.Addr[0],
+ DestIp.v4.Addr[1],
+ DestIp.v4.Addr[2],
+ DestIp.v4.Addr[3])
+ );
+
+ if ((StatCode = DoDiscover (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ Type,
+ LayerPtr,
+ UseBis,
+ &DestIp,
+ 0
+ )) != EFI_TIMEOUT) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nDiscover() status == %r (%Xh)",
+ StatCode,
+ StatCode)
+ );
+
+ return StatCode;
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_WARN, "\nDiscover() TIMEOUT"));
+
+ return EFI_TIMEOUT;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* BcDiscover()
+ */
+EFI_STATUS
+EFIAPI
+BcDiscover (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN UINT16 Type,
+ IN UINT16 *LayerPtr,
+ IN BOOLEAN UseBis,
+ IN EFI_PXE_BASE_CODE_DISCOVER_INFO * DiscoverInfoPtr OPTIONAL
+ )
+/*++
+Routine description:
+
+Parameters:
+ This :=
+ Type :=
+ LayerPtr :=
+ UseBis :=
+ DiscoverInfoPtr :=
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;
+ PXE_SERVER_LISTS DefaultSrvList;
+ PXE_SERVER_LISTS *ServerListPtr;
+ PXE_SERVER_LISTS *McastServerListPtr;
+ EFI_STATUS Status;
+ UNION_PTR LocalPtr;
+ UINTN Index;
+ UINTN Index2;
+ BOOLEAN AcquiredSrvList;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ ServerListPtr = NULL;
+ McastServerListPtr = NULL;
+ AcquiredSrvList = FALSE;
+
+ PxebcMode = Private->EfiBc.Mode;
+
+ if (!GetMem (Private)) {
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (UseBis) {
+ if (!PxebcMode->BisSupported) {
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
+
+ if (Private->TotalSeconds == 0) {
+ //
+ // put in seconds field of DHCP send packets
+ //
+ Private->TotalSeconds = 4;
+ }
+
+ ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
+
+ //
+ // if layer number not zero, use previous discover
+ //
+ if (*LayerPtr != 0) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0"));
+
+ if (DiscoverInfoPtr != NULL) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n"));
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!PxebcMode->PxeDiscoverValid) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n"));
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!PxebcMode->PxeReplyReceived) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n"));
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (UseBis && !PxebcMode->PxeBisReplyReceived) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() layer != 0 && PxeBisReplyReceived == 0\n"));
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DefaultInfo.UseUCast = TRUE;
+ DiscoverInfoPtr = &DefaultInfo;
+
+ DefaultSrvList.Ipv4List.IpCount = 1;
+ CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4);
+
+ ServerListPtr = &DefaultSrvList;
+ }
+ //
+ // layer is zero - see if info is supplied or if we need to use info from a cached offer
+ //
+ else if (!DiscoverInfoPtr) {
+ //
+ // not supplied - generate it
+ // make sure that there is cached, appropriate information
+ // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail
+ //
+ DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
+
+ if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() !ack && !proxy"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DiscoverInfoPtr = &DefaultInfo;
+
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
+
+ //
+ // if multicast enabled, need multicast address
+ //
+ if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) {
+ DefaultInfo.UseMCast = TRUE;
+
+ CopyMem (
+ ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp),
+ &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ }
+
+ DefaultInfo.UseBCast = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0);
+
+ DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0);
+
+ DefaultInfo.UseUCast = (BOOLEAN)
+ (
+ (DefaultInfo.MustUseList) ||
+ ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))
+ );
+
+ if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList (
+ Type,
+ DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1],
+ &ServerListPtr
+ )) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() type not in list"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Info supplied - make SrvList if required
+ // if we use ucast discovery or must use list, there better be one
+ //
+ else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) {
+ //
+ // there better be a list
+ //
+ if (DiscoverInfoPtr->IpCnt == 0) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() no bootserver list"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // get its size
+ //
+ for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
+ if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
+ if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) {
+ if (Index2 != 0) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() accept any?"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ } else {
+ Index2 = 1;
+ DefaultSrvList.Ipv4List.IpCount = 0;
+ ServerListPtr = &DefaultSrvList;
+ break;
+ }
+ } else {
+ ++Index2;
+ }
+ }
+ }
+
+ if (Index2 == 0) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() !Index2?"));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ServerListPtr == NULL) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS),
+ (VOID **) &ServerListPtr
+ );
+
+ if (EFI_ERROR (Status) || ServerListPtr == NULL) {
+ ServerListPtr = NULL;
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // build an array of IP addresses from the server list
+ //
+ AcquiredSrvList = TRUE;
+ ServerListPtr->Ipv4List.IpCount = (UINT8) Index2;
+
+ for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {
+ if (DiscoverInfoPtr->SrvList[Index].Type == Type) {
+ CopyMem (
+ &ServerListPtr->Ipv4List.IpList[Index2++],
+ &DiscoverInfoPtr->SrvList[Index].IpAddr.v4,
+ sizeof ServerListPtr->Ipv4List.IpList[0]
+ );
+ }
+ }
+ }
+ }
+
+ if (DiscoverInfoPtr->MustUseList) {
+ McastServerListPtr = ServerListPtr;
+ }
+
+ if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) {
+ DEBUG ((EFI_D_WARN, "\nBcDiscover() Nothing to use!\n"));
+
+ EfiReleaseLock (&Private->Lock);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE;
+
+ StatCode = Discover (
+ Private,
+ Type,
+ LayerPtr,
+ UseBis,
+ DiscoverInfoPtr,
+ McastServerListPtr,
+ ServerListPtr
+ );
+
+ if (AcquiredSrvList) {
+ gBS->FreePool (ServerListPtr);
+ }
+
+ FreeMem (Private);
+
+ //
+ // Unlock the instance data
+ //
+ DEBUG (
+ (EFI_D_INFO,
+ "\nBcDiscover() status == %r (%Xh)\n",
+ StatCode,
+ StatCode)
+ );
+
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+BcSetPackets (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ BOOLEAN *NewDhcpDiscoverValid, OPTIONAL
+ BOOLEAN *NewDhcpAckReceived, OPTIONAL
+ BOOLEAN *NewProxyOfferReceived, OPTIONAL
+ BOOLEAN *NewPxeDiscoverValid, OPTIONAL
+ BOOLEAN *NewPxeReplyReceived, OPTIONAL
+ BOOLEAN *NewPxeBisReplyReceived, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
+ )
+/*++
+Routine description:
+
+Parameters:
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;
+ EFI_STATUS Status;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ PxebcMode = Private->EfiBc.Mode;
+
+ if (Private->DhcpPacketBuffer == NULL) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),
+ &Private->DhcpPacketBuffer
+ );
+
+ if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {
+ Private->DhcpPacketBuffer = NULL;
+ EfiReleaseLock (&Private->Lock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // Issue BC command
+ //
+ //
+ // reset
+ //
+ Private->FileSize = 0;
+ if (NewDhcpDiscoverValid != NULL) {
+ PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
+ }
+
+ if (NewDhcpAckReceived != NULL) {
+ PxebcMode->DhcpAckReceived = *NewDhcpAckReceived;
+ }
+
+ if (NewProxyOfferReceived != NULL) {
+ PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived;
+ }
+
+ if (NewPxeDiscoverValid != NULL) {
+ PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid;
+ }
+
+ if (NewPxeReplyReceived != NULL) {
+ PxebcMode->PxeReplyReceived = *NewPxeReplyReceived;
+ }
+
+ if (NewPxeBisReplyReceived != NULL) {
+ PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
+ }
+
+ if (NewDhcpDiscover != NULL) {
+ CopyMem (
+ &PxebcMode->DhcpDiscover,
+ NewDhcpDiscover,
+ sizeof *NewDhcpDiscover
+ );
+ }
+
+ if (NewDhcpAck != NULL) {
+ CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX);
+ }
+
+ if (NewProxyOffer != NULL) {
+ CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX);
+ }
+
+ if (NewPxeDiscover != NULL) {
+ CopyMem (
+ &PxebcMode->PxeDiscover,
+ NewPxeDiscover,
+ sizeof *NewPxeDiscover
+ );
+ }
+
+ if (NewPxeReply != NULL) {
+ CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX);
+ }
+
+ if (NewPxeBisReply != NULL) {
+ CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX);
+ }
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+ return EFI_SUCCESS;
+}
+
+/* eof - pxe_bc_dhcp.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c
new file mode 100644
index 0000000..6737ede
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_igmp.c
@@ -0,0 +1,476 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+--*/
+
+
+
+
+#define RAND_MAX 0x10000
+#include "bc.h"
+
+//
+// Definitions for internet group management protocol version 2 message
+// structure Per RFC 2236, November 1997
+//
+STATIC UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 };
+STATIC IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } };
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+ClearGroupTimer (
+ PXE_BASECODE_DEVICE *Private,
+ UINTN TimerId
+ )
+{
+ if (Private == NULL) {
+ return ;
+ }
+
+ if (TimerId >= Private->MCastGroupCount) {
+ return ;
+ }
+
+ if (Private->IgmpGroupEvent[TimerId] == NULL) {
+ return ;
+ }
+
+ gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
+ Private->IgmpGroupEvent[TimerId] = NULL;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+SetGroupTimer (
+ PXE_BASECODE_DEVICE *Private,
+ UINTN TimerId,
+ UINTN MaxRespTime
+ )
+/*++
+Routine description:
+ Set IGMP response timeout value.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ TimerId := Timer ID#
+ MaxRespTime := Base response timeout value in tenths of seconds
+
+Returns:
+--*/
+{
+ EFI_STATUS EfiStatus;
+
+ if (Private == NULL) {
+ return ;
+ }
+
+ if (TimerId >= Private->MCastGroupCount) {
+ return ;
+ }
+
+ if (Private->IgmpGroupEvent[TimerId] != NULL) {
+ gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
+ }
+
+ EfiStatus = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Private->IgmpGroupEvent[TimerId]
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->IgmpGroupEvent[TimerId] = NULL;
+ return ;
+ }
+
+ EfiStatus = gBS->SetTimer (
+ Private->IgmpGroupEvent[TimerId],
+ TimerRelative,
+ MaxRespTime * 1000000 + Random (Private) % RAND_MAX
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
+ Private->IgmpGroupEvent[TimerId] = NULL;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+SendIgmpMessage (
+ PXE_BASECODE_DEVICE *Private,
+ UINT8 Type,
+ INTN GroupId
+ )
+/*++
+Routine description:
+ Send an IGMP message
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ Type := Message type opcode
+ GroupId := Group ID#
+
+Returns:
+--*/
+{
+ Private->IgmpMessage.Type = Type;
+ Private->IgmpMessage.MaxRespTime = 0;
+ Private->IgmpMessage.Checksum = 0;
+ Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId];
+ Private->IgmpMessage.Checksum = IpChecksum (
+ (UINT16 *) &Private->IgmpMessage,
+ sizeof Private->IgmpMessage
+ );
+
+ Ipv4SendWOp (
+ Private,
+ 0,
+ (UINT8 *) &Private->IgmpMessage,
+ sizeof Private->IgmpMessage,
+ PROT_IGMP,
+ RouterAlertOption,
+ sizeof RouterAlertOption,
+ ((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress),
+ EFI_PXE_BASE_CODE_FUNCTION_IGMP
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+ReportIgmp (
+ PXE_BASECODE_DEVICE *Private,
+ INTN GroupId
+ )
+/*++
+Routine description:
+ Send an IGMP report message.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ GroupId := Group ID#
+
+Returns:
+--*/
+{
+ //
+ // if version 1 querier, send v1 report
+ //
+ UINT8 Type;
+
+ if (Private->Igmpv1TimeoutEvent != NULL) {
+ if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
+ Private->Igmpv1TimeoutEvent = NULL;
+ Private->UseIgmpv1Reporting = TRUE;
+ }
+ }
+
+ Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT);
+
+ SendIgmpMessage (Private, Type, GroupId);
+ ClearGroupTimer (Private, GroupId);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+IgmpCheckTimers (
+ PXE_BASECODE_DEVICE *Private
+ )
+/*++
+Routine description:
+ Check IGMP timers and send reports for all groups that have expired.
+Parameters:
+ Private := Pointer to PxeBc interface
+
+Returns:
+--*/
+{
+ UINTN GroupId;
+
+ if (Private == NULL) {
+ return ;
+ }
+
+ for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
+ if (Private->IgmpGroupEvent[GroupId] == NULL) {
+ continue;
+ }
+
+ if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) {
+ //
+ // send a report
+ //
+ ReportIgmp (Private, GroupId);
+ }
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+INTN
+FindMulticastGroup (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GroupAddress
+ )
+/*++
+Routine description:
+ Fund group ID# (index).
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ GroupAddress := Group multicast address
+
+Returns:
+ 0 := Group not found
+ other := Group ID#
+--*/
+{
+ UINTN GroupId;
+
+ for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
+ if (Private->MCastGroup[GroupId] == GroupAddress) {
+ return GroupId + 1;
+ }
+ }
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+IgmpJoinGroup (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *GroupPtr
+ )
+/*++
+Routine description:
+ Join multicast group.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ GroupPtr := Pointer to group mutlicast IP address.
+
+Returns:
+--*/
+{
+ UINT32 Grp;
+
+ Grp = *(UINT32 *) GroupPtr;
+
+#if SUPPORT_IPV6
+ if (Private->EfiBc.Mode->UsingIpv6) {
+ //
+ // TBD
+ //
+ }
+#endif
+ //
+ // see if we already have it or if we can't take anymore
+ //
+ if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) {
+ return ;
+ }
+ //
+ // add the group
+ //
+ Private->MCastGroup[Private->MCastGroupCount] = Grp;
+
+ ReportIgmp (Private, Private->MCastGroupCount);
+ //
+ // send a report
+ // so it will get sent again per RFC 2236
+ //
+ SetGroupTimer (
+ Private,
+ Private->MCastGroupCount++,
+ UNSOLICITED_REPORT_INTERVAL * 10
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+IgmpLeaveGroup (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *GroupPtr
+ )
+/*++
+Routine description:
+ Leave multicast group.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ GroupPtr := Mutlicast group IP address.
+
+Returns:
+--*/
+{
+ UINT32 Grp;
+ UINTN GroupId;
+
+ Grp = *(UINT32 *) GroupPtr;
+
+#if SUPPORT_IPV6
+ if (Private->EfiBc.Mode->UsingIpv6) {
+ //
+ // TBD
+ //
+ }
+#endif
+ //
+ // if not in group, ignore
+ //
+ GroupId = FindMulticastGroup (Private, Grp);
+
+ if (GroupId == 0) {
+ return ;
+ }
+ //
+ // if not v1 querrier, send leave group IGMP message
+ //
+ if (Private->Igmpv1TimeoutEvent != NULL) {
+ if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
+ Private->Igmpv1TimeoutEvent = NULL;
+ Private->UseIgmpv1Reporting = TRUE;
+ } else {
+ SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1);
+ }
+ }
+
+ while (GroupId < Private->MCastGroupCount) {
+ Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId];
+ Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId];
+ ++GroupId;
+ }
+
+ --Private->MCastGroupCount;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+HandleIgmp (
+ PXE_BASECODE_DEVICE *Private,
+ IGMPV2_MESSAGE *IgmpMessagePtr,
+ UINTN IgmpLength
+ )
+/*++
+Routine description:
+ Handle received IGMP packet
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ IgmpMessagePtr := Pointer to IGMP packet
+ IgmpLength := packet length in bytes
+
+Returns:
+--*/
+{
+ EFI_STATUS EfiStatus;
+ UINTN GroupId;
+ INTN MaxRespTime;
+
+ if (Private == NULL) {
+ return ;
+ }
+
+ if (Private->MCastGroupCount == 0) {
+ //
+ // if we don't belong to any multicast groups, ignore
+ //
+ return ;
+ }
+ //
+ // verify checksum
+ //
+ if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) {
+ //
+ // bad checksum - ignore packet
+ //
+ return ;
+ }
+
+ switch (IgmpMessagePtr->Type) {
+ case IGMP_TYPE_QUERY:
+ //
+ // if a version 1 querier, note the fact and set max resp time
+ //
+ MaxRespTime = IgmpMessagePtr->MaxRespTime;
+
+ if (MaxRespTime == 0) {
+ Private->UseIgmpv1Reporting = TRUE;
+
+ if (Private->Igmpv1TimeoutEvent != NULL) {
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
+ }
+
+ EfiStatus = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Private->Igmpv1TimeoutEvent
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ Private->Igmpv1TimeoutEvent = NULL;
+ } else {
+ EfiStatus = gBS->SetTimer (
+ Private->Igmpv1TimeoutEvent,
+ TimerRelative,
+ (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
+ );
+ }
+
+ MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10;
+ }
+ //
+ // if a general query (!GroupAddress), set all our group timers
+ //
+ if (!IgmpMessagePtr->GroupAddress) {
+ for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
+ SetGroupTimer (Private, GroupId, MaxRespTime);
+ }
+ } else {
+ //
+ // specific query - set only specific group
+ //
+ GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
+
+ if (GroupId != 0) {
+ SetGroupTimer (Private, GroupId - 1, MaxRespTime);
+ }
+ }
+
+ break;
+
+ //
+ // if we have a timer running for this group, clear it
+ //
+ case IGMP_TYPE_V1REPORT:
+ case IGMP_TYPE_REPORT:
+ GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
+
+ if (GroupId != 0) {
+ ClearGroupTimer (Private, GroupId - 1);
+ }
+
+ break;
+ }
+}
+
+/* EOF - pxe_bc_igmp.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c
new file mode 100644
index 0000000..26bc210
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_ip.c
@@ -0,0 +1,861 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ pxe_bc_ip.c
+
+Abstract:
+
+--*/
+
+
+#include "bc.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+BOOLEAN
+OnSameSubnet (
+ IN UINTN IpLength,
+ IN EFI_IP_ADDRESS *Ip1,
+ IN EFI_IP_ADDRESS *Ip2,
+ IN EFI_IP_ADDRESS *SubnetMask
+ )
+/*++
+
+ Routine Description:
+ Check if two IP addresses are on the same subnet.
+
+ Arguments:
+ IpLength - Length of IP address in bytes.
+ Ip1 - IP address to check.
+ Ip2 - IP address to check.
+ SubnetMask - Subnet mask to check with.
+
+ Returns:
+ TRUE - IP addresses are on the same subnet.
+ FALSE - IP addresses are on different subnets.
+
+--*/
+{
+ if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {
+ return FALSE;
+ }
+
+ while (IpLength-- != 0) {
+ if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+IpAddRouter (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_IP_ADDRESS *RouterIpPtr
+ )
+/*++
+
+ Routine Description:
+ Add router to router table.
+
+ Arguments:
+ Private - Pointer PxeBc instance data.
+ RouterIpPtr - Pointer to router IP address.
+
+ Returns:
+ Nothing
+
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ UINTN Index;
+
+ if (Private == NULL || RouterIpPtr == NULL) {
+ return ;
+ }
+
+ PxeBcMode = Private->EfiBc.Mode;
+
+ //
+ // if we are filled up or this is not on the same subnet, forget it
+ //
+ if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||
+ !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {
+ return ;
+ }
+ //
+ // make sure we don't already have it
+ //
+ for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
+ if (!CompareMem (
+ &PxeBcMode->RouteTable[Index].GwAddr,
+ RouterIpPtr,
+ Private->IpLength
+ )) {
+ return ;
+ }
+ }
+ //
+ // keep it
+ //
+ ZeroMem (
+ &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],
+ sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)
+ );
+
+ CopyMem (
+ &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,
+ RouterIpPtr,
+ Private->IpLength
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// return router ip to use for DestIp (0 if none)
+//
+STATIC
+EFI_IP_ADDRESS *
+GetRouterIp (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *DestIpPtr
+ )
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ UINTN Index;
+
+ if (Private == NULL || DestIpPtr == NULL) {
+ return NULL;
+ }
+
+ PxeBcMode = Private->EfiBc.Mode;
+
+ for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
+ if (OnSameSubnet (
+ Private->IpLength,
+ &PxeBcMode->RouteTable[Index].IpAddr,
+ DestIpPtr,
+ &PxeBcMode->RouteTable[Index].SubnetMask
+ )) {
+ return &PxeBcMode->RouteTable[Index].GwAddr;
+ }
+ }
+
+ return NULL;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// routine to send ipv4 packet
+// ipv4 header of length HdrLth in TransmitBufferPtr
+// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data
+// and gets dest MAC address
+//
+#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)
+#define IP_TX_HEADER IP_TX_BUFFER->IpHeader
+
+EFI_STATUS
+Ipv4Xmt (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GatewayIp,
+ UINTN IpHeaderLength,
+ UINTN TotalHeaderLength,
+ VOID *Data,
+ UINTN DataLength,
+ EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+{
+ EFI_MAC_ADDRESS DestMac;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ EFI_STATUS StatCode;
+ UINTN PacketLength;
+
+ Snp = Private->SimpleNetwork;
+ PxeBcMode = Private->EfiBc.Mode;
+ StatCode = EFI_SUCCESS;
+ PacketLength = TotalHeaderLength + DataLength;
+
+ //
+ // get dest MAC address
+ // multicast - convert to hw equiv
+ // unicast on same net, use arp
+ // on different net, arp for router
+ //
+ if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {
+ CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac));
+ } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {
+ StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);
+ } else {
+ UINT32 Ip;
+
+ if (OnSameSubnet (
+ Private->IpLength,
+ &PxeBcMode->StationIp,
+ (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,
+ &PxeBcMode->SubnetMask
+ )) {
+ Ip = IP_TX_HEADER.DestAddr.L;
+ } else if (GatewayIp != 0) {
+ Ip = GatewayIp;
+ } else {
+ EFI_IP_ADDRESS *TmpIp;
+
+ TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);
+
+ if (TmpIp == NULL) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nIpv4Xmit() Exit #1 %xh (%r)",
+ EFI_NO_RESPONSE,
+ EFI_NO_RESPONSE)
+ );
+
+ return EFI_NO_RESPONSE;
+ //
+ // no router
+ //
+ }
+
+ Ip = TmpIp->Addr[0];
+ }
+
+ if (!GetHwAddr (
+ Private,
+ (EFI_IP_ADDRESS *) &Ip,
+ (EFI_MAC_ADDRESS *) &DestMac
+ )) {
+ if (!PxeBcMode->AutoArp) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nIpv4Xmit() Exit #2 %xh (%r)",
+ EFI_DEVICE_ERROR,
+ EFI_DEVICE_ERROR)
+ );
+
+ return EFI_DEVICE_ERROR;
+ } else {
+ StatCode = DoArp (
+ Private,
+ (EFI_IP_ADDRESS *) &Ip,
+ (EFI_MAC_ADDRESS *) &DestMac
+ );
+ }
+ }
+ }
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG ((EFI_D_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));
+ return StatCode;
+ }
+ //
+ // fill in packet info
+ //
+ SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);
+ IP_TX_HEADER.TotalLength = HTONS (PacketLength);
+ IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);
+ CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);
+
+ //
+ // send it
+ //
+ return SendPacket (
+ Private,
+ (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,
+ &IP_TX_HEADER,
+ PacketLength,
+ &DestMac,
+ PXE_PROTOCOL_ETHERNET_IP,
+ Function
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// send ipv4 packet with option
+//
+EFI_STATUS
+Ipv4SendWOp (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GatewayIp,
+ UINT8 *Msg,
+ UINTN MessageLength,
+ UINT8 Prot,
+ UINT8 *Option,
+ UINTN OptionLength,
+ UINT32 DestIp,
+ EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ UINTN HdrLth;
+
+ PxeBcMode = Private->EfiBc.Mode;
+ HdrLth = sizeof (IPV4_HEADER) + OptionLength;
+
+ ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
+ IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;
+ IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;
+ IP_TX_HEADER.Protocol = Prot;
+ IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;
+ IP_TX_HEADER.DestAddr.L = DestIp;
+ IP_TX_HEADER.Id = Random (Private);
+ CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);
+ return Ipv4Xmt (
+ Private,
+ GatewayIp,
+ HdrLth,
+ HdrLth,
+ Msg,
+ MessageLength,
+ Function
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
+//
+EFI_STATUS
+Ip4Send (
+ PXE_BASECODE_DEVICE *Private, // pointer to instance data
+ UINTN MayFrag, //
+ UINT8 Prot, // protocol
+ UINT32 SrcIp, // Source IP address
+ UINT32 DestIp, // Destination IP address
+ UINT32 GatewayIp, // used if not NULL and needed
+ UINTN HdrSize, // protocol header byte length
+ UINT8 *MessagePtr, // pointer to data
+ UINTN MessageLength // data byte length
+ )
+{
+ EFI_STATUS StatCode;
+ UINTN TotDataLength;
+
+ TotDataLength = HdrSize + MessageLength;
+
+ if (TotDataLength > MAX_IPV4_DATA_SIZE) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nIp4Send() Exit #1 %xh (%r)",
+ EFI_BAD_BUFFER_SIZE,
+ EFI_BAD_BUFFER_SIZE)
+ );
+
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
+ IP_TX_HEADER.TimeToLive = DEFAULT_TTL;
+ IP_TX_HEADER.Protocol = Prot;
+ IP_TX_HEADER.SrcAddr.L = SrcIp;
+ IP_TX_HEADER.DestAddr.L = DestIp;
+ IP_TX_HEADER.Id = Random (Private);
+
+ if (!MayFrag) {
+ *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;
+ }
+ //
+ // check for need to fragment
+ //
+ if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {
+ UINTN DataLengthSent;
+ UINT16 FragmentOffset;
+
+ FragmentOffset = IP_MORE_FRAG;
+ //
+ // frag offset field
+ //
+ if (!MayFrag) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nIp4Send() Exit #2 %xh (%r)",
+ EFI_BAD_BUFFER_SIZE,
+ EFI_BAD_BUFFER_SIZE)
+ );
+
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ //
+ // send out in fragments - first includes upper level header
+ // all are max and include more frag bit except last
+ //
+ * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;
+
+#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
+#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)
+
+ DataLengthSent = IPV4_FRAG_SIZE - HdrSize;
+
+ StatCode = Ipv4Xmt (
+ Private,
+ GatewayIp,
+ sizeof (IPV4_HEADER),
+ sizeof (IPV4_HEADER) + HdrSize,
+ MessagePtr,
+ DataLengthSent,
+ Private->Function
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nIp4Send() Exit #3 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+
+ return StatCode;
+ }
+
+ MessagePtr += DataLengthSent;
+ MessageLength -= DataLengthSent;
+ FragmentOffset += IPV4_FRAG_OFF_INC;
+ IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);
+
+ while (MessageLength > IPV4_FRAG_SIZE) {
+ StatCode = Ipv4Xmt (
+ Private,
+ GatewayIp,
+ sizeof (IPV4_HEADER),
+ sizeof (IPV4_HEADER),
+ MessagePtr,
+ IPV4_FRAG_SIZE,
+ Private->Function
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nIp4Send() Exit #3 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+
+ return StatCode;
+ }
+
+ MessagePtr += IPV4_FRAG_SIZE;
+ MessageLength -= IPV4_FRAG_SIZE;
+ FragmentOffset += IPV4_FRAG_OFF_INC;
+ IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);
+ }
+
+ * (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);
+ HdrSize = 0;
+ }
+ //
+ // transmit
+ //
+ return Ipv4Xmt (
+ Private,
+ GatewayIp,
+ sizeof (IPV4_HEADER),
+ sizeof (IPV4_HEADER) + HdrSize,
+ MessagePtr,
+ MessageLength,
+ Private->Function
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// return true if dst IP in receive header matched with what's enabled
+//
+STATIC
+BOOLEAN
+IPgood (
+ PXE_BASECODE_DEVICE *Private,
+ IPV4_HEADER *IpHeader
+ )
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ UINTN Index;
+
+ PxeBcMode = Private->EfiBc.Mode;
+
+ if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {
+ return TRUE;
+ }
+
+ if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&
+ IS_MULTICAST (&IpHeader->DestAddr)
+ ) {
+ return TRUE;
+ }
+
+ if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&
+ PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L
+ ) {
+ return TRUE;
+ }
+
+ if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {
+ return TRUE;
+ }
+
+ for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {
+ if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// receive up to MessageLength message into MessagePtr for protocol Prot
+// return message length, src/dest ips if select any, and pointer to protocol
+// header routine will filter based on source and/or dest ip if OpFlags set.
+//
+EFI_STATUS
+IpReceive (
+ PXE_BASECODE_DEVICE *Private,
+ PXE_OPFLAGS OpFlags,
+ EFI_IP_ADDRESS *SrcIpPtr,
+ EFI_IP_ADDRESS *DestIpPtr,
+ UINT8 Prot,
+ VOID *HeaderPtr,
+ UINTN HdrSize,
+ UINT8 *MessagePtr,
+ UINTN *MessageLengthPtr,
+ EFI_EVENT TimeoutEvent
+ )
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ EFI_STATUS StatCode;
+ UINTN ByteCount;
+ UINTN FragmentCount;
+ UINTN ExpectedPacketLength;
+ UINTN Id;
+ BOOLEAN GotFirstFragment;
+ BOOLEAN GotLastFragment;
+
+ DEBUG (
+ (EFI_D_NET,
+ "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",
+ HeaderPtr,
+ HdrSize,
+ MessagePtr,
+ *MessageLengthPtr)
+ );
+
+ PxeBcMode = Private->EfiBc.Mode;
+ PxeBcMode->IcmpErrorReceived = FALSE;
+
+ ExpectedPacketLength = 0;
+ GotFirstFragment = FALSE;
+ GotLastFragment = FALSE;
+ FragmentCount = 0;
+ ByteCount = 0;
+ Id = 0;
+
+ for (;;) {
+ IPV4_HEADER IpHdr;
+ UINTN FFlds;
+ UINTN TotalLength;
+ UINTN FragmentOffset;
+ UINTN HeaderSize;
+ UINTN BufferSize;
+ UINTN IpHeaderLength;
+ UINTN DataLength;
+ UINT16 Protocol;
+ UINT8 *NextHdrPtr;
+ UINT8 *PacketPtr;
+
+ StatCode = WaitForReceive (
+ Private,
+ Private->Function,
+ TimeoutEvent,
+ &HeaderSize,
+ &BufferSize,
+ &Protocol
+ );
+
+ if (EFI_ERROR (StatCode)) {
+ return StatCode;
+ }
+
+ PacketPtr = Private->ReceiveBufferPtr + HeaderSize;
+
+ if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {
+ HandleArpReceive (
+ Private,
+ (ARP_PACKET *) PacketPtr,
+ Private->ReceiveBufferPtr
+ );
+
+ continue;
+ }
+
+ if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {
+ continue;
+ }
+
+#if SUPPORT_IPV6
+ if (PxeBcMode->UsingIpv6) {
+ //
+ // TBD
+ //
+ }
+#endif
+
+#define IpRxHeader ((IPV4_HEADER *) PacketPtr)
+
+ //
+ // filter for version & check sum
+ //
+ IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);
+
+ if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {
+ continue;
+ }
+
+ if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {
+ continue;
+ }
+
+ CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr));
+ //IpHdr = *IpRxHeader;
+ TotalLength = NTOHS (IpHdr.TotalLength);
+
+ if (IpHdr.Protocol == PROT_TCP) {
+ //
+ // The NextHdrPtr is used to seed the header buffer we are passing back.
+ // That being the case, we want to see everything in pPkt which contains
+ // everything but the ethernet (or whatever) frame. IP + TCP in this case.
+ //
+ DataLength = TotalLength;
+ NextHdrPtr = PacketPtr;
+ } else {
+ DataLength = TotalLength - IpHeaderLength;
+ NextHdrPtr = PacketPtr + IpHeaderLength;
+ }
+ //
+ // If this is an ICMP, it might not be for us.
+ // Double check the state of the IP stack and the
+ // packet fields before assuming it is an ICMP
+ // error. ICMP requests are not supported by the
+ // PxeBc IP stack and should be ignored.
+ //
+ if (IpHdr.Protocol == PROT_ICMP) {
+ ICMPV4_HEADER *Icmpv4;
+
+ Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;
+
+ //
+ // For now only obvious ICMP error replies will be accepted by
+ // this stack. This still makes us vulnerable to DoS attacks.
+ // But at least we will not be killed by DHCP daemons.
+ //
+ switch (Icmpv4->Type) {
+ case ICMP_REDIRECT:
+ case ICMP_ECHO:
+ case ICMP_ROUTER_ADV:
+ case ICMP_ROUTER_SOLICIT:
+ case ICMP_TIMESTAMP:
+ case ICMP_TIMESTAMP_REPLY:
+ case ICMP_INFO_REQ:
+ case ICMP_INFO_REQ_REPLY:
+ case ICMP_SUBNET_MASK_REQ:
+ case ICMP_SUBNET_MASK_REPLY:
+ default:
+ continue;
+
+ //
+ // %%TBD - This should be implemented.
+ //
+ case ICMP_ECHO_REPLY:
+ continue;
+
+ case ICMP_DEST_UNREACHABLE:
+ case ICMP_TIME_EXCEEDED:
+ case ICMP_PARAMETER_PROBLEM:
+ case ICMP_SOURCE_QUENCH:
+ PxeBcMode->IcmpErrorReceived = TRUE;
+
+ CopyMem (
+ &PxeBcMode->IcmpError,
+ NextHdrPtr,
+ sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
+ );
+
+ DEBUG (
+ (EFI_D_NET,
+ "\nIpReceive() Exit #1 %Xh (%r)",
+ EFI_ICMP_ERROR,
+ EFI_ICMP_ERROR)
+ );
+ }
+
+ return EFI_ICMP_ERROR;
+ }
+
+ if (IpHdr.Protocol == PROT_IGMP) {
+ HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);
+
+ DEBUG ((EFI_D_NET, "\n IGMP"));
+ continue;
+ }
+ //
+ // check for protocol
+ //
+ if (IpHdr.Protocol != Prot) {
+ continue;
+ }
+ //
+ // do filtering
+ //
+ if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {
+ DEBUG ((EFI_D_NET, "\n Not expected source IP address."));
+ continue;
+ }
+
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {
+ if (!IPgood (Private, &IpHdr)) {
+ continue;
+ }
+ } else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {
+ if (DestIpPtr == NULL) {
+ if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {
+ continue;
+ }
+ } else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {
+ continue;
+ }
+ }
+ //
+ // get some data we need
+ //
+ FFlds = NTOHS (IpHdr.FragmentFields);
+ FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);
+
+ /* Keep count of fragments that belong to this session.
+ * If we get packets with a different IP ID number,
+ * ignore them. Ignored packets should be handled
+ * by the upper level protocol.
+ */
+ if (FragmentCount == 0) {
+ Id = IpHdr.Id;
+
+ if (DestIpPtr != NULL) {
+ DestIpPtr->Addr[0] = IpHdr.DestAddr.L;
+ }
+
+ if (SrcIpPtr != NULL) {
+ SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;
+ }
+ } else {
+ if (IpHdr.Id != Id) {
+ continue;
+ }
+ }
+
+ ++FragmentCount;
+
+ /* Fragment management.
+ */
+ if (FragmentOffset == 0) {
+ /* This is the first fragment (may also be the
+ * only fragment).
+ */
+ GotFirstFragment = TRUE;
+
+ /* If there is a separate protocol header buffer,
+ * copy the header, adjust the data pointer and
+ * the data length.
+ */
+ if (HdrSize != 0) {
+ CopyMem (HeaderPtr, NextHdrPtr, HdrSize);
+
+ NextHdrPtr += HdrSize;
+ DataLength -= HdrSize;
+ }
+ } else {
+ /* If there is a separate protocol header buffer,
+ * adjust the fragment offset.
+ */
+ FragmentOffset -= HdrSize;
+ }
+
+ /* See if this is the last fragment.
+ */
+ if (!(FFlds & IP_MORE_FRAG)) {
+ //
+ // This is the last fragment (may also be the only fragment).
+ //
+ GotLastFragment = TRUE;
+
+ /* Compute the expected length of the assembled
+ * packet. This will be used to decide if we
+ * have gotten all of the fragments.
+ */
+ ExpectedPacketLength = FragmentOffset + DataLength;
+ }
+
+ DEBUG (
+ (EFI_D_NET,
+ "\n ID = %Xh Off = %d Len = %d",
+ Id,
+ FragmentOffset,
+ DataLength)
+ );
+
+ /* Check for receive buffer overflow.
+ */
+ if (FragmentOffset + DataLength > *MessageLengthPtr) {
+ /* There is not enough space in the receive
+ * buffer for the fragment.
+ */
+ DEBUG (
+ (EFI_D_NET,
+ "\nIpReceive() Exit #3 %Xh (%r)",
+ EFI_BUFFER_TOO_SMALL,
+ EFI_BUFFER_TOO_SMALL)
+ );
+
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ /* Copy data into receive buffer.
+ */
+ if (DataLength != 0) {
+ DEBUG ((EFI_D_NET, " To = %Xh", MessagePtr + FragmentOffset));
+
+ CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);
+ ByteCount += DataLength;
+ }
+
+ /* If we have seen the first and last fragments and
+ * the receive byte count is at least as large as the
+ * expected byte count, return SUCCESS.
+ *
+ * We could be tricked by receiving a fragment twice
+ * but the upper level protocol should figure this
+ * out.
+ */
+ if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {
+ *MessageLengthPtr = ExpectedPacketLength;
+ return EFI_SUCCESS;
+ }
+ }
+}
+
+/* eof - pxe_bc_ip.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c
new file mode 100644
index 0000000..3e0b0f5
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_mtftp.c
@@ -0,0 +1,2391 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ pxe_bc_mtftp.c
+
+Abstract:
+ TFTP and MTFTP (multicast TFTP) implementation.
+
+Revision History
+
+--*/
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// The following #define is used to create a version that does not wait to
+// open after a listen. This is just for a special regression test of MTFTP
+// server to make sure multiple opens are handled correctly. Normally this
+// next line should be a comment.
+// #define SpecialNowaitVersion // comment out for normal operation
+//
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+#include "bc.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+UINT64
+Swap64 (
+ UINT64 n
+ )
+{
+ union {
+ UINT64 n;
+ UINT8 b[8];
+ } u;
+
+ UINT8 t;
+
+ u.n = n;
+
+ t = u.b[0];
+ u.b[0] = u.b[7];
+ u.b[7] = t;
+
+ t = u.b[1];
+ u.b[1] = u.b[6];
+ u.b[6] = t;
+
+ t = u.b[2];
+ u.b[2] = u.b[5];
+ u.b[5] = t;
+
+ t = u.b[3];
+ u.b[3] = u.b[4];
+ u.b[4] = t;
+
+ return u.n;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+TftpUdpRead (
+ PXE_BASECODE_DEVICE *Private,
+ UINT16 Operation,
+ VOID *HeaderPtr,
+ UINTN *BufferSizePtr,
+ VOID *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_IP_ADDRESS *OurIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
+ UINT16 Timeout
+ )
+/*++
+Routine description:
+ Read TFTP packet. If TFTP ERROR packet is read, fill in TFTP error
+ information in Mode structure and return TFTP_ERROR status.
+
+Parameters:
+ Private :=
+ Operation :=
+ HeaderPtr :=
+ BufferSizePtr :=
+ BufferPtr :=
+ ServerIpPtr :=
+ ServerPortPtr :=
+ OurIpPtr :=
+ OurPortPtr :=
+ Timeout :=
+
+Returns:
+ EFI_SUCCESS :=
+ EFI_TFTP_ERROR :=
+ other :=
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ EFI_STATUS Status;
+ EFI_EVENT TimeoutEvent;
+ UINTN HeaderSize;
+
+ //
+ //
+ //
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ Timeout * 10000000 + 1000000
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return Status;
+ }
+ //
+ //
+ //
+ HeaderSize = Private->BigBlkNumFlag ? sizeof (struct Tftpv4Ack8) : sizeof (struct Tftpv4Ack);
+
+#define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)
+
+ Status = UdpRead (
+ Private,
+ Operation,
+ OurIpPtr,
+ OurPortPtr,
+ ServerIpPtr,
+ ServerPortPtr,
+ &HeaderSize,
+ HeaderPtr,
+ BufferSizePtr,
+ BufferPtr,
+ TimeoutEvent
+ );
+
+ if (Status != EFI_SUCCESS || ERROR_MESSAGE_PTR->OpCode != HTONS (TFTP_ERROR)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return Status;
+ }
+ //
+ // got an error packet
+ // write one byte error code followed by error message
+ //
+ PxeBcMode = Private->EfiBc.Mode;
+ PxeBcMode->TftpErrorReceived = TRUE;
+ PxeBcMode->TftpError.ErrorCode = (UINT8) NTOHS (ERROR_MESSAGE_PTR->ErrCode);
+ HeaderSize = EFI_MIN (*BufferSizePtr, sizeof PxeBcMode->TftpError.ErrorString);
+ CopyMem (PxeBcMode->TftpError.ErrorString, BufferPtr, HeaderSize);
+
+ gBS->CloseEvent (TimeoutEvent);
+ return EFI_TFTP_ERROR;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+VOID
+SendError (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr
+ )
+/*++
+Routine description:
+ Send TFTP ERROR message to TFTP server
+
+Parameters:
+ Private :=
+ ServerIpPtr :=
+ ServerPortPtr :=
+ OurPortPtr :=
+
+Returns:
+--*/
+{
+ struct Tftpv4Error *ErrStr;
+ UINTN Len;
+
+ ErrStr = (VOID *) Private->TftpErrorBuffer;
+ Len = sizeof *ErrStr;
+
+ ErrStr->OpCode = HTONS (TFTP_ERROR);
+ ErrStr->ErrCode = HTONS (TFTP_ERR_OPTION);
+ ErrStr->ErrMsg[0] = 0;
+
+ UdpWrite (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
+ ServerIpPtr,
+ ServerPortPtr,
+ 0,
+ 0,
+ OurPortPtr,
+ 0,
+ 0,
+ &Len,
+ ErrStr
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+SendAckAndGetData (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_IP_ADDRESS *ReplyIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
+ UINT16 Timeout,
+ UINTN *ReplyLenPtr,
+ UINT8 *PxeBcMode,
+ UINT64 *BlockNumPtr,
+ BOOLEAN AckOnly
+ )
+/*++
+Routine description:
+ Send TFTP ACK packet to server and read next DATA packet.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ ServerIpPtr := Pointer to TFTP server IP address
+ ServerPortPtr := Pointer to TFTP server UDP port
+ ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
+ OurPortPtr := Pointer to TFTP client UDP port
+ Timeout :=
+ ReplyLenPtr := Pointer to packet length
+ PxeBcMode := Pointer to packet buffer
+ BlockNumPtr := Pointer to block number
+ AckOnly := TRUE == Send last ack - do not wait for reply
+
+Returns:
+--*/
+{
+ struct Tftpv4Data DataBuffer;
+ struct Tftpv4Ack *Ack2Ptr;
+ struct Tftpv4Ack8 *Ack8Ptr;
+ EFI_STATUS Status;
+ UINTN Len;
+
+ Ack2Ptr = (VOID *) Private->TftpAckBuffer;
+ Ack8Ptr = (VOID *) Private->TftpAckBuffer;
+
+ if (Private->BigBlkNumFlag) {
+ Len = sizeof (struct Tftpv4Ack8);
+
+ Ack8Ptr->OpCode = HTONS (TFTP_ACK8);
+ Ack8Ptr->BlockNum = Swap64 (*BlockNumPtr);
+
+ Status = UdpWrite (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
+ ServerIpPtr,
+ ServerPortPtr,
+ 0,
+ 0,
+ OurPortPtr,
+ 0,
+ 0,
+ &Len,
+ Ack8Ptr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Len = sizeof (struct Tftpv4Ack);
+
+ Ack2Ptr->OpCode = HTONS (TFTP_ACK);
+ Ack2Ptr->BlockNum = HTONS ((UINT16) *BlockNumPtr);
+
+ Status = UdpWrite (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
+ ServerIpPtr,
+ ServerPortPtr,
+ 0,
+ 0,
+ OurPortPtr,
+ 0,
+ 0,
+ &Len,
+ Ack2Ptr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (AckOnly) {
+ //
+ // ACK of last packet. This is just a courtesy.
+ // Do not wait for response.
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // read reply
+ //
+ Status = TftpUdpRead (
+ Private,
+ 0,
+ &DataBuffer,
+ ReplyLenPtr,
+ PxeBcMode,
+ ServerIpPtr,
+ ServerPortPtr,
+ ReplyIpPtr,
+ OurPortPtr,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+ //
+ // got a good reply (so far)
+ // check for next data packet
+ //
+ if (!Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
+ }
+
+ *BlockNumPtr = NTOHS (DataBuffer.Header.BlockNum);
+ return Status;
+ }
+
+ if (Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA8)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
+ }
+
+ *BlockNumPtr = Swap64 (*(UINT64 *) &DataBuffer.Header.BlockNum);
+ return Status;
+ }
+
+ return EFI_PROTOCOL_ERROR;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+LockStepReceive (
+ PXE_BASECODE_DEVICE *Private,
+ UINTN PacketSize,
+ UINT64 *BufferSizePtr,
+ UINT64 Offset,
+ UINT8 *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_IP_ADDRESS *ReplyIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
+ UINT64 LastBlock,
+ UINT16 Timeout,
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+ Read rest of file after successfull M/TFTP request.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ PacketSize := Pointer to packet size
+ BufferSizePtr := Pointer to buffer (file) size
+ Offset := Offset into buffer of next packet
+ BufferPtr := Pointer to receive buffer
+ ServerIpPtr := Pointer to TFTP server IP address
+ ServerPortPtr := Pointer to TFTP server UDP port
+ ReplyIpPtr := Pointer to TFTP DATA packet destination IP address
+ OurPortPtr := Pointer to TFTP client UDP port
+ LastBlock := Last block number received
+ Timeout :=
+ DontUseBuffer := TRUE == throw away data, just count # of bytes
+
+Returns:
+--*/
+{
+ EFI_STATUS Status;
+ UINT64 BlockNum;
+ UINT64 BufferSize;
+ UINTN Retries;
+ UINTN SaveLen;
+ UINTN ReplyLen;
+
+ ReplyLen = PacketSize;
+ BlockNum = LastBlock;
+
+ DEBUG ((EFI_D_INFO, "\nLockStepReceive() PacketSize = %d", PacketSize));
+
+ if (DontUseBuffer) {
+ BufferSize = PacketSize;
+ } else {
+ BufferSize = *BufferSizePtr - Offset;
+ BufferPtr += Offset;
+ }
+
+ while (ReplyLen >= 512 && ReplyLen == PacketSize) {
+ if (BufferSize < PacketSize) {
+ ReplyLen = (UINTN) ((BufferSize > 0) ? BufferSize : 0);
+ }
+
+ SaveLen = ReplyLen;
+
+ //
+ // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout
+ //
+ Retries = NUM_ACK_RETRIES;
+
+ do {
+ ReplyLen = SaveLen;
+
+ Status = SendAckAndGetData (
+ Private,
+ ServerIpPtr,
+ ServerPortPtr,
+ ReplyIpPtr,
+ OurPortPtr,
+ Timeout,
+ (UINTN *) &ReplyLen,
+ BufferPtr,
+ &BlockNum,
+ FALSE
+ );
+
+ if (!EFI_ERROR (Status) || Status == EFI_BUFFER_TOO_SMALL) {
+ if (BlockNum == LastBlock) {
+ DEBUG ((EFI_D_NET, "\nresend"));
+ //
+ // a resend - continue
+ //
+ Status = EFI_TIMEOUT;
+ } else if (Private->BigBlkNumFlag) {
+ if (BlockNum != ++LastBlock) {
+ DEBUG ((EFI_D_NET, "\nLockStepReceive() Exit #1a"));
+ //
+ // not correct blocknum - error
+ //
+ return EFI_PROTOCOL_ERROR;
+ }
+ } else {
+ LastBlock = (LastBlock + 1) & 0xFFFF;
+ if (BlockNum != LastBlock) {
+ DEBUG ((EFI_D_NET, "\nLockStepReceive() Exit #1b"));
+ return EFI_PROTOCOL_ERROR;
+ //
+ // not correct blocknum - error
+ //
+ }
+ }
+ }
+ } while (Status == EFI_TIMEOUT && --Retries);
+
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);
+ }
+
+ return Status;
+ }
+
+ if (DontUseBuffer) {
+ BufferSize += ReplyLen;
+ } else {
+ BufferPtr += ReplyLen;
+ BufferSize -= ReplyLen;
+ }
+ }
+ //
+ // while (ReplyLen == PacketSize);
+ //
+ if (DontUseBuffer) {
+ if (BufferSizePtr != NULL) {
+ *BufferSizePtr = (BufferSize - PacketSize);
+ }
+ } else {
+ *BufferSizePtr -= BufferSize;
+ }
+
+ /* Send ACK of last packet. */
+ ReplyLen = 0;
+
+ SendAckAndGetData (
+ Private,
+ ServerIpPtr,
+ ServerPortPtr,
+ ReplyIpPtr,
+ OurPortPtr,
+ Timeout,
+ (UINTN *) &ReplyLen,
+ BufferPtr,
+ &BlockNum,
+ TRUE
+ );
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// some literals
+//
+STATIC UINT8 Mode[] = MODE_BINARY;
+STATIC UINT8 BlockSizeOp[] = OP_BLKSIZE;
+STATIC UINT8 TsizeOp[] = OP_TFRSIZE;
+STATIC UINT8 OverwriteOp[] = OP_OVERWRITE;
+STATIC UINT8 BigBlkNumOp[] = OP_BIGBLKNUM;
+STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort = TFTP_OPEN_PORT;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+UINT8 *
+FindOption (
+ UINT8 *OptionPtr,
+ INTN OpLen,
+ UINT8 *OackPtr,
+ INTN OackSize
+ )
+/*++
+Routine description:
+ Check TFTP OACK packet for option.
+
+Parameters:
+ OptionPtr := Pointer to option string to find
+ OpLen := Length of option string
+ OackPtr := Pointer to OACK data
+ OackSize := Length of OACK data
+
+Returns:
+ Pointer to value field if option found or NULL if not found.
+--*/
+{
+ if ((OackSize -= OpLen) <= 0) {
+ return NULL;
+ }
+
+ do {
+ if (!CompareMem (OackPtr, OptionPtr, OpLen)) {
+ return OackPtr + OpLen;
+ }
+
+ ++OackPtr;
+ } while (--OackSize);
+
+ return NULL;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#define BKSZOP 1 // block size
+#define TSIZEOP 2 // transfer size
+#define OVERWRITEOP 4 // overwrite
+#define BIGBLKNUMOP 8 // big block numbers
+STATIC
+EFI_STATUS
+TftpRwReq (
+ UINT16 Req,
+ UINT16 Options,
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
+ UINT8 *FilenamePtr,
+ UINTN *PacketSizePtr,
+ VOID *Buffer
+ )
+/*++
+Routine description:
+ Send TFTP RRQ/WRQ packet.
+
+Parameters:
+ Req := Type of request to send
+ Options := One or more of the #define values above
+ Private := Pointer to PxeBc interface
+ ServerIpPtr := Pointer to TFTP server IP address
+ ServerPortPtr := Pointer to TFTP server UDP port
+ OurPortPtr := Pointer to TFTP client UDP port
+ FilenamePtr := Pointer to TFTP file or directory name
+ PacketSizePtr := Pointer to block size
+ Buffer :=
+
+Returns:
+--*/
+{
+ union {
+ UINT8 Data[514];
+ struct Tftpv4Req ReqStr;
+ } *u;
+
+ UINT16 OpFlags;
+ INTN Len;
+ INTN TotalLen;
+ UINT8 *Ptr;
+
+ if (*OurPortPtr == 0) {
+ OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;
+ } else {
+ OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT;
+ }
+ //
+ // build the basic request - opcode, filename, mode
+ //
+ u = Buffer;
+ u->ReqStr.OpCode = HTONS (Req);
+ TotalLen = sizeof (Mode) + sizeof (u->ReqStr.OpCode) + (Len = 1 + AsciiStrLen ((CHAR8 *)FilenamePtr));
+
+ CopyMem (u->ReqStr.FileName, FilenamePtr, Len);
+ Ptr = (UINT8 *) (u->ReqStr.FileName + Len);
+
+ CopyMem (Ptr, Mode, sizeof (Mode));
+ Ptr += sizeof (Mode);
+
+ if (Options & BKSZOP) {
+ CopyMem (Ptr, BlockSizeOp, sizeof (BlockSizeOp));
+ UtoA10 (*PacketSizePtr, Ptr + sizeof (BlockSizeOp));
+
+ TotalLen += (Len = 1 + AsciiStrLen ((CHAR8 *)Ptr + sizeof (BlockSizeOp)) + sizeof (BlockSizeOp));
+
+ Ptr += Len;
+ }
+
+ if (Options & TSIZEOP) {
+ CopyMem (Ptr, TsizeOp, sizeof (TsizeOp));
+ CopyMem (Ptr + sizeof (TsizeOp), "0", 2);
+ TotalLen += sizeof (TsizeOp) + 2;
+ Ptr += sizeof (TsizeOp) + 2;
+ }
+
+ if (Options & OVERWRITEOP) {
+ CopyMem (Ptr, OverwriteOp, sizeof (OverwriteOp));
+ CopyMem (Ptr + sizeof (OverwriteOp), "1", 2);
+ TotalLen += sizeof (OverwriteOp) + 2;
+ Ptr += sizeof (OverwriteOp) + 2;
+ }
+
+ if (Options & BIGBLKNUMOP) {
+ CopyMem (Ptr, BigBlkNumOp, sizeof (BigBlkNumOp));
+ CopyMem (Ptr + sizeof (BigBlkNumOp), "8", 2);
+ TotalLen += sizeof (BigBlkNumOp) + 2;
+ Ptr += sizeof (BigBlkNumOp) + 2;
+ }
+ //
+ // send it
+ //
+ return UdpWrite (
+ Private,
+ OpFlags,
+ ServerIpPtr,
+ ServerPortPtr,
+ 0,
+ 0,
+ OurPortPtr,
+ 0,
+ 0,
+ (UINTN *) &TotalLen,
+ u
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+TftpRwReqwResp (
+ UINT16 Req,
+ UINT16 Options,
+ PXE_BASECODE_DEVICE *Private,
+ VOID *HeaderPtr,
+ UINTN *PacketSizePtr,
+ UINTN *ReplyLenPtr,
+ VOID *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerReplyPortPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,
+ UINT8 *FilenamePtr,
+ UINT16 Timeout
+ )
+/*++
+Routine description:
+ Start TFTP session. Issue request and wait for response.
+ Retry three times on error. If failed using options,
+ retry three times w/o options on error.
+
+Parameters:
+ Req := TFTP request type
+ Options := TFTP option bits
+ Private := Pointer to PxeBc interface
+ HeaderPtr :=
+ PacketSizePtr := Pointer to block size
+ ReplyLenPtr :=
+ BufferPtr :=
+ ServerIpPtr := Pointer to TFTP server IP address
+ ServerPortPtr := Pointer to TFTP server UDP port
+ ServerReplyPortPtr :=
+ OurPortPtr := Pointer to TFTP client UDP Port
+ FilenamePtr := Pointer to file or directory name
+ Timeout :=
+
+Returns:
+--*/
+{
+ EFI_STATUS Status;
+ UINTN SaveReplyLen;
+ INTN Retries;
+ UINT8 Buffer[514];
+
+ SaveReplyLen = *ReplyLenPtr;
+ Retries = 3;
+ Private->BigBlkNumFlag = FALSE;
+ *OurPortPtr = 0;
+ //
+ // generate random
+ //
+ do {
+ if (*OurPortPtr != 0) {
+ if (++ *OurPortPtr == 0) {
+ *OurPortPtr = PXE_RND_PORT_LOW;
+ }
+ }
+ //
+ // send request from our Ip = StationIp
+ //
+ if ((Status = TftpRwReq (
+ Req,
+ Options,
+ Private,
+ ServerIpPtr,
+ ServerPortPtr,
+ OurPortPtr,
+ FilenamePtr,
+ PacketSizePtr,
+ Buffer
+ )) != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nTftpRwReqwResp() Exit #1 %xh (%r)",
+ Status,
+ Status)
+ );
+
+ return Status;
+ }
+ //
+ // read reply to our Ip = StationIp
+ //
+ *ReplyLenPtr = SaveReplyLen;
+
+ Status = TftpUdpRead (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,
+ HeaderPtr,
+ ReplyLenPtr,
+ BufferPtr,
+ ServerIpPtr,
+ ServerReplyPortPtr,
+ 0,
+ OurPortPtr,
+ Timeout
+ );
+ } while (Status == EFI_TIMEOUT && --Retries);
+
+ if (!Options || Status != EFI_TFTP_ERROR) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nTftpRwReqwResp() Exit #2 %xh (%r)",
+ Status,
+ Status)
+ );
+ return Status;
+ }
+
+ Status = TftpRwReqwResp (
+ Req,
+ 0,
+ Private,
+ HeaderPtr,
+ PacketSizePtr,
+ ReplyLenPtr,
+ BufferPtr,
+ ServerIpPtr,
+ ServerPortPtr,
+ ServerReplyPortPtr,
+ OurPortPtr,
+ FilenamePtr,
+ Timeout
+ );
+
+ DEBUG ((EFI_D_WARN, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status, Status));
+
+ return Status;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// mtftp listen
+// read on mcast ip, cport, from sport, for data packet
+// returns success if gets multicast last packet or all up to last block
+// if not missing, then finished
+//
+STATIC
+EFI_STATUS
+MtftpListen (
+ PXE_BASECODE_DEVICE *Private,
+ UINT64 *BufferSizePtr,
+ UINT8 *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr,
+ UINT64 *StartBlockPtr,
+ UINTN *NumMissedPtr,
+ UINT16 TransTimeout,
+ UINT16 ListenTimeout,
+ UINT64 FinalBlock,
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+ Listen for MTFTP traffic and save desired packets.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ BufferSizePtr :=
+ BufferPtr :=
+ ServerIpPtr := Pointer to TFTP server IP address
+ MtftpInfoPtr := Pointer to MTFTP session information
+ StartBlockPtr := IN=first block we are looking for OUT=first block received
+ NumMissedPtr := Number of blocks missed
+ TransTimeout :=
+ ListenTimeout :=
+ FinalBlock :=
+ DontUseBuffer := TRUE == throw packets away, just count bytes
+
+Returns:
+--*/
+{
+ EFI_STATUS Status;
+ struct Tftpv4Ack Header;
+ UINT64 Offset;
+ UINT64 BlockNum;
+ UINT64 LastBlockNum;
+ UINT64 BufferSize;
+ UINTN NumMissed;
+ UINTN PacketSize;
+ UINTN SaveReplyLen;
+ UINTN ReplyLen;
+ UINT16 Timeout;
+
+ LastBlockNum = *StartBlockPtr;
+ Timeout = ListenTimeout;
+ *NumMissedPtr = 0;
+ PacketSize = 0;
+ BufferSize = *BufferSizePtr;
+ ReplyLen = MAX_TFTP_PKT_SIZE;;
+
+ //
+ // receive
+ //
+ do {
+ if ((SaveReplyLen = ReplyLen) > BufferSize) {
+ SaveReplyLen = (UINTN) BufferSize;
+ }
+
+ /* %%TBD - add big block number support */
+
+ //
+ // get data - loop on resends
+ //
+ do {
+ ReplyLen = SaveReplyLen;
+
+ if ((Status = TftpUdpRead (
+ Private,
+ 0,
+ &Header,
+ &ReplyLen,
+ BufferPtr,
+ ServerIpPtr,
+ &MtftpInfoPtr->SPort,
+ &MtftpInfoPtr->MCastIp,
+ &MtftpInfoPtr->CPort,
+ Timeout
+ )) != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // make sure a data packet
+ //
+ if (Header.OpCode != HTONS (TFTP_DATA)) {
+ return EFI_PROTOCOL_ERROR;
+ }
+ } while ((BlockNum = NTOHS (Header.BlockNum)) == LastBlockNum);
+
+ //
+ // make sure still going up
+ //
+ if (LastBlockNum > BlockNum) {
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ if (BlockNum - LastBlockNum > 0xFFFFFFFF) {
+ return EFI_PROTOCOL_ERROR;
+ } else {
+ NumMissed = (UINTN) (BlockNum - LastBlockNum - 1);
+ }
+
+ LastBlockNum = BlockNum;
+
+ //
+ // if first time through, some reinitialization
+ //
+ if (!PacketSize) {
+ *StartBlockPtr = BlockNum;
+ PacketSize = ReplyLen;
+ Timeout = TransTimeout;
+ } else {
+ *NumMissedPtr = (UINT16) (*NumMissedPtr + NumMissed);
+ }
+ //
+ // if missed packets, update start block,
+ // etc. and move packet to proper place in buffer
+ //
+ if (NumMissed) {
+ *StartBlockPtr = BlockNum;
+ if (!DontUseBuffer) {
+ Offset = NumMissed * PacketSize;
+ CopyMem (BufferPtr + Offset, BufferPtr, ReplyLen);
+ BufferPtr += Offset;
+ BufferSize -= Offset;
+ }
+ }
+
+ if (!DontUseBuffer) {
+ BufferPtr += ReplyLen;
+ BufferSize -= ReplyLen;
+ }
+ } while (ReplyLen == PacketSize && BlockNum != FinalBlock);
+
+ *BufferSizePtr = BufferSize;
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+MtftpOpen (
+ PXE_BASECODE_DEVICE * Private,
+ UINT64 *BufferSizePtr,
+ UINT8 *BufferPtr,
+ UINTN *PacketSizePtr,
+ EFI_IP_ADDRESS * ServerIpPtr,
+ UINT8 *FilenamePtr,
+ EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr,
+ UINT8 *CompletionStatusPtr,
+#define GOTUNI 1
+#define GOTMULTI 2
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+ Open MTFTP session.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ BufferSizePtr := IN=buffer size OUT=transfer size
+ BufferPtr :=
+ PacketSizePtr :=
+ ServerIpPtr :=
+ FilenamePtr :=
+ MtftpInfoPtr :=
+ CompletionStatusPtr :=
+ DontUseBuffer :=
+
+Returns:
+// mtftp open session
+// return code EFI_SUCCESS
+// and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
+// and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
+// and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
+// (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
+--*/
+{
+ EFI_STATUS Status;
+ EFI_IP_ADDRESS OurReplyIp;
+ struct Tftpv4Ack Header;
+ INTN ReplyLen;
+ INTN Retries;
+ UINT8 *BufferPtr2;
+ UINT8 TmpBuf[514];
+
+ Retries = NUM_MTFTP_OPEN_RETRIES;
+ BufferPtr2 = BufferPtr;
+ *PacketSizePtr = (UINTN) (EFI_MIN (*BufferSizePtr, MAX_TFTP_PKT_SIZE));
+
+ do {
+ //
+ // send a read request
+ //
+ *CompletionStatusPtr = 0;
+
+ if ((Status = TftpRwReq (
+ TFTP_RRQ,
+ 0,
+ Private,
+ ServerIpPtr,
+ &MtftpInfoPtr->SPort,
+ &MtftpInfoPtr->CPort,
+ FilenamePtr,
+ PacketSizePtr,
+ TmpBuf
+ )) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ for (;;) {
+ //
+ // read reply
+ //
+ ZeroMem (&OurReplyIp, Private->IpLength);
+ ReplyLen = *PacketSizePtr;
+
+ if ((Status = TftpUdpRead (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER,
+ &Header,
+ (UINTN *) &ReplyLen,
+ BufferPtr2,
+ ServerIpPtr,
+ &MtftpInfoPtr->SPort,
+ &OurReplyIp,
+ &MtftpInfoPtr->CPort,
+ MtftpInfoPtr->TransmitTimeout
+ )) == EFI_SUCCESS) {
+ //
+ // check for first data packet
+ //
+ if (Header.OpCode != HTONS (TFTP_DATA)) {
+ return EFI_PROTOCOL_ERROR;
+ }
+ //
+ // check block num
+ //
+ if (Header.BlockNum != HTONS (1)) {
+ //
+ // it's not first
+ // if we are not the primary client,
+ // we probably got first and now second
+ // multicast but no unicast, so
+ // *CompletionStatusPtr = GOTMULTI - if this is
+ // the second, can just go on to listen
+ // starting with 2 as the last block
+ // received
+ //
+ if (Header.BlockNum != HTONS (2)) {
+ //
+ // not second
+ //
+ *CompletionStatusPtr = 0;
+ }
+
+ return Status;
+ }
+
+ //
+ // now actual
+ //
+ *PacketSizePtr = ReplyLen;
+ //
+ // see if a unicast data packet
+ //
+ if (!CompareMem (
+ &OurReplyIp,
+ &Private->EfiBc.Mode->StationIp,
+ Private->IpLength
+ )) {
+ *CompletionStatusPtr |= GOTUNI;
+ //
+ // it is
+ // if already got multicast packet,
+ // got em both
+ //
+ if (*CompletionStatusPtr & GOTMULTI) {
+ break;
+ }
+ } else if (!CompareMem (
+ &OurReplyIp,
+ &MtftpInfoPtr->MCastIp,
+ Private->IpLength
+ )) {
+ //
+ // otherwise see if a multicast data packet
+ //
+ *CompletionStatusPtr |= GOTMULTI;
+ //
+ // it is
+ // got first - bump pointer so that if
+ // second multi comes along, we're OK
+ //
+ if (!DontUseBuffer) {
+ BufferPtr2 = (UINT8 *) BufferPtr + ReplyLen;
+ }
+ //
+ // if already got unicast packet,
+ // got em both
+ //
+ if (*CompletionStatusPtr & GOTUNI) {
+ break;
+ }
+ } else {
+ //
+ // else protocol error
+ //
+ return EFI_PROTOCOL_ERROR;
+ }
+ } else if (Status == EFI_TIMEOUT) {
+ //
+ // bad return code - if timed out, retry
+ //
+ break;
+ } else {
+ //
+ // else just bad - failed MTFTP open
+ //
+ return Status;
+ }
+ }
+ } while (Status == EFI_TIMEOUT && --Retries);
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // open failed
+ //
+ return Status;
+ }
+ //
+ // got em both - go into receive mode
+ // routine to read rest of file after a successful open (TFTP or MTFTP)
+ // sends ACK and gets next data packet until short packet arrives,
+ // then sends ACK and (hopefully) times out
+ //
+ return LockStepReceive (
+ Private,
+ (UINT16) ReplyLen,
+ BufferSizePtr,
+ ReplyLen,
+ BufferPtr,
+ ServerIpPtr,
+ &MtftpInfoPtr->SPort,
+ &MtftpInfoPtr->MCastIp,
+ &MtftpInfoPtr->CPort,
+ 1,
+ MtftpInfoPtr->TransmitTimeout,
+ DontUseBuffer
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+MtftpDownload (
+ PXE_BASECODE_DEVICE *Private,
+ UINT64 *BufferSizePtr,
+ UINT8 *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ UINT8 *FilenamePtr,
+ EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr,
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+// mtftp
+// loop
+// listen
+// if did not get any packets, try MTFTP open
+// if got all packets, return
+// compute listen timeout and loop
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ BufferSizePtr :=
+ BufferPtr :=
+ ServerIpPtr :=
+ FilenamePtr :=
+ MtftpInfoPtr :=
+ DontUseBuffer :=
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;
+ EFI_STATUS Status;
+ UINT64 StartBlock;
+ UINT64 LastBlock;
+ UINT64 LastStartBlock;
+ UINT64 BufferSize;
+ UINTN Offset;
+ UINTN NumMissed;
+ UINT16 TransTimeout;
+ UINT16 ListenTimeout;
+ UINT8 *BufferPtrLocal;
+
+ TransTimeout = MtftpInfoPtr->TransmitTimeout;
+ ListenTimeout = MtftpInfoPtr->ListenTimeout;
+ LastBlock = 0;
+ LastStartBlock = 0;
+ Offset = 0;
+
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
+ Filter.IpCnt = 2;
+ CopyMem (&Filter.IpList[0], &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&Filter.IpList[1], &MtftpInfoPtr->MCastIp, sizeof (EFI_IP_ADDRESS));
+
+ if ((Status = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ for (;;) {
+ StartBlock = LastStartBlock;
+ BufferSize = *BufferSizePtr - Offset;
+
+ if (DontUseBuffer) {
+ //
+ // overwrie the temp buf
+ //
+ BufferPtrLocal = BufferPtr;
+ } else {
+ BufferPtrLocal = BufferPtr + Offset;
+
+ }
+ //
+ // special !!! do not leave enabled in saved version on Source Safe
+ // Following code put in in order to create a special version for regression
+ // test of MTFTP server to make sure it handles mulitple opens correctly.
+ // This code should NOT be enabled normally.
+ //
+#ifdef SpecialNowaitVersion
+#pragma message ("This is special version for MTFTP regression test")
+ if (StartBlock || !LastBlock)
+#endif
+ if (((Status = MtftpListen (
+ Private,
+ &BufferSize,
+ BufferPtrLocal,
+ ServerIpPtr,
+ MtftpInfoPtr,
+ &StartBlock,
+ &NumMissed,
+ TransTimeout,
+ ListenTimeout,
+ LastBlock,
+ DontUseBuffer
+ )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {
+ return Status;
+ //
+ // failed
+ //
+ }
+ //
+ // if none were received, start block is not reset
+ //
+ if (StartBlock == LastStartBlock) {
+ UINT8 CompStat;
+
+ //
+ // timed out with none received - try MTFTP open
+ //
+ if ((Status = MtftpOpen (
+ Private,
+ BufferSizePtr,
+ BufferPtr,
+ &Offset,
+ ServerIpPtr,
+ FilenamePtr,
+ MtftpInfoPtr,
+ &CompStat,
+ DontUseBuffer
+ )) != EFI_SUCCESS) {
+ //
+ // open failure - try TFTP
+ //
+ return Status;
+ }
+ //
+ // return code EFI_SUCCESS
+ // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done
+ // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest
+ // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all
+ // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)
+ //
+ if (CompStat == (GOTUNI | GOTMULTI)) {
+ //
+ // finished - got it all
+ //
+ return Status;
+ }
+
+ if (CompStat) {
+ //
+ // offset is two packet lengths
+ //
+ Offset <<= 1;
+ //
+ // last block received
+ //
+ LastStartBlock = 2;
+ } else {
+ Offset = 0;
+ LastStartBlock = 0;
+ }
+
+ ListenTimeout = TransTimeout;
+ continue;
+ }
+ //
+ // did we get the last block
+ //
+ if (Status == EFI_SUCCESS) {
+ //
+ // yes - set the file size if this was first time
+ //
+ if (!LastBlock) {
+ *BufferSizePtr -= BufferSize;
+ }
+ //
+ // if buffer was too small, finished
+ //
+ if (!DontUseBuffer) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // if we got them all, finished
+ //
+ if (!NumMissed && StartBlock == LastStartBlock + 1) {
+ return Status;
+ }
+ //
+ // did not get them all - set last block
+ //
+ LastBlock = (UINT16) (StartBlock - 1);
+ }
+ //
+ // compute listen timeout
+ //
+ ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));
+
+ //
+ // reset
+ //
+ Offset = 0;
+ LastStartBlock = 0;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+TftpInfo (
+ PXE_BASECODE_DEVICE *Private,
+ UINT64 *BufferSizePtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
+ UINT8 *FilenamePtr,
+ UINTN *PacketSizePtr
+ )
+/*++
+Routine description:
+// TFTP info request routine
+// send read request with block size and transfer size options
+// get reply
+// send error to terminate session
+// if OACK received, set info
+
+Parameters:
+ Private :=
+ BufferSizePtr :=
+ ServerIpPtr :=
+ SrvPort :=
+ FilenamePtr :=
+ PacketSizePtr :=
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_UDP_PORT OurPort;
+ EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
+ EFI_STATUS Status;
+ UINT64 BlockNum;
+ UINTN Offset;
+ UINTN ReplyLen;
+ UINT8 *Ptr;
+
+ union {
+ struct Tftpv4Oack OAck2Ptr;
+ struct Tftpv4Ack Ack2Ptr;
+ struct Tftpv4Data Datastr;
+ } u;
+
+ OurPort = 0;
+ ServerReplyPort = 0;
+ ReplyLen = sizeof (u.Datastr.Data);
+
+ //
+ // send a write request with the blocksize option -
+ // sets our IP and port - and receive reply - sets his port
+ // will retry operation up to 3 times if no response,
+ // and will retry without options on an error reply
+ //
+ if ((Status = TftpRwReqwResp (
+ TFTP_RRQ,
+ /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,
+ Private,
+ &u,
+ PacketSizePtr,
+ &ReplyLen,
+ u.Datastr.Data,
+ ServerIpPtr,
+ &SrvPort,
+ &ServerReplyPort,
+ &OurPort,
+ FilenamePtr,
+ REQ_RESP_TIMEOUT
+ )) != EFI_SUCCESS) {
+ DEBUG ((EFI_D_WARN, "\nTftpInfo() Exit #1"));
+ return Status;
+ }
+ //
+ // check for good OACK
+ //
+ if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
+ //
+ // now parse it for options
+ // bigblk#
+ //
+ Ptr = FindOption (
+ BigBlkNumOp,
+ sizeof (BigBlkNumOp),
+ u.OAck2Ptr.OpAck[0].Option,
+ ReplyLen + sizeof (u.Ack2Ptr.BlockNum)
+ );
+
+ if (Ptr != NULL) {
+ if (AtoU (Ptr) == 8) {
+ Private->BigBlkNumFlag = TRUE;
+ } else {
+ return EFI_PROTOCOL_ERROR;
+ }
+ }
+ //
+ // blksize
+ //
+ Ptr = FindOption (
+ BlockSizeOp,
+ sizeof (BlockSizeOp),
+ u.OAck2Ptr.OpAck[0].Option,
+ ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
+ );
+
+ *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
+
+ //
+ // tsize
+ //
+ Ptr = FindOption (
+ TsizeOp,
+ sizeof (TsizeOp),
+ u.OAck2Ptr.OpAck[0].Option,
+ ReplyLen
+ );
+
+ if (Ptr != NULL) {
+ *BufferSizePtr = AtoU64 (Ptr);
+
+ //
+ // teminate session with error
+ //
+ SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
+
+ return EFI_SUCCESS;
+ }
+
+ Offset = 0;
+ BlockNum = 0;
+ } else {
+ //
+ // if MTFTP get filesize, return unsupported
+ //
+ if (SrvPort != TftpRequestPort) {
+ SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);
+ DEBUG ((EFI_D_WARN, "\nTftpInfo() Exit #3"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Offset = ReplyLen;
+ //
+ // last block received
+ //
+ BlockNum = 1;
+ }
+ //
+ // does not support the option - do a download with no buffer
+ //
+ *BufferSizePtr = 0;
+
+ Status = LockStepReceive (
+ Private,
+ (UINT16) ReplyLen,
+ BufferSizePtr,
+ Offset,
+ (UINT8 *) &u,
+ ServerIpPtr,
+ &ServerReplyPort,
+ &Private->EfiBc.Mode->StationIp,
+ &OurPort,
+ BlockNum,
+ ACK_TIMEOUT,
+ TRUE
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status));
+ }
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+TftpDownload (
+ PXE_BASECODE_DEVICE *Private,
+ UINT64 *BufferSizePtr,
+ UINT8 *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ UINT8 *FilenamePtr,
+ UINTN *PacketSizePtr,
+ EFI_PXE_BASE_CODE_UDP_PORT SrvPort,
+ UINT16 Req,
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+// tftp read session
+// send read request
+// [get OACK
+// send ACK]
+// loop
+// get data
+// send ACK
+// while data size is max
+
+Parameters:
+ Private :=
+ BufferSizePtr :=
+ BufferPtr :=
+ ServerIpPtr :=
+ FilenamePtr :=
+ PacketSizePtr :=
+ SrvPort :=
+ Req :=
+ DontUseBuffer :=
+
+Returns:
+--*/
+{
+ EFI_PXE_BASE_CODE_UDP_PORT OurPort;
+ EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
+ EFI_STATUS Status;
+ UINT64 Offset;
+ UINT64 BlockNum;
+ UINTN ReplyLen;
+ UINT8 *Ptr;
+
+ union {
+ struct Tftpv4Ack Ack2Ptr;
+ struct Tftpv4Oack OAck2Ptr;
+ struct Tftpv4Data Data;
+ struct Tftpv4Ack8 Ack8Ptr;
+ struct Tftpv4Data8 Data8;
+ } U;
+
+ OurPort = 0;
+ ServerReplyPort = 0;
+ ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);
+
+ //
+ // send a read request with the blocksize option - sets our IP and port
+ // - and receive reply - sets his port will retry operation up to 3
+ // times if no response, and will retry without options on an error
+ // reply
+ //
+ if ((Status = TftpRwReqwResp (
+ Req,
+ /* BIGBLKNUMOP | */BKSZOP,
+ Private,
+ &U,
+ PacketSizePtr,
+ &ReplyLen,
+ BufferPtr,
+ ServerIpPtr,
+ &SrvPort,
+ &ServerReplyPort,
+ &OurPort,
+ FilenamePtr,
+ REQ_RESP_TIMEOUT
+ )) != EFI_SUCCESS) {
+ DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status));
+ return Status;
+ }
+ //
+ // check for OACK
+ //
+ if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
+ //
+ // get the OACK
+ //
+ CopyMem (U.Data.Data, BufferPtr, ReplyLen);
+
+ Ptr = FindOption (
+ BigBlkNumOp,
+ sizeof (BigBlkNumOp),
+ U.OAck2Ptr.OpAck[0].Option,
+ ReplyLen + sizeof (U.Ack2Ptr.BlockNum)
+ );
+
+ if (Ptr != NULL) {
+ if (AtoU (Ptr) == 8) {
+ Private->BigBlkNumFlag = TRUE;
+ } else {
+ return EFI_PROTOCOL_ERROR;
+ }
+ }
+ //
+ // now parse it for blocksize option
+ //
+ Ptr = FindOption (
+ BlockSizeOp,
+ sizeof (BlockSizeOp),
+ U.OAck2Ptr.OpAck[0].Option,
+ ReplyLen += sizeof (U.Ack2Ptr.BlockNum)
+ );
+
+ ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512;
+
+ Offset = 0;
+ //
+ // last block received
+ //
+ BlockNum = 0;
+ } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {
+ //
+ // or data
+ //
+ DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status));
+
+ return EFI_PROTOCOL_ERROR;
+ } else {
+ //
+ // got good data packet
+ //
+ Offset = ReplyLen;
+ //
+ // last block received
+ //
+ BlockNum = 1;
+ }
+
+ if (PacketSizePtr != NULL) {
+ *PacketSizePtr = ReplyLen;
+ }
+ //
+ // routine to read rest of file after a successful open (TFTP or MTFTP)
+ // sends ACK and gets next data packet until short packet arrives, then sends
+ // ACK and (hopefully) times out
+ // if first packet has been read, BufferPtr and BufferSize must reflect fact
+ //
+ Status = LockStepReceive (
+ Private,
+ ReplyLen,
+ BufferSizePtr,
+ Offset,
+ BufferPtr,
+ ServerIpPtr,
+ &ServerReplyPort,
+ &Private->EfiBc.Mode->StationIp,
+ &OurPort,
+ BlockNum,
+ ACK_TIMEOUT,
+ DontUseBuffer
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status));
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = TftpInfo (
+ Private,
+ BufferSizePtr,
+ ServerIpPtr,
+ SrvPort,
+ FilenamePtr,
+ PacketSizePtr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+STATIC
+EFI_STATUS
+TftpUpload (
+ PXE_BASECODE_DEVICE *Private,
+ UINT64 *BufferSizePtr,
+ VOID *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ UINT8 *FilenamePtr,
+ UINTN *PacketSizePtr,
+ BOOLEAN Overwrite
+ )
+/*++
+Routine description:
+// tftp write session
+// send write request
+// get OACK or ACK
+// loop
+// send min (rest of data, max data packet)
+// get ACK
+// while data size is max
+
+Parameters:
+ Private :=
+ BufferSizePtr :=
+ BufferPtr :=
+ ServerIpPtr :=
+ FilenamePtr :=
+ PacketSizePtr :=
+ Overwrite :=
+
+Returns:
+--*/
+{
+ struct Tftpv4Ack Header;
+ EFI_PXE_BASE_CODE_UDP_PORT OurPort;
+ EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;
+ EFI_STATUS Status;
+ UINT64 BlockNum;
+ UINT64 TransferSize;
+ UINTN ReplyLen;
+ UINTN TransferLen;
+ UINT16 Options;
+ UINT8 *Ptr;
+
+ union {
+ struct Tftpv4Oack OAck2Ptr;
+ struct Tftpv4Ack Ack2Ptr;
+ struct Tftpv4Data Datastr;
+ } u;
+
+ OurPort = 0;
+ ServerReplyPort = 0;
+ TransferSize = *BufferSizePtr;
+ ReplyLen = sizeof (u.Datastr.Data);
+ Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);
+
+ //
+ // send a write request with the blocksize option - sets our IP and port -
+ // and receive reply - sets his port
+ // will retry operation up to 3 times if no response, and will retry without
+ // options on an error reply
+ //
+ if ((Status = TftpRwReqwResp (
+ TFTP_WRQ,
+ Options,
+ Private,
+ &u,
+ PacketSizePtr,
+ &ReplyLen,
+ u.Datastr.Data,
+ ServerIpPtr,
+ &TftpRequestPort,
+ &ServerReplyPort,
+ &OurPort,
+ FilenamePtr,
+ REQ_RESP_TIMEOUT
+ )) != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // check for OACK
+ //
+ if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {
+ //
+ // parse it for blocksize option
+ //
+ Ptr = FindOption (
+ BlockSizeOp,
+ sizeof (BlockSizeOp),
+ u.OAck2Ptr.OpAck[0].Option,
+ ReplyLen += sizeof (u.Ack2Ptr.BlockNum)
+ );
+ *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;
+ }
+ //
+ // or ACK
+ //
+ else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {
+ //
+ // option was not supported
+ //
+ *PacketSizePtr = 512;
+ } else {
+ return EFI_PROTOCOL_ERROR;
+ }
+ //
+ // loop
+ //
+ Header.OpCode = HTONS (TFTP_DATA);
+ BlockNum = 1;
+ Header.BlockNum = HTONS (1);
+
+ do {
+ UINTN HeaderSize;
+ INTN Retries;
+
+ Retries = NUM_ACK_RETRIES;
+ HeaderSize = sizeof (Header);
+ TransferLen = (UINTN) (EFI_MIN (*PacketSizePtr, TransferSize));
+
+ //
+ // write a data packet and get an ack
+ //
+ do {
+ //
+ // write
+ //
+ if ((Status = UdpWrite (
+ Private,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
+ ServerIpPtr,
+ &ServerReplyPort,
+ 0,
+ 0,
+ &OurPort,
+ &HeaderSize,
+ &Header,
+ &TransferLen,
+ BufferPtr
+ )) != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // read reply
+ //
+ ReplyLen = sizeof (u.Datastr.Data);
+
+ if ((Status = TftpUdpRead (
+ Private,
+ 0,
+ &u,
+ &ReplyLen,
+ u.Datastr.Data,
+ ServerIpPtr,
+ &ServerReplyPort,
+ 0,
+ &OurPort,
+ ACK_TIMEOUT
+ )) == EFI_SUCCESS) {
+ //
+ // check for ACK for this data packet
+ //
+ if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ if (u.Ack2Ptr.BlockNum != Header.BlockNum) {
+ //
+ // not for this packet - continue
+ //
+ Status = EFI_TIMEOUT;
+ }
+ }
+ } while (Status == EFI_TIMEOUT && --Retries);
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);
+ TransferSize -= TransferLen;
+ ++BlockNum;
+ Header.BlockNum = HTONS ((UINT16) BlockNum);
+ } while (TransferLen == *PacketSizePtr);
+
+ return EFI_SUCCESS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+PxeBcMtftp (
+ PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
+ UINT64 *BufferSizePtr,
+ VOID *BufferPtr,
+ EFI_IP_ADDRESS *ServerIpPtr,
+ UINT8 *FilenamePtr,
+ UINTN *PacketSizePtr,
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL
+ IN BOOLEAN Overwrite,
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+ MTFTP API entry point
+
+Parameters:
+ Private :=
+ Operation :=
+ BufferSizePtr :=
+ BufferPtr :=
+ ServerIpPtr :=
+ FilenamePtr :=
+ PacketSizePtr :=
+ MtftpInfoPtr :=
+ Overwrite :=
+ DontUseBuffer :=
+
+Returns:
+ * EFI_INVALID_PARAMETER
+ * EFI_OUT_OF_RESOURCES
+ * EFI_BAD_BUFFER_SIZE
+ * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),
+ * TftpDownload() and TftpUpload().
+--*/
+{
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;
+ EFI_STATUS StatCode;
+ EFI_STATUS Status;
+ UINT64 BufferSizeLocal;
+ UINTN PacketSize;
+ UINT8 *BufferPtrLocal;
+
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
+ Filter.IpCnt = 0;
+ Filter.reserved = 0;
+
+ /* No error has occurred, yet. */
+ Private->EfiBc.Mode->TftpErrorReceived = FALSE;
+
+ /* We must at least have an MTFTP server IP address and
+ * a pointer to the buffer size.
+ */
+ if (!ServerIpPtr || !BufferSizePtr) {
+ DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #1"));
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;
+
+ //
+ // make sure filter set to unicast at start
+ //
+ if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_NET,
+ "\nPxeBcMtftp() Exit IpFilter() == %Xh",
+ StatCode)
+ );
+
+ return StatCode;
+ }
+ //
+ // set unset parms to default values
+ //
+ if (!PacketSizePtr) {
+ *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;
+ }
+
+ if (*PacketSizePtr > *BufferSizePtr) {
+ *PacketSizePtr = (UINTN) *BufferSizePtr;
+ }
+
+ if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {
+ *PacketSizePtr = MIN_TFTP_PKT_SIZE;
+ }
+
+ if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {
+ *PacketSizePtr = BUFFER_ALLOCATE_SIZE;
+ }
+
+ if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {
+ *PacketSizePtr = MAX_TFTP_PKT_SIZE;
+ }
+
+ if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
+ StatCode = TftpInfo (
+ Private,
+ BufferSizePtr,
+ ServerIpPtr,
+ TftpRequestPort,
+ FilenamePtr,
+ PacketSizePtr
+ );
+
+ if (StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
+ StatCode)
+ );
+ }
+
+ return StatCode;
+ }
+
+ if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {
+ if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {
+ DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #2"));
+ return EFI_INVALID_PARAMETER;
+ } else {
+ StatCode = TftpInfo (
+ Private,
+ BufferSizePtr,
+ ServerIpPtr,
+ MtftpInfoPtr->SPort,
+ FilenamePtr,
+ PacketSizePtr
+ );
+
+ gBS->Stall (10000);
+
+ if (StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxeBcMtftp() Exit TftpInfo() == %Xh",
+ StatCode)
+ );
+ }
+
+ return StatCode;
+ }
+ }
+
+ if (!BufferPtr && !DontUseBuffer) {
+ //
+ // if dontusebuffer is false and no buffer???
+ //
+ DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #3"));
+ //
+ // DontUseBuffer can be true only for read_file operation
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DontUseBuffer) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ BUFFER_ALLOCATE_SIZE,
+ (VOID **) &BufferPtrLocal
+ );
+
+ if (EFI_ERROR (Status) || BufferPtrLocal == NULL) {
+ DEBUG ((EFI_D_NET, "\nPxeBcMtftp() Exit #4"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BufferSizeLocal = BUFFER_ALLOCATE_SIZE;
+ } else {
+ if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {
+ DEBUG ((EFI_D_WARN, "\nPxeBcMtftp() Exit #5"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ BufferPtrLocal = BufferPtr;
+ BufferSizeLocal = *BufferSizePtr;
+ }
+
+ switch (Operation) {
+ case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
+ if (FilenamePtr == NULL ||
+ MtftpInfoPtr == NULL ||
+ MtftpInfoPtr->MCastIp.Addr[0] == 0 ||
+ MtftpInfoPtr->SPort == 0 ||
+ MtftpInfoPtr->CPort == 0 ||
+ MtftpInfoPtr->ListenTimeout == 0 ||
+ MtftpInfoPtr->TransmitTimeout == 0
+ ) {
+ StatCode = EFI_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // try MTFTP - if fails, drop into TFTP read
+ //
+ if ((StatCode = MtftpDownload (
+ Private,
+ &BufferSizeLocal,
+ BufferPtrLocal,
+ ServerIpPtr,
+ FilenamePtr,
+ MtftpInfoPtr,
+ DontUseBuffer
+ )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
+ if (BufferSizePtr /* %% !DontUseBuffer */ ) {
+ *BufferSizePtr = BufferSizeLocal;
+ }
+
+ break;
+ }
+ //
+ // go back to unicast
+ //
+ if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {
+ break;
+ }
+
+ /* fall thru */
+ case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
+ if (FilenamePtr == NULL) {
+ StatCode = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ StatCode = TftpDownload (
+ Private,
+ &BufferSizeLocal,
+ BufferPtrLocal,
+ ServerIpPtr,
+ FilenamePtr,
+ PacketSizePtr,
+ TftpRequestPort,
+ TFTP_RRQ,
+ DontUseBuffer
+ );
+
+ if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
+ if (BufferSizePtr /* !DontUseBuffer */ ) {
+ *BufferSizePtr = BufferSizeLocal;
+ }
+ }
+
+ break;
+
+ case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
+ if (FilenamePtr == NULL || DontUseBuffer) {
+ //
+ // not a valid option
+ //
+ StatCode = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ StatCode = TftpUpload (
+ Private,
+ BufferSizePtr,
+ BufferPtr,
+ ServerIpPtr,
+ FilenamePtr,
+ PacketSizePtr,
+ Overwrite
+ );
+
+ if (StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxeBcMtftp() Exit #6 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ }
+
+ return StatCode;
+
+ case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
+ if (FilenamePtr == NULL || DontUseBuffer) {
+ //
+ // not a valid option
+ //
+ StatCode = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ StatCode = TftpDownload (
+ Private,
+ BufferSizePtr,
+ BufferPtr,
+ ServerIpPtr,
+ FilenamePtr,
+ PacketSizePtr,
+ TftpRequestPort,
+ TFTP_DIR,
+ DontUseBuffer
+ );
+
+ if (StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxeBcMtftp() Exit #7 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ }
+
+ return StatCode;
+
+ case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
+ if (DontUseBuffer) {
+ StatCode = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxeBcMtftp() Exit #9 %xh (%r)",
+ EFI_INVALID_PARAMETER,
+ EFI_INVALID_PARAMETER)
+ );
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StatCode = TftpDownload (
+ Private,
+ BufferSizePtr,
+ BufferPtr,
+ ServerIpPtr,
+ (UINT8 *) "/",
+ PacketSizePtr,
+ MtftpInfoPtr->SPort,
+ TFTP_DIR,
+ DontUseBuffer
+ );
+
+ break;
+
+ default:
+ StatCode = EFI_INVALID_PARAMETER;
+ }
+
+ if (DontUseBuffer) {
+ gBS->FreePool (BufferPtrLocal);
+ }
+
+ if (StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nPxeBcMtftp() Exit #8 %xh (%r)",
+ StatCode,
+ StatCode)
+ );
+ }
+
+ gBS->Stall (10000);
+
+ return StatCode;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+BcMtftp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
+ IN OUT VOID *BufferPtr,
+ IN BOOLEAN Overwrite,
+ IN OUT UINT64 *BufferSizePtr,
+ IN UINTN *BlockSizePtr OPTIONAL,
+ IN EFI_IP_ADDRESS * ServerIpPtr,
+ IN UINT8 *FilenamePtr,
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,
+ IN BOOLEAN DontUseBuffer
+ )
+/*++
+Routine description:
+ MTFTP API entry point.
+
+Parameters:
+ This :=
+ Operation :=
+ BufferPtr :=
+ Overwrite :=
+ BufferSizePtr :=
+ BlockSizePtr :=
+ ServerIpPtr :=
+ FilenamePtr :=
+ MtftpInfoPtr :=
+ DontUseBuffer :=
+
+Returns:
+ * EFI_INVALID_PARAMETER
+ * Status is also returned from PxeBcMtftp();
+--*/
+{
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+ //
+ // Issue BC command
+ //
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
+ Filter.IpCnt = 0;
+ Filter.reserved = 0;
+
+ DEBUG ((EFI_D_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));
+
+ StatCode = PxeBcMtftp (
+ Private,
+ Operation,
+ BufferSizePtr,
+ BufferPtr,
+ ServerIpPtr,
+ FilenamePtr,
+ BlockSizePtr,
+ MtftpInfoPtr,
+ Overwrite,
+ DontUseBuffer
+ );
+
+ //
+ // restore to unicast
+ //
+ IpFilter (Private, &Filter);
+
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+/* eof - PxeBcMtftp.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c
new file mode 100644
index 0000000..ab9d3b7
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c
@@ -0,0 +1,577 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ pxe_bc_udp.c
+
+Abstract:
+
+--*/
+
+
+#include "bc.h"
+
+//
+// //////////////////////////////////////////////////////////////////////
+//
+// Udp Write Routine - called by base code - e.g. TFTP - already locked
+//
+EFI_STATUS
+UdpWrite (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 OpFlags,
+ IN EFI_IP_ADDRESS *DestIpPtr,
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,
+ IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSizeptr,
+ IN VOID *BufferPtr
+ )
+/*++
+Routine description:
+ UDP write packet.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ OpFlags :=
+ DestIpPtr :=
+ DestPortPtr :=
+ GatewayIpPtr :=
+ SrcIpPtr :=
+ SrcPortPtr :=
+ HeaderSizePtr :=
+ HeaderPtr :=
+ BufferSizeptr :=
+ BufferPtr :=
+
+Returns:
+ EFI_SUCCESS :=
+ EFI_INVALID_PARAMETER :=
+ other :=
+--*/
+{
+ UINTN TotalLength;
+ UINTN HeaderSize;
+ EFI_PXE_BASE_CODE_UDP_PORT DefaultSrcPort;
+
+ //
+ //
+ //
+ HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;
+ DefaultSrcPort = 0;
+
+ //
+ // check parameters
+ //
+ if (BufferSizeptr == NULL ||
+ BufferPtr == NULL ||
+ DestIpPtr == NULL ||
+ DestPortPtr == NULL ||
+ (HeaderSizePtr != NULL && *HeaderSizePtr == 0) ||
+ (HeaderSize != 0 && HeaderPtr == NULL) ||
+ (GatewayIpPtr != NULL && !IS_INADDR_UNICAST(GatewayIpPtr)) ||
+ (OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT))
+ ) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nUdpWrite() Exit #1 %xh (%r)",
+ EFI_INVALID_PARAMETER,
+ EFI_INVALID_PARAMETER)
+ );
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TotalLength = *BufferSizeptr + HeaderSize + sizeof (UDPV4_HEADER);
+
+ if (TotalLength > 0x0000ffff) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nUdpWrite() Exit #2 %xh (%r)",
+ EFI_BAD_BUFFER_SIZE,
+ EFI_BAD_BUFFER_SIZE)
+ );
+
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (SrcIpPtr == NULL) {
+ SrcIpPtr = &Private->EfiBc.Mode->StationIp;
+ }
+
+ if (SrcPortPtr == NULL) {
+ SrcPortPtr = &DefaultSrcPort;
+ OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;
+ }
+
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {
+ *SrcPortPtr = Private->RandomPort;
+
+ if (++Private->RandomPort == 0) {
+ Private->RandomPort = PXE_RND_PORT_LOW;
+ }
+ }
+
+#define IpTxBuffer ((IPV4_BUFFER *) Private->TransmitBufferPtr)
+ //
+ // build pseudo header and udp header in transmit buffer
+ //
+#define Udpv4Base ((UDPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (UDPV4_PSEUDO_HEADER)))
+
+ Udpv4Base->Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];
+ Udpv4Base->Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];
+ Udpv4Base->Udpv4PseudoHeader.Zero = 0;
+ Udpv4Base->Udpv4PseudoHeader.Protocol = PROT_UDP;
+ Udpv4Base->Udpv4PseudoHeader.TotalLength = HTONS (TotalLength);
+ Udpv4Base->Udpv4Header.SrcPort = HTONS (*SrcPortPtr);
+ Udpv4Base->Udpv4Header.DestPort = HTONS (*DestPortPtr);
+ Udpv4Base->Udpv4Header.TotalLength = Udpv4Base->Udpv4PseudoHeader.TotalLength;
+ Udpv4Base->Udpv4Header.Checksum = 0;
+
+ if (HeaderSize != 0) {
+ CopyMem (IpTxBuffer->u.Udp.Data, HeaderPtr, HeaderSize);
+ }
+
+ HeaderSize += sizeof (UDPV4_HEADER);
+
+ Udpv4Base->Udpv4Header.Checksum = IpChecksum2 (
+ (UINT16 *) Udpv4Base,
+ HeaderSize + sizeof (UDPV4_PSEUDO_HEADER),
+ (UINT16 *) BufferPtr,
+ (UINT16) *BufferSizeptr
+ );
+
+ if (Udpv4Base->Udpv4Header.Checksum == 0) {
+ Udpv4Base->Udpv4Header.Checksum = 0xffff;
+ //
+ // transmit zero checksum as ones complement
+ //
+ }
+
+ return Ip4Send (
+ Private,
+ OpFlags,
+ PROT_UDP,
+ Udpv4Base->Udpv4PseudoHeader.SrcAddr.L,
+ Udpv4Base->Udpv4PseudoHeader.DestAddr.L,
+ (GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0,
+ HeaderSize,
+ BufferPtr,
+ *BufferSizeptr
+ );
+}
+//
+// //////////////////////////////////////////////////////////
+//
+// BC Udp Write Routine
+//
+EFI_STATUS
+EFIAPI
+BcUdpWrite (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN EFI_IP_ADDRESS *DestIpPtr,
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,
+ IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSizeptr,
+ IN VOID *BufferPtr
+ )
+/*++
+Routine description:
+ UDP write API entry point.
+
+Parameters:
+ This := Pointer to PxeBc interface.
+ OpFlags :=
+ DestIpPtr :=
+ DestPortPtr :=
+ GatewayIpPtr :=
+ SrcIpPtr :=
+ SrcPortPtr :=
+ HeaderSizePtr :=
+ HeaderPtr :=
+ BufferSizeptr :=
+ BufferPtr :=
+
+Returns:
+ EFI_SUCCESS :=
+ other :=
+--*/
+{
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE;
+
+ //
+ // Issue BC command
+ //
+ StatCode = UdpWrite (
+ Private,
+ OpFlags,
+ DestIpPtr,
+ DestPortPtr,
+ GatewayIpPtr,
+ SrcIpPtr,
+ SrcPortPtr,
+ HeaderSizePtr,
+ HeaderPtr,
+ BufferSizeptr,
+ BufferPtr
+ );
+
+ //
+ // Unlock the instance data
+ //
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+//
+// /////////////////////////////////////////////////////////////////////
+//
+// Udp Read Routine - called by base code - e.g. TFTP - already locked
+//
+EFI_STATUS
+UdpRead (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSizeptr,
+ IN VOID *BufferPtr,
+ EFI_EVENT TimeoutEvent
+ )
+/*++
+Routine description:
+ UDP read packet.
+
+Parameters:
+ Private := Pointer to PxeBc interface
+ OpFlags :=
+ DestIpPtr :=
+ DestPortPtr :=
+ SrcIpPtr :=
+ SrcPortPtr :=
+ HeaderSizePtr :=
+ HeaderPtr :=
+ BufferSizeptr :=
+ BufferPtr :=
+ TimeoutEvent :=
+
+Returns:
+ EFI_SUCCESS :=
+ EFI_INVALID_PARAMETER :=
+ other :=
+--*/
+{
+ EFI_STATUS StatCode;
+ EFI_IP_ADDRESS TmpSrcIp;
+ EFI_IP_ADDRESS TmpDestIp;
+ UINTN BufferSize;
+ UINTN HeaderSize;
+
+ //
+ // combination structure of pseudo header/udp header
+ //
+#pragma pack (1)
+ struct {
+ UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;
+ UDPV4_HEADER Udpv4Header;
+ UINT8 ProtHdr[64];
+ } Hdrs;
+#pragma pack ()
+
+ HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;
+ //
+ // read [with filtering]
+ // check parameters
+ //
+ if (BufferSizeptr == NULL ||
+ BufferPtr == NULL ||
+ (HeaderSize != 0 && HeaderPtr == NULL) ||
+ (OpFlags &~UDP_FILTER_MASK)
+ //
+ // if filtering on a particular IP/Port, need it
+ //
+ ||
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr == NULL) ||
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && SrcPortPtr == NULL) ||
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && DestPortPtr == NULL)
+ ) {
+ DEBUG ((EFI_D_INFO, "\nUdpRead() Exit #1 Invalid Parameter"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // in case we loop
+ //
+ BufferSize = *BufferSizeptr;
+ //
+ // we need source and dest IPs for pseudo header
+ //
+ if (SrcIpPtr == NULL) {
+ SrcIpPtr = &TmpSrcIp;
+ }
+
+ if (DestIpPtr == NULL) {
+ DestIpPtr = &TmpDestIp;
+ CopyMem (&TmpDestIp, &Private->EfiBc.Mode->StationIp, sizeof (TmpDestIp));
+ }
+
+#if SUPPORT_IPV6
+ if (Private->EfiBc.Mode->UsingIpv6) {
+ //
+ // %%TBD
+ //
+ }
+#endif
+
+ for (;;) {
+ *BufferSizeptr = BufferSize;
+
+ StatCode = IpReceive (
+ Private,
+ OpFlags,
+ SrcIpPtr,
+ DestIpPtr,
+ PROT_UDP,
+ &Hdrs.Udpv4Header,
+ HeaderSize + sizeof Hdrs.Udpv4Header,
+ BufferPtr,
+ BufferSizeptr,
+ TimeoutEvent
+ );
+
+ if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
+ UINT16 SPort;
+ UINT16 DPort;
+
+ SPort = NTOHS (Hdrs.Udpv4Header.SrcPort);
+ DPort = NTOHS (Hdrs.Udpv4Header.DestPort);
+
+ //
+ // do filtering
+ //
+ if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) {
+ continue;
+ }
+
+ if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) {
+ continue;
+ }
+ //
+ // check checksum
+ //
+ if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) {
+ Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];
+ Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];
+ Hdrs.Udpv4PseudoHeader.Zero = 0;
+ Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP;
+ Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength;
+
+ if (Hdrs.Udpv4Header.Checksum == 0xffff) {
+ Hdrs.Udpv4Header.Checksum = 0;
+ }
+
+ if (IpChecksum2 (
+ (UINT16 *) &Hdrs.Udpv4PseudoHeader,
+ HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header),
+ (UINT16 *) BufferPtr,
+ *BufferSizeptr
+ )) {
+ DEBUG (
+ (EFI_D_INFO,
+ "\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh",
+ &Hdrs.Udpv4PseudoHeader)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nUdpRead() Header size == %d",
+ HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader))
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nUdpRead() BufferPtr == %Xh",
+ BufferPtr)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "\nUdpRead() Buffer size == %d",
+ *BufferSizeptr)
+ );
+ DEBUG ((EFI_D_INFO, "\nUdpRead() Exit #2 Device Error"));
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // all passed
+ //
+ if (SrcPortPtr != NULL) {
+ *SrcPortPtr = SPort;
+ }
+
+ if (DestPortPtr != NULL) {
+ *DestPortPtr = DPort;
+ }
+
+ if (HeaderSize != 0) {
+ CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize);
+ }
+ }
+
+ switch (StatCode) {
+ case EFI_SUCCESS:
+ case EFI_TIMEOUT:
+ break;
+
+ default:
+ DEBUG (
+ (EFI_D_INFO,
+ "\nUdpRead() Exit #3 %Xh %r",
+ StatCode,
+ StatCode)
+ );
+ }
+
+ return StatCode;
+ }
+}
+//
+// //////////////////////////////////////////////////////////
+//
+// BC Udp Read Routine
+//
+EFI_STATUS
+EFIAPI
+BcUdpRead (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+/*++
+Routine description:
+ UDP read API entry point.
+
+Parameters:
+ This := Pointer to PxeBc interface.
+ OpFlags :=
+ DestIpPtr :=
+ DestPortPtr :=
+ SrcIpPtr :=
+ SrcPortPtr :=
+ HeaderSizePtr :=
+ HeaderPtr :=
+ BufferSizeptr :=
+ BufferPtr :=
+
+Returns:
+ EFI_SUCCESS :=
+ other :=
+--*/
+{
+ EFI_STATUS StatCode;
+ PXE_BASECODE_DEVICE *Private;
+
+ //
+ // Lock the instance data and make sure started
+ //
+ StatCode = EFI_SUCCESS;
+
+ if (This == NULL) {
+ DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiAcquireLock (&Private->Lock);
+
+ if (This->Mode == NULL || !This->Mode->Started) {
+ DEBUG ((EFI_D_ERROR, "BC was not started."));
+ EfiReleaseLock (&Private->Lock);
+ return EFI_NOT_STARTED;
+ }
+
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ;
+
+ //
+ // Issue BC command
+ //
+ StatCode = UdpRead (
+ Private,
+ OpFlags,
+ DestIp,
+ DestPort,
+ SrcIp,
+ SrcPort,
+ HeaderSize,
+ HeaderPtr,
+ BufferSize,
+ BufferPtr,
+ 0
+ );
+
+ //
+ // Unlock the instance data and return
+ //
+ EfiReleaseLock (&Private->Lock);
+ return StatCode;
+}
+
+/* eof - pxe_bc_udp.c */
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c
new file mode 100644
index 0000000..8897bc7
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c
@@ -0,0 +1,1697 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ pxe_loadfile.c
+
+Abstract:
+ An implementation of the load file protocol for network devices.
+
+--*/
+
+
+#include "bc.h"
+
+#define DO_MENU (EFI_SUCCESS)
+#define NO_MENU (DO_MENU + 1)
+#define LOCAL_BOOT (EFI_ABORTED)
+#define AUTO_SELECT (NO_MENU)
+
+#define NUMBER_ROWS 25 // we set to mode 0
+#define MAX_MENULIST 23
+
+#define Ctl(x) (0x1F & (x))
+
+typedef union {
+ DHCPV4_OP_STRUCT *OpPtr;
+ PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr;
+ PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr;
+ PXE_OP_BOOT_MENU *MenuPtr;
+ UINT8 *BytePtr;
+} UNION_PTR;
+
+
+STATIC
+EFI_PXE_BASE_CODE_CALLBACK_STATUS
+EFIAPI
+bc_callback (
+ IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function,
+ IN BOOLEAN Received,
+ IN UINT32 PacketLength,
+ IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ PxeBc callback routine for status updates and aborts.
+
+Arguments:
+
+ This - Pointer to PxeBcCallback interface
+ Function - PxeBc function ID#
+ Received - Receive/transmit flag
+ PacketLength - Length of received packet (0 == idle callback)
+ PacketPtr - Pointer to received packet (NULL == idle callback)
+
+Returns:
+
+ EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE -
+ EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT -
+
+--*/
+{
+ STATIC UINTN Propeller;
+
+ EFI_INPUT_KEY Key;
+ UINTN Row;
+ UINTN Col;
+
+ Propeller = 0;
+ //
+ // Resolve Warning 4 unreferenced parameter problem
+ //
+ This = This;
+
+ //
+ // Check for user abort.
+ //
+ if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {
+ if (!Key.ScanCode) {
+ if (Key.UnicodeChar == Ctl ('c')) {
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
+ }
+ } else if (Key.ScanCode == SCAN_ESC) {
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
+ }
+ }
+ //
+ // Do nothing if this is a receive.
+ //
+ if (Received) {
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+ }
+ //
+ // The display code is only for these functions.
+ //
+ switch (Function) {
+ case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
+ //
+ // If this is a transmit and not a M/TFTP open request,
+ // return now. Do not print a dot for each M/TFTP packet
+ // that is sent, only for the open packets.
+ //
+ if (PacketLength != 0 && PacketPtr != NULL) {
+ if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+ }
+ }
+
+ break;
+
+ case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
+ case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
+ break;
+
+ default:
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+ }
+ //
+ // Display routines
+ //
+ if (PacketLength != 0 && PacketPtr != NULL) {
+ //
+ // Display a '.' when a packet is transmitted.
+ //
+ AsciiPrint (".");
+ } else if (PacketLength == 0 && PacketPtr == NULL) {
+ //
+ // Display a propeller when waiting for packets if at
+ // least 200 ms have passed.
+ //
+ Row = gST->ConOut->Mode->CursorRow;
+ Col = gST->ConOut->Mode->CursorColumn;
+
+ AsciiPrint ("%c", "/-\\|"[Propeller]);
+ gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);
+
+ Propeller = (Propeller + 1) & 3;
+ }
+
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+}
+
+STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = {
+ EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION,
+ &bc_callback
+};
+
+STATIC
+VOID
+PrintIpv4 (
+ UINT8 *Ptr
+ )
+/*++
+
+Routine Description:
+
+ Display an IPv4 address in dot notation.
+
+Arguments:
+
+ Ptr - Pointer to IPv4 address.
+
+Returns:
+
+ None
+
+--*/
+{
+ if (Ptr != NULL) {
+ AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);
+ }
+}
+
+STATIC
+VOID
+ShowMyInfo (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+/*++
+
+Routine Description:
+
+ Display client and server IP information.
+
+Arguments:
+
+ Private - Pointer to PxeBc interface
+
+Returns:
+
+ None
+
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ UINTN Index;
+
+ //
+ // Do nothing if a NULL pointer is passed in.
+ //
+ if (Private == NULL) {
+ return ;
+ }
+ //
+ // Get pointer to PXE BaseCode mode structure
+ //
+ PxeBcMode = Private->EfiBc.Mode;
+
+ //
+ // Display client IP address
+ //
+ AsciiPrint ("\rCLIENT IP: ");
+ PrintIpv4 (PxeBcMode->StationIp.v4.Addr);
+
+ //
+ // Display subnet mask
+ //
+ AsciiPrint (" MASK: ");
+ PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);
+
+ //
+ // Display DHCP and proxyDHCP IP addresses
+ //
+ if (PxeBcMode->ProxyOfferReceived) {
+ AsciiPrint ("\nDHCP IP: ");
+ PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
+
+ AsciiPrint (" PROXY IP: ");
+ PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
+ } else {
+ AsciiPrint (" DHCP IP: ");
+ PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
+ }
+ //
+ // Display gateway IP addresses
+ //
+ for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
+ if ((Index % 3) == 0) {
+ AsciiPrint ("\r\nGATEWAY IP:");
+ }
+
+ AsciiPrint (" ");
+ PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);
+ AsciiPrint (" ");
+ }
+
+ AsciiPrint ("\n");
+}
+
+STATIC
+EFI_STATUS
+DoPrompt (
+ PXE_BASECODE_DEVICE *Private,
+ PXE_OP_BOOT_PROMPT *BootPromptPtr
+ )
+/*++
+
+Routine Description:
+
+ Display prompt and wait for input.
+
+Arguments:
+
+ Private - Pointer to PxeBc interface
+ BootPromptPtr - Pointer to PXE boot prompt option
+
+Returns:
+
+ AUTO_SELECT -
+ DO_MENU -
+ NO_MENU -
+ LOCAL_BOOT -
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_EVENT TimeoutEvent;
+ EFI_EVENT SecondsEvent;
+ INT32 SecColumn;
+ INT32 SecRow;
+ UINT8 SaveChar;
+ UINT8 SecsLeft;
+
+ //
+ // if auto select, just get right to it
+ //
+ if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {
+ return AUTO_SELECT;
+ }
+ //
+ // if no timeout, go directly to display of menu
+ //
+ if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {
+ return DO_MENU;
+ }
+ //
+ //
+ //
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ return DO_MENU;
+ }
+
+ Status = gBS->SetTimer (
+ TimeoutEvent,
+ TimerRelative,
+ BootPromptPtr->Timeout * 10000000 + 100000
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return DO_MENU;
+ }
+ //
+ //
+ //
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER,
+ EFI_TPL_CALLBACK,
+ NULL,
+ NULL,
+ &SecondsEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (TimeoutEvent);
+ return DO_MENU;
+ }
+
+ Status = gBS->SetTimer (
+ SecondsEvent,
+ TimerPeriodic,
+ 10000000
+ ); /* 1 second */
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (SecondsEvent);
+ gBS->CloseEvent (TimeoutEvent);
+ return DO_MENU;
+ }
+ //
+ // display the prompt
+ // IMPORTANT! This prompt is an ASCII character string that may
+ // not be terminated with a NULL byte.
+ //
+ SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];
+ BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;
+
+ AsciiPrint ("%a ", BootPromptPtr->Prompt);
+ BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;
+
+ //
+ // wait until time expires or selection made - menu or local
+ //
+ SecColumn = gST->ConOut->Mode->CursorColumn;
+ SecRow = gST->ConOut->Mode->CursorRow;
+ SecsLeft = BootPromptPtr->Timeout;
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
+ AsciiPrint ("(%d) ", SecsLeft);
+
+ //
+ // set the default action to be AUTO_SELECT
+ //
+ Status = AUTO_SELECT;
+
+ while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
+ EFI_INPUT_KEY Key;
+
+ if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {
+ --SecsLeft;
+ gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
+ AsciiPrint ("(%d) ", SecsLeft);
+ }
+
+ if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
+ UINT8 Buffer[512];
+ UINTN BufferSize;
+ EFI_STATUS Status;
+
+ BufferSize = sizeof Buffer;
+
+ Status = Private->EfiBc.UdpRead (
+ &Private->EfiBc,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
+ NULL, /* dest ip */
+ NULL, /* dest port */
+ NULL, /* src ip */
+ NULL, /* src port */
+ NULL, /* hdr size */
+ NULL, /* hdr ptr */
+ &BufferSize,
+ Buffer
+ );
+
+ continue;
+ }
+
+ if (Key.ScanCode == 0) {
+ switch (Key.UnicodeChar) {
+ case Ctl ('c'):
+ Status = LOCAL_BOOT;
+ break;
+
+ case Ctl ('m'):
+ case 'm':
+ case 'M':
+ Status = DO_MENU;
+ break;
+
+ default:
+ continue;
+ }
+ } else {
+ switch (Key.ScanCode) {
+ case SCAN_F8:
+ Status = DO_MENU;
+ break;
+
+ case SCAN_ESC:
+ Status = LOCAL_BOOT;
+ break;
+
+ default:
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ gBS->CloseEvent (SecondsEvent);
+ gBS->CloseEvent (TimeoutEvent);
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
+ AsciiPrint (" ");
+
+ return Status;
+}
+
+STATIC
+VOID
+PrintMenuItem (
+ PXE_BOOT_MENU_ENTRY *MenuItemPtr
+ )
+/*++
+
+Routine Description:
+
+ Display one menu item.
+
+Arguments:
+
+ MenuItemPtr - Pointer to PXE menu item option.
+
+Returns:
+
+ None
+
+--*/
+{
+ UINT8 Length;
+ UINT8 SaveChar;
+
+ Length = (UINT8) EFI_MIN (70, MenuItemPtr->DataLen);
+ SaveChar = MenuItemPtr->Data[Length];
+
+ MenuItemPtr->Data[Length] = 0;
+ AsciiPrint (" %a\n", MenuItemPtr->Data);
+ MenuItemPtr->Data[Length] = SaveChar;
+}
+
+STATIC
+EFI_STATUS
+DoMenu (
+ PXE_BASECODE_DEVICE *Private,
+ DHCP_RECEIVE_BUFFER *RxBufferPtr
+ )
+/*++
+
+Routine Description:
+
+ Display and process menu.
+
+Arguments:
+
+ Private - Pointer to PxeBc interface
+ RxBufferPtr - Pointer to receive buffer
+
+Returns:
+
+ NO_MENU -
+ LOCAL_BOOT -
+
+--*/
+{
+ PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;
+ PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];
+ EFI_STATUS Status;
+ UNION_PTR Ptr;
+ UINTN SaveNumRte;
+ UINTN TopRow;
+ UINTN MenuLth;
+ UINTN NumMenuItems;
+ UINTN Index;
+ UINTN Longest;
+ UINTN Selected;
+ UINT16 Type;
+ UINT16 Layer;
+ BOOLEAN Done;
+
+ Selected = 0;
+ Layer = 0;
+
+ DEBUG ((EFI_D_WARN, "\nDoMenu() Enter."));
+
+ /* see if we have a menu/prompt */
+ if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",
+ RxBufferPtr->OpAdds.Status)
+ );
+
+ return NO_MENU;
+ }
+
+ DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
+
+ //
+ // if not USE_BOOTFILE or no bootfile given, must have menu stuff
+ //
+ if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
+ DEBUG ((EFI_D_WARN, "\nDoMenu() DHCP w/ bootfile. "));
+ return NO_MENU;
+ }
+ //
+ // do prompt & menu if necessary
+ //
+ Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);
+
+ if (Status == LOCAL_BOOT) {
+ DEBUG ((EFI_D_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));
+
+ return Status;
+ }
+
+ Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
+
+ MenuLth = Ptr.MenuPtr->Header.Length;
+ Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;
+
+ //
+ // build menu items array
+ //
+ for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems <= MAX_MENULIST;) {
+ UINTN lth;
+
+ lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);
+
+ MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;
+
+ if (lth > Longest) {
+ //
+ // check if too long
+ //
+ if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {
+ Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));
+ }
+ }
+
+ Index += lth;
+ Ptr.BytePtr += lth;
+ }
+
+ if (Status != AUTO_SELECT) {
+ UINT8 BlankBuf[75];
+
+ SetMem (BlankBuf, sizeof BlankBuf, ' ');
+ BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;
+ AsciiPrint ("\n");
+
+ //
+ // now put up menu
+ //
+ for (Index = 0; Index < NumMenuItems; ++Index) {
+ PrintMenuItem (MenuItemPtrs[Index]);
+ }
+
+ TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;
+
+ //
+ // now wait for a selection
+ //
+ Done = FALSE;
+ do {
+ //
+ // highlight selection
+ //
+ EFI_INPUT_KEY Key;
+ UINTN NewSelected;
+
+ NewSelected = Selected;
+
+ //
+ // highlight selected row
+ //
+ gST->ConOut->SetAttribute (
+ gST->ConOut,
+ EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)
+ );
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);
+
+ AsciiPrint (" --->%a\r", BlankBuf);
+
+ PrintMenuItem (MenuItemPtrs[Selected]);
+ gST->ConOut->SetAttribute (
+ gST->ConOut,
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
+ );
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);
+
+ //
+ // wait for a keystroke
+ //
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
+ UINT8 TmpBuf[512];
+ UINTN TmpBufLen;
+
+ TmpBufLen = sizeof TmpBuf;
+
+ Private->EfiBc.UdpRead (
+ &Private->EfiBc,
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
+ NULL, /* dest ip */
+ NULL, /* dest port */
+ NULL, /* src ip */
+ NULL, /* src port */
+ NULL, /* hdr size */
+ NULL, /* hdr ptr */
+ &TmpBufLen,
+ TmpBuf
+ );
+ }
+
+ if (!Key.ScanCode) {
+ switch (Key.UnicodeChar) {
+ case Ctl ('c'):
+ Key.ScanCode = SCAN_ESC;
+ break;
+
+ case Ctl ('j'): /* linefeed */
+ case Ctl ('m'): /* return */
+ Done = TRUE;
+ break;
+
+ case Ctl ('i'): /* tab */
+ case ' ':
+ case 'd':
+ case 'D':
+ Key.ScanCode = SCAN_DOWN;
+ break;
+
+ case Ctl ('h'): /* backspace */
+ case 'u':
+ case 'U':
+ Key.ScanCode = SCAN_UP;
+ break;
+
+ default:
+ Key.ScanCode = 0;
+ }
+ }
+
+ switch (Key.ScanCode) {
+ case SCAN_LEFT:
+ case SCAN_UP:
+ if (NewSelected) {
+ --NewSelected;
+ }
+
+ break;
+
+ case SCAN_DOWN:
+ case SCAN_RIGHT:
+ if (++NewSelected == NumMenuItems) {
+ --NewSelected;
+ }
+
+ break;
+
+ case SCAN_PAGE_UP:
+ case SCAN_HOME:
+ NewSelected = 0;
+ break;
+
+ case SCAN_PAGE_DOWN:
+ case SCAN_END:
+ NewSelected = NumMenuItems - 1;
+ break;
+
+ case SCAN_ESC:
+ return LOCAL_BOOT;
+ }
+
+ /* unhighlight last selected row */
+ gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);
+
+ AsciiPrint ("%a\r", BlankBuf);
+
+ PrintMenuItem (MenuItemPtrs[Selected]);
+
+ Selected = NewSelected;
+ } while (!Done);
+ }
+
+ SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;
+
+ Type = NTOHS (MenuItemPtrs[Selected]->Type);
+
+ if (Type == 0) {
+ DEBUG ((EFI_D_WARN, "\nDoMenu() Local boot selected. "));
+ return LOCAL_BOOT;
+ }
+
+ AsciiPrint ("Discover");
+
+ Status = Private->EfiBc.Discover (
+ &Private->EfiBc,
+ Type,
+ &Layer,
+ (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ AsciiPrint ("\r \r");
+
+ DEBUG (
+ (EFI_D_WARN,
+ "\nDoMenu() Return w/ %xh (%r).",
+ Status,
+ Status)
+ );
+
+ return Status;
+ }
+
+ AsciiPrint ("\rBOOT_SERVER_IP: ");
+ PrintIpv4 ((UINT8 *) &Private->ServerIp);
+
+ for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {
+ if ((Index % 3) == 0) {
+ AsciiPrint ("\r\nGATEWAY IP:");
+ }
+
+ AsciiPrint (" ");
+ PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);
+ AsciiPrint (" ");
+ }
+
+ AsciiPrint ("\n");
+
+ DEBUG ((EFI_D_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+UINT16
+GetValue (
+ DHCPV4_OP_STRUCT *OpPtr
+ )
+/*++
+
+Routine Description:
+
+ Get value 8- or 16-bit value from DHCP option.
+
+Arguments:
+
+ OpPtr - Pointer to DHCP option
+
+Returns:
+
+ Value from DHCP option
+
+--*/
+{
+ if (OpPtr->Header.Length == 1) {
+ return OpPtr->Data[0];
+ } else {
+ return NTOHS (OpPtr->Data);
+ }
+}
+
+STATIC
+UINT8 *
+_PxeBcFindOpt (
+ UINT8 *BufferPtr,
+ UINTN BufferLen,
+ UINT8 OpCode
+ )
+/*++
+
+Routine Description:
+
+ Locate opcode in buffer.
+
+Arguments:
+
+ BufferPtr - Pointer to buffer
+ BufferLen - Length of buffer
+ OpCode - Option number
+
+Returns:
+
+ Pointer to opcode, may be NULL
+
+--*/
+{
+ if (BufferPtr == NULL) {
+ return NULL;
+ }
+
+ while (BufferLen != 0) {
+ if (*BufferPtr == OpCode) {
+ return BufferPtr;
+ }
+
+ switch (*BufferPtr) {
+ case OP_END:
+ return NULL;
+
+ case OP_PAD:
+ ++BufferPtr;
+ --BufferLen;
+ continue;
+ }
+
+ if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {
+ return NULL;
+ }
+
+ BufferLen -= 2 + BufferPtr[1];
+ BufferPtr += 2 + BufferPtr[1];
+ }
+
+ return NULL;
+}
+
+UINT8 *
+PxeBcFindDhcpOpt (
+ EFI_PXE_BASE_CODE_PACKET *PacketPtr,
+ UINT8 OpCode
+ )
+/*++
+
+Routine Description:
+
+ Find option in packet
+
+Arguments:
+
+ PacketPtr - Pointer to packet
+ OpCode - option number
+
+Returns:
+
+ Pointer to option in packet
+
+--*/
+{
+ UINTN PacketLen;
+ UINT8 Overload;
+ UINT8 *OptionBufferPtr;
+
+ //
+ //
+ //
+ PacketLen = 380;
+ Overload = 0;
+
+ //
+ // Figure size of DHCP option space.
+ //
+ OptionBufferPtr = _PxeBcFindOpt (
+ PacketPtr->Dhcpv4.DhcpOptions,
+ 380,
+ OP_DHCP_MAX_MESSAGE_SZ
+ );
+
+ if (OptionBufferPtr != NULL) {
+ if (OptionBufferPtr[1] == 2) {
+ UINT16 n;
+
+ CopyMem (&n, &OptionBufferPtr[2], 2);
+ PacketLen = HTONS (n);
+
+ if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {
+ PacketLen = 380;
+ } else {
+ PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;
+ }
+ }
+ }
+ //
+ // Look for option overloading.
+ //
+ OptionBufferPtr = _PxeBcFindOpt (
+ PacketPtr->Dhcpv4.DhcpOptions,
+ PacketLen,
+ OP_DHCP_OPTION_OVERLOAD
+ );
+
+ if (OptionBufferPtr != NULL) {
+ if (OptionBufferPtr[1] == 1) {
+ Overload = OptionBufferPtr[2];
+ }
+ }
+ //
+ // Look for caller's option.
+ //
+ OptionBufferPtr = _PxeBcFindOpt (
+ PacketPtr->Dhcpv4.DhcpOptions,
+ PacketLen,
+ OpCode
+ );
+
+ if (OptionBufferPtr != NULL) {
+ return OptionBufferPtr;
+ }
+
+ if (Overload & OVLD_FILE) {
+ OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);
+
+ if (OptionBufferPtr != NULL) {
+ return OptionBufferPtr;
+ }
+ }
+
+ if (Overload & OVLD_SRVR_NAME) {
+ OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);
+
+ if (OptionBufferPtr != NULL) {
+ return OptionBufferPtr;
+ }
+ }
+
+ return NULL;
+}
+
+STATIC
+EFI_STATUS
+DownloadFile (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN OUT UINT64 *BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Download file into buffer
+
+Arguments:
+
+ Private - Pointer to PxeBc interface
+ BufferSize - pointer to size of download buffer
+ Buffer - Pointer to buffer
+
+Returns:
+
+ EFI_BUFFER_TOO_SMALL -
+ EFI_NOT_FOUND -
+ EFI_PROTOCOL_ERROR -
+
+--*/
+{
+ EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo;
+ EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;
+ DHCP_RECEIVE_BUFFER *RxBuf;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+
+ RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;
+ BlockSize = 0x8000;
+
+ DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter."));
+
+ if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {
+ if (Private->FileSize != 0) {
+ *BufferSize = Private->FileSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ AsciiPrint ("\nTSize");
+
+ OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
+ } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {
+ OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;
+
+ ZeroMem (&MtftpInfo, sizeof MtftpInfo);
+
+ *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;
+
+ CopyMem (
+ &MtftpInfo.CPort,
+ RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,
+ sizeof MtftpInfo.CPort
+ );
+
+ CopyMem (
+ &MtftpInfo.SPort,
+ RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,
+ sizeof MtftpInfo.SPort
+ );
+
+ MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);
+
+ MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);
+
+ AsciiPrint ("\nMTFTP");
+ } else {
+ AsciiPrint ("\nTFTP");
+
+ OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
+ }
+
+ Private->FileSize = 0;
+
+ RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;
+
+ Status = Private->EfiBc.Mtftp (
+ &Private->EfiBc,
+ OpCode,
+ Buffer,
+ FALSE,
+ BufferSize,
+ &BlockSize,
+ &Private->ServerIp,
+ (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,
+ &MtftpInfo,
+ FALSE
+ );
+
+ if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
+ DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #1 %Xh", Status));
+ return Status;
+ }
+
+ if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {
+ Private->FileSize = 0xFFFFFFFF;
+ } else {
+ Private->FileSize = (UINTN) *BufferSize;
+ }
+
+ if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
+ DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #2"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #3 %Xh", Status));
+ return Status;
+ }
+
+ if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {
+ UINT64 CredentialLen;
+ UINTN BlockSize;
+ UINT8 CredentialFilename[256];
+ UINT8 *op;
+ VOID *CredentialBuffer;
+
+ //
+ // Get name of credential file. It may be in the BOOTP
+ // bootfile field or a DHCP option.
+ //
+ ZeroMem (CredentialFilename, sizeof CredentialFilename);
+
+ op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);
+
+ if (op != NULL) {
+ if (op[1] == 0) {
+ /* No credential filename */
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (CredentialFilename, &op[2], op[1]);
+ } else {
+ if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {
+ /* No credential filename */
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (CredentialFilename, &op[2], 128);
+ }
+ //
+ // Get size of credential file. It may be available as a
+ // DHCP option. If not, use the TFTP get file size.
+ //
+ CredentialLen = 0;
+
+ op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);
+
+ if (op != NULL) {
+ /*
+ * This is actually the size of the credential file
+ * buffer. The actual credential file size will be
+ * returned when we download the file.
+ */
+ if (op[1] == 2) {
+ UINT16 n;
+
+ CopyMem (&n, &op[2], 2);
+ CredentialLen = HTONS (n) * 512;
+ }
+ }
+
+ if (CredentialLen == 0) {
+ BlockSize = 8192;
+
+ Status = Private->EfiBc.Mtftp (
+ &Private->EfiBc,
+ EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ NULL,
+ FALSE,
+ &CredentialLen,
+ &BlockSize,
+ &Private->ServerIp,
+ CredentialFilename,
+ NULL,
+ FALSE
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CredentialLen == 0) {
+ //
+ // %%TBD -- EFI error for invalid credential
+ // file.
+ //
+ return EFI_PROTOCOL_ERROR;
+ }
+ }
+ //
+ // Allocate credential file buffer.
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN) CredentialLen,
+ &CredentialBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Download credential file.
+ //
+ BlockSize = 8192;
+
+ Status = Private->EfiBc.Mtftp (
+ &Private->EfiBc,
+ EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ CredentialBuffer,
+ FALSE,
+ &CredentialLen,
+ &BlockSize,
+ &Private->ServerIp,
+ CredentialFilename,
+ NULL,
+ FALSE
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (CredentialBuffer);
+ return Status;
+ }
+ //
+ // Verify credentials.
+ //
+ if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // %%TBD -- An EFI error code for failing credential verification.
+ //
+ Status = EFI_PROTOCOL_ERROR;
+ }
+
+ gBS->FreePool (CredentialBuffer);
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+LoadfileStart (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN OUT UINT64 *BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Start PXE DHCP. Get DHCP and proxyDHCP information.
+ Display remote boot menu and prompt. Select item from menu.
+
+Arguments:
+
+ Private - Pointer to PxeBc interface
+ BufferSize - Pointer to download buffer size
+ Buffer - Pointer to download buffer
+
+Returns:
+
+ EFI_SUCCESS -
+ EFI_NOT_READY -
+
+--*/
+{
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ EFI_STATUS Status;
+ VOID *RxBuf;
+
+ DEBUG ((EFI_D_WARN, "\nLoadfileStart() Enter."));
+
+ //
+ // Try to start BaseCode, for now only IPv4 is supported
+ // so don't try to start using IPv6.
+ //
+ Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_ALREADY_STARTED) {
+ DEBUG ((EFI_D_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));
+ return Status;
+ }
+ }
+ //
+ // Get pointers to PXE mode structure, SNP protocol structure
+ // and SNP mode structure.
+ //
+ PxeBcMode = Private->EfiBc.Mode;
+ Snp = Private->SimpleNetwork;
+ SnpMode = Snp->Mode;
+
+ //
+ // Display client MAC address, like 16-bit PXE ROMs
+ //
+ AsciiPrint ("\nCLIENT MAC ADDR: ");
+
+ {
+ UINTN Index;
+ UINTN hlen;
+
+ hlen = SnpMode->HwAddressSize;
+
+ for (Index = 0; Index < hlen; ++Index) {
+ AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);
+ }
+ }
+
+ AsciiPrint ("\nDHCP");
+
+ Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));
+ AsciiPrint ("\r \r");
+ return Status;
+ }
+
+ ShowMyInfo (Private);
+
+ RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
+#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)
+
+ Status = DoMenu (Private, RxBufferPtr);
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // did a discovery - take info from discovery packet
+ //
+ RxBuf = &PXE_ACK_BUFFER;
+ } else if (Status == NO_MENU) {
+ //
+ // did not do a discovery - take info from rxbuf
+ //
+ Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;
+
+ if (!(Private->ServerIp.Addr[0])) {
+ *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;
+ }
+ } else {
+ DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));
+ return Status;
+ }
+
+ if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
+ DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit Not ready?"));
+ return EFI_NOT_READY;
+ }
+ //
+ // check for file size option sent
+ //
+ if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {
+ Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);
+ }
+
+ Private->BootServerReceiveBuffer = RxBufferPtr;
+
+ Status = DownloadFile (Private, BufferSize, Buffer);
+
+ DEBUG (
+ (EFI_D_WARN,
+ "\nLoadfileStart() Exit. DownloadFile() = %Xh",
+ Status)
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+LoadFile (
+ IN EFI_LOAD_FILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Loadfile interface for PxeBc interface
+
+Arguments:
+
+ This - Pointer to Loadfile interface
+ FilePath - Not used and not checked
+ BootPolicy - Must be TRUE
+ BufferSize - Pointer to buffer size
+ Buffer - Pointer to download buffer or NULL
+
+Returns:
+
+ EFI_INVALID_PARAMETER -
+ EFI_UNSUPPORTED -
+ EFI_SUCCESS -
+ EFI_BUFFER_TOO_SMALL -
+
+--*/
+{
+ LOADFILE_DEVICE *LoadfilePtr;
+ UINT64 TmpBufSz;
+ INT32 OrigMode;
+ INT32 OrigAttribute;
+ BOOLEAN RemoveCallback;
+ BOOLEAN NewMakeCallback;
+ EFI_STATUS Status;
+ EFI_STATUS TempStatus;
+ //
+ //
+ //
+ OrigMode = gST->ConOut->Mode->Mode;
+ OrigAttribute = gST->ConOut->Mode->Attribute;
+ RemoveCallback = FALSE;
+
+ AsciiPrint ("Running LoadFile()\n");
+
+ //
+ // Resolve Warning 4 unreferenced parameter problem
+ //
+ FilePath = NULL;
+
+ //
+ // If either if these parameters are NULL, we cannot continue.
+ //
+ if (This == NULL || BufferSize == NULL) {
+ DEBUG ((EFI_D_WARN, "\nLoadFile() This or BufferSize == NULL"));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We only support BootPolicy == TRUE
+ //
+ if (!BootPolicy) {
+ DEBUG ((EFI_D_WARN, "\nLoadFile() BootPolicy == FALSE"));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get pointer to LoadFile protocol structure.
+ //
+ LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);
+
+ if (LoadfilePtr == NULL) {
+ DEBUG (
+ (EFI_D_NET,
+ "\nLoadFile() Could not get pointer to LoadFile structure")
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Lock interface
+ //
+ EfiAcquireLock (&LoadfilePtr->Lock);
+
+ //
+ // Set console output mode and display attribute
+ //
+ if (OrigMode != 0) {
+ gST->ConOut->SetMode (gST->ConOut, 0);
+ }
+
+ gST->ConOut->SetAttribute (
+ gST->ConOut,
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)
+ );
+
+ //
+ // See if BaseCode already has a Callback protocol attached.
+ // If there is none, attach our own Callback protocol.
+ //
+ Status = gBS->HandleProtocol (
+ LoadfilePtr->Private->Handle,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr
+ );
+
+ switch (Status) {
+ case EFI_SUCCESS:
+ //
+ // There is already a callback routine. Do nothing.
+ //
+ DEBUG ((EFI_D_WARN, "\nLoadFile() BC callback exists."));
+ break;
+
+ case EFI_UNSUPPORTED:
+ //
+ // No BaseCode Callback protocol found. Add our own.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &LoadfilePtr->Private->Handle,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &_bc_callback
+ );
+
+ DEBUG ((EFI_D_WARN, "\nLoadFile() Callback install status == %xh", Status));
+
+ RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);
+
+ if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {
+ NewMakeCallback = TRUE;
+ LoadfilePtr->Private->EfiBc.SetParameters (
+ &LoadfilePtr->Private->EfiBc,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &NewMakeCallback
+ );
+ }
+
+ break;
+
+ default:
+ DEBUG ((EFI_D_WARN, "\nLoadFile() Callback check status == %xh", Status));
+ }
+ //
+ // Check for starting or for continuing after already getting
+ // the file size.
+ //
+ if (LoadfilePtr->Private->FileSize == 0) {
+ TmpBufSz = 0;
+ Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);
+
+ if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {
+ *BufferSize = 0xFFFFFFFF;
+ } else {
+ *BufferSize = (UINTN) TmpBufSz;
+ }
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // This is done so loadfile will work even if the boot manager
+ // did not make the first call with Buffer == NULL.
+ //
+ Buffer = NULL;
+ }
+ } else if (Buffer == NULL) {
+ DEBUG ((EFI_D_WARN, "\nLoadfile() Get buffer size"));
+
+ //
+ // Continuing from previous LoadFile request. Make sure there
+ // is a buffer and that it is big enough.
+ //
+ *BufferSize = LoadfilePtr->Private->FileSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ DEBUG ((EFI_D_WARN, "\nLoadFile() Download file"));
+
+ //
+ // Everything looks good, try to download the file.
+ //
+ TmpBufSz = *BufferSize;
+ Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);
+
+ //
+ // Next call to loadfile will start DHCP process again.
+ //
+ LoadfilePtr->Private->FileSize = 0;
+ }
+ //
+ // If we added a callback protocol, now is the time to remove it.
+ //
+ if (RemoveCallback) {
+ NewMakeCallback = FALSE;
+ TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (
+ &LoadfilePtr->Private->EfiBc,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &NewMakeCallback
+ );
+
+ if (TempStatus == EFI_SUCCESS) {
+ gBS->UninstallProtocolInterface (
+ LoadfilePtr->Private->Handle,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ &_bc_callback
+ );
+ }
+ }
+ //
+ // Restore display mode and attribute
+ //
+ if (OrigMode != 0) {
+ gST->ConOut->SetMode (gST->ConOut, OrigMode);
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);
+
+ //
+ // Unlock interface
+ //
+ EfiReleaseLock (&LoadfilePtr->Lock);
+
+ DEBUG ((EFI_D_WARN, "\nBC.Loadfile() Status == %xh\n", Status));
+
+ switch (Status) {
+ case EFI_SUCCESS: /* 0 */
+ return EFI_SUCCESS;
+
+ case EFI_BUFFER_TOO_SMALL: /* 5 */
+ //
+ // Error is only displayed when we are actually trying to
+ // download the boot image.
+ //
+ if (Buffer == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");
+ break;
+
+ case EFI_DEVICE_ERROR: /* 7 */
+ AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");
+ break;
+
+ case EFI_OUT_OF_RESOURCES: /* 9 */
+ AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");
+ break;
+
+ case EFI_NO_MEDIA: /* 12 */
+ AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");
+ break;
+
+ case EFI_NO_RESPONSE: /* 16 */
+ AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");
+ break;
+
+ case EFI_TIMEOUT: /* 18 */
+ AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");
+ break;
+
+ case EFI_ABORTED: /* 21 */
+ AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");
+ break;
+
+ case EFI_ICMP_ERROR: /* 22 */
+ AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");
+
+ if (LoadfilePtr->Private->EfiBc.Mode == NULL) {
+ break;
+ }
+
+ if (!LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {
+ break;
+ }
+
+ AsciiPrint (
+ "PXE-E98: Type: %xh Code: %xh ",
+ LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,
+ LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code
+ );
+
+ switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {
+ case 0x03:
+ switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {
+ case 0x00: /* net unreachable */
+ AsciiPrint ("Net unreachable");
+ break;
+
+ case 0x01: /* host unreachable */
+ AsciiPrint ("Host unreachable");
+ break;
+
+ case 0x02: /* protocol unreachable */
+ AsciiPrint ("Protocol unreachable");
+ break;
+
+ case 0x03: /* port unreachable */
+ AsciiPrint ("Port unreachable");
+ break;
+
+ case 0x04: /* Fragmentation needed */
+ AsciiPrint ("Fragmentation needed");
+ break;
+
+ case 0x05: /* Source route failed */
+ AsciiPrint ("Source route failed");
+ break;
+ }
+
+ break;
+ }
+
+ AsciiPrint ("\n");
+
+ break;
+
+ case EFI_TFTP_ERROR: /* 23 */
+ AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");
+
+ if (LoadfilePtr->Private->EfiBc.Mode == NULL) {
+ break;
+ }
+
+ if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) {
+ AsciiPrint (
+ "PXE-E98: Code: %xh %a\n",
+ LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,
+ LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString
+ );
+ }
+
+ break;
+
+ default:
+ AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);
+ }
+
+ LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);
+
+ return Status;
+}
diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h b/EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h
new file mode 100644
index 0000000..3cc0724
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/tftp.h
@@ -0,0 +1,153 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ tftp.h
+
+Abstract:
+
+--*/
+
+#ifndef __TFTP_H__
+#define __TFTP_H__
+
+//
+// Definitions for trivial file transfer protocol functionality with IP v4
+// Per RFC 1350, July 1992 and RFC 2347, 8, and 9, May 1998
+//
+#pragma pack(1)
+//
+// max and min packet sizes
+// (all data packets in transmission except last)
+//
+#define MAX_TFTP_PKT_SIZE (BUFFER_ALLOCATE_SIZE - 512)
+#define MIN_TFTP_PKT_SIZE 512
+
+//
+// TFTPv4 OpCodes
+//
+#define TFTP_RRQ 1 // read request
+#define TFTP_WRQ 2 // write request
+#define TFTP_DATA 3 // data
+#define TFTP_ACK 4 // acknowledgement
+#define TFTP_ERROR 5 // error packet
+#define TFTP_OACK 6 // option acknowledge
+#define TFTP_DIR 7 // read directory request
+#define TFTP_DATA8 8
+#define TFTP_ACK8 9
+
+//
+// request packet (read or write)
+// Fields shown (except file name) are not to be referenced directly,
+// since their placement is variable within a request packet.
+// All are null terminated case insensitive ascii strings.
+//
+struct Tftpv4Req {
+ UINT16 OpCode; // TFTP Op code
+ UINT8 FileName[2]; // file name
+ UINT8 Mode[2]; // "netascii" or "octet"
+ struct { // optionally, one or more option requests
+ UINT8 Option[2]; // option name
+ UINT8 Value[2]; // value requested
+ } OpReq[1];
+};
+
+//
+// modes
+//
+#define MODE_ASCII "netascii"
+#define MODE_BINARY "octet"
+
+//
+// option strings
+//
+#define OP_BLKSIZE "blksize" // block size option
+#define OP_TIMEOUT "timeout" // time to wait before retransmitting
+#define OP_TFRSIZE "tsize" // total transfer size option
+#define OP_OVERWRITE "overwrite" // overwrite file option
+#define OP_BIGBLKNUM "bigblk#" // big block number
+// See RFC 2347, 8, and 9 for more information on TFTP options
+// option acknowledge packet (optional)
+// options not acknowledged are rejected
+//
+struct Tftpv4Oack {
+ UINT16 OpCode; // TFTP Op code
+ struct { // optionally, one or more option acknowledgements
+ UINT8 Option[2]; // option name (of those requested)
+ UINT8 Value[2]; // value acknowledged
+ } OpAck[1];
+};
+
+//
+// acknowledge packet
+//
+struct Tftpv4Ack {
+ UINT16 OpCode; // TFTP Op code
+ UINT16 BlockNum;
+};
+
+//
+// data packet
+//
+struct Tftpv4Data {
+ struct Tftpv4Ack Header;
+ UINT8 Data[512];
+};
+
+//
+// big block number ack packet
+//
+struct Tftpv4Ack8 {
+ UINT16 OpCode;
+ UINT64 BlockNum;
+};
+
+//
+// big block number data packet
+//
+struct Tftpv4Data8 {
+ struct Tftpv4Ack8 Header;
+ UINT8 Data[506];
+};
+
+//
+// error packet
+//
+struct Tftpv4Error {
+ UINT16 OpCode; // TFTP Op code
+ UINT16 ErrCode; // error code
+ UINT8 ErrMsg[1]; // error message (nul terminated)
+};
+
+#pragma pack()
+//
+// error codes
+//
+#define TFTP_ERR_UNDEF 0 // Not defined, see error message (if any).
+#define TFTP_ERR_NOT_FOUND 1 // File not found.
+#define TFTP_ERR_ACCESS 2 // Access violation.
+#define TFTP_ERR_FULL 3 // Disk full or allocation exceeded.
+#define TFTP_ERR_ILLEGAL 4 // Illegal TFTP operation.
+#define TFTP_ERR_BAD_ID 5 // Unknown transfer ID.
+#define TFTP_ERR_EXISTS 6 // File already exists.
+#define TFTP_ERR_NO_USER 7 // No such user.
+#define TFTP_ERR_OPTION 8 // Option negotiation termination
+//
+// some defines
+//
+#define REQ_RESP_TIMEOUT 5 // Wait five seconds for request response.
+#define ACK_TIMEOUT 4 // Wait four seconds for ack response.
+#define NUM_ACK_RETRIES 3
+#define NUM_MTFTP_OPEN_RETRIES 3
+
+#endif /* __TFTP_H__ */
+
+/* EOF - tftp.h */
diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c
new file mode 100644
index 0000000..b48b5d0
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/ComponentName.c
@@ -0,0 +1,169 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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",
+ (CHAR16 *) 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/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd
new file mode 100644
index 0000000..090884a
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.mbd
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Dhcp4</BaseName>
+ <Guid>a46c3330-be36-4977-9d24-a7cf92eef0fe</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa
new file mode 100644
index 0000000..96bfc9b
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/Dhcp4.msa
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Dhcp4</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>a46c3330-be36-4977-9d24-a7cf92eef0fe</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>ComponentName.c</Filename>
+ <Filename>PxeDhcp4.c</Filename>
+ <Filename>PxeDhcp4.h</Filename>
+ <Filename>PxeDhcp4InitSelect.c</Filename>
+ <Filename>PxeDhcp4Release.c</Filename>
+ <Filename>PxeDhcp4RenewRebind.c</Filename>
+ <Filename>PxeDhcp4Run.c</Filename>
+ <Filename>PxeDhcp4Setup.c</Filename>
+ <Filename>support.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">PxeDhcp4Callback</Protocol>
+ <Protocol Usage="BY_START">PxeDhcp4</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">SimpleNetwork</Protocol>
+ <Protocol Usage="TO_START">PxeBaseCode</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ <ModuleUnloadImage></ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>gPxeDhcp4DriverBinding</DriverBinding>
+ <ComponentName>gPxeDhcp4ComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c
new file mode 100644
index 0000000..57a44a0
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.c
@@ -0,0 +1,342 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that contains a PxeBaseCode protocol can be
+ supported.
+
+ Arguments:
+ This - Protocol instance pointer.
+ ControllerHandle - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_ALREADY_STARTED - This driver is already running on this
+ device.
+ other - This driver does not support this device.
+
+--*/
+{
+ 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
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Start this driver on ControllerHandle by opening a PxeBaseCode
+ protocol and installing a PxeDhcp4 protocol on ControllerHandle.
+
+ Arguments:
+ This - Protocol instance pointer.
+ ControllerHandle - Handle of device to bind driver to.
+ RemainingDevicePath - Not used, always produce all possible
+ children.
+
+ Returns:
+ EFI_SUCCESS - This driver is added to ControllerHandle.
+ EFI_ALREADY_STARTED - This driver is already running on
+ ControllerHandle.
+ other - This driver does not support this device.
+
+--*/
+{
+ 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.
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (PXE_DHCP4_PRIVATE_DATA),
+ (VOID **) &Private
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto error_exit;
+ }
+ //
+ //
+ //
+ ZeroMem (Private, sizeof (PXE_DHCP4_PRIVATE_DATA));
+
+ 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;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+ Routine Description:
+ Stop this driver on ControllerHandle by removing PXE DHCP
+ protocol and closing the PXE Base Code protocol on
+ ControllerHandle.
+
+ Arguments:
+ This - Protocol instance pointer.
+ ControllerHandle - Handle of device to stop driver on.
+ NumberOfChildren - Not used.
+ ChildHandleBuffer - Not used.
+
+ Returns:
+ EFI_SUCCESS - This driver is removed ControllerHandle.
+ other - This driver was not removed from this
+ device.
+
+--*/
+{
+ 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) {
+ gBS->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
+ //
+ gBS->FreePool (Private);
+
+ return Status;
+}
+
+/* EOF - PxeDhcp4.c */
diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h
new file mode 100644
index 0000000..136d392
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4.h
@@ -0,0 +1,307 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ PxeDhcp4.h
+
+Abstract:
+ Common header for PxeDhcp4 protocol driver
+
+--*/
+#ifndef _PXEDHCP4_H
+#define _PXEDHCP4_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_DRIVER_BINDING_PROTOCOL gPxeDhcp4DriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName;
+
+#endif /* _PXEDHCP4_H */
+
+/* EOF - PxeDhcp4.h */
diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c
new file mode 100644
index 0000000..8b7cd28
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4InitSelect.c
@@ -0,0 +1,786 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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
+ )
+/*++
+ -2 = ignore, stop waiting
+ -1 = ignore, keep waiting
+ 0 = accept, keep waiting
+ 1 = accept, stop waiting
+--*/
+{
+ 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
+ )
+/*++
+ -2 = ignore, stop waiting
+ -1 = ignore, keep waiting
+ 0 = accept, keep waiting
+ 1 = accept, stop waiting
+--*/
+{
+ 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/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c
new file mode 100644
index 0000000..6086e55
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Release.c
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c
new file mode 100644
index 0000000..2905255
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4RenewRebind.c
@@ -0,0 +1,408 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ PxeDhcp4RenewRebind.c
+
+Abstract:
+
+--*/
+
+
+#include "PxeDhcp4.h"
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+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
+ )
+/*++
+Routine Description:
+
+Parameters:
+
+Returns:
+ -2 = ignore, stop waiting
+ -1 = ignore, keep waiting
+ 0 = accept, keep waiting
+ 1 = accept, stop waiting
+--*/
+{
+ 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/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c
new file mode 100644
index 0000000..50f97a8
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Run.c
@@ -0,0 +1,196 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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);
+
+ switch (efi_status) {
+ case EFI_NO_RESPONSE:
+ case EFI_TIMEOUT:
+ case EFI_SUCCESS:
+ break;
+
+ case EFI_ABORTED:
+ default:
+ 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/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c
new file mode 100644
index 0000000..09ba041
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/PxeDhcp4Setup.c
@@ -0,0 +1,268 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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.
+ //
+ EfiStatus = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_PXE_DHCP4_DATA),
+ (VOID **) &This->Data
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ This->Data = NULL;
+ return EfiStatus;
+ }
+
+ 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) {
+ gBS->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/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml
new file mode 100644
index 0000000..e7afd62
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/build.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="Dhcp4"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Network\PxeDhcp4\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Dhcp4">
+ <GenBuild baseName="Dhcp4" mbdFilename="${MODULE_DIR}\Dhcp4.mbd" msaFilename="${MODULE_DIR}\Dhcp4.msa"/>
+ </target>
+ <target depends="Dhcp4_clean" name="clean"/>
+ <target depends="Dhcp4_cleanall" name="cleanall"/>
+ <target name="Dhcp4_clean">
+ <OutputDirSetup baseName="Dhcp4" mbdFilename="${MODULE_DIR}\Dhcp4.mbd" msaFilename="${MODULE_DIR}\Dhcp4.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Dhcp4_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Dhcp4_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Dhcp4_cleanall">
+ <OutputDirSetup baseName="Dhcp4" mbdFilename="${MODULE_DIR}\Dhcp4.mbd" msaFilename="${MODULE_DIR}\Dhcp4.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Dhcp4_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Dhcp4_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Dhcp4*"/>
+ </delete>
+ </target>
+</project> \ No newline at end of file
diff --git a/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c
new file mode 100644
index 0000000..50c9913
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/PxeDhcp4/Dxe/support.c
@@ -0,0 +1,1126 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ 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;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+find_opt (
+ IN DHCP4_PACKET *Packet,
+ IN UINT8 OpCode,
+ IN UINTN Skip,
+ OUT DHCP4_OP **OpPtr
+ )
+/*++
+Routine description:
+ Locate option inside DHCP packet.
+
+Parameters:
+ Packet := Pointer to DHCP packet structure.
+ OpCode := Option op-code to find.
+ Skip := Number of found op-codes to skip.
+ OpPtr := Pointer to found op-code pointer.
+
+Returns:
+ EFI_SUCCESS := Option was found
+ EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
+ EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD
+ EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0
+ EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid
+ EFI_NOT_FOUND := op-code was not found in packet
+ EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option
+ does not have a valid value.
+--*/
+{
+ 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;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+add_opt (
+ IN DHCP4_PACKET *Packet,
+ IN DHCP4_OP *OpPtr
+ )
+/*++
+Routine description:
+ Add option to DHCP packet.
+
+Parameters:
+ Packet := Pointer to DHCP packet structure.
+ OpPtr := Pointer to DHCP option.
+
+Returns:
+ EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
+ EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END
+ EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid
+ EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and
+ is not valid
+ EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and
+ is not valid
+ EFI_DEVICE_ERROR := Cannot determine end of packet
+ EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option
+ EFI_SUCCESS := Option added to DHCP packet
+--*/
+{
+ 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;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+EFI_STATUS
+start_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OPTIONAL EFI_IP_ADDRESS *StationIp,
+ IN OPTIONAL EFI_IP_ADDRESS *SubnetMask
+ )
+/*++
+Routine description:
+ Setup PXE BaseCode UDP stack.
+
+Parameters:
+ Private := Pointer to PxeDhcp4 private data.
+ StationIp := Pointer to IP address or NULL if not known.
+ SubnetMask := Pointer to subnet mask or NULL if not known.
+
+Returns:
+ EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL
+ EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given
+ EFI_SUCCESS := UDP stack is ready
+ other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp()
+--*/
+{
+ 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
+ )
+/*++
+Routine description:
+ Create periodic and timeout receive events.
+
+Parameters:
+ Private := Pointer to PxeDhcp4 private data.
+ SecondsTimeout := Number of seconds to wait before timeout.
+
+Returns:
+--*/
+{
+ 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 (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_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 (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_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;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+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
+ )
+/*++
+Routine description:
+ Transmit DHCP packet.
+
+Parameters:
+ Private := Pointer to PxeDhcp4 private data
+ dest_ip := Pointer to destination IP address
+ gateway_ip := Pointer to gateway IP address or NULL
+ src_ip := Pointer to source IP address or NULL
+ buffer := Pointer to buffer to transmit
+ BufferSize := Size of buffer in bytes
+
+Returns:
+ EFI_INVALID_PARAMETER := Private == NULL || dest_ip == NULL ||
+ buffer == NULL || BufferSize < 300 || Private->PxeBc == NULL
+ EFI_SUCCESS := Buffer was transmitted
+ other := Return from PxeBc->UdpWrite()
+--*/
+{
+ 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
+ );
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+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
+ )
+/*++
+Routine description:
+ Receive DHCP packet.
+
+Parameters:
+ Private := Pointer to PxeDhcp4 private data
+ buffer := Pointer to buffer to receive DHCP packet
+ BufferSize := Pointer to buffer size in bytes
+ dest_ip := Pointer to destination IP address
+ src_ip := Pointer to source IP address
+ op_flags := UDP receive operation flags
+
+Returns:
+ EFI_INVALID_PARAMETER :=
+ EFI_SUCCESS := Packet received
+ other := Return from PxeBc->UdpRead()
+--*/
+{
+ 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 */
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c
new file mode 100644
index 0000000..3cc2d98
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/ComponentName.c
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ ComponentName.c
+
+Abstract:
+
+--*/
+
+#include "Snp.h"
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetControllerName (
+ 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 gSimpleNetworkComponentName = {
+ SimpleNetworkComponentNameGetDriverName,
+ SimpleNetworkComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = {
+ {
+ "eng",
+ (CHAR16 *) L"Simple Network Protocol Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetDriverName (
+ 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,
+ gSimpleNetworkComponentName.SupportedLanguages,
+ mSimpleNetworkDriverNameTable,
+ DriverName
+ );
+}
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetControllerName (
+ 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;
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd
new file mode 100644
index 0000000..293812b
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.mbd
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>SNP</BaseName>
+ <Guid>A2f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:19</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>BaseMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa
new file mode 100644
index 0000000..c8ce3d7
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/SNP.msa
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>SNP</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>A2f436EA-A127-4EF8-957C-8048606FF670</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for DiskIo module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:19</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>callback.c</Filename>
+ <Filename>get_status.c</Filename>
+ <Filename>initialize.c</Filename>
+ <Filename>mcast_ip_to_mac.c</Filename>
+ <Filename>nvdata.c</Filename>
+ <Filename>receive.c</Filename>
+ <Filename>receive_filters.c</Filename>
+ <Filename>reset.c</Filename>
+ <Filename>shutdown.c</Filename>
+ <Filename>snp.c</Filename>
+ <Filename>snp.h</Filename>
+ <Filename>start.c</Filename>
+ <Filename>station_address.c</Filename>
+ <Filename>statistics.c</Filename>
+ <Filename>stop.c</Filename>
+ <Filename>transmit.c</Filename>
+ <Filename>WaitForPacket.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="BY_START">SimpleNetwork</Protocol>
+ <Protocol Usage="TO_START">PciIo</Protocol>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ <Protocol Usage="SOMETIMES_CONSUMED">NetworkInterfaceIdentifier</Protocol>
+ <Protocol Usage="TO_START">NetworkInterfaceIdentifier2</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ <ModuleUnloadImage></ModuleUnloadImage>
+ </Extern>
+ <Extern>
+ <DriverBinding>mSimpleNetworkDriverBinding</DriverBinding>
+ <ComponentName>gSimpleNetworkComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c
new file mode 100644
index 0000000..dff0da1
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/WaitForPacket.c
@@ -0,0 +1,100 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ WaitForPacket.c
+
+Abstract:
+ Event handler to check for available packet.
+
+--*/
+
+
+#include "snp.h"
+
+VOID
+EFIAPI
+SnpWaitForPacketNotify (
+ EFI_EVENT Event,
+ VOID *SnpPtr
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ PXE_DB_GET_STATUS PxeDbGetStatus;
+
+ //
+ // Do nothing if either parameter is a NULL pointer.
+ //
+ if (Event == NULL || SnpPtr == NULL) {
+ return ;
+ }
+ //
+ // Do nothing if the SNP interface is not initialized.
+ //
+ switch (((SNP_DRIVER *) SnpPtr)->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ case EfiSimpleNetworkStarted:
+ default:
+ return ;
+ }
+ //
+ // Fill in CDB for UNDI GetStatus().
+ //
+ ((SNP_DRIVER *) SnpPtr)->cdb.OpCode = PXE_OPCODE_GET_STATUS;
+ ((SNP_DRIVER *) SnpPtr)->cdb.OpFlags = 0;
+ ((SNP_DRIVER *) SnpPtr)->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ ((SNP_DRIVER *) SnpPtr)->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ ((SNP_DRIVER *) SnpPtr)->cdb.DBsize = sizeof (UINT32) * 2;
+ ((SNP_DRIVER *) SnpPtr)->cdb.DBaddr = (UINT64) (UINTN) (((SNP_DRIVER *) SnpPtr)->db);
+ ((SNP_DRIVER *) SnpPtr)->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ ((SNP_DRIVER *) SnpPtr)->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ ((SNP_DRIVER *) SnpPtr)->cdb.IFnum = ((SNP_DRIVER *) SnpPtr)->if_num;
+ ((SNP_DRIVER *) SnpPtr)->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Clear contents of DB buffer.
+ //
+ ZeroMem (((SNP_DRIVER *) SnpPtr)->db, sizeof (UINT32) * 2);
+
+ //
+ // Issue UNDI command and check result.
+ //
+ (*((SNP_DRIVER *) SnpPtr)->issue_undi32_command) ((UINT64) (UINTN) &((SNP_DRIVER *) SnpPtr)->cdb);
+
+ if (((SNP_DRIVER *) SnpPtr)->cdb.StatCode != EFI_SUCCESS) {
+ return ;
+ }
+ //
+ // We might have a packet. Check the receive length and signal
+ // the event if the length is not zero.
+ //
+ CopyMem (
+ &PxeDbGetStatus,
+ ((SNP_DRIVER *) SnpPtr)->db,
+ sizeof (UINT32) * 2
+ );
+
+ if (PxeDbGetStatus.RxFrameLen != 0) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/* eof - WaitForPacket.c */
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml
new file mode 100644
index 0000000..7387603
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/build.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="SNP"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Universal\Network\Snp32_64\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="SNP">
+ <GenBuild baseName="SNP" mbdFilename="${MODULE_DIR}\SNP.mbd" msaFilename="${MODULE_DIR}\SNP.msa"/>
+ </target>
+ <target depends="SNP_clean" name="clean"/>
+ <target depends="SNP_cleanall" name="cleanall"/>
+ <target name="SNP_clean">
+ <OutputDirSetup baseName="SNP" mbdFilename="${MODULE_DIR}\SNP.mbd" msaFilename="${MODULE_DIR}\SNP.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SNP_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SNP_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="SNP_cleanall">
+ <OutputDirSetup baseName="SNP" mbdFilename="${MODULE_DIR}\SNP.mbd" msaFilename="${MODULE_DIR}\SNP.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\SNP_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\SNP_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**SNP*"/>
+ </delete>
+ </target>
+</project> \ No newline at end of file
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c
new file mode 100644
index 0000000..488efc6
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/callback.c
@@ -0,0 +1,613 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ callback.c
+
+Abstract:
+ This file contains two sets of callback routines for undi3.0 and undi3.1.
+ the callback routines for Undi3.1 have an extra parameter UniqueId which
+ stores the interface context for the NIC that snp is trying to talk..
+
+--*/
+
+
+#include "snp.h"
+
+//
+// Global variables
+// these 2 global variables are used only for 3.0 undi. we could not place
+// them in the snp structure because we will not know which snp structure
+// in the callback context!
+//
+STATIC BOOLEAN mInitializeLock = TRUE;
+STATIC EFI_LOCK mLock;
+
+//
+// End Global variables
+//
+extern EFI_PCI_IO_PROTOCOL *mPciIoFncs;
+
+VOID
+snp_undi32_callback_v2p_30 (
+ IN UINT64 CpuAddr,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with a virtual or CPU address that SNP provided
+ to convert it to a physical or device address. Since EFI uses the identical
+ mapping, this routine returns the physical address same as the virtual address
+ for most of the addresses. an address above 4GB cannot generally be used as a
+ device address, it needs to be mapped to a lower physical address. This routine
+ does not call the map routine itself, but it assumes that the mapping was done
+ at the time of providing the address to UNDI. This routine just looks up the
+ address in a map table (which is the v2p structure chain)
+
+Arguments:
+ CpuAddr - virtual address of a buffer
+ DeviceAddrPtr - pointer to the physical address
+
+Returns:
+ void - The DeviceAddrPtr will contain 0 in case of any error
+
+--*/
+{
+ struct s_v2p *v2p;
+ //
+ // Do nothing if virtual address is zero or physical pointer is NULL.
+ // No need to map if the virtual address is within 4GB limit since
+ // EFI uses identical mapping
+ //
+ if ((CpuAddr == 0) || (DeviceAddrPtr == 0)) {
+ DEBUG ((EFI_D_ERROR, "\nv2p: Null virtual address or physical pointer.\n"));
+ return ;
+ }
+
+ if (CpuAddr < FOUR_GIGABYTES) {
+ *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;
+ return ;
+ }
+ //
+ // SNP creates a vaddr tp paddr mapping at the time of calling undi with any
+ // big address, this callback routine just looks up in the v2p list and
+ // returns the physical address for any given virtual address.
+ //
+ if (find_v2p (&v2p, (VOID *) (UINTN) CpuAddr) != EFI_SUCCESS) {
+ *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;
+ } else {
+ *(UINT64 *) (UINTN) DeviceAddrPtr = v2p->paddr;
+ }
+}
+
+VOID
+snp_undi32_callback_block_30 (
+ IN UINT32 Enable
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants to have exclusive access to a critical
+ section of the code/data
+
+Arguments:
+ Enable - non-zero indicates acquire
+ zero indicates release
+
+Returns:
+ void
+--*/
+{
+ //
+ // tcpip was calling snp at tpl_notify and if we acquire a lock that was
+ // created at a lower level (TPL_CALLBACK) it gives an assert!
+ //
+ if (mInitializeLock) {
+ EfiInitializeLock (&mLock, EFI_TPL_NOTIFY);
+ mInitializeLock = FALSE;
+ }
+
+ if (Enable != 0) {
+ EfiAcquireLock (&mLock);
+ } else {
+ EfiReleaseLock (&mLock);
+ }
+}
+
+VOID
+snp_undi32_callback_delay_30 (
+ IN UINT64 MicroSeconds
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with the number of micro seconds when it wants to
+ pause.
+
+Arguments:
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10
+
+Returns:
+ void
+--*/
+{
+ if (MicroSeconds != 0) {
+ gBS->Stall ((UINTN) MicroSeconds);
+ }
+}
+
+VOID
+snp_undi32_callback_memio_30 (
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 Address,
+ IN OUT UINT64 BufferAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ This is the IO routine for UNDI. This is not currently being used by UNDI3.0
+ because Undi3.0 uses io/mem offsets relative to the beginning of the device
+ io/mem address and so it needs to use the PCI_IO_FUNCTION that abstracts the
+ start of the device's io/mem addresses. Since SNP cannot retrive the context
+ of the undi3.0 interface it cannot use the PCI_IO_FUNCTION that specific for
+ that NIC and uses one global IO functions structure, this does not work.
+ This however works fine for EFI1.0 Undis because they use absolute addresses
+ for io/mem access.
+
+Arguments:
+ ReadOrWrite - indicates read or write, IO or Memory
+ NumBytes - number of bytes to read or write
+ Address - IO or memory address to read from or write to
+ BufferAddr - memory location to read into or that contains the bytes
+ to write
+
+Returns:
+
+--*/
+{
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ switch (NumBytes) {
+ case 2:
+ Width = 1;
+ break;
+
+ case 4:
+ Width = 2;
+ break;
+
+ case 8:
+ Width = 3;
+ break;
+
+ default:
+ Width = 0;
+ }
+
+ switch (ReadOrWrite) {
+ case PXE_IO_READ:
+ mPciIoFncs->Io.Read (
+ mPciIoFncs,
+ Width,
+ 1, // BAR 1, IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_IO_WRITE:
+ mPciIoFncs->Io.Write (
+ mPciIoFncs,
+ Width,
+ 1, // BAR 1, IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_READ:
+ mPciIoFncs->Mem.Read (
+ mPciIoFncs,
+ Width,
+ 0, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_WRITE:
+ mPciIoFncs->Mem.Write (
+ mPciIoFncs,
+ Width,
+ 0, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+ }
+
+ return ;
+}
+//
+// New callbacks for 3.1:
+// there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses
+// the MemMap call to map the required address by itself!
+//
+VOID
+snp_undi32_callback_block (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI3.1 at undi_start time.
+ UNDI call this routine when it wants to have exclusive access to a critical
+ section of the code/data
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ Enable - non-zero indicates acquire
+ zero indicates release
+
+Returns:
+ void
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+ //
+ // tcpip was calling snp at tpl_notify and when we acquire a lock that was
+ // created at a lower level (TPL_CALLBACK) it gives an assert!
+ //
+ if (Enable != 0) {
+ EfiAcquireLock (&snp->lock);
+ } else {
+ EfiReleaseLock (&snp->lock);
+ }
+}
+
+VOID
+snp_undi32_callback_delay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with the number of micro seconds when it wants to
+ pause.
+
+Arguments:
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10
+
+Returns:
+ void
+--*/
+{
+ if (MicroSeconds != 0) {
+ gBS->Stall ((UINTN) MicroSeconds);
+ }
+}
+
+/*
+ * IO routine for UNDI start CPB.
+ */
+VOID
+snp_undi32_callback_memio (
+ UINT64 UniqueId,
+ UINT8 ReadOrWrite,
+ UINT8 NumBytes,
+ UINT64 Address,
+ UINT64 BufferAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ This is the IO routine for UNDI3.1.
+
+Arguments:
+ ReadOrWrite - indicates read or write, IO or Memory
+ NumBytes - number of bytes to read or write
+ Address - IO or memory address to read from or write to
+ BufferAddr - memory location to read into or that contains the bytes
+ to write
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+
+ Width = 0;
+ switch (NumBytes) {
+ case 2:
+ Width = 1;
+ break;
+
+ case 4:
+ Width = 2;
+ break;
+
+ case 8:
+ Width = 3;
+ break;
+ }
+
+ switch (ReadOrWrite) {
+ case PXE_IO_READ:
+ snp->IoFncs->Io.Read (
+ snp->IoFncs,
+ Width,
+ snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_IO_WRITE:
+ snp->IoFncs->Io.Write (
+ snp->IoFncs,
+ Width,
+ snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_READ:
+ snp->IoFncs->Mem.Read (
+ snp->IoFncs,
+ Width,
+ snp->MemoryBarIndex, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_WRITE:
+ snp->IoFncs->Mem.Write (
+ snp->IoFncs,
+ Width,
+ snp->MemoryBarIndex, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+ }
+
+ return ;
+}
+
+VOID
+snp_undi32_callback_map (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it has to map a CPU address to a device
+ address.
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ CpuAddr - Virtual address to be mapped!
+ NumBytes - size of memory to be mapped
+ Direction - direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ DeviceAddrPtr - pointer to return the mapped device address
+
+Returns:
+ None
+
+--*/
+{
+ EFI_PHYSICAL_ADDRESS *DevAddrPtr;
+ EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
+ UINTN BuffSize;
+ SNP_DRIVER *snp;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ BuffSize = (UINTN) NumBytes;
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+ DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
+
+ if (CpuAddr == 0) {
+ *DevAddrPtr = 0;
+ return ;
+ }
+
+ switch (Direction) {
+ case TO_AND_FROM_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
+ break;
+
+ case FROM_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterWrite;
+ break;
+
+ case TO_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterRead;
+ break;
+
+ default:
+ *DevAddrPtr = 0;
+ //
+ // any non zero indicates error!
+ //
+ return ;
+ }
+ //
+ // find an unused map_list entry
+ //
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ if (snp->map_list[Index].virt == 0) {
+ break;
+ }
+ }
+
+ if (Index >= MAX_MAP_LENGTH) {
+ SNP_PRINT (L"SNP maplist is FULL\n");
+ *DevAddrPtr = 0;
+ return ;
+ }
+
+ snp->map_list[Index].virt = (EFI_PHYSICAL_ADDRESS) CpuAddr;
+
+ Status = snp->IoFncs->Map (
+ snp->IoFncs,
+ DirectionFlag,
+ (VOID *) (UINTN) CpuAddr,
+ &BuffSize,
+ DevAddrPtr,
+ &(snp->map_list[Index].map_cookie)
+ );
+ if (Status != EFI_SUCCESS) {
+ *DevAddrPtr = 0;
+ snp->map_list[Index].virt = 0;
+ }
+
+ return ;
+}
+
+VOID
+snp_undi32_callback_unmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants to unmap an address that was previously
+ mapped using map callback
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ CpuAddr - Virtual address that was mapped!
+ NumBytes - size of memory mapped
+ Direction- direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ DeviceAddr - the mapped device address
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ UINT16 Index;
+
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ if (snp->map_list[Index].virt == CpuAddr) {
+ break;
+ }
+ }
+
+ if (Index >= MAX_MAP_LENGTH)
+ {
+#if SNP_DEBUG
+ Print (L"SNP could not find a mapping, failed to unmap.\n");
+#endif
+ return ;
+ }
+
+ snp->IoFncs->Unmap (snp->IoFncs, snp->map_list[Index].map_cookie);
+ snp->map_list[Index].virt = 0;
+ snp->map_list[Index].map_cookie = NULL;
+ return ;
+}
+
+VOID
+snp_undi32_callback_sync (
+ UINT64 UniqueId,
+ UINT64 CpuAddr,
+ UINT32 NumBytes,
+ UINT32 Direction,
+ UINT64 DeviceAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants synchronize the virtual buffer contents
+ with the mapped buffer contents. The virtual and mapped buffers need not
+ correspond to the same physical memory (especially if the virtual address is
+ > 4GB). Depending on the direction for which the buffer is mapped, undi will
+ need to synchronize their contents whenever it writes to/reads from the buffer
+ using either the cpu address or the device address.
+
+ EFI does not provide a sync call, since virt=physical, we sould just do
+ the synchronization ourself here!
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ CpuAddr - Virtual address that was mapped!
+ NumBytes - size of memory mapped
+ Direction- direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ DeviceAddr - the mapped device address
+
+Returns:
+
+--*/
+{
+ if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
+ return ;
+
+ }
+
+ switch (Direction) {
+ case FROM_DEVICE:
+ CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
+ break;
+
+ case TO_DEVICE:
+ CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
+ break;
+ }
+
+ return ;
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c
new file mode 100644
index 0000000..a3fa173
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/get_status.c
@@ -0,0 +1,193 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ get_status.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_getstatus (
+ SNP_DRIVER *snp,
+ UINT32 *InterruptStatusPtr,
+ VOID **TransmitBufferListPtr
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to get the status of the interrupts, get the list of
+ transmit buffers that completed transmitting!
+
+Arguments:
+ snp - pointer to snp driver structure
+ InterruptStatusPtr - a non null pointer gets the interrupt status
+ TransmitBufferListPtrs - a non null ointer gets the list of pointers of previously
+ transmitted buffers whose transmission was completed
+ asynchrnously.
+
+Returns:
+
+--*/
+{
+ PXE_DB_GET_STATUS *db;
+ UINT16 InterruptFlags;
+ UINT64 TempData;
+
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_GET_STATUS;
+
+ snp->cdb.OpFlags = 0;
+
+ if (TransmitBufferListPtr != NULL) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;
+ }
+
+ if (InterruptStatusPtr != NULL) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;
+ }
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+
+ //
+ // size DB for return of one buffer
+ //
+ snp->cdb.DBsize = (UINT16) (((UINT16) (sizeof (PXE_DB_GET_STATUS)) - (UINT16) (sizeof db->TxBuffer)) + (UINT16) (sizeof db->TxBuffer[0]));
+
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_status() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.get_status() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // report the values back..
+ //
+ if (InterruptStatusPtr != NULL) {
+ InterruptFlags = (UINT16) (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);
+
+ *InterruptStatusPtr = 0;
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ }
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
+ }
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
+ }
+
+ }
+
+ if (TransmitBufferListPtr != NULL) {
+ *TransmitBufferListPtr =
+ (
+ (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) ||
+ (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY)
+ ) ? 0 : (VOID *) (UINTN) db->TxBuffer[0];
+
+ TempData = (UINT64) (UINTN) (*TransmitBufferListPtr);
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ del_v2p ((VOID *) (UINTN) (db->TxBuffer[0]));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_get_status (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINT32 *InterruptStatusPtr OPTIONAL,
+ OUT VOID **TransmitBufferListPtr OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for getting the status
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_getstatus routine to actually get the undi status
+
+Arguments:
+ this - context pointer
+ InterruptStatusPtr - a non null pointer gets the interrupt status
+ TransmitBufferListPtrs - a non null ointer gets the list of pointers of previously
+ transmitted buffers whose transmission was completed
+ asynchrnously.
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (InterruptStatusPtr == NULL && TransmitBufferListPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return pxe_getstatus (snp, InterruptStatusPtr, TransmitBufferListPtr);
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c
new file mode 100644
index 0000000..d05395b
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/initialize.c
@@ -0,0 +1,244 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ initialize.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-09 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+VOID
+EFIAPI
+SnpWaitForPacketNotify (
+ IN EFI_EVENT Event,
+ IN VOID *SnpPtr
+ );
+
+EFI_STATUS
+pxe_init (
+ SNP_DRIVER *snp,
+ UINT16 CableDetectFlag
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to initialize the interface.
+
+Arguments:
+ snp - pointer to snp driver structure
+ CableDetectFlag - Do/don't detect the cable (depending on what undi supports)
+
+Returns:
+
+--*/
+{
+ PXE_CPB_INITIALIZE *cpb;
+ VOID *addr;
+ EFI_STATUS Status;
+
+ cpb = snp->cpb;
+ if (snp->tx_rx_bufsize != 0) {
+ Status = snp->IoFncs->AllocateBuffer (
+ snp->IoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->pxe_init() AllocateBuffer %xh (%r)\n",
+ Status,
+ Status)
+ );
+
+ return Status;
+ }
+
+ ASSERT (addr);
+
+ snp->tx_rx_buffer = addr;
+ }
+
+ cpb->MemoryAddr = (UINT64) (UINTN) snp->tx_rx_buffer;
+
+ cpb->MemoryLength = snp->tx_rx_bufsize;
+
+ //
+ // let UNDI decide/detect these values
+ //
+ cpb->LinkSpeed = 0;
+ cpb->TxBufCnt = 0;
+ cpb->TxBufSize = 0;
+ cpb->RxBufCnt = 0;
+ cpb->RxBufSize = 0;
+
+ cpb->DuplexMode = PXE_DUPLEX_DEFAULT;
+
+ cpb->LoopBackMode = LOOPBACK_NORMAL;
+
+ snp->cdb.OpCode = PXE_OPCODE_INITIALIZE;
+ snp->cdb.OpFlags = CableDetectFlag;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_INITIALIZE);
+ snp->cdb.DBsize = sizeof (PXE_DB_INITIALIZE);
+
+ snp->cdb.CPBaddr = (UINT64) (UINTN) snp->cpb;
+ snp->cdb.DBaddr = (UINT64) (UINTN) snp->db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.initialize() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode == PXE_STATCODE_SUCCESS) {
+ snp->mode.State = EfiSimpleNetworkInitialized;
+
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi.initialize() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ if (snp->tx_rx_buffer != NULL) {
+ snp->IoFncs->FreeBuffer (
+ snp->IoFncs,
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),
+ (VOID *) snp->tx_rx_buffer
+ );
+ }
+
+ snp->tx_rx_buffer = NULL;
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN UINTN extra_rx_buffer_size OPTIONAL,
+ IN UINTN extra_tx_buffer_size OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for initializing the interface
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_initialize routine to actually do the undi initialization
+
+Arguments:
+ this - context pointer
+ extra_rx_buffer_size - optional parameter, indicates extra space for rx_buffers
+ extra_tx_buffer_size - optional parameter, indicates extra space for tx_buffers
+
+Returns:
+
+--*/
+{
+ EFI_STATUS EfiStatus;
+ SNP_DRIVER *snp;
+
+ //
+ //
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ //
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ //
+ //
+ EfiStatus = gBS->CreateEvent (
+ EFI_EVENT_NOTIFY_WAIT,
+ EFI_TPL_NOTIFY,
+ &SnpWaitForPacketNotify,
+ snp,
+ &snp->snp.WaitForPacket
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ snp->snp.WaitForPacket = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ //
+ //
+ snp->mode.MCastFilterCount = 0;
+ snp->mode.ReceiveFilterSetting = 0;
+ ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);
+ CopyMem (
+ &snp->mode.CurrentAddress,
+ &snp->mode.PermanentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ //
+ // Compute tx/rx buffer sizes based on UNDI init info and parameters.
+ //
+ snp->tx_rx_bufsize = (UINT32) (snp->init_info.MemoryRequired + extra_rx_buffer_size + extra_tx_buffer_size);
+
+ if (snp->mode.MediaPresentSupported) {
+ if (pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {
+ snp->mode.MediaPresent = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+
+ snp->mode.MediaPresent = FALSE;
+
+ EfiStatus = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
+
+ if (EFI_ERROR (EfiStatus)) {
+ gBS->CloseEvent (snp->snp.WaitForPacket);
+ }
+
+ return EfiStatus;
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c
new file mode 100644
index 0000000..995e33e
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/mcast_ip_to_mac.c
@@ -0,0 +1,167 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ mcast_ip_to_mac.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_ip2mac (
+ IN SNP_DRIVER *snp,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ IN OUT EFI_MAC_ADDRESS *MAC
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to convert an multicast IP address to a MAC address
+
+Arguments:
+ snp - pointer to snp driver structure
+ IPv6 - flag to indicate if this is an ipv6 address
+ IP - multicast IP address
+ MAC - pointer to hold the return MAC address
+
+Returns:
+
+--*/
+{
+ PXE_CPB_MCAST_IP_TO_MAC *cpb;
+ PXE_DB_MCAST_IP_TO_MAC *db;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_MCAST_IP_TO_MAC;
+ snp->cdb.OpFlags = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC);
+ snp->cdb.CPBsize = sizeof (PXE_CPB_MCAST_IP_TO_MAC);
+ snp->cdb.DBsize = sizeof (PXE_DB_MCAST_IP_TO_MAC);
+
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ CopyMem (&cpb->IP, IP, sizeof (PXE_IP_ADDR));
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.mcast_ip_to_mac() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_INVALID_CPB:
+ return EFI_INVALID_PARAMETER;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+ return EFI_UNSUPPORTED;
+
+ default:
+ //
+ // UNDI command failed. Return EFI_DEVICE_ERROR
+ // to caller.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (MAC, &db->MAC, sizeof (PXE_MAC_ADDR));
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_mcast_ip_to_mac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for converting a multicast IP address to
+ a MAC address.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_ip2mac routine to actually do the conversion
+
+Arguments:
+ this - context pointer
+ IPv6 - flag to indicate if this is an ipv6 address
+ IP - multicast IP address
+ MAC - pointer to hold the return MAC address
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (IP == NULL || MAC == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return pxe_ip2mac (snp, IPv6, IP, MAC);
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c
new file mode 100644
index 0000000..0167e4d
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/nvdata.c
@@ -0,0 +1,183 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ nvdata.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_nvdata_read (
+ IN SNP_DRIVER *snp,
+ IN UINTN RegOffset,
+ IN UINTN NumBytes,
+ IN OUT VOID *BufferPtr
+ )
+/*++
+
+Routine Description:
+ This routine calls Undi to read the desired number of eeprom bytes.
+
+Arguments:
+ snp - pointer to the snp driver structure
+ RegOffset - eeprom register value relative to the base address
+ NumBytes - number of bytes to read
+ BufferPtr - pointer where to read into
+
+Returns:
+
+--*/
+{
+ PXE_DB_NVDATA *db;
+
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_NVDATA;
+
+ snp->cdb.OpFlags = PXE_OPFLAGS_NVDATA_READ;
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_NVDATA);
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata () "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.nvdata() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_UNSUPPORTED;
+
+ default:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.nvdata() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (BufferPtr, db->Data.Byte + RegOffset, NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_nvdata (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ReadOrWrite,
+ IN UINTN RegOffset,
+ IN UINTN NumBytes,
+ IN OUT VOID *BufferPtr
+ )
+/*++
+
+Routine Description:
+ This is an interface call provided by SNP.
+ It does the basic checking on the input parameters and retrieves snp structure
+ and then calls the read_nvdata() call which does the actual reading
+
+Arguments:
+ this - context pointer
+ ReadOrWrite - true for reading and false for writing
+ RegOffset - eeprom register relative to the base
+ NumBytes - how many bytes to read
+ BufferPtr - address of memory to read into
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Return error if non-volatile memory variables are not valid.
+ //
+ if (snp->mode.NvRamSize == 0 || snp->mode.NvRamAccessSize == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check for invalid parameter combinations.
+ //
+ if ((NumBytes == 0) ||
+ (BufferPtr == NULL) ||
+ (RegOffset >= snp->mode.NvRamSize) ||
+ (RegOffset + NumBytes > snp->mode.NvRamSize) ||
+ (NumBytes % snp->mode.NvRamAccessSize != 0) ||
+ (RegOffset % snp->mode.NvRamAccessSize != 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // check the implementation flags of undi if we can write the nvdata!
+ //
+ if (!ReadOrWrite) {
+ return EFI_UNSUPPORTED;
+ } else {
+ return pxe_nvdata_read (snp, RegOffset, NumBytes, BufferPtr);
+ }
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c
new file mode 100644
index 0000000..5a41b8a
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive.c
@@ -0,0 +1,255 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ receive.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_receive (
+ SNP_DRIVER *snp,
+ VOID *BufferPtr,
+ UINTN *BuffSizePtr,
+ UINTN *HeaderSizePtr,
+ EFI_MAC_ADDRESS *SourceAddrPtr,
+ EFI_MAC_ADDRESS *DestinationAddrPtr,
+ UINT16 *ProtocolPtr
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to receive a packet and fills in the data in the
+ input pointers!
+
+Arguments:
+ snp - pointer to snp driver structure
+ BufferPtr - pointer to the memory for the received data
+ BuffSizePtr - is a pointer to the length of the buffer on entry and contains
+ the length of the received data on return
+ HeaderSizePtr - pointer to the header portion of the data received.
+ SourceAddrPtr - optional parameter, is a pointer to contain the source
+ ethernet address on return
+ DestinationAddrPtr - optional parameter, is a pointer to contain the destination
+ ethernet address on return
+ ProtocolPtr - optional parameter, is a pointer to contain the protocol type
+ from the ethernet header on return
+
+
+Returns:
+
+--*/
+{
+ PXE_CPB_RECEIVE *cpb;
+ PXE_DB_RECEIVE *db;
+ UINTN buf_size;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ buf_size = *BuffSizePtr;
+ //
+ // IMPORTANT NOTE:
+ // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB,
+ // DO NOT call the map function on the given buffer, instead use
+ // a global buffer. The reason is that UNDI3.0 has some unnecessary check of
+ // making sure that all the addresses (whether or not they will be given
+ // to the NIC ) supplied to it are below 4GB. It may or may not use
+ // the mapped address after all (like in case of CPB and DB)!
+ // Instead of using the global buffer whose address is allocated within the
+ // 2GB limit if I start mapping the given buffer we lose the data, here is
+ // why!!!
+ // if our address is > 4GB, the map call creates another buffer below 2GB and
+ // copies data to/from the original buffer to the mapped buffer either at
+ // map time or unmap time depending on the map direction.
+ // UNDI will not complain since we already mapped the buffer to be
+ // within the 2GB limit but will not use (I know undi) the mapped address
+ // since it does not give the user buffers to the NIC's receive unit,
+ // It just copies the received packet into the user buffer using the virtual
+ // (CPU) address rather than the mapped (device or physical) address.
+ // When the UNDI call returns, if we then unmap the buffer, we will lose
+ // the contents because unmap copies the contents of the mapped buffer into
+ // the original buffer (since the direction is FROM_DEVICE) !!!
+ //
+ // this is not a problem in Undi 3.1 because this undi uses it's map callback
+ // routine to map a cpu address to device address and it does it only if
+ // it is giving the address to the device and unmaps it before using the cpu
+ // address!
+ //
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ cpb->BufferAddr = (UINT64) (UINTN) snp->receive_buf;
+ cpb->BufferLen = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ } else {
+ cpb->BufferAddr = (UINT64) (UINTN) BufferPtr;
+ cpb->BufferLen = (UINT32) *BuffSizePtr;
+ }
+
+ cpb->reserved = 0;
+
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_RECEIVE);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_RECEIVE);
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_INFO, "\nsnp->undi.receive () "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_NO_DATA:
+ DEBUG (
+ (EFI_D_INFO,
+ "\nsnp->undi.receive () %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_NOT_READY;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ *BuffSizePtr = db->FrameLen;
+
+ if (HeaderSizePtr != NULL) {
+ *HeaderSizePtr = db->MediaHeaderLen;
+ }
+
+ if (SourceAddrPtr != NULL) {
+ CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize);
+ }
+
+ if (DestinationAddrPtr != NULL) {
+ CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize);
+ }
+
+ if (ProtocolPtr != NULL) {
+ *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /* we need to do the byte swapping */
+ }
+
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ }
+
+ return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINTN *HeaderSizePtr OPTIONAL,
+ IN OUT UINTN *BuffSizePtr,
+ OUT VOID *BufferPtr,
+ OUT EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
+ OUT EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
+ OUT UINT16 *ProtocolPtr OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for receiving network data.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_receive routine to actually do the receive!
+
+Arguments:
+ this - context pointer
+ HeaderSizePtr - optional parameter and is a pointer to the header portion of
+ the data received.
+ BuffSizePtr - is a pointer to the length of the buffer on entry and contains
+ the length of the received data on return
+ BufferPtr - pointer to the memory for the received data
+ SourceAddrPtr - optional parameter, is a pointer to contain the source
+ ethernet address on return
+ DestinationAddrPtr - optional parameter, is a pointer to contain the destination
+ ethernet address on return
+ ProtocolPtr - optional parameter, is a pointer to contain the protocol type
+ from the ethernet header on return
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!snp->mode.ReceiveFilterSetting) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return pxe_receive (
+ snp,
+ BufferPtr,
+ BuffSizePtr,
+ HeaderSizePtr,
+ SourceAddrPtr,
+ DestinationAddrPtr,
+ ProtocolPtr
+ );
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c
new file mode 100644
index 0000000..233448c
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/receive_filters.c
@@ -0,0 +1,411 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ receive_filters.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_rcvfilter_enable (
+ SNP_DRIVER *snp,
+ UINT32 EnableFlags,
+ UINTN MCastAddressCount,
+ EFI_MAC_ADDRESS *MCastAddressList
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to enable the receive filters.
+
+Arguments:
+ snp - pointer to snp driver structure
+ EnableFlags - bit mask for enabling the receive filters
+ MCastAddressCount - multicast address count for a new multicast address list
+ MCastAddressList - list of new multicast addresses
+
+Returns:
+
+--*/
+{
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ }
+
+ if (MCastAddressCount != 0) {
+ snp->cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
+ snp->cdb.CPBaddr = (UINT64) (UINTN) snp->cpb;
+ CopyMem (snp->cpb, MCastAddressList, snp->cdb.CPBsize);
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_INVALID_CDB:
+ case PXE_STATCODE_INVALID_CPB:
+ case PXE_STATCODE_INVALID_PARAMETER:
+ return EFI_INVALID_PARAMETER;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+pxe_rcvfilter_disable (
+ SNP_DRIVER *snp,
+ UINT32 DisableFlags,
+ BOOLEAN ResetMCastList
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to disable the receive filters.
+
+Arguments:
+ snp - pointer to snp driver structure
+ DisableFlags - bit mask for disabling the receive filters
+ ResetMCastList - boolean flag to reset/delete the multicast filter list
+
+Returns:
+
+--*/
+{
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ snp->cdb.OpFlags = (UINT16) (DisableFlags ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
+
+ if (ResetMCastList) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+pxe_rcvfilter_read (
+ SNP_DRIVER *snp
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to read the receive filters.
+
+Arguments:
+ snp - pointer to snp driver structure
+
+Returns:
+
+--*/
+{
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = (UINT16) (snp->mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ if (snp->cdb.DBsize == 0) {
+ snp->cdb.DBaddr = (UINT64) NULL;
+ } else {
+ snp->cdb.DBaddr = (UINT64) (UINTN) snp->db;
+ ZeroMem (snp->db, snp->cdb.DBsize);
+ }
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Convert UNDI32 StatFlags to EFI SNP filter flags.
+ //
+ snp->mode.ReceiveFilterSetting = 0;
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+ }
+
+ CopyMem (snp->mode.MCastFilter, snp->db, snp->cdb.DBsize);
+
+ //
+ // Count number of active entries in multicast filter list.
+ //
+ {
+ EFI_MAC_ADDRESS ZeroMacAddr;
+
+ SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
+
+ for (snp->mode.MCastFilterCount = 0;
+ snp->mode.MCastFilterCount < snp->mode.MaxMCastFilterCount;
+ snp->mode.MCastFilterCount++
+ ) {
+ if (CompareMem (
+ &snp->mode.MCastFilter[snp->mode.MCastFilterCount],
+ &ZeroMacAddr,
+ sizeof ZeroMacAddr
+ ) == 0) {
+ break;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_receive_filters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINT32 EnableFlags,
+ IN UINT32 DisableFlags,
+ IN BOOLEAN ResetMCastList,
+ IN UINTN MCastAddressCount OPTIONAL,
+ IN EFI_MAC_ADDRESS * MCastAddressList OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for reading/enabling/disabling the
+ receive filters.
+ This routine basically retrieves snp structure, checks the SNP state and
+ checks the parameter validity, calls one of the above routines to actually
+ do the work
+
+Arguments:
+ this - context pointer
+ EnableFlags - bit mask for enabling the receive filters
+ DisableFlags - bit mask for disabling the receive filters
+ ResetMCastList - boolean flag to reset/delete the multicast filter list
+ MCastAddressCount - multicast address count for a new multicast address list
+ MCastAddressList - list of new multicast addresses
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // check if we are asked to enable or disable something that the UNDI
+ // does not even support!
+ //
+ if ((EnableFlags &~snp->mode.ReceiveFilterMask) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DisableFlags &~snp->mode.ReceiveFilterMask) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ResetMCastList) {
+ DisableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & snp->mode.ReceiveFilterMask;
+ MCastAddressCount = 0;
+ MCastAddressList = NULL;
+ } else {
+ if (MCastAddressCount != 0) {
+ if (MCastAddressCount > snp->mode.MaxMCastFilterCount) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MCastAddressList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (EnableFlags == 0 && DisableFlags == 0 && !ResetMCastList && MCastAddressCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastAddressCount == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((EnableFlags != 0) || (MCastAddressCount != 0)) {
+ Status = pxe_rcvfilter_enable (
+ snp,
+ EnableFlags,
+ MCastAddressCount,
+ MCastAddressList
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ }
+
+ if ((DisableFlags != 0) || ResetMCastList) {
+ Status = pxe_rcvfilter_disable (snp, DisableFlags, ResetMCastList);
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ }
+
+ return pxe_rcvfilter_read (snp);
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c
new file mode 100644
index 0000000..8d56ecf
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/reset.c
@@ -0,0 +1,129 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ reset.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-09 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_reset (
+ SNP_DRIVER *snp
+ )
+/*++
+
+Routine Description:
+ This routine calls undi to reset the nic.
+
+Arguments:
+ snp - pointer to the snp driver structure
+
+Returns:
+ EFI_SUCCESSFUL for a successful completion
+ other for failed calls
+
+--*/
+{
+ snp->cdb.OpCode = PXE_OPCODE_RESET;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.reset() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi32.reset() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ //
+ // UNDI could not be reset. Return UNDI error.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ExtendedVerification
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for resetting the NIC
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_reset routine to actually do the reset!
+
+Arguments:
+ this - context pointer
+ ExtendedVerification - not implemented
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ //
+ // Resolve Warning 4 unreferenced parameter problem
+ //
+ ExtendedVerification = 0;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ return pxe_reset (snp);
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c
new file mode 100644
index 0000000..efa6cf7
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/shutdown.c
@@ -0,0 +1,152 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ shutdown.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-14 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_shutdown (
+ IN SNP_DRIVER *snp
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to shut down the interface.
+
+Arguments:
+ snp - pointer to snp driver structure
+
+Returns:
+
+--*/
+{
+ snp->cdb.OpCode = PXE_OPCODE_SHUTDOWN;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI could not be shutdown. Return UNDI error.
+ //
+ DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Free allocated memory.
+ //
+ if (snp->tx_rx_buffer != NULL) {
+ snp->IoFncs->FreeBuffer (
+ snp->IoFncs,
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),
+ (VOID *) snp->tx_rx_buffer
+ );
+ }
+
+ snp->tx_rx_buffer = NULL;
+ snp->tx_rx_bufsize = 0;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for shutting down the interface
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_shutdown routine to actually do the undi shutdown
+
+Arguments:
+ this - context pointer
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS status;
+
+ //
+ //
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ //
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ //
+ //
+ status = pxe_shutdown (snp);
+
+ snp->mode.State = EfiSimpleNetworkStarted;
+ snp->mode.ReceiveFilterSetting = 0;
+
+ snp->mode.MCastFilterCount = 0;
+ snp->mode.ReceiveFilterSetting = 0;
+ ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);
+ CopyMem (
+ &snp->mode.CurrentAddress,
+ &snp->mode.PermanentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ gBS->CloseEvent (snp->snp.WaitForPacket);
+
+ return status;
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c
new file mode 100644
index 0000000..ab3c997
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c
@@ -0,0 +1,1315 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ snp.c
+
+Abstract:
+
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_start (
+ SNP_DRIVER *snp
+ );
+EFI_STATUS
+pxe_stop (
+ SNP_DRIVER *snp
+ );
+EFI_STATUS
+pxe_init (
+ SNP_DRIVER *snp,
+ UINT16 OpFlags
+ );
+EFI_STATUS
+pxe_shutdown (
+ SNP_DRIVER *snp
+ );
+EFI_STATUS
+pxe_get_stn_addr (
+ SNP_DRIVER *snp
+ );
+
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+ IN EFI_HANDLE image_handle,
+ IN EFI_SYSTEM_TABLE *system_table
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Simple Network Protocol Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {
+ SimpleNetworkDriverSupported,
+ SimpleNetworkDriverStart,
+ SimpleNetworkDriverStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Module global variables needed to support undi 3.0 interface
+//
+EFI_PCI_IO_PROTOCOL *mPciIoFncs;
+struct s_v2p *_v2p = NULL; // undi3.0 map_list head
+// End Global variables
+//
+EFI_STATUS
+add_v2p (
+ IN OUT struct s_v2p **v2p,
+ EFI_PCI_IO_PROTOCOL_OPERATION type,
+ VOID *vaddr,
+ UINTN bsize
+ )
+/*++
+
+Routine Description:
+ This routine maps the given CPU address to a Device address. It creates a
+ an entry in the map list with the virtual and physical addresses and the
+ un map cookie.
+
+Arguments:
+ v2p - pointer to return a map list node pointer.
+ type - the direction in which the data flows from the given virtual address
+ device->cpu or cpu->device or both ways.
+ vaddr - virtual address (or CPU address) to be mapped
+ bsize - size of the buffer to be mapped.
+
+Returns:
+
+ EFI_SUCEESS - routine has completed the mapping
+ other - error as indicated.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (struct s_v2p),
+ (VOID **) v2p
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ type,
+ vaddr,
+ &bsize,
+ &(*v2p)->paddr,
+ &(*v2p)->unmap
+ );
+ if (Status != EFI_SUCCESS) {
+ gBS->FreePool (*v2p);
+ return Status;
+ }
+ (*v2p)->vaddr = vaddr;
+ (*v2p)->bsize = bsize;
+ (*v2p)->next = _v2p;
+ _v2p = *v2p;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+find_v2p (
+ struct s_v2p **v2p,
+ VOID *vaddr
+ )
+/*++
+
+Routine Description:
+ This routine searches the linked list of mapped address nodes (for undi3.0
+ interface) to find the node that corresponds to the given virtual address and
+ returns a pointer to that node.
+
+Arguments:
+ v2p - pointer to return a map list node pointer.
+ vaddr - virtual address (or CPU address) to be searched in the map list
+
+Returns:
+
+ EFI_SUCEESS - if a match found!
+ Other - match not found
+
+--*/
+{
+ struct s_v2p *v;
+
+ if (v2p == NULL || vaddr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (v = _v2p; v != NULL; v = v->next) {
+ if (v->vaddr == vaddr) {
+ *v2p = v;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+del_v2p (
+ VOID *vaddr
+ )
+/*++
+
+Routine Description:
+ This routine unmaps the given virtual address and frees the memory allocated
+ for the map list node corresponding to that address.
+
+Arguments:
+ vaddr - virtual address (or CPU address) to be unmapped
+
+Returns:
+ EFI_SUCEESS - if successfully unmapped
+ Other - as indicated by the error
+
+
+--*/
+{
+ struct s_v2p *v;
+ struct s_v2p *t;
+ EFI_STATUS Status;
+
+ if (vaddr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (_v2p == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Is our node at the head of the list??
+ //
+ if ((v = _v2p)->vaddr == vaddr) {
+ _v2p = _v2p->next;
+
+ Status = mPciIoFncs->Unmap (mPciIoFncs, v->unmap);
+
+ gBS->FreePool (v);
+
+#if SNP_DEBUG
+ if (Status) {
+ Print (L"Unmap failed with status = %x\n", Status);
+ }
+#endif
+ return Status;
+ }
+
+ for (; v->next != NULL; v = t) {
+ if ((t = v->next)->vaddr == vaddr) {
+ v->next = t->next;
+ Status = mPciIoFncs->Unmap (mPciIoFncs, t->unmap);
+ gBS->FreePool (t);
+#if SNP_DEBUG
+ if (Status) {
+ Print (L"Unmap failed with status = %x\n", Status);
+ }
+#endif
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+#if SNP_DEBUG
+VOID
+snp_wait_for_key (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Wait for a key stroke, used for debugging purposes
+
+Arguments:
+ none
+
+Returns:
+ none
+
+--*/
+{
+ EFI_INPUT_KEY key;
+
+ Aprint ("\nPress any key to continue\n");
+
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &key) == EFI_NOT_READY) {
+ ;
+ }
+}
+#endif
+
+STATIC
+EFI_STATUS
+issue_hwundi_command (
+ UINT64 cdb
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+#if SNP_DEBUG
+ Aprint ("\nissue_hwundi_command() - This should not be called!");
+ snp_wait_for_key ();
+#endif
+ if (cdb == 0) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // %%TBD - For now, nothing is done.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+UINT8
+calc_8bit_cksum (
+ VOID *ptr,
+ UINTN len
+ )
+/*++
+
+Routine Description:
+ Compute 8-bit checksum of a buffer.
+
+Arguments:
+ ptr - Pointer to buffer.
+ len - Length of buffer in bytes.
+
+Returns:
+ 8-bit checksum of all bytes in buffer.
+ If ptr is NULL or len is zero, zero is returned.
+
+--*/
+{
+ UINT8 *bptr;
+ UINT8 cksum;
+
+ bptr = ptr;
+ cksum = 0;
+
+ if (ptr == NULL || len == 0) {
+ return 0;
+ }
+
+ while (len--) {
+ cksum = (UINT8) (cksum +*bptr++);
+ }
+
+ return cksum;
+}
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+ Routine Description:
+ Test to see if this driver supports Controller. Any Controller
+ that contains a Nii protocol can be supported.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_ALREADY_STARTED - This driver is already running on this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
+ PXE_UNDI *pxe;
+ BOOLEAN IsUndi31;
+
+ IsUndi31 = FALSE;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &NiiProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED)
+ {
+#if SNP_DEBUG
+ Aprint ("Support(): Already Started. on handle %x\n", Controller);
+#endif
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (!EFI_ERROR (Status))
+ {
+
+#if SNP_DEBUG
+ Aprint ("Support(): UNDI3.1 found on handle %x\n", Controller);
+ snp_wait_for_key ();
+#endif
+ IsUndi31 = TRUE;
+ } else {
+ //
+ // try the older 3.0 driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ (VOID **) &NiiProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+#if SNP_DEBUG
+ Aprint ("Support(): UNDI3.0 found on handle %x\n", Controller);
+ snp_wait_for_key ();
+#endif
+ }
+ //
+ // check the version, we don't want to connect to the undi16
+ //
+ if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ //
+ // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
+ //
+ if (NiiProtocol->ID & 0x0F) {
+ DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);
+
+ //
+ // Verify !PXE revisions.
+ //
+ if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
+ DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (pxe->hw.Rev < PXE_ROMID_REV) {
+ DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
+
+ DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+
+ } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
+ DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ //
+ // Do S/W UNDI specific checks.
+ //
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
+ if (pxe->sw.EntryPoint < pxe->sw.Len) {
+ DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (pxe->sw.BusCnt == 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ Status = EFI_SUCCESS;
+#if SNP_DEBUG
+ Aprint ("Support(): supported on %x\n", Controller);
+ snp_wait_for_key ();
+#endif
+
+Done:
+ if (IsUndi31) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ } else {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ called for any handle that we said "supported" in the above call!
+
+Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to start
+ RemainingDevicePath - Not used.
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ other - This driver failed to start this device.
+
+--*/
+{
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
+ EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;
+ EFI_STATUS Status;
+ PXE_UNDI *pxe;
+ SNP_DRIVER *snp;
+ VOID *addr;
+ VOID *addrUnmap;
+ EFI_PHYSICAL_ADDRESS paddr;
+ EFI_HANDLE Handle;
+ UINTN Size;
+ BOOLEAN UndiNew;
+ PXE_PCI_CONFIG_INFO ConfigInfo;
+ PCI_TYPE00 *ConfigHeader;
+ UINT32 *TempBar;
+ UINT8 BarIndex;
+ PXE_STATFLAGS InitStatFlags;
+
+ DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &NiiDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateDevicePath (
+ &gEfiPciIoProtocolGuid,
+ &NiiDevicePath,
+ &Handle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &mPciIoFncs,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the NII interface. look for 3.1 undi first, if it is not there
+ // then look for 3.0, validate the interface.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &Nii,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // probably not a 3.1 UNDI
+ //
+ UndiNew = TRUE;
+#if SNP_DEBUG
+ Aprint ("Start(): UNDI3.1 found\n");
+ snp_wait_for_key ();
+#endif
+ } else {
+ UndiNew = FALSE;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ (VOID **) &Nii,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+ }
+
+#if SNP_DEBUG
+ Aprint ("Start(): UNDI3.0 found\n");
+ snp_wait_for_key ();
+#endif
+ }
+
+ pxe = (PXE_UNDI *) (UINTN) (Nii->ID);
+
+ if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
+ goto NiiError;
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
+ //
+ // We can get any packets.
+ //
+ } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
+ //
+ // We need to be able to get broadcast packets for DHCP.
+ // If we do not have promiscuous support, we must at least have
+ // broadcast support or we cannot do DHCP!
+ //
+ } else {
+ DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
+ goto NiiError;
+ }
+ //
+ // OK, we like this UNDI, and we know snp is not already there on this handle
+ // Allocate and initialize a new simple network protocol structure.
+ //
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
+ goto NiiError;
+ }
+
+ snp = (SNP_DRIVER *) (UINTN) addr;
+
+ if (!UndiNew) {
+ Size = SNP_MEM_PAGES (sizeof (SNP_DRIVER));
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &addrUnmap
+ );
+
+ ASSERT (paddr);
+
+ DEBUG ((EFI_D_NET, "\nSNP_DRIVER @ %Xh, sizeof(SNP_DRIVER) == %d", addr, sizeof (SNP_DRIVER)));
+ snp = (SNP_DRIVER *) (UINTN) paddr;
+ snp->SnpDriverUnmap = addrUnmap;
+ }
+
+ ZeroMem (snp, sizeof (SNP_DRIVER));
+
+ snp->IoFncs = mPciIoFncs;
+ snp->IsOldUndi = (BOOLEAN) (!UndiNew);
+
+ snp->Signature = SNP_DRIVER_SIGNATURE;
+
+ EfiInitializeLock (&snp->lock, EFI_TPL_NOTIFY);
+
+ snp->snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+ snp->snp.Start = snp_undi32_start;
+ snp->snp.Stop = snp_undi32_stop;
+ snp->snp.Initialize = snp_undi32_initialize;
+ snp->snp.Reset = snp_undi32_reset;
+ snp->snp.Shutdown = snp_undi32_shutdown;
+ snp->snp.ReceiveFilters = snp_undi32_receive_filters;
+ snp->snp.StationAddress = snp_undi32_station_address;
+ snp->snp.Statistics = snp_undi32_statistics;
+ snp->snp.MCastIpToMac = snp_undi32_mcast_ip_to_mac;
+ snp->snp.NvData = snp_undi32_nvdata;
+ snp->snp.GetStatus = snp_undi32_get_status;
+ snp->snp.Transmit = snp_undi32_transmit;
+ snp->snp.Receive = snp_undi32_receive;
+ snp->snp.WaitForPacket = NULL;
+
+ snp->snp.Mode = &snp->mode;
+
+ snp->tx_rx_bufsize = 0;
+ snp->tx_rx_buffer = NULL;
+
+ snp->if_num = Nii->IfNum;
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
+ snp->is_swundi = FALSE;
+ snp->issue_undi32_command = &issue_hwundi_command;
+ } else {
+ snp->is_swundi = TRUE;
+
+ if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
+ snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;
+ } else {
+ snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);
+ }
+ }
+ //
+ // Allocate a global CPB and DB buffer for this UNDI interface.
+ // we do this because:
+ //
+ // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
+ // within 2GB limit, create them here and map them so that when undi calls
+ // v2p callback to check if the physical address is < 2gb, we will pass.
+ //
+ // -This is not a requirement for 3.1 or later UNDIs but the code looks
+ // simpler if we use the same cpb, db variables for both old and new undi
+ // interfaces from all the SNP interface calls (we don't map the buffers
+ // for the newer undi interfaces though)
+ // .
+ // -it is OK to allocate one global set of CPB, DB pair for each UNDI
+ // interface as EFI does not multi-task and so SNP will not be re-entered!
+ //
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (4096),
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
+ goto Error_DeleteSNP;
+ }
+
+ if (snp->IsOldUndi) {
+ Size = SNP_MEM_PAGES (4096);
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &snp->CpbUnmap
+ );
+
+ ASSERT (paddr);
+
+ snp->cpb = (VOID *) (UINTN) paddr;
+ snp->db = (VOID *) ((UINTN) paddr + 2048);
+ } else {
+ snp->cpb = (VOID *) (UINTN) addr;
+ snp->db = (VOID *) ((UINTN) addr + 2048);
+ }
+ //
+ // pxe_start call is going to give the callback functions to UNDI, these callback
+ // functions use the BarIndex values from the snp structure, so these must be initialized
+ // with default values before doing a pxe_start. The correct values can be obtained after
+ // getting the config information from UNDI
+ //
+ snp->MemoryBarIndex = 0;
+ snp->IoBarIndex = 1;
+
+ //
+ // we need the undi init information many times in this snp code, just get it
+ // once here and store it in the snp driver structure. to get Init Info
+ // from UNDI we have to start undi first.
+ //
+ Status = pxe_start (snp);
+
+ if (Status != EFI_SUCCESS) {
+ goto Error_DeleteCPBDB;
+ }
+
+ snp->cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.DBsize = sizeof snp->init_info;
+ snp->cdb.DBaddr = (UINT64) (UINTN) &snp->init_info;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ //
+ // Save the INIT Stat Code...
+ //
+ InitStatFlags = snp->cdb.StatFlags;
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nsnp->undi.init_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));
+ pxe_stop (snp);
+ goto Error_DeleteCPBDB;
+ }
+
+ snp->cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.DBsize = sizeof ConfigInfo;
+ snp->cdb.DBaddr = (UINT64) (UINTN) &ConfigInfo;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nsnp->undi.config_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));
+ pxe_stop (snp);
+ goto Error_DeleteCPBDB;
+ }
+ //
+ // Find the correct BAR to do IO.
+ //
+ //
+ // Enumerate through the PCI BARs for the device to determine which one is
+ // the IO BAR. Save the index of the BAR into the adapter info structure.
+ // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped
+ //
+ ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];
+ TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];
+ for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
+ if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
+ //
+ // This is a 64-bit memory bar, skip this and the
+ // next bar as well.
+ //
+ TempBar++;
+ }
+
+ if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
+ snp->IoBarIndex = BarIndex;
+ break;
+ }
+
+ TempBar++;
+ }
+
+ //
+ // We allocate 2 more global buffers for undi 3.0 interface. We use these
+ // buffers to pass to undi when the user buffers are beyond 4GB.
+ // UNDI 3.0 wants all the addresses passed to it to be
+ // within 2GB limit, create them here and map them so that when undi calls
+ // v2p callback to check if the physical address is < 2gb, we will pass.
+ //
+ // For 3.1 and later UNDIs, we do not do this because undi is
+ // going to call the map() callback if and only if it wants to use the
+ // device address for any address it receives.
+ //
+ if (snp->IsOldUndi) {
+ //
+ // buffer for receive
+ //
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Size,
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nCould not allocate receive buffer.\n"));
+ goto Error_DeleteCPBDB;
+ }
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &snp->ReceiveBufUnmap
+ );
+
+ ASSERT (paddr);
+
+ snp->receive_buf = (UINT8 *) (UINTN) paddr;
+
+ //
+ // buffer for fill_header
+ //
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Size,
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nCould not allocate fill_header buffer.\n"));
+ goto Error_DeleteRCVBuf;
+ }
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &snp->FillHdrBufUnmap
+ );
+
+ ASSERT (paddr);
+ snp->fill_hdr_buf = (UINT8 *) (UINTN) paddr;
+ }
+ //
+ // Initialize simple network protocol mode structure
+ //
+ snp->mode.State = EfiSimpleNetworkStopped;
+ snp->mode.HwAddressSize = snp->init_info.HWaddrLen;
+ snp->mode.MediaHeaderSize = snp->init_info.MediaHeaderLen;
+ snp->mode.MaxPacketSize = snp->init_info.FrameDataLen;
+ snp->mode.NvRamAccessSize = snp->init_info.NvWidth;
+ snp->mode.NvRamSize = snp->init_info.NvCount * snp->mode.NvRamAccessSize;
+ snp->mode.IfType = snp->init_info.IFtype;
+ snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;
+ snp->mode.MCastFilterCount = 0;
+
+ switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
+ case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
+ snp->mode.MediaPresentSupported = TRUE;
+ break;
+
+ case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
+ default:
+ snp->mode.MediaPresentSupported = FALSE;
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
+ snp->mode.MacAddressChangeable = TRUE;
+ } else {
+ snp->mode.MacAddressChangeable = FALSE;
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
+ snp->mode.MultipleTxSupported = TRUE;
+ } else {
+ snp->mode.MultipleTxSupported = FALSE;
+ }
+
+ snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+
+ }
+
+ if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+ }
+
+ snp->mode.ReceiveFilterSetting = 0;
+
+ //
+ // need to get the station address to save in the mode structure. we need to
+ // initialize the UNDI first for this.
+ //
+ snp->tx_rx_bufsize = snp->init_info.MemoryRequired;
+ Status = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
+
+ if (Status) {
+ pxe_stop (snp);
+ goto Error_DeleteHdrBuf;
+ }
+
+ Status = pxe_get_stn_addr (snp);
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr() failed.\n"));
+ pxe_shutdown (snp);
+ pxe_stop (snp);
+ goto Error_DeleteHdrBuf;
+ }
+
+ snp->mode.MediaPresent = FALSE;
+
+ //
+ // We should not leave UNDI started and initialized here. this DriverStart()
+ // routine must only find and attach the SNP interface to UNDI layer that it
+ // finds on the given handle!
+ // The UNDI layer will be started when upper layers call snp->start.
+ // How ever, this DriverStart() must fill up the snp mode structure which
+ // contains the MAC address of the NIC. For this reason we started and
+ // initialized UNDI here, now we are done, do a shutdown and stop of the
+ // UNDI interface!
+ //
+ pxe_shutdown (snp);
+ pxe_stop (snp);
+
+ //
+ // add SNP to the undi handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(snp->snp)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+Error_DeleteHdrBuf:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->FillHdrBufUnmap
+ );
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ Size,
+ snp->fill_hdr_buf
+ );
+ }
+
+Error_DeleteRCVBuf:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->ReceiveBufUnmap
+ );
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ Size,
+ snp->receive_buf
+ );
+
+ }
+
+Error_DeleteCPBDB:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->CpbUnmap
+ );
+ }
+
+ Status = mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (4096),
+ snp->cpb
+ );
+
+Error_DeleteSNP:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->SnpDriverUnmap
+ );
+ }
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ snp
+ );
+NiiError:
+ if (!UndiNew) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
+ SNP_DRIVER *Snp;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &SnpProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ &Snp->snp
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!Snp->IsOldUndi) {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ pxe_shutdown (Snp);
+ pxe_stop (Snp);
+
+ if (Snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->FillHdrBufUnmap
+ );
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen),
+ Snp->fill_hdr_buf
+ );
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->ReceiveBufUnmap
+ );
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen + Snp->init_info.FrameDataLen),
+ Snp->receive_buf
+ );
+
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->CpbUnmap
+ );
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->SnpDriverUnmap
+ );
+ }
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (4096),
+ Snp->cpb
+ );
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ Snp
+ );
+
+ return Status;
+}
+
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h
new file mode 100644
index 0000000..05c5a8b
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.h
@@ -0,0 +1,410 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ snp.h
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+--*/
+#ifndef _SNP_H
+#define _SNP_H
+
+
+#include "IndustryStandard/pci22.h"
+
+#define SNP_DEBUG 0
+#define FOUR_GIGABYTES (UINT64) 0x100000000ULL
+
+#if SNP_DEBUG
+#undef D_NET
+#define D_NET D_WARN
+#define SNP_PRINT(DebugInfo) Print (DebugInfo)
+#else
+#define SNP_PRINT(DebugInfo)
+#endif
+
+#define SNP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('s', 'n', 'd', 's')
+#define MAX_MAP_LENGTH 100
+
+#define PCI_BAR_IO_MASK 0x00000003
+#define PCI_BAR_IO_MODE 0x00000001
+
+#define PCI_BAR_MEM_MASK 0x0000000F
+#define PCI_BAR_MEM_MODE 0x00000000
+#define PCI_BAR_MEM_64BIT 0x00000004
+
+typedef struct {
+ UINT32 Signature;
+ EFI_LOCK lock;
+
+ EFI_SIMPLE_NETWORK_PROTOCOL snp;
+ EFI_SIMPLE_NETWORK_MODE mode;
+
+ EFI_HANDLE device_handle;
+ EFI_DEVICE_PATH_PROTOCOL *device_path;
+
+ //
+ // Local instance data needed by SNP driver
+ //
+ // Pointer to S/W UNDI API entry point
+ // This will be NULL for H/W UNDI
+ //
+ EFI_STATUS (*issue_undi32_command) (UINT64 cdb);
+
+ BOOLEAN is_swundi;
+
+ //
+ // undi interface number, if one undi manages more nics
+ //
+ PXE_IFNUM if_num;
+
+ //
+ // Allocated tx/rx buffer that was passed to UNDI Initialize.
+ //
+ UINT32 tx_rx_bufsize;
+ VOID *tx_rx_buffer;
+ //
+ // mappable buffers for receive and fill header for undi3.0
+ // these will be used if the user buffers are above 4GB limit (instead of
+ // mapping the user buffers)
+ //
+ UINT8 *receive_buf;
+ VOID *ReceiveBufUnmap;
+ UINT8 *fill_hdr_buf;
+ VOID *FillHdrBufUnmap;
+
+ EFI_PCI_IO_PROTOCOL *IoFncs;
+ UINT8 IoBarIndex;
+ UINT8 MemoryBarIndex;
+ BOOLEAN IsOldUndi; // true for EFI1.0 UNDI (3.0) drivers
+ //
+ // Buffers for command descriptor block, command parameter block
+ // and data block.
+ //
+ PXE_CDB cdb;
+ VOID *cpb;
+ VOID *CpbUnmap;
+ VOID *db;
+
+ //
+ // UNDI structure, we need to remember the init info for a long time!
+ //
+ PXE_DB_GET_INIT_INFO init_info;
+
+ VOID *SnpDriverUnmap;
+ //
+ // when ever we map an address, we must remember it's address and the un-map
+ // cookie so that we can unmap later
+ //
+ struct s_map_list {
+ EFI_PHYSICAL_ADDRESS virt;
+ VOID *map_cookie;
+ } map_list[MAX_MAP_LENGTH];
+}
+SNP_DRIVER;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, snp, SNP_DRIVER_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName;
+extern EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding;
+
+//
+// Virtual to physical mapping for all UNDI 3.0s.
+//
+extern struct s_v2p {
+ struct s_v2p *next;
+ VOID *vaddr;
+ UINTN bsize;
+ EFI_PHYSICAL_ADDRESS paddr;
+ VOID *unmap;
+}
+*_v2p;
+
+EFI_STATUS
+add_v2p (
+ struct s_v2p **v2p,
+ EFI_PCI_IO_PROTOCOL_OPERATION type,
+ VOID *vaddr,
+ UINTN bsize
+ )
+;
+
+EFI_STATUS
+find_v2p (
+ struct s_v2p **v2p,
+ VOID *vaddr
+ )
+;
+
+EFI_STATUS
+del_v2p (
+ VOID *vaddr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_block_30 (
+ IN UINT32 Enable
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_delay_30 (
+ IN UINT64 MicroSeconds
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_memio_30 (
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddress,
+ IN OUT UINT64 BufferPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_v2p_30 (
+ IN UINT64 CpuAddr,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_block (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_delay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_memio (
+ IN UINT64 UniqueId,
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddr,
+ IN OUT UINT64 BufferPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_map (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_unmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr // not a pointer to device address
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_sync (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr // not a pointer to device address
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN UINTN extra_rx_buffer_size OPTIONAL,
+ IN UINTN extra_tx_buffer_size OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ExtendedVerification
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive_filters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINT32 enable,
+ IN UINT32 disable,
+ IN BOOLEAN reset_mcast_filter,
+ IN UINTN mcast_filter_count OPTIONAL,
+ IN EFI_MAC_ADDRESS * mcast_filter OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_station_address (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN reset,
+ IN EFI_MAC_ADDRESS *new OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN reset,
+ IN OUT UINTN *statistics_size OPTIONAL,
+ IN OUT EFI_NETWORK_STATISTICS * statistics_table OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_mcast_ip_to_mac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_nvdata (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN read_write,
+ IN UINTN offset,
+ IN UINTN buffer_size,
+ IN OUT VOID *buffer
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_get_status (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINT32 *interrupt_status OPTIONAL,
+ OUT VOID **tx_buffer OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINTN header_size,
+ IN UINTN buffer_size,
+ IN VOID *buffer,
+ IN EFI_MAC_ADDRESS * src_addr OPTIONAL,
+ IN EFI_MAC_ADDRESS * dest_addr OPTIONAL,
+ IN UINT16 *protocol OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINTN *header_size OPTIONAL,
+ IN OUT UINTN *buffer_size,
+ OUT VOID *buffer,
+ OUT EFI_MAC_ADDRESS * src_addr OPTIONAL,
+ OUT EFI_MAC_ADDRESS * dest_addr OPTIONAL,
+ OUT UINT16 *protocol OPTIONAL
+ )
+;
+
+typedef
+EFI_STATUS
+(*issue_undi32_command) (
+ UINT64 cdb
+ );
+typedef
+VOID
+(*ptr) (
+ VOID
+ );
+
+#define SNP_MEM_PAGES(x) (((x) - 1) / 4096 + 1)
+
+#if SNP_DEBUG
+extern
+VOID
+snp_wait_for_key (
+ VOID
+ )
+;
+#endif
+
+#endif /* _SNP_H */
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c
new file mode 100644
index 0000000..1fab0de
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/start.c
@@ -0,0 +1,191 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ start.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-07 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_start (
+ SNP_DRIVER *snp
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to start the interface and changes the snp state!
+
+Arguments:
+ snp - pointer to snp driver structure
+
+Returns:
+
+--*/
+{
+ PXE_CPB_START_30 *cpb;
+ PXE_CPB_START_31 *cpb_31;
+
+ cpb = snp->cpb;
+ cpb_31 = snp->cpb;
+ //
+ // Initialize UNDI Start CDB for H/W UNDI
+ //
+ snp->cdb.OpCode = PXE_OPCODE_START;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Make changes to H/W UNDI Start CDB if this is
+ // a S/W UNDI.
+ //
+ if (snp->is_swundi) {
+ if (snp->IsOldUndi) {
+ snp->cdb.CPBsize = sizeof (PXE_CPB_START_30);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+
+ cpb->Delay = (UINT64) &snp_undi32_callback_delay_30;
+ cpb->Block = (UINT64) &snp_undi32_callback_block_30;
+
+ //
+ // Virtual == Physical. This can be set to zero.
+ //
+ cpb->Virt2Phys = (UINT64) &snp_undi32_callback_v2p_30;
+ cpb->Mem_IO = (UINT64) &snp_undi32_callback_memio_30;
+ } else {
+ snp->cdb.CPBsize = sizeof (PXE_CPB_START_31);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb_31;
+
+ cpb_31->Delay = (UINT64) &snp_undi32_callback_delay;
+ cpb_31->Block = (UINT64) &snp_undi32_callback_block;
+
+ //
+ // Virtual == Physical. This can be set to zero.
+ //
+ cpb_31->Virt2Phys = (UINT64) 0;
+ cpb_31->Mem_IO = (UINT64) &snp_undi32_callback_memio;
+
+ cpb_31->Map_Mem = (UINT64) &snp_undi32_callback_map;
+ cpb_31->UnMap_Mem = (UINT64) &snp_undi32_callback_unmap;
+ cpb_31->Sync_Mem = (UINT64) &snp_undi32_callback_sync;
+
+ cpb_31->Unique_ID = (UINT64) (UINTN) snp;
+ }
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.start() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI could not be started. Return UNDI error.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.start() %xh:%xh\n",
+ snp->cdb.StatCode,
+ snp->cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set simple network state to Started and return success.
+ //
+ snp->mode.State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for starting the interface
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_start routine to actually do start undi interface
+
+Arguments:
+ This - context pointer
+
+Returns:
+ EFI_INVALID_PARAMETER - "This" is Null
+ - No SNP driver can be extracted from "This"
+ EFI_ALREADY_STARTED - The state of SNP is EfiSimpleNetworkStarted
+ or EfiSimpleNetworkInitialized
+ EFI_DEVICE_ERROR - The state of SNP is other than EfiSimpleNetworkStarted,
+ EfiSimpleNetworkInitialized, and EfiSimpleNetworkStopped
+ EFI_SUCCESS - UNDI interface is succesfully started
+ Other - Error occurs while calling pxe_start function.
+
+--*/
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (Snp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Snp->mode.State) {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ return EFI_ALREADY_STARTED;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = pxe_start (Snp);
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // clear the map_list in SNP structure
+ //
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ Snp->map_list[Index].virt = 0;
+ Snp->map_list[Index].map_cookie = 0;
+ }
+
+ Snp->mode.MCastFilterCount = 0;
+
+ return Status;
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c
new file mode 100644
index 0000000..2d143ef
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/station_address.c
@@ -0,0 +1,248 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ station_address.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_get_stn_addr (
+ SNP_DRIVER *snp
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to read the MAC address of the NIC and updates the
+ mode structure with the address.
+
+Arguments:
+ snp - pointer to snp driver structure
+
+Returns:
+
+--*/
+{
+ PXE_DB_STATION_ADDRESS *db;
+
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;
+
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS);
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.station_addr() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set new station address in SNP->Mode structure and return success.
+ //
+ CopyMem (
+ &(snp->mode.CurrentAddress),
+ &db->StationAddr,
+ snp->mode.HwAddressSize
+ );
+
+ CopyMem (
+ &snp->mode.BroadcastAddress,
+ &db->BroadcastAddr,
+ snp->mode.HwAddressSize
+ );
+
+ CopyMem (
+ &snp->mode.PermanentAddress,
+ &db->PermanentAddr,
+ snp->mode.HwAddressSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+pxe_set_stn_addr (
+ SNP_DRIVER *snp,
+ EFI_MAC_ADDRESS *NewMacAddr
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to set a new MAC address for the NIC,
+
+Arguments:
+ snp - pointer to snp driver structure
+ NewMacAddr - pointer to a mac address to be set for the nic, if this is NULL
+ then this routine resets the mac address to the NIC's original
+ address.
+
+Returns:
+
+--*/
+{
+ PXE_CPB_STATION_ADDRESS *cpb;
+ PXE_DB_STATION_ADDRESS *db;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
+
+ if (NewMacAddr == NULL) {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_RESET;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ } else {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;
+ //
+ // even though the OPFLAGS are set to READ, supplying a new address
+ // in the CPB will make undi change the mac address to the new one.
+ //
+ CopyMem (&cpb->StationAddr, NewMacAddr, snp->mode.HwAddressSize);
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_STATION_ADDRESS);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+ }
+
+ snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS);
+ snp->cdb.DBaddr = (UINT64) (UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.station_addr() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // read the changed address and save it in SNP->Mode structure
+ //
+ pxe_get_stn_addr (snp);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_station_address (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN ResetFlag,
+ IN EFI_MAC_ADDRESS * NewMacAddr OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for changing the NIC's mac address.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the above routines to actually do the work
+
+Arguments:
+ this - context pointer
+ NewMacAddr - pointer to a mac address to be set for the nic, if this is NULL
+ then this routine resets the mac address to the NIC's original
+ address.
+ ResetFlag - If true, the mac address will change to NIC's original address
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check for invalid parameter combinations.
+ //
+ if (!ResetFlag && NewMacAddr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ResetFlag) {
+ Status = pxe_set_stn_addr (snp, NULL);
+ } else {
+ Status = pxe_set_stn_addr (snp, NewMacAddr);
+
+ }
+
+ return Status;
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c
new file mode 100644
index 0000000..1c148a7
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/statistics.c
@@ -0,0 +1,193 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ statistics.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+--*/
+
+
+#include "Snp.h"
+
+EFI_STATUS
+EFIAPI
+snp_undi32_statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN ResetFlag,
+ IN OUT UINTN *StatTableSizePtr OPTIONAL,
+ IN OUT EFI_NETWORK_STATISTICS * StatTablePtr OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for getting the NIC's statistics.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_ routine to actually do the
+
+Arguments:
+ this - context pointer
+ ResetFlag - true to reset the NIC's statistics counters to zero.
+ StatTableSizePtr - pointer to the statistics table size
+ StatTablePtr - pointer to the statistics table
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ PXE_DB_STATISTICS *db;
+ UINT64 *stp;
+ UINT64 mask;
+ UINTN size;
+ UINTN n;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // if we are not resetting the counters, we have to have a valid stat table
+ // with >0 size. if no reset, no table and no size, return success.
+ //
+ if (!ResetFlag && StatTableSizePtr == NULL) {
+ return StatTablePtr ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
+ }
+ //
+ // Initialize UNDI Statistics CDB
+ //
+ snp->cdb.OpCode = PXE_OPCODE_STATISTICS;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ if (ResetFlag) {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_RESET;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ db = snp->db;
+ } else {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_READ;
+ snp->cdb.DBsize = sizeof (PXE_DB_STATISTICS);
+ snp->cdb.DBaddr = (UINT64) (UINTN) (db = snp->db);
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.statistics() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.statistics() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_UNSUPPORTED;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.statistics() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ResetFlag) {
+ return EFI_SUCCESS;
+ }
+
+ if (StatTablePtr == NULL) {
+ *StatTableSizePtr = sizeof (EFI_NETWORK_STATISTICS);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Convert the UNDI statistics information to SNP statistics
+ // information.
+ //
+ ZeroMem (StatTablePtr, *StatTableSizePtr);
+ stp = (UINT64 *) StatTablePtr;
+ size = 0;
+
+ for (n = 0, mask = 1; n < 64; n++, mask = LShiftU64 (mask, 1), stp++) {
+ //
+ // There must be room for a full UINT64. Partial
+ // numbers will not be stored.
+ //
+ if ((n + 1) * sizeof (UINT64) > *StatTableSizePtr) {
+ break;
+ }
+
+ if (db->Supported & mask) {
+ *stp = db->Data[n];
+ size = n + 1;
+ } else {
+ SetMem (stp, sizeof (UINT64), 0xFF);
+ }
+ }
+ //
+ // Compute size up to last supported statistic.
+ //
+ while (++n < 64) {
+ if (db->Supported & (mask = LShiftU64 (mask, 1))) {
+ size = n;
+ }
+ }
+
+ size *= sizeof (UINT64);
+
+ if (*StatTableSizePtr >= size) {
+ *StatTableSizePtr = size;
+ return EFI_SUCCESS;
+ } else {
+ *StatTableSizePtr = size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c
new file mode 100644
index 0000000..c68731d
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/stop.c
@@ -0,0 +1,120 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ stop.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-09 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_stop (
+ SNP_DRIVER *snp
+ )
+/*++
+
+Routine Description:
+ this routine calls undi to stop the interface and changes the snp state
+
+Arguments:
+ snp - pointer to snp driver structure
+
+Returns:
+
+--*/
+{
+ snp->cdb.OpCode = PXE_OPCODE_STOP;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.stop() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi.stop() %xh:%xh\n",
+ snp->cdb.StatCode,
+ snp->cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set simple network state to Started and return success.
+ //
+ snp->mode.State = EfiSimpleNetworkStopped;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+/*++
+
+Routine Description:
+ This is the SNP interface routine for stopping the interface.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_stop routine to actually stop the undi interface
+
+Arguments:
+ this - context pointer
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ return pxe_stop (snp);
+}
diff --git a/EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c
new file mode 100644
index 0000000..b48e2c7
--- /dev/null
+++ b/EdkModulePkg/Universal/Network/Snp32_64/Dxe/transmit.c
@@ -0,0 +1,396 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+
+ transmit.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+--*/
+
+
+#include "snp.h"
+
+EFI_STATUS
+pxe_fillheader (
+ SNP_DRIVER *snp,
+ VOID *MacHeaderPtr,
+ UINTN MacHeaderSize,
+ VOID *BufferPtr,
+ UINTN BufferLength,
+ EFI_MAC_ADDRESS *DestinationAddrPtr,
+ EFI_MAC_ADDRESS *SourceAddrPtr,
+ UINT16 *ProtocolPtr
+ )
+/*++
+
+Routine Description:
+ This routine calls undi to create the meadia header for the given data buffer.
+
+Arguments:
+ snp - pointer to SNP driver structure
+ MacHeaderPtr - address where the media header will be filled in.
+ MacHeaderSize - size of the memory at MacHeaderPtr
+ BufferPtr - data buffer pointer
+ BufferLength - Size of data in the BufferPtr
+ DestinationAddrPtr - address of the destination mac address buffer
+ SourceAddrPtr - address of the source mac address buffer
+ ProtocolPtr - address of the protocol type
+
+Returns:
+ EFI_SUCCESS - if successfully completed the undi call
+ Other - error return from undi call.
+
+--*/
+{
+ PXE_CPB_FILL_HEADER_FRAGMENTED *cpb;
+ EFI_STATUS Status;
+ struct s_v2p *pkt_v2p;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ if (SourceAddrPtr) {
+ CopyMem (
+ (VOID *) cpb->SrcAddr,
+ (VOID *) SourceAddrPtr,
+ snp->mode.HwAddressSize
+ );
+ } else {
+ CopyMem (
+ (VOID *) cpb->SrcAddr,
+ (VOID *) &(snp->mode.CurrentAddress),
+ snp->mode.HwAddressSize
+ );
+ }
+
+ CopyMem (
+ (VOID *) cpb->DestAddr,
+ (VOID *) DestinationAddrPtr,
+ snp->mode.HwAddressSize
+ );
+
+ //
+ // we need to do the byte swapping
+ //
+ cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);
+
+ cpb->PacketLen = (UINT32) (BufferLength);
+ cpb->MediaHeaderLen = (UINT16) MacHeaderSize;
+
+ cpb->FragCnt = 2;
+ cpb->reserved = 0;
+
+ cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) MacHeaderPtr;
+ cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize;
+ cpb->FragDesc[1].FragAddr = (UINT64) (UINTN) BufferPtr;
+ cpb->FragDesc[1].FragLen = (UINT32) BufferLength;
+
+ cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;
+
+ if (snp->IsOldUndi) {
+ TempData = (UINT64) (UINTN) MacHeaderPtr;
+ if (TempData >= FOUR_GIGABYTES) {
+ cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) snp->fill_hdr_buf;
+ cpb->FragDesc[0].FragLen = (UINT32) snp->init_info.MediaHeaderLen;
+ }
+
+ TempData = (UINT64) (UINTN) (BufferPtr);
+ if (TempData >= FOUR_GIGABYTES) {
+ //
+ // Let the device just read this buffer
+ //
+ Status = add_v2p (
+ &pkt_v2p,
+ EfiPciIoOperationBusMasterRead,
+ BufferPtr,
+ BufferLength
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // give the virtual address to UNDI and it will call back on Virt2Phys
+ // to get the mapped address, if it needs it
+ //
+ cpb->FragDesc[1].FragLen = (UINT32) pkt_v2p->bsize;
+ }
+ }
+
+ snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER;
+ snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;
+
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->IsOldUndi) {
+ TempData = (UINT64) (UINTN) (BufferPtr);
+ if (TempData >= FOUR_GIGABYTES) {
+ del_v2p (BufferPtr);
+ }
+ //
+ // if we used the global buffer for header, copy the contents
+ //
+ TempData = (UINT64) (UINTN) MacHeaderPtr;
+ if (TempData >= FOUR_GIGABYTES) {
+ CopyMem (
+ MacHeaderPtr,
+ snp->fill_hdr_buf,
+ snp->init_info.MediaHeaderLen
+ );
+ }
+ }
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ return EFI_SUCCESS;
+
+ case PXE_STATCODE_INVALID_PARAMETER:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.fill_header() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.fill_header() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+EFI_STATUS
+pxe_transmit (
+ SNP_DRIVER *snp,
+ VOID *BufferPtr,
+ UINTN BufferLength
+ )
+/*++
+
+Routine Description:
+ This routine calls undi to transmit the given data buffer
+
+Arguments:
+ snp - pointer to SNP driver structure
+ BufferPtr - data buffer pointer
+ BufferLength - Size of data in the BufferPtr
+
+Returns:
+ EFI_SUCCESS - if successfully completed the undi call
+ Other - error return from undi call.
+
+--*/
+{
+ PXE_CPB_TRANSMIT *cpb;
+ EFI_STATUS Status;
+ struct s_v2p *v2p;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ cpb->FrameAddr = (UINT64) (UINTN) BufferPtr;
+ cpb->DataLen = (UINT32) BufferLength;
+
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ //
+ // we need to create a mapping now and give it to the undi when it calls
+ // the Virt2Phys on this address.
+ // this is a transmit, just map it for the device to READ
+ //
+ Status = add_v2p (
+ &v2p,
+ EfiPciIoOperationBusMasterRead,
+ BufferPtr,
+ BufferLength
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ cpb->DataLen = (UINT32) v2p->bsize;
+ }
+
+ cpb->MediaheaderLen = 0;
+ cpb->reserved = 0;
+
+ snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT);
+ snp->cdb.CPBaddr = (UINT64) (UINTN) cpb;
+
+ snp->cdb.OpCode = PXE_OPCODE_TRANSMIT;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() "));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %X", snp->cdb.DBaddr));
+ DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %X\n", cpb->FrameAddr));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() "));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));
+
+ //
+ // we will unmap the buffers in get_status call, not here
+ //
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ return EFI_SUCCESS;
+
+ case PXE_STATCODE_QUEUE_FULL:
+ case PXE_STATCODE_BUSY:
+ Status = EFI_NOT_READY;
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.transmit() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+snp_undi32_transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINTN MacHeaderSize,
+ IN UINTN BufferLength,
+ IN VOID *BufferPtr,
+ IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
+ IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
+ IN UINT16 *ProtocolPtr OPTIONAL
+ )
+/*++
+
+Routine Description:
+ This is the snp interface routine for transmitting a packet. this routine
+ basically retrieves the snp structure, checks the snp state and calls
+ pxe_fill_header and pxe_transmit calls to complete the transmission.
+
+Arguments:
+ this - pointer to SNP driver context
+ MacHeaderSize - size of the memory at MacHeaderPtr
+ BufferLength - Size of data in the BufferPtr
+ BufferPtr - data buffer pointer
+ SourceAddrPtr - address of the source mac address buffer
+ DestinationAddrPtr - address of the destination mac address buffer
+ ProtocolPtr - address of the protocol type
+
+Returns:
+ EFI_SUCCESS - if successfully completed the undi call
+ Other - error return from undi call.
+
+--*/
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (BufferPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferLength < snp->mode.MediaHeaderSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // if the MacHeaderSize is non-zero, we need to fill up the header and for that
+ // we need the destination address and the protocol
+ //
+ if (MacHeaderSize != 0) {
+ if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = pxe_fillheader (
+ snp,
+ BufferPtr,
+ MacHeaderSize,
+ (UINT8 *) BufferPtr + MacHeaderSize,
+ BufferLength - MacHeaderSize,
+ DestinationAddrPtr,
+ SourceAddrPtr,
+ ProtocolPtr
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ }
+
+ return pxe_transmit (snp, BufferPtr, BufferLength);
+}